Skip to content
Merged
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
62 changes: 59 additions & 3 deletions implementations/cli/smoke/legacy-packaged-manager.smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSyn
import { createServer, type AddressInfo } from "node:net";
import { tmpdir } from "node:os";
import { homedir } from "node:os";
import { join } from "node:path";
import { basename, join } from "node:path";

const originalHome = process.env.HOME ?? homedir();
const originalXdg = process.env.XDG_CONFIG_HOME ?? join(originalHome, ".config");
Expand Down Expand Up @@ -58,13 +58,69 @@ try {
assert.equal(spawnSync("sh", ["-c", "command -v cotal"], { env: cleanEnv, encoding: "utf8" }).stdout.trim(), fixtureCotal, "the fixture PATH masks the operator cotal binary");
assert.equal(run(npm, ["root"], current).stdout.trim(), join(realpathSync(current), "node_modules"), "current package install resolves into the isolated prefix before installation");
assert.equal(run(npm, ["root"], old).stdout.trim(), join(realpathSync(old), "node_modules"), "old package install resolves into the isolated prefix before installation");
for (const dir of ["bin", "packages/core", "packages/workspace", "implementations/cli", "implementations/manager", "implementations/delivery", "implementations/auth", "extensions/connector-core"]) {
// The packed set is DERIVED, never hand-listed. A hand-listed set silently omits the next
// workspace package anyone adds to a dependency here, and the omission is invisible while the
// missing package happens to be published at the current version: npm fetches the registry copy
// and the install succeeds, so a cell named "installed current packaged closure" passes while one
// member came from npm rather than from this build. That is how `@cotal-ai/runtime` sat outside
// the set unnoticed, and it only surfaced on a release PR, where the version being packed is by
// definition not yet published.
const workspacePackages = new Map<string, string>();
for (const dir of readdirSync(repo, { withFileTypes: true }).filter((e) => e.isDirectory()).flatMap((e) =>
["bin"].includes(e.name) ? [e.name] : readdirSync(join(repo, e.name), { withFileTypes: true })
.filter((c) => c.isDirectory()).map((c) => join(e.name, c.name)))) {
try {
const meta = JSON.parse(readFileSync(join(repo, dir, "package.json"), "utf8")) as { name?: string; private?: boolean };
if (meta.name && !meta.private) workspacePackages.set(meta.name, dir);
} catch { /* not a package */ }
}
// Start from the entry point and take the transitive closure of its workspace: deps.
const needed = new Set<string>();
const queue = ["cotal-ai"];
while (queue.length) {
const name = queue.shift()!;
const dir = workspacePackages.get(name);
if (dir === undefined || needed.has(name)) continue;
needed.add(name);
const meta = JSON.parse(readFileSync(join(repo, dir, "package.json"), "utf8")) as { dependencies?: Record<string, string> };
for (const [dep, range] of Object.entries(meta.dependencies ?? {})) if (range.startsWith("workspace:")) queue.push(dep);
}
for (const name of needed) {
const dir = workspacePackages.get(name)!;
const packed = run(pnpm, ["-C", join(repo, dir), "pack", "--pack-destination", packs], repo);
assert.equal(packed.status, 0, `packed ${dir}: ${packed.stdout}\n${packed.stderr}`);
}
const tarballs = readdirSync(packs).filter((name) => name.endsWith(".tgz")).map((name) => join(packs, name));
assert.equal(tarballs.length, needed.size, `packed ${tarballs.length} tarball(s) for ${needed.size} closure member(s): ${[...needed].join(", ")}`);
writeFileSync(join(current, "package.json"), JSON.stringify({ name: "current-fixture", private: true }));
assert.equal(run(npm, ["install", "--ignore-scripts", "--no-audit", "--no-fund", ...tarballs], current).status, 0, "installed current packaged closure");
const install = run(npm, ["install", "--ignore-scripts", "--no-audit", "--no-fund", ...tarballs], current);
assert.equal(install.status, 0, `installed current packaged closure: ${install.stdout}\n${install.stderr}`);
// The guard is PROVENANCE, and deliberately not `--offline`. Forbidding the registry outright was
// tried and is wrong here: this fixture installs under an isolated HOME whose npm cache starts
// empty, so `--offline` fails on legitimate third-party dependencies -- `@cotal-ai/lang` needs
// `acorn` -- exactly as readily as on a workspace package that leaked to the registry. A complete
// and correct closure still ENOTCACHEDs, so the guard would red every run including the release
// it exists to unblock. It cannot tell the defect from the intended behaviour.
//
// The narrower property is the one worth asserting: any WORKSPACE package that ends up installed
// must have come from a tarball this run packed. Third-party packages resolve from npm, which is
// correct and stays silent. Membership is keyed on the workspace set rather than on an
// `@cotal-ai/` name prefix, because the entry point `cotal-ai` carries no scope and a prefix test
// would exempt the one package the closure is rooted at.
const packedTarballs = new Set(tarballs.map((path) => basename(path)));
const lock = JSON.parse(readFileSync(join(current, "node_modules", ".package-lock.json"), "utf8")) as { packages?: Record<string, { resolved?: string }> };
let checked = 0;
for (const [path, entry] of Object.entries(lock.packages ?? {})) {
const name = path.slice(path.lastIndexOf("node_modules/") + "node_modules/".length);
if (!workspacePackages.has(name)) continue;
checked += 1;
// A missing `resolved` fails. An unrecorded source is an unanswered question, not a clean bill.
assert.ok(entry.resolved?.startsWith("file:") && packedTarballs.has(basename(entry.resolved)),
`${name} resolved from ${entry.resolved ?? "an unrecorded source"} rather than from a tarball packed by this run: it came from the registry, so the packed closure is incomplete`);
}
// Without this the guard goes vacuous the day npm moves the hidden lockfile or reshapes its keys:
// nothing would match, zero packages would be checked, and the loop above would pass in silence.
assert.equal(checked, needed.size, `provenance checked ${checked} workspace package(s) but the closure has ${needed.size} -- the lockfile is not being read as expected`);
writeFileSync(join(old, "package.json"), JSON.stringify({ name: "old-fixture", private: true }));
assert.equal(run(npm, ["install", "--ignore-scripts", "--no-audit", "--no-fund", "cotal-ai@0.42.0"], old).status, 0, "installed published old package");
const oldRuntime = readFileSync(join(old, "node_modules", "@cotal-ai", "core", "dist", "runtime.js"), "utf8");
Expand Down
Loading