test(plugins): review round for the shipped starter packs (#1873 SP2)

The SP1 listing test also requires a nonempty shipped listing, and a
new SP2 case pins that installing a plug-in named after any shipped
pack refuses core-name, so an installed pack cannot replace one.
This commit was merged in pull request #1953.
This commit is contained in:
jason.woltje committed 2026-11-12 16:06:08 -06:00
1 parent 1f2a726d19
commit dfef78834a
2 files changed
+24 -1

No files matched your search

@@ -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);
}
});
@@ -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()));