Merge branch 'main' into feature/minimum-package-age-from-list

This commit is contained in:
Reinier Criel 2026-03-26 14:37:07 -07:00
commit e9db22eb50
13 changed files with 145 additions and 31 deletions

View file

@ -45,7 +45,7 @@ export function setEcoSystem(setting) {
ecosystemSettings.ecoSystem = setting;
}
const defaultMinimumPackageAge = 24;
const defaultMinimumPackageAge = 48;
/** @returns {number} */
export function getMinimumPackageAgeHours() {
// Priority 1: CLI argument

View file

@ -2,18 +2,18 @@ import { describe, it, after } from "node:test";
import assert from "node:assert";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { unlinkSync } from "node:fs";
import { unlinkSync, writeFileSync } from "node:fs";
import { createHash } from "node:crypto";
import {
DOWNLOAD_URLS,
downloadFile,
verifyChecksum,
} from "./downloadAgent.js";
describe("downloadAgent checksums", { timeout: 120_000 }, () => {
const downloadedFiles = [];
describe("downloadAgent", () => {
const tempFiles = [];
after(() => {
for (const file of downloadedFiles) {
for (const file of tempFiles) {
try {
unlinkSync(file);
} catch {
@ -24,22 +24,33 @@ describe("downloadAgent checksums", { timeout: 120_000 }, () => {
for (const [platform, architectures] of Object.entries(DOWNLOAD_URLS)) {
for (const [arch, { url, checksum }] of Object.entries(architectures)) {
it(`${platform}/${arch} checksum matches`, async () => {
const destPath = join(
tmpdir(),
`safe-chain-test-${platform}-${arch}-${Date.now()}`
);
downloadedFiles.push(destPath);
await downloadFile(url, destPath);
const isValid = await verifyChecksum(destPath, checksum);
assert.strictEqual(
isValid,
true,
`Checksum mismatch for ${platform}/${arch} (${url})`
it(`${platform}/${arch} has a valid download definition`, () => {
assert.match(
url,
/^https:\/\/github\.com\/AikidoSec\/safechain-internals\/releases\/download\/v\d+\.\d+\.\d+\/.+/,
);
assert.match(checksum, /^sha256:[a-f0-9]{64}$/);
});
}
}
it("verifies checksum for a local file", async () => {
const destPath = join(tmpdir(), `safe-chain-test-${Date.now()}`);
tempFiles.push(destPath);
writeFileSync(destPath, "safe-chain-test");
const expectedHash = createHash("sha256")
.update("safe-chain-test")
.digest("hex");
assert.equal(
await verifyChecksum(destPath, `sha256:${expectedHash}`),
true,
);
assert.equal(
await verifyChecksum(destPath, `sha256:${"0".repeat(64)}`),
false,
);
});
});

View file

@ -91,9 +91,7 @@ async function setupShell(shell) {
);
} else {
ui.writeError(
`${chalk.bold("- " + shell.name + ":")} ${chalk.red(
"Setup failed",
)}. Please check your ${shell.name} configuration.`,
`${chalk.bold("- " + shell.name + ":")} ${chalk.red("Setup failed")}`,
);
if (error) {
let message = ` Error: ${error.message}`;
@ -102,6 +100,12 @@ async function setupShell(shell) {
}
ui.writeError(message);
}
ui.emptyLine();
ui.writeInformation(` ${chalk.bold("To set up manually:")}`);
for (const instruction of shell.getManualSetupInstructions()) {
ui.writeInformation(` ${instruction}`);
}
ui.emptyLine();
}
return success;

View file

@ -11,6 +11,8 @@ import { ui } from "../environment/userInteraction.js";
* @property {() => boolean} isInstalled
* @property {(tools: import("./helpers.js").AikidoTool[]) => boolean|Promise<boolean>} setup
* @property {(tools: import("./helpers.js").AikidoTool[]) => boolean} teardown
* @property {() => string[]} getManualSetupInstructions
* @property {() => string[]} getManualTeardownInstructions
*/
/**

View file

@ -123,6 +123,22 @@ function cygpathw(path) {
}
}
function getManualTeardownInstructions() {
return [
`Remove the following line from your ~/.bashrc file:`,
` source ~/.safe-chain/scripts/init-posix.sh`,
`Then restart your terminal or run: source ~/.bashrc`,
];
}
function getManualSetupInstructions() {
return [
`Add the following line to your ~/.bashrc file:`,
` source ~/.safe-chain/scripts/init-posix.sh`,
`Then restart your terminal or run: source ~/.bashrc`,
];
}
/**
* @type {import("../shellDetection.js").Shell}
*/
@ -131,4 +147,6 @@ export default {
isInstalled,
setup,
teardown,
getManualSetupInstructions,
getManualTeardownInstructions,
};

View file

@ -66,6 +66,22 @@ function getStartupFile() {
}
}
function getManualTeardownInstructions() {
return [
`Remove the following line from your ~/.config/fish/config.fish file:`,
` source ~/.safe-chain/scripts/init-fish.fish`,
`Then restart your terminal or run: source ~/.config/fish/config.fish`,
];
}
function getManualSetupInstructions() {
return [
`Add the following line to your ~/.config/fish/config.fish file:`,
` source ~/.safe-chain/scripts/init-fish.fish`,
`Then restart your terminal or run: source ~/.config/fish/config.fish`,
];
}
/**
* @type {import("../shellDetection.js").Shell}
*/
@ -74,4 +90,6 @@ export default {
isInstalled,
setup,
teardown,
getManualSetupInstructions,
getManualTeardownInstructions,
};

View file

@ -71,6 +71,22 @@ function getStartupFile() {
}
}
function getManualTeardownInstructions() {
return [
`Remove the following line from your PowerShell profile (run "echo $PROFILE" to find its location):`,
` . "$HOME\\.safe-chain\\scripts\\init-pwsh.ps1"`,
`Then restart your terminal or run: . $PROFILE`,
];
}
function getManualSetupInstructions() {
return [
`Add the following line to your PowerShell profile (run "echo $PROFILE" to find its location):`,
` . "$HOME\\.safe-chain\\scripts\\init-pwsh.ps1"`,
`Then restart your terminal or run: . $PROFILE`,
];
}
/**
* @type {import("../shellDetection.js").Shell}
*/
@ -79,4 +95,6 @@ export default {
isInstalled,
setup,
teardown,
getManualSetupInstructions,
getManualTeardownInstructions,
};

View file

@ -71,6 +71,22 @@ function getStartupFile() {
}
}
function getManualTeardownInstructions() {
return [
`Remove the following line from your PowerShell profile (run "echo $PROFILE" to find its location):`,
` . "$HOME\\.safe-chain\\scripts\\init-pwsh.ps1"`,
`Then restart your terminal or run: . $PROFILE`,
];
}
function getManualSetupInstructions() {
return [
`Add the following line to your PowerShell profile (run "echo $PROFILE" to find its location):`,
` . "$HOME\\.safe-chain\\scripts\\init-pwsh.ps1"`,
`Then restart your terminal or run: . $PROFILE`,
];
}
/**
* @type {import("../shellDetection.js").Shell}
*/
@ -79,4 +95,6 @@ export default {
isInstalled,
setup,
teardown,
getManualSetupInstructions,
getManualTeardownInstructions,
};

View file

@ -66,9 +66,27 @@ function getStartupFile() {
}
}
function getManualTeardownInstructions() {
return [
`Remove the following line from your ~/.zshrc file:`,
` source ~/.safe-chain/scripts/init-posix.sh`,
`Then restart your terminal or run: source ~/.zshrc`,
];
}
function getManualSetupInstructions() {
return [
`Add the following line to your ~/.zshrc file:`,
` source ~/.safe-chain/scripts/init-posix.sh`,
`Then restart your terminal or run: source ~/.zshrc`,
];
}
export default {
name: shellName,
isInstalled,
setup,
teardown,
getManualSetupInstructions,
getManualTeardownInstructions,
};

View file

@ -47,8 +47,14 @@ export async function teardown() {
ui.writeError(
`${chalk.bold("- " + shell.name + ":")} ${chalk.red(
"Teardown failed"
)}. Please check your ${shell.name} configuration.`
)}`
);
ui.emptyLine();
ui.writeInformation(` ${chalk.bold("To tear down manually:")}`);
for (const instruction of shell.getManualTeardownInstructions()) {
ui.writeInformation(` ${instruction}`);
}
ui.emptyLine();
}
}