Each root agent an organization does not exclude, and each agent a project defines, becomes a copy when the organization's bus boots. The root file is read once, through loadRootAgents, at the cli boot step; the snapshot is fixed until the next boot. A bound copy joins the organization document's roles and goes through validateBusinessDocument and checkRoles with the organization's own credential map. A copy whose role needs a credential service is unbound and refuses at launch by name and service (credential-unbound); a copy the organization refuses is copy-refused; every agent in a project whose union refuses is project-refused, naming the project. A project agent launches only with its own project's mounts and takes a thread only in its project (project-agent-elsewhere). Refusal events carry the code alone. The bus's instances read carries the copies with their running runs, and the Agents grid shows each copy's real status and reason. channel-proof re-pins webui bus.mjs for four STATUS entries; no proof or transport change. packages/business gets the agent-copies.mjs re-export.
73 lines
5.0 KiB
JavaScript
73 lines
5.0 KiB
JavaScript
// Row 164 freezes reviewed proof bytes and the literal entry-path rule.
|
|
// Row 196 intentionally re-pins human.mjs for the distinct user nonce and shared human
|
|
// walk, and webui bus.mjs for initial-spawn nonce plus peer refusal status. Entry paths
|
|
// and the ban on channel plug-ins importing a proof caller are retained.
|
|
// Row 254 (#1759) re-pins human-cli.mjs for the 130 s library.sync client timeout and webui
|
|
// bus.mjs for six library-* STATUS entries; no proof or transport change.
|
|
// Row 236 (#1742) re-pins human-cli.mjs for the same 130 s wait on the grants verbs; no proof or
|
|
// transport change.
|
|
// Row 252 (#1753, Webby N5) re-pins human.mjs, whose readProcess also keeps the five
|
|
// MOSAIC_BUS_CONSOLE_* keys for the Console wrapper's proof, and webui bus.mjs for consoleCall,
|
|
// which shares humanCall's spawn as transport(). The human proof and its spawn are unchanged.
|
|
// Row 225 (C2-10b) re-pins webui bus.mjs for one STATUS entry, library-revert-not-agent: 409; no proof
|
|
// or transport change.
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { createHash } from "node:crypto";
|
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { provedRuntime } from "../../cli/tests/channel-fixture.mjs";
|
|
import { Client } from "../src/client.mjs";
|
|
|
|
const baselines = {
|
|
"packages/bus/src/human.mjs": "bb13c146717cdc46d75d157177e400edac4d3e10f14fe511027a25fd44cec885",
|
|
"packages/bus/src/human-cli.mjs": "271b9781d73cf31cc562a56180e3ebcd725b5fde148a83347a201fdef2fc28af",
|
|
// Row 239 (#1745): EXIT outcome-unknown-revoked 1; no proof or transport change.
|
|
"packages/cli/src/transport.mjs": "662642a8ce739fcb6c188ad07125a94e008c8a305eced127c8041d472c56e55b",
|
|
// Row 165 (#1662): seven STATUS entries for the role instance routes (organization-instance-exists,
|
|
// organization-unknown-instance, organization-credentials-out-of-scope, organization-launch-not-configured,
|
|
// organization-no-change, organization-project-mismatch, organization-unresolvable-instance), no proof or
|
|
// transport change. Row 155 (#1649) added eight for the assistant routes.
|
|
// Row 171 (#1668): project-name-is-repo maps to 409; no proof or transport change.
|
|
// Row 194 (#1692, brief item 7, sage-1610 a): organization-tracker-required 400 and
|
|
// organization-tracker-bot-taken 409; no proof or transport change.
|
|
// Row 301 (#1808, mos-1449): the user transport moved from user-bus.mjs into bus.mjs; humanCall unchanged.
|
|
// Row 239 (#1745): outcome-unknown-revoked joins OPEN (duckworth-0165 C1), and STATUS gets
|
|
// revision-conflict-revoked 409 and outcome-unknown-revoked 503; no proof or transport change.
|
|
// #1839: artifact Console replies alone may use 2 MiB; the proof and other limits are unchanged.
|
|
// #1873 U1: humanCall, busCaller, userCall and userCaller take an optional signal and absolute
|
|
// deadline; userCall shares transport(). Nonces, argv and limits are unchanged.
|
|
// #1873 A3: STATUS maps credential-unbound, copy-refused, project-refused and project-agent-elsewhere
|
|
// to 409; no proof or transport change.
|
|
"packages/webui/src/bus.mjs": "d8f3e0eb5299fdb192e98a1238ca693aae7c36af9a21de72d5f5d39610589377",
|
|
};
|
|
const repoFile = path => new URL("../../../" + path, import.meta.url);
|
|
|
|
test("channel conversion preserves the four proof/transport byte baselines and modules cannot import a proof caller", () => {
|
|
for (const [file, hash] of Object.entries(baselines))
|
|
assert.equal(createHash("sha256").update(readFileSync(repoFile(file))).digest("hex"), hash, file);
|
|
for (const name of ["cli", "webui"]) {
|
|
const source = readFileSync(repoFile(`packages/plugins/channel/${name}/index.mjs`), "utf8");
|
|
assert.doesNotMatch(source, /human-cli|humanTransport|humanCall|verifyHuman|readProcess|child_process|spawn/);
|
|
}
|
|
});
|
|
|
|
test("channel recovery still requires the same shim path and rejects an absent or forged proof", { timeout: 20000 }, async t => {
|
|
const s = await provedRuntime(t);
|
|
const direct = new Client({ path: s.socket });
|
|
await assert.rejects(direct.call("plugins"), e => ["invalid-envelope", "unauthenticated", "human-required"].includes(e.code));
|
|
const forged = new Client({ path: s.socket, human: { business: "demo", pid: process.pid, startTime: "0", nonce: "a".repeat(64) } });
|
|
await assert.rejects(forged.call("plugins"), e => e.code === "human-required");
|
|
const genuine = await s.shimCall(s.shim, { business: "demo", verb: "plugins" });
|
|
assert.equal(genuine.status, 0, genuine.stderr);
|
|
assert.deepEqual(JSON.parse(genuine.stdout).plugins.channel, []);
|
|
let other = readFileSync(s.shim, "utf8");
|
|
other = other.replace("'./client.mjs'", JSON.stringify(new URL("../src/client.mjs", import.meta.url).href));
|
|
other = other.replace("'./human.mjs'", JSON.stringify(new URL("../src/human.mjs", import.meta.url).href));
|
|
const differentPath = join(s.root, "other-human-cli.mjs");
|
|
writeFileSync(differentPath, other);
|
|
const refused = await s.shimCall(differentPath, { business: "demo", verb: "plugins" });
|
|
assert.notEqual(refused.status, 0);
|
|
assert.equal(refused.stderr.trim(), "human-required");
|
|
});
|