AikidoSec-safe-chain/test/e2e/certbundle.e2e.spec.js
2026-03-31 09:59:08 +02:00

347 lines
13 KiB
JavaScript

import { describe, it, before, beforeEach, afterEach } from "node:test";
import { DockerTestContainer } from "./DockerTestContainer.js";
import assert from "node:assert";
describe("E2E: NODE_EXTRA_CA_CERTS merging", () => {
let container;
before(async () => {
DockerTestContainer.buildImage();
});
beforeEach(async () => {
// Run a new Docker container for each test
container = new DockerTestContainer();
await container.start();
const installationShell = await container.openShell("zsh");
await installationShell.runCommand("safe-chain setup");
});
afterEach(async () => {
// Stop and clean up the container after each test
if (container) {
await container.stop();
container = null;
}
});
it(`npm install works without NODE_EXTRA_CA_CERTS set`, async () => {
const shell = await container.openShell("zsh");
// Ensure NODE_EXTRA_CA_CERTS is not set
await shell.runCommand("unset NODE_EXTRA_CA_CERTS");
const result = await shell.runCommand("npm install axios@1.13.0");
assert.ok(
result.output.includes("added") || result.output.includes("up to date"),
`npm install failed without NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
});
it(`npm install works with valid NODE_EXTRA_CA_CERTS set`, async () => {
const shell = await container.openShell("zsh");
// Create a temporary valid certificate (using the system's Mozilla CA bundle)
await shell.runCommand("cp /etc/ssl/certs/ca-certificates.crt /tmp/valid-certs.pem");
// Verify the cert file was created
const { output: checkOutput } = await shell.runCommand("test -f /tmp/valid-certs.pem && echo exists");
assert.ok(
checkOutput.includes("exists"),
`Certificate file was not created at /tmp/valid-certs.pem`
);
// Set NODE_EXTRA_CA_CERTS and run npm install
const result = await shell.runCommand(
"NODE_EXTRA_CA_CERTS=/tmp/valid-certs.pem npm install axios@1.13.0"
);
assert.ok(
result.output.includes("added") || result.output.includes("up to date"),
`npm install failed with valid NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
});
it(`npm install works with non-existent NODE_EXTRA_CA_CERTS path`, async () => {
const shell = await container.openShell("zsh");
// Set NODE_EXTRA_CA_CERTS to a non-existent path
const result = await shell.runCommand(
'export NODE_EXTRA_CA_CERTS="/tmp/nonexistent-certs.pem" && npm install axios@1.13.0'
);
// Should still succeed - safe-chain should gracefully handle missing user certs
assert.ok(
result.output.includes("added") || result.output.includes("up to date"),
`npm install failed with non-existent NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
// Should show a warning
assert.ok(
result.output.includes("Safe-chain") || result.output.includes("Could not read"),
`Expected safe-chain warning about missing certs. Output was:\n${result.output}`
);
});
it(`npm install works with invalid (non-PEM) NODE_EXTRA_CA_CERTS`, async () => {
const shell = await container.openShell("zsh");
// Create an invalid certificate file (not valid PEM)
await shell.runCommand(
'echo "This is not a valid PEM certificate" > /tmp/invalid-certs.pem'
);
// Set NODE_EXTRA_CA_CERTS to invalid cert
const result = await shell.runCommand(
'export NODE_EXTRA_CA_CERTS="/tmp/invalid-certs.pem" && npm install axios@1.13.0'
);
// Should still succeed - safe-chain should skip invalid user certs
assert.ok(
result.output.includes("added") || result.output.includes("up to date"),
`npm install failed with invalid NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
// Should show a warning about invalid cert
assert.ok(
result.output.includes("Safe-chain") || result.output.includes("Could not read"),
`Expected safe-chain warning about invalid certs. Output was:\n${result.output}`
);
});
it(`npm install handles NODE_EXTRA_CA_CERTS with path traversal attempt`, async () => {
const shell = await container.openShell("zsh");
// Try to set NODE_EXTRA_CA_CERTS with path traversal
const result = await shell.runCommand(
'export NODE_EXTRA_CA_CERTS="/tmp/../../../etc/passwd" && npm install axios@1.13.0'
);
// Should still succeed - safe-chain should reject path traversal
assert.ok(
result.output.includes("added") || result.output.includes("up to date"),
`npm install failed with path traversal NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
});
it(`npm install handles empty NODE_EXTRA_CA_CERTS`, async () => {
const shell = await container.openShell("zsh");
// Create an empty certificate file
await shell.runCommand("touch /tmp/empty-certs.pem");
const result = await shell.runCommand(
'export NODE_EXTRA_CA_CERTS="/tmp/empty-certs.pem" && npm install axios@1.13.0'
);
// Should still succeed - empty file should be ignored gracefully
assert.ok(
result.output.includes("added") || result.output.includes("up to date"),
`npm install failed with empty NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
});
it(`npm install handles NODE_EXTRA_CA_CERTS pointing to a directory`, async () => {
const shell = await container.openShell("zsh");
// Create a directory instead of a file
await shell.runCommand("mkdir -p /tmp/cert-dir");
const result = await shell.runCommand(
'export NODE_EXTRA_CA_CERTS="/tmp/cert-dir" && npm install axios@1.13.0'
);
// Should still succeed - directory should be treated as invalid cert file
assert.ok(
result.output.includes("added") || result.output.includes("up to date"),
`npm install failed when NODE_EXTRA_CA_CERTS points to directory. Output was:\n${result.output}`
);
});
it(`npm install handles relative NODE_EXTRA_CA_CERTS path`, async () => {
const shell = await container.openShell("zsh");
// Create a cert file and try to reference it with relative path
await shell.runCommand(
"mkdir -p /tmp/cert-test && cp /etc/ssl/certs/ca-certificates.crt /tmp/cert-test/certs.pem"
);
const result = await shell.runCommand(
'cd /tmp/cert-test && export NODE_EXTRA_CA_CERTS="./certs.pem" && npm install axios@1.13.0'
);
// Should still succeed - relative paths should be resolved properly
assert.ok(
result.output.includes("added") || result.output.includes("up to date"),
`npm install failed with relative NODE_EXTRA_CA_CERTS path. Output was:\n${result.output}`
);
});
it(`npm install handles absolute NODE_EXTRA_CA_CERTS path`, async () => {
const shell = await container.openShell("zsh");
// Create cert file with absolute path
await shell.runCommand("cp /etc/ssl/certs/ca-certificates.crt /tmp/absolute-certs.pem");
const result = await shell.runCommand(
"NODE_EXTRA_CA_CERTS=/tmp/absolute-certs.pem npm install axios@1.13.0"
);
assert.ok(
result.output.includes("added") || result.output.includes("up to date"),
`npm install failed with absolute NODE_EXTRA_CA_CERTS path. Output was:\n${result.output}`
);
});
it(`npm install with multiple packages still respects merged certificates`, async () => {
const shell = await container.openShell("zsh");
// Create valid cert
await shell.runCommand("cp /etc/ssl/certs/ca-certificates.crt /tmp/merge-certs.pem");
const result = await shell.runCommand(
"NODE_EXTRA_CA_CERTS=/tmp/merge-certs.pem npm install axios@1.13.0 lodash"
);
assert.ok(
result.output.includes("added") || result.output.includes("up to date"),
`npm install with multiple packages failed. Output was:\n${result.output}`
);
});
it(`npm install correctly blocks malware even with merged certificates`, async () => {
const shell = await container.openShell("zsh");
// Create valid cert
await shell.runCommand("cp /etc/ssl/certs/ca-certificates.crt /tmp/secure-merge-certs.pem");
const result = await shell.runCommand(
"NODE_EXTRA_CA_CERTS=/tmp/secure-merge-certs.pem npm install safe-chain-test"
);
// Should block the malware package
assert.ok(
result.output.includes("Malicious") || result.output.includes("blocked"),
`Malware package should be blocked even with merged certificates. Output was:\n${result.output}`
);
});
it(`pip install works without NODE_EXTRA_CA_CERTS set`, async () => {
const shell = await container.openShell("zsh");
await shell.runCommand("safe-chain setup");
await shell.runCommand("unset NODE_EXTRA_CA_CERTS");
const result = await shell.runCommand(
"pip3 install --break-system-packages requests"
);
assert.ok(
result.output.includes("Successfully installed") || result.output.includes("Requirement already satisfied"),
`pip3 install failed without NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
});
it(`pip install works with valid NODE_EXTRA_CA_CERTS set`, async () => {
const shell = await container.openShell("zsh");
await shell.runCommand("safe-chain setup");
// Create a temporary valid certificate
await shell.runCommand("cp /etc/ssl/certs/ca-certificates.crt /tmp/pip-valid-certs.pem");
const result = await shell.runCommand(
"NODE_EXTRA_CA_CERTS=/tmp/pip-valid-certs.pem pip3 install --break-system-packages requests"
);
assert.ok(
result.output.includes("Successfully installed") || result.output.includes("Requirement already satisfied"),
`pip3 install failed with valid NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
});
it(`pip install handles non-existent NODE_EXTRA_CA_CERTS gracefully`, async () => {
const shell = await container.openShell("zsh");
await shell.runCommand("safe-chain setup");
const result = await shell.runCommand(
'export NODE_EXTRA_CA_CERTS="/tmp/nonexistent-pip-certs.pem" && pip3 install --break-system-packages requests'
);
// Should still work - gracefully handle missing user certs
assert.ok(
result.output.includes("Successfully installed") || result.output.includes("Requirement already satisfied"),
`pip3 install failed with non-existent NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
});
it(`pip install handles invalid NODE_EXTRA_CA_CERTS gracefully`, async () => {
const shell = await container.openShell("zsh");
await shell.runCommand("safe-chain setup");
// Create invalid cert
await shell.runCommand(
'echo "invalid certificate content" > /tmp/pip-invalid-certs.pem'
);
const result = await shell.runCommand(
'export NODE_EXTRA_CA_CERTS="/tmp/pip-invalid-certs.pem" && pip3 install --break-system-packages requests'
);
// Should still work - skip invalid user certs
assert.ok(
result.output.includes("Successfully installed") || result.output.includes("Requirement already satisfied"),
`pip3 install failed with invalid NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
});
it(`yarn install works with valid NODE_EXTRA_CA_CERTS set`, async () => {
const shell = await container.openShell("zsh");
// Create valid cert
await shell.runCommand("cp /etc/ssl/certs/ca-certificates.crt /tmp/yarn-certs.pem");
const result = await shell.runCommand(
"NODE_EXTRA_CA_CERTS=/tmp/yarn-certs.pem yarn add axios@1.13.0"
);
assert.ok(
!result.output.toLowerCase().includes("error") || result.output.includes("Done"),
`yarn add failed with valid NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
});
it(`pnpm install works with valid NODE_EXTRA_CA_CERTS set`, async () => {
const shell = await container.openShell("zsh");
// Create valid cert
await shell.runCommand("cp /etc/ssl/certs/ca-certificates.crt /tmp/pnpm-certs.pem");
const result = await shell.runCommand(
"NODE_EXTRA_CA_CERTS=/tmp/pnpm-certs.pem pnpm add axios@1.13.0"
);
assert.ok(
!result.output.toLowerCase().includes("error") || result.output.includes("Progress"),
`pnpm add failed with valid NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
});
it(`bun install works with valid NODE_EXTRA_CA_CERTS set`, async () => {
const shell = await container.openShell("bash");
// Create valid cert and run bun in the same command to ensure file exists
const result = await shell.runCommand(
"cp /etc/ssl/certs/ca-certificates.crt /tmp/bun-certs.pem && NODE_EXTRA_CA_CERTS=/tmp/bun-certs.pem bun i axios@1.13.0"
);
assert.ok(
!result.output.toLowerCase().includes("error") || result.output.includes("installed"),
`bun i failed with valid NODE_EXTRA_CA_CERTS. Output was:\n${result.output}`
);
});
});