mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-07 05:56:21 -10:00
When two missions each have a slice folder of the same name, the slice list (GET /api/slices) keeps only one of them, and the routes that find a slice by name serve that one, so nothing told a person the other slice existed. rig scope audit, and the daemon's audit route behind the dashboard, now add a low-severity slice_name_shared finding to each such slice, naming the other missions and suggesting a rename. It is advice: it doesn't change the audit's result or exit code, which slice the list keeps, or any route. Limits: the check looks for a same-named folder under each other mission's slices directory, which is narrower than every case the indexer can drop; renaming a slice folder unbinds rows that name the old slice; addressing a slice by mission is a separate, larger change. Reported in #2487 by @ziadeh.
44 lines
2.1 KiB
TypeScript
44 lines
2.1 KiB
TypeScript
// The CLI twin of the daemon's slice_name_shared advisory: two missions with a slice folder of the same
|
|
// name leave one of them out of the slice list and the routes that find a slice by name. Advisory only.
|
|
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { Command } from "commander";
|
|
import { scopeCommand } from "../src/commands/scope.js";
|
|
|
|
let workspace: string;
|
|
let missionsRoot: string;
|
|
beforeEach(() => {
|
|
workspace = fs.mkdtempSync(path.join(os.tmpdir(), "cli-slice-name-audit-"));
|
|
missionsRoot = path.join(workspace, "missions");
|
|
for (const mission of ["alpha", "beta"]) {
|
|
fs.mkdirSync(path.join(missionsRoot, mission, "slices", "01-login"), { recursive: true });
|
|
fs.writeFileSync(path.join(missionsRoot, mission, "SPEC.md"), "# mission\n");
|
|
fs.writeFileSync(path.join(missionsRoot, mission, "slices", "01-login", "SPEC.md"), "# login\n");
|
|
}
|
|
});
|
|
afterEach(() => fs.rmSync(workspace, { recursive: true, force: true }));
|
|
|
|
async function audit(mission: string): Promise<{ slices: Array<{ name: string; findings: Array<{ kind: string; severity: string; message: string }> }> }> {
|
|
const buf: string[] = [];
|
|
const origWrite = process.stdout.write.bind(process.stdout);
|
|
process.stdout.write = ((c: unknown) => { buf.push(String(c)); return true; }) as typeof process.stdout.write;
|
|
const program = new Command();
|
|
program.addCommand(scopeCommand());
|
|
program.exitOverride();
|
|
try {
|
|
await program.parseAsync(["node", "rig", "scope", "audit", "--mission", mission, "--json", "--workspace", workspace]);
|
|
} finally {
|
|
process.stdout.write = origWrite;
|
|
}
|
|
return JSON.parse(buf.join(""));
|
|
}
|
|
|
|
describe("rig scope audit — a slice name another mission also uses", () => {
|
|
it("names the other mission, as advice that blocks nothing", async () => {
|
|
const shared = (await audit("alpha")).slices.find((s) => s.name === "01-login")!.findings.find((f) => f.kind === "slice_name_shared");
|
|
expect(shared).toMatchObject({ severity: "low", message: expect.stringContaining("beta") });
|
|
});
|
|
});
|