Lands Gizmoduck's round 1 candidate,ed4193316on gizmoduck/row235-e (one commit on62ddc96cc), approved by Duckworth (duckworth-0089, REVIEW-r1d9ecec514on duckworth/reviews, #1741 comment 30022). 13 paths, manifest dad377ca8fe4. No 235 path changed between62ddc96ccand this commit's parent. Patch-id c355d2fc457d, the same as 62ddc96cc..ed4193316. broker.mjs keeps row 213's import and decision.raise creative refusal as landed. Creative roles (mos-1163, mos-1164, sage-1908): #hostDefinition refuses host-creative-role at the raise and at the step 1 recheck, and #hostAccess refuses it at host.run before reading the grant record, which stays for hosts.revoke. Duckworth checked from the code that a creative role can't raise, approve or spend a host grant, and ruled the upsert mutant equivalent. Evidence: Gizmoduck's runs on my slot. B1-B37 on 5df4b52c5, and run 2 on 534f2254a (10:12:52-10:14:51Z): grant-host 9/9, grant-executor 37/37 and grant-enroll 24/24, each run whole, with B16, B23, B27, B38 and B39 killed. B1-B39: 38 killed, and B17 is equivalent (sage-1904). Gate on my slot, 10:30:55-10:42:43Z on29ce1e360plus the 13 paths: bus 596/0 (its first whole run on this head, duckworth-0089 N1), business 200/0, cli 666/0, and every scripts/test-*.sh green (auth 15, conductor 17, config 31, discord 78, extension-package 18, foundation 44, land-work 86, queue 156 and 28, release 14, task 98, all 0 failed).
53 lines
2.8 KiB
JavaScript
53 lines
2.8 KiB
JavaScript
// `mosaic hosts` (row 234, #1740, r6 E4): the broker's hosts.status, hosts.check and hosts.remove. The
|
|
// human runs all three. With --tester the tester's session runs them. check logs in as mosaic-installer
|
|
// and runs `list` on the host, then marks the host ready. remove drops a host no grant uses. Nothing here
|
|
// reads a key: the answers carry fingerprints only. Row 235 (#1741, r6 section 6, X3) adds revoke, which
|
|
// takes an agent's grant on a host away at once, and sweep, which removes the lines a failure left.
|
|
import { CliError } from "./errors.mjs";
|
|
|
|
export const HOSTS_USAGE =
|
|
"mosaic hosts [status] [--json] [--tester] [--business ID] | check|remove|sweep HOST [--tester] [--business ID] | revoke AGENT HOST --reason R [--tester] [--business ID]";
|
|
|
|
function parse(args) {
|
|
const out = { positional: [], flags: new Set(), values: {} };
|
|
for (let i = 0; i < args.length; i++) {
|
|
const arg = args[i];
|
|
if (arg === "--json" || arg === "--tester") out.flags.add(arg);
|
|
else if (arg === "--business" || arg === "--reason") {
|
|
if (!args[i + 1] || Object.hasOwn(out.values, arg)) throw new CliError(HOSTS_USAGE, 4);
|
|
out.values[arg] = args[++i];
|
|
} else if (arg.startsWith("--")) throw new CliError(HOSTS_USAGE, 4);
|
|
else out.positional.push(arg);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
const line = (h) =>
|
|
[h.host, h.state, `${h.user}@${h.address}:${h.port}`, h.sudo ? "sudo" : "no-sudo", h.checkedAt ?? "unchecked",
|
|
...(h.hostLineLeft.length ? [`line left: ${h.hostLineLeft.join(" ")}`] : []),
|
|
...(h.revoking?.length ? [`revoking: ${h.revoking.join(" ")}`] : [])].join("\t");
|
|
|
|
export async function hostsCommand(args, io, callFor) {
|
|
const parsed = parse(args);
|
|
const [verb = "status", first, second, ...extra] = parsed.positional;
|
|
const one = first !== undefined && second === undefined;
|
|
const shape = { status: first === undefined, check: one, remove: one, sweep: one, revoke: second !== undefined };
|
|
// N10: own keys only, so `constructor` or `toString` is a usage error, not a verb.
|
|
if (extra.length || !Object.hasOwn(shape, verb) || !shape[verb] || (parsed.flags.has("--json") && verb !== "status") ||
|
|
(verb === "revoke") !== Object.hasOwn(parsed.values, "--reason"))
|
|
throw new CliError(HOSTS_USAGE, 4);
|
|
try {
|
|
const call = callFor(parsed);
|
|
if (verb === "status") {
|
|
const rows = await call("hosts.status", {});
|
|
io.stdout.write(parsed.flags.has("--json") ? JSON.stringify(rows, null, 2) + "\n" : rows.map(line).join("\n") + (rows.length ? "\n" : ""));
|
|
return;
|
|
}
|
|
const args = verb === "revoke" ? { agent: first, host: second, reason: parsed.values["--reason"] } : { host: first };
|
|
io.stdout.write(JSON.stringify(await call(`hosts.${verb}`, args), null, 2) + "\n");
|
|
} catch (error) {
|
|
if (error instanceof CliError) throw error;
|
|
throw new CliError(error.message, 2);
|
|
}
|
|
}
|