mirror of
https://github.com/AikidoSec/safe-chain.git
synced 2026-05-26 12:10:49 +00:00
Improve cli output.
This commit is contained in:
parent
32f5ef9b16
commit
ccaa7934ee
9 changed files with 41 additions and 25 deletions
|
|
@ -5,6 +5,7 @@ import { ui } from "./environment/userInteraction.js";
|
||||||
import { getPackageManager } from "./packagemanager/currentPackageManager.js";
|
import { getPackageManager } from "./packagemanager/currentPackageManager.js";
|
||||||
import { initializeCliArguments } from "./config/cliArguments.js";
|
import { initializeCliArguments } from "./config/cliArguments.js";
|
||||||
import { createSafeChainProxy } from "./registryProxy/registryProxy.js";
|
import { createSafeChainProxy } from "./registryProxy/registryProxy.js";
|
||||||
|
import chalk from "chalk";
|
||||||
|
|
||||||
export async function main(args) {
|
export async function main(args) {
|
||||||
const proxy = createSafeChainProxy();
|
const proxy = createSafeChainProxy();
|
||||||
|
|
@ -27,5 +28,12 @@ export async function main(args) {
|
||||||
await proxy.stopServer();
|
await proxy.stopServer();
|
||||||
proxy.verifyNoMaliciousPackages();
|
proxy.verifyNoMaliciousPackages();
|
||||||
|
|
||||||
|
ui.emptyLine();
|
||||||
|
ui.writeInformation(
|
||||||
|
`${chalk.green(
|
||||||
|
"✔"
|
||||||
|
)} Safe-chain: Command completed, no malicious packages found.`
|
||||||
|
);
|
||||||
|
|
||||||
return result.status;
|
return result.status;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ export async function scanCommand(args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!audit || audit.isAllowed) {
|
if (!audit || audit.isAllowed) {
|
||||||
spinner.succeed("Safe-chain: No malicious packages detected.");
|
spinner.stop();
|
||||||
} else {
|
} else {
|
||||||
printMaliciousChanges(audit.disallowedChanges, spinner);
|
printMaliciousChanges(audit.disallowedChanges, spinner);
|
||||||
await onMalwareFound();
|
await onMalwareFound();
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ describe("scanCommand", async () => {
|
||||||
setText: () => {},
|
setText: () => {},
|
||||||
succeed: () => {},
|
succeed: () => {},
|
||||||
fail: () => {},
|
fail: () => {},
|
||||||
|
stop: () => {},
|
||||||
}));
|
}));
|
||||||
const mockConfirm = mock.fn(() => true);
|
const mockConfirm = mock.fn(() => true);
|
||||||
let malwareAction = MALWARE_ACTION_PROMPT;
|
let malwareAction = MALWARE_ACTION_PROMPT;
|
||||||
|
|
@ -88,29 +89,31 @@ describe("scanCommand", async () => {
|
||||||
const { scanCommand } = await import("./index.js");
|
const { scanCommand } = await import("./index.js");
|
||||||
|
|
||||||
it("should succeed when there are no changes", async () => {
|
it("should succeed when there are no changes", async () => {
|
||||||
let successMessageWasSet = false;
|
let progressWasStopped = false;
|
||||||
mockStartProcess.mock.mockImplementationOnce(() => ({
|
mockStartProcess.mock.mockImplementationOnce(() => ({
|
||||||
setText: () => {},
|
setText: () => {},
|
||||||
succeed: () => {
|
succeed: () => {},
|
||||||
successMessageWasSet = true;
|
|
||||||
},
|
|
||||||
fail: () => {},
|
fail: () => {},
|
||||||
|
stop: () => {
|
||||||
|
progressWasStopped = true;
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
mockGetDependencyUpdatesForCommand.mock.mockImplementation(() => []);
|
mockGetDependencyUpdatesForCommand.mock.mockImplementation(() => []);
|
||||||
|
|
||||||
await scanCommand(["install", "lodash"]);
|
await scanCommand(["install", "lodash"]);
|
||||||
|
|
||||||
assert.equal(successMessageWasSet, true);
|
assert.equal(progressWasStopped, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should succeed when changes are not malicious", async () => {
|
it("should succeed when changes are not malicious", async () => {
|
||||||
let successMessageWasSet = false;
|
let progressWasStopped = false;
|
||||||
mockStartProcess.mock.mockImplementationOnce(() => ({
|
mockStartProcess.mock.mockImplementationOnce(() => ({
|
||||||
setText: () => {},
|
setText: () => {},
|
||||||
succeed: () => {
|
succeed: () => {},
|
||||||
successMessageWasSet = true;
|
|
||||||
},
|
|
||||||
fail: () => {},
|
fail: () => {},
|
||||||
|
stop: () => {
|
||||||
|
progressWasStopped = true;
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
mockGetDependencyUpdatesForCommand.mock.mockImplementation(() => [
|
mockGetDependencyUpdatesForCommand.mock.mockImplementation(() => [
|
||||||
{ name: "lodash", version: "4.17.21" },
|
{ name: "lodash", version: "4.17.21" },
|
||||||
|
|
@ -118,7 +121,7 @@ describe("scanCommand", async () => {
|
||||||
|
|
||||||
await scanCommand(["install", "lodash"]);
|
await scanCommand(["install", "lodash"]);
|
||||||
|
|
||||||
assert.equal(successMessageWasSet, true);
|
assert.equal(progressWasStopped, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should throw an error when timing out", async () => {
|
it("should throw an error when timing out", async () => {
|
||||||
|
|
@ -129,6 +132,7 @@ describe("scanCommand", async () => {
|
||||||
fail: () => {
|
fail: () => {
|
||||||
failureMessageWasSet = true;
|
failureMessageWasSet = true;
|
||||||
},
|
},
|
||||||
|
stop: () => {},
|
||||||
}));
|
}));
|
||||||
getScanTimeoutMock.mock.mockImplementationOnce(() => 100);
|
getScanTimeoutMock.mock.mockImplementationOnce(() => 100);
|
||||||
mockGetDependencyUpdatesForCommand.mock.mockImplementation(async () => {
|
mockGetDependencyUpdatesForCommand.mock.mockImplementation(async () => {
|
||||||
|
|
@ -149,6 +153,7 @@ describe("scanCommand", async () => {
|
||||||
fail: () => {
|
fail: () => {
|
||||||
failureMessageWasSet = true;
|
failureMessageWasSet = true;
|
||||||
},
|
},
|
||||||
|
stop: () => {},
|
||||||
}));
|
}));
|
||||||
mockGetDependencyUpdatesForCommand.mock.mockImplementation(() => [
|
mockGetDependencyUpdatesForCommand.mock.mockImplementation(() => [
|
||||||
{ name: "malicious", version: "1.0.0" },
|
{ name: "malicious", version: "1.0.0" },
|
||||||
|
|
@ -173,6 +178,7 @@ describe("scanCommand", async () => {
|
||||||
fail: (message) => {
|
fail: (message) => {
|
||||||
failureMessages.push(message);
|
failureMessages.push(message);
|
||||||
},
|
},
|
||||||
|
stop: () => {},
|
||||||
}));
|
}));
|
||||||
getScanTimeoutMock.mock.mockImplementationOnce(() => 100);
|
getScanTimeoutMock.mock.mockImplementationOnce(() => 100);
|
||||||
mockGetDependencyUpdatesForCommand.mock.mockImplementation(async () => {
|
mockGetDependencyUpdatesForCommand.mock.mockImplementation(async () => {
|
||||||
|
|
@ -194,21 +200,22 @@ describe("scanCommand", async () => {
|
||||||
it("should exit immediately when malicious changes are detected in block mode", async () => {
|
it("should exit immediately when malicious changes are detected in block mode", async () => {
|
||||||
// Set malware action to block mode for this test
|
// Set malware action to block mode for this test
|
||||||
malwareAction = MALWARE_ACTION_BLOCK;
|
malwareAction = MALWARE_ACTION_BLOCK;
|
||||||
|
|
||||||
// Reset mock call count
|
// Reset mock call count
|
||||||
mockConfirm.mock.resetCalls();
|
mockConfirm.mock.resetCalls();
|
||||||
|
|
||||||
let failureMessageWasSet = false;
|
let failureMessageWasSet = false;
|
||||||
let exitCode = null;
|
let exitCode = null;
|
||||||
|
|
||||||
mockStartProcess.mock.mockImplementationOnce(() => ({
|
mockStartProcess.mock.mockImplementationOnce(() => ({
|
||||||
setText: () => {},
|
setText: () => {},
|
||||||
succeed: () => {},
|
succeed: () => {},
|
||||||
fail: () => {
|
fail: () => {
|
||||||
failureMessageWasSet = true;
|
failureMessageWasSet = true;
|
||||||
},
|
},
|
||||||
|
stop: () => {},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
mockGetDependencyUpdatesForCommand.mock.mockImplementation(() => [
|
mockGetDependencyUpdatesForCommand.mock.mockImplementation(() => [
|
||||||
{ name: "malicious", version: "1.0.0" },
|
{ name: "malicious", version: "1.0.0" },
|
||||||
]);
|
]);
|
||||||
|
|
@ -241,19 +248,20 @@ describe("scanCommand", async () => {
|
||||||
it("should exit immediately when malicious changes are detected in block mode without prompting", async () => {
|
it("should exit immediately when malicious changes are detected in block mode without prompting", async () => {
|
||||||
// Set malware action to block mode for this test
|
// Set malware action to block mode for this test
|
||||||
malwareAction = MALWARE_ACTION_BLOCK;
|
malwareAction = MALWARE_ACTION_BLOCK;
|
||||||
|
|
||||||
// Reset mock call count
|
// Reset mock call count
|
||||||
mockConfirm.mock.resetCalls();
|
mockConfirm.mock.resetCalls();
|
||||||
|
|
||||||
let processExited = false;
|
let processExited = false;
|
||||||
let userWasPrompted = false;
|
let userWasPrompted = false;
|
||||||
|
|
||||||
mockStartProcess.mock.mockImplementationOnce(() => ({
|
mockStartProcess.mock.mockImplementationOnce(() => ({
|
||||||
setText: () => {},
|
setText: () => {},
|
||||||
succeed: () => {},
|
succeed: () => {},
|
||||||
fail: () => {},
|
fail: () => {},
|
||||||
|
stop: () => {},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
mockGetDependencyUpdatesForCommand.mock.mockImplementation(() => [
|
mockGetDependencyUpdatesForCommand.mock.mockImplementation(() => [
|
||||||
{ name: "malicious", version: "1.0.0" },
|
{ name: "malicious", version: "1.0.0" },
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ describe("E2E: npm coverage using PATH", () => {
|
||||||
const result = await shell.runCommand("npm i axios");
|
const result = await shell.runCommand("npm i axios");
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
result.output.includes("No malicious packages detected."),
|
result.output.includes("no malicious packages found."),
|
||||||
`Output did not include expected text. Output was:\n${result.output}`
|
`Output did not include expected text. Output was:\n${result.output}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ describe("E2E: npm coverage", () => {
|
||||||
const result = await shell.runCommand("npm i axios");
|
const result = await shell.runCommand("npm i axios");
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
result.output.includes("No malicious packages detected."),
|
result.output.includes("no malicious packages found."),
|
||||||
`Output did not include expected text. Output was:\n${result.output}`
|
`Output did not include expected text. Output was:\n${result.output}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ describe("E2E: pnpm coverage", () => {
|
||||||
const result = await shell.runCommand("pnpm add axios");
|
const result = await shell.runCommand("pnpm add axios");
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
result.output.includes("No malicious packages detected."),
|
result.output.includes("no malicious packages found."),
|
||||||
`Output did not include expected text. Output was:\n${result.output}`
|
`Output did not include expected text. Output was:\n${result.output}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ describe("E2E: pnpm coverage", () => {
|
||||||
const result = await shell.runCommand("pnpm add axios");
|
const result = await shell.runCommand("pnpm add axios");
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
result.output.includes("No malicious packages detected."),
|
result.output.includes("no malicious packages found."),
|
||||||
`Output did not include expected text. Output was:\n${result.output}`
|
`Output did not include expected text. Output was:\n${result.output}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ describe("E2E: yarn coverage", () => {
|
||||||
const result = await shell.runCommand("yarn add axios");
|
const result = await shell.runCommand("yarn add axios");
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
result.output.includes("No malicious packages detected."),
|
result.output.includes("no malicious packages found."),
|
||||||
`Output did not include expected text. Output was:\n${result.output}`
|
`Output did not include expected text. Output was:\n${result.output}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ describe("E2E: yarn coverage", () => {
|
||||||
const result = await shell.runCommand("yarn add axios");
|
const result = await shell.runCommand("yarn add axios");
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
result.output.includes("No malicious packages detected."),
|
result.output.includes("no malicious packages found."),
|
||||||
`Output did not include expected text. Output was:\n${result.output}`
|
`Output did not include expected text. Output was:\n${result.output}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue