Files
stack/packages/organization/tests/case1-project-key.test.mjs
jason.woltje 4c8bf9ca4e fix(organization,cli): refusals name the file by label, never by host path
PR #1916 rule: a refusal names the field or file, never a config value
or a host path. readJsonFile's three refusals and parseJsonFileText now
name the file by its `what` label only. Callers whose label alone is
ambiguous add a name that already passed a strict pattern (business id,
role name, org id, turn id, project key) or a fixed path under the data
root. Exit codes, refusal codes and check order are unchanged.

organization: util, access, project, config-command, library-seats,
org-service deleteOrg receipt, agent-levels regex; T1 files role.mjs and
organization-config.mjs change only the readJsonFile label.
cli: access lock, accounts owner, host state/lock, notifier journal,
notify-config, run-evidence, dev-fixture, git-socket, org-bus, org-console.
discord: turn record label names the turn id.

Sentinel tests (sk-test-NOT-A-SECRET-1234 as a path component) cover each
changed refusal and fail on BASE; old path pins updated.
2026-11-11 01:04:15 -06:00

67 lines
3.1 KiB
JavaScript

// Row 325 (#1821): factory validation must load the repository's actual project document.
import { test } from "node:test";
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { REPO, REPO_ROLES, systemConfig, tmp, writeJson } from "./helpers.mjs";
const CASE1 = join(REPO, "docs/guides/case1-business.mosaic-stack.json");
const PROJECT = join(REPO, ".mosaic/project.json");
const document = () => JSON.parse(readFileSync(CASE1, "utf8"));
function fixture(t, { oldKey = false } = {}) {
const root = tmp();
t.after(() => rmSync(root, { recursive: true, force: true }));
const doc = document();
assert.equal(Object.keys(doc.projects).length, 1);
const [key] = Object.keys(doc.projects);
const projectRoot = join(root, "checkout");
const projectFile = join(projectRoot, ".mosaic/project.json");
const bytes = readFileSync(PROJECT);
mkdirSync(join(projectRoot, ".mosaic"), { recursive: true });
writeFileSync(projectFile, bytes);
assert.deepEqual(readFileSync(projectFile), bytes, "fixture must use the real project's unmodified bytes");
const entry = { ...doc.projects[key], root: projectRoot };
doc.projects = { [oldKey ? "mosaic-stack" : key]: entry };
const config = systemConfig(root);
writeJson(join(root, "config/businesses/mosaic-stack.json"), doc);
return {
project: JSON.parse(bytes), projectFile,
validate: () => spawnSync(process.execPath, [join(REPO, "packages/organization/src/cli.mjs"), "validate", "mosaic-stack"], {
env: { ...process.env, HOME: root, MOSAIC_CONFIG: config, MOSAIC_ROLES_DIR: REPO_ROLES },
encoding: "utf8", timeout: 30000,
}),
};
}
test("row 325: the Case 1 project's sole key matches the repository project id", () => {
const doc = document();
const project = JSON.parse(readFileSync(PROJECT, "utf8"));
assert.equal(project.id, "stack");
assert.deepEqual(Object.keys(doc.projects), [project.id]);
assert.equal(doc.id, "mosaic-stack");
assert.equal(doc.projects[project.id].root, "/srv/mosaic/src/mosaic-stack");
});
test("row 325: real business validate reports the copied repository project valid", (t) => {
const x = fixture(t);
const r = x.validate();
assert.equal(r.status, 0, r.stdout + r.stderr);
const result = JSON.parse(r.stdout);
assert.equal(result.business, "mosaic-stack");
assert.deepEqual(result.projects, { [x.project.id]: "valid" });
assert.doesNotMatch(r.stderr, /no project file|project variables/);
});
test("row 325: the old mosaic-stack project key refuses against those same project bytes", (t) => {
const x = fixture(t, { oldKey: true });
const r = x.validate();
assert.equal(r.status, 2, r.stdout + r.stderr);
assert.equal(r.stdout, "");
assert.match(r.stderr, /project file of project mosaic-stack has id that does not match the declared project key/);
// The refusal names the declared key, never the project root (PR #1916).
assert.ok(!r.stderr.includes(x.projectFile), r.stderr);
assert.doesNotMatch(r.stderr, /no project file/);
});