Skip to content
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ The no-secret preflight checks the target release is unused and verifies the
previous catalog's exact downloaded bytes, detached signatures, and pinned
public key. The credentialed build step resolves each private BOM commit and
release tag exactly before the signing key is exposed. Archives are fail-closed on unsafe ZIP paths/metadata,
compression bombs, executable extras, missing source-package license metadata, and wrong PE
compression bombs, executable extras, and wrong PE
platforms.

## Pull-request checks
Expand Down
1 change: 0 additions & 1 deletion scripts/publish-catalog.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@ export async function inspectArchive(spec, archivePath, zipUtils, sequence) {
try { manifest = JSON.parse(manifestEntry.data.toString("utf8")); } catch { fail(`${spec.id}: archive manifest.json is invalid JSON`); }
requiredManifest(manifest, spec, spec.build?.provider ?? spec.id);
const licenseEntry = files.find((entry) => /^license(?:[._-].*)?$/i.test(path.posix.basename(entry.name)));
if (spec.kind !== "app" && !licenseEntry && typeof manifest.license !== "string") fail(`${spec.id}: archive license is missing`);
const expected = ["manifest.json", spec.entrypoint, spec.icon, ...(licenseEntry ? [licenseEntry.name] : [])].sort();
const actual = files.map((entry) => entry.name).sort();
if (spec.kind === "app" ? (expected.some((name) => !actual.includes(name)) ||
Expand Down
10 changes: 1 addition & 9 deletions scripts/publish-catalog.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ async function mutateCentral(file, entryName, mutate) {
await writeFile(file, bytes);
}

test("archive policy rejects traversal, collisions, missing license, and extra files", async () => {
test("archive policy rejects traversal, collisions, and extra files", async () => {
const dir = await mkdtemp(path.join(tmpdir(), "kosmos-archive-"));
try {
const spec = archiveSpec();
Expand All @@ -159,14 +159,6 @@ test("archive policy rejects traversal, collisions, missing license, and extra f
const extra = path.join(dir, "extra.kspkg");
await writeArchive(extra, spec, [{ name: "payload.exe", data: peFixture() }]);
await assert.rejects(() => inspectArchive(spec, extra, { readZip }, 8), /unexpected/);
const noLicense = path.join(dir, "no-license.kspkg");
const noLicenseSpec = { ...spec, artifact: { name: "no-license.kspkg" } };
writeZip(noLicense, [
{ name: "manifest.json", data: JSON.stringify(completeManifest(noLicenseSpec)) },
{ name: noLicenseSpec.entrypoint, data: peFixture() },
{ name: noLicenseSpec.icon, data: Buffer.from("icon") },
]);
await assert.rejects(() => inspectArchive(noLicenseSpec, noLicense, { readZip }, 8), /license/);
const traversal = path.join(dir, "traversal.kspkg");
await writeArchive(traversal, spec, [{ name: "../escape.txt", data: Buffer.from("x") }]);
await assert.rejects(() => inspectArchive(spec, traversal, { readZip }, 8), /unsafe|unexpected/);
Expand Down
Loading