diff --git a/packages/plugins/tests/starter-pack-shipped.test.mjs b/packages/plugins/tests/starter-pack-shipped.test.mjs index cc6da46d0..ab13a199f 100644 --- a/packages/plugins/tests/starter-pack-shipped.test.mjs +++ b/packages/plugins/tests/starter-pack-shipped.test.mjs @@ -5,11 +5,13 @@ import test from "node:test"; import assert from "node:assert/strict"; import { randomUUID } from "node:crypto"; -import { appendFileSync, readFileSync, rmSync } from "node:fs"; +import { appendFileSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; import { hasModule, loadInstalled } from "../src/loader.mjs"; import { checkPack, installedStarterPacks } from "../src/starter-pack.mjs"; +import { installPlugin } from "../src/install.mjs"; +import { pluginHash } from "../src/pinned.mjs"; import { compositionOf, entryFromTemplate, readTemplate, templateHash } from "../../organization/src/definitions.mjs"; import { loadRole } from "../../organization/src/role.mjs"; import { buildRegistry, checkComposition } from "../../organization/src/composition.mjs"; @@ -228,3 +230,23 @@ test("SP2 a template edit refuses the packs that pin it until they are re-pinned appendFileSync(join(rolesDir, `${CHIEF}.md`), "\nOne more line.\n"); await assert.rejects(checkLines("coding", rolesDir), /the chief moved/); }); + +// An installed plug-in cannot take a shipped pack's name, so it cannot replace a reviewed pack. +test("SP2 installing a plug-in named after a shipped pack refuses core-name", async (t) => { + const root = tmp(); + t.after(() => rmSync(root, { recursive: true, force: true })); + for (const id of IDS) { + const src = join(root, `src-${id}`), dataRoot = join(root, `data-${id}`); + mkdirSync(join(src, "starter-pack"), { recursive: true }); + mkdirSync(dataRoot); + const doc = (await moduleOf(id)).starterPack(); + writeFileSync(join(src, "starter-pack", "index.mjs"), `export const interfaceVersion = 1;\nexport function starterPack() { return ${JSON.stringify(doc)}; }\n`); + const manifest = { name: id, version: "1.0.0", kinds: ["starter-pack"], interfaceVersions: { "starter-pack": 1 }, sha256: "0".repeat(64), + source: { path: "fixture", version: "1.0.0" }, signature: null, tools: [], actions: [], services: [], roleTemplates: [] }; + writeFileSync(join(src, "plugin.json"), JSON.stringify(manifest)); + manifest.sha256 = pluginHash(src); + writeFileSync(join(src, "plugin.json"), JSON.stringify(manifest)); + assert.throws(() => installPlugin({ dataRoot, source: src, expectedHash: manifest.sha256 }), + (e) => e?.name === "PluginError" && e.code === "core-name", id); + } +}); diff --git a/packages/plugins/tests/starter-pack.test.mjs b/packages/plugins/tests/starter-pack.test.mjs index bd0a5205a..d5fd6ee23 100644 --- a/packages/plugins/tests/starter-pack.test.mjs +++ b/packages/plugins/tests/starter-pack.test.mjs @@ -516,6 +516,7 @@ test("SP1 installedStarterPacks lists shipped packs with origin shipped", async const { installedStarterPacks } = await sp(); const real = await installedStarterPacks({ rolesDir: ROLES }); assert.deepEqual(real.refused, []); + assert.ok(real.packs.length > 0); assert.ok(real.packs.every((p) => p.origin === "shipped")); const f = tree(t); f.core("coding", moduleText(pack()));