Merge branch 'main' into manual-setup-teardown-instructions

This commit is contained in:
Sander Declerck 2026-03-26 13:37:20 +01:00
commit 8717e25b79
No known key found for this signature in database
4 changed files with 36 additions and 26 deletions

View file

@ -12,7 +12,7 @@ permissions:
jobs: jobs:
set-version: set-version:
name: Set version number name: Set version number
runs-on: standard-runner-no-rights-public-ip runs-on: open-source-releaser
outputs: outputs:
version: ${{ steps.get_version.outputs.tag }} version: ${{ steps.get_version.outputs.tag }}
is_prerelease: ${{ steps.check_prerelease.outputs.is_prerelease }} is_prerelease: ${{ steps.check_prerelease.outputs.is_prerelease }}
@ -44,8 +44,7 @@ jobs:
publish-binaries: publish-binaries:
name: Publish to GitHub release name: Publish to GitHub release
needs: [set-version, create-binaries] needs: [set-version, create-binaries]
runs-on: standard-runner-no-rights-public-ip runs-on: open-source-releaser
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3

View file

@ -7,7 +7,7 @@
- ✅ **Block malware on developer laptops and CI/CD** - ✅ **Block malware on developer laptops and CI/CD**
- ✅ **Supports npm and PyPI** more package managers coming - ✅ **Supports npm and PyPI** more package managers coming
- ✅ **Blocks packages newer than 24 hours** without breaking your build - ✅ **Blocks packages newer than 48 hours** without breaking your build
- ✅ **Tokenless, free, no build data shared** - ✅ **Tokenless, free, no build data shared**
Aikido Safe Chain supports the following package managers: Aikido Safe Chain supports the following package managers:
@ -113,7 +113,7 @@ The Aikido Safe Chain works by running a lightweight proxy server that intercept
### Minimum package age (npm only) ### Minimum package age (npm only)
For npm packages, Safe Chain temporarily suppresses packages published within the last 24 hours (by default) until they have been validated against malware. This provides an additional security layer during the critical period when newly published packages are most vulnerable to containing undetected threats. You can configure this threshold or bypass this protection entirely - see the [Minimum Package Age Configuration](#minimum-package-age) section below. For npm packages, Safe Chain temporarily suppresses packages published within the last 48 hours (by default) until they have been validated against malware. This provides an additional security layer during the critical period when newly published packages are most vulnerable to containing undetected threats. You can configure this threshold or bypass this protection entirely - see the [Minimum Package Age Configuration](#minimum-package-age) section below.
⚠️ This feature **only applies to npm-based package managers** (npm, npx, yarn, pnpm, pnpx, bun, bunx) and does not apply to Python package managers (uv, pip, pip3, poetry, pipx). ⚠️ This feature **only applies to npm-based package managers** (npm, npx, yarn, pnpm, pnpx, bun, bunx) and does not apply to Python package managers (uv, pip, pip3, poetry, pipx).
@ -183,7 +183,7 @@ You can set the logging level through multiple sources (in order of priority):
## Minimum Package Age ## Minimum Package Age
You can configure how long packages must exist before Safe Chain allows their installation. By default, packages must be at least 24 hours old before they can be installed through npm-based package managers. You can configure how long packages must exist before Safe Chain allows their installation. By default, packages must be at least 48 hours old before they can be installed through npm-based package managers.
### Configuration Options ### Configuration Options

View file

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

View file

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