Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,7 @@ test("maintained outer launcher rejects inherited startup settings before the ve
writeFileSync(join(directory, "exports.test.mjs"), launcher);
assert.deepEqual(readFileSync(join(directory, "exports.test.mjs")), launcher);
writeFileSync(join(directory, "archive-controls.test.mjs"), "export {};\n");
writeFileSync(join(directory, "archive-parser.test.mjs"), "export {};\n");
writeFileSync(join(directory, "committed-archive.mjs"), `export { cleanEnvironment } from ${JSON.stringify(new URL("./committed-archive.mjs", import.meta.url).href)};\n`);
const startupMarker = join(directory, "startup-ran");
const verifierMarker = join(directory, "synthetic-verifier-ran");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import assert from "node:assert/strict";
import test from "node:test";
import { digest, readArchive, resolveTools } from "./committed-archive.mjs";

// Exercise both public constructor names with the actual npm-bundled parser.
// In-memory archive bytes keep these controls independent of package staging.
for (const exportName of ["Parse", "Parser"]) {
test(`archive admission preserves safety with the ${exportName} tar API`, async () => {
const { tar } = resolveTools();
const Parser = tar.Parser ?? tar.Parse;
const parserApi = { [exportName]: Parser };
const archive = (path, type = "File") => {
const payload = Buffer.from("admitted bytes");
const header = new tar.Header({ path, type, size: type === "File" ? payload.length : 0, linkpath: type === "SymbolicLink" ? "allowed.txt" : "", mode: 0o644 });
const bytes = Buffer.alloc(2048);
header.encode(bytes);
if (type === "File") payload.copy(bytes, 512);
return bytes;
};
const read = (bytes, admit = () => {}, expectedHash = digest(bytes)) => readArchive(parserApi, "/control.tar", expectedHash, admit, {
lstatSync: () => ({ isFile: () => true, size: bytes.length }),
readFileSync: () => bytes,
});
const bytes = archive("allowed.txt");
const admitted = [];
const files = await read(bytes, path => admitted.push(path));
assert.deepEqual(admitted, ["allowed.txt"]);
assert.equal(files.get("allowed.txt").toString(), "admitted bytes");
await assert.rejects(read(bytes, () => assert.fail("must authenticate first"), "0".repeat(64)), /identity changed/);
await assert.rejects(read(bytes, () => assert.fail("unbound entry")), /unbound entry/);
await assert.rejects(read(archive("../escape")), /nonliteral input path/);
await assert.rejects(read(archive("link.txt", "SymbolicLink")), /nonregular archive entry/);
const duplicate = Buffer.concat([bytes.subarray(0, 1024), bytes]);
await assert.rejects(read(duplicate), /duplicate or excessive archive entries/);
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,8 @@ export async function readArchive(tar, filename, expectedHash, admit, fileSystem
const files = new Map();
let expanded = 0;
await new Promise((resolvePromise, reject) => {
const parser = new tar.Parser({ strict: true, maxMetaEntrySize: 1024 * 1024 });
const Parser = tar.Parser ?? tar.Parse;
const parser = new Parser({ strict: true, maxMetaEntrySize: 1024 * 1024 });
parser.on("error", reject);
parser.on("end", resolvePromise);
parser.on("entry", entry => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { test } from "node:test";
import { fileURLToPath } from "node:url";

await import(new URL("./archive-controls.test.mjs", import.meta.url).href);
await import(new URL("./archive-parser.test.mjs", import.meta.url).href);
const { cleanEnvironment } = await import(new URL("./committed-archive.mjs", import.meta.url).href);

test("S3 HTTP root/subpath exports work from a clean packed revision without source fallback", { timeout: 300_000 }, () => {
Expand Down
Loading