test/container.test.mjs
Alle Dateien · Rohdatei öffnen
// Copyright 2026 Richard Andresik. SPDX-License-Identifier: Apache-2.0
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import { spawnSync } from "node:child_process";
import test from "node:test";
import { paired } from "./endpoint.mjs";
const root = fileURLToPath(new URL("../", import.meta.url));
const read = name => readFile(new URL("../" + name, import.meta.url), "utf8");
test("container recipe fixes its inputs, copies only public files and runs without privilege", async () => {
const dockerfile = await read("Dockerfile");
const lock = JSON.parse(await read("container-lock.json"));
const digest = lock.base.split("@sha256:")[1];
assert.equal(digest.length, 64);
assert.ok([...digest].every(char => "0123456789abcdef".includes(char)));
assert.ok(dockerfile.includes("FROM " + lock.base + "\n"));
assert.ok(dockerfile.includes("USER 1000:1000\n"));
assert.ok(dockerfile.includes('CMD ["node", "tools/lab.mjs"]'));
assert.equal(dockerfile.includes("EXPOSE"), false);
assert.equal(dockerfile.includes("ADD "), false);
const copies = dockerfile.split("\n").filter(line => line.startsWith("COPY "));
const copied = copies.flatMap(line => JSON.parse(line.slice(5)).slice(0, -1));
assert.deepEqual(copied.sort(), [...lock.files].sort());
assert.equal(new Set(copied).size, copied.length);
for (const name of copied) {
assert.equal(name.includes(".."), false);
assert.equal(name.includes("*"), false);
assert.equal(name.endsWith(".PFL.md"), false);
assert.ok(!name.startsWith("/") && !name.endsWith("/"));
}
const ignore = (await read(".dockerignore")).split("\n").filter(line => line && !line.startsWith("#"));
assert.equal(ignore.shift(), "**");
assert.deepEqual(ignore.filter(line => !["!src/", "!test/", "!tools/"].includes(line)).sort(),
lock.files.map(name => "!" + name).sort());
assert.ok(lock.debianSnapshot.endsWith("Z"));
assert.ok(dockerfile.includes(lock.debianSnapshot));
for (const name of ["git", "openssl", "python3", "jq", "ripgrep", "file", "coreutils", "strace", "tini", "ca-certificates"])
assert.ok(lock.packages.includes(name));
assert.ok(dockerfile.includes(lock.debianRelease + "-security main"));
assert.equal(lock.npm.url, "https://registry.npmjs.org/npm/-/npm-" + lock.npm.version + ".tgz");
assert.equal(Buffer.from(lock.npm.integrity.slice(7), "base64").length, 64);
assert.ok(lock.npm.integrity.startsWith("sha512-"));
assert.ok(dockerfile.includes("lock.npm.integrity"));
assert.ok(dockerfile.includes("--ignore-scripts --no-audit --no-fund"));
});
test("fuzz cases repeat from a seed, reject changed messages and keep both peers progressing", async () => {
const { fuzz } = await import("../tools/fuzz.mjs");
const first = await fuzz({ seed: 1387, iterations: 12 });
const second = await fuzz({ seed: 1387, iterations: 12 });
assert.deepEqual(first, second);
assert.equal(first.iterations, 12);
assert.equal(first.rejected, 60);
assert.equal(first.roundTrips, 48);
assert.equal(first.planSha256.length, 64);
assert.notEqual((await fuzz({ seed: 1388, iterations: 12 })).planSha256, first.planSha256);
});
test("fuzzing detects lost authentication instead of counting accepted attacks as success", async () => {
const { fuzz } = await import("../tools/fuzz.mjs");
let calls = 0;
const brokenPair = async () => {
const peers = await paired();
const real = peers.secondary.session;
peers.secondary.session = { ...real, acceptPublicMessage: async () => { calls++; return true; } };
return peers;
};
await assert.rejects(fuzz({ seed: 42, iterations: 1, makePair: brokenPair }), /seed=42 iteration=0/);
assert.ok(calls > 0);
});
test("invalid fuzz bounds are refused before generating keys or running work", async () => {
const { fuzz } = await import("../tools/fuzz.mjs");
for (const options of [{ seed: 0 }, { seed: -1 }, { seed: 1.5 }, { seed: 2 ** 32 },
{ iterations: 0 }, { iterations: 100001 }, { iterations: 2.5 }]) {
await assert.rejects(fuzz({ ...options, makePair: () => { assert.fail("key generation must not start"); } }));
}
const cli = spawnSync(process.execPath, ["tools/fuzz.mjs", "--iterations", "infinity"], { cwd: root, encoding: "utf8" });
assert.notEqual(cli.status, 0);
assert.ok(cli.stderr.includes("iterations"));
});