Files
openrig/packages/cli/test/startup-proof.test.ts
mvschwarz c7f501a744 Release 0.4.3
"Rigs that survive." Crash the daemon or the whole machine — power-off,
not a graceful stop — and on reboot the seats come back to their
original sessions with pre-crash markers recalled, zero fresh-prime.
Proven at the operating-system level via a real hard power-off
capstone.

Survival backbone:
- Crash-restore resume-token ledger (FR-3 → FR-7 + FR-6.1 periodic
  freshness re-stamp): capture-on-adoption, snapshot-refresh, restore-
  target-pin, 1h advisory freshness threshold with --fresh re-verify,
  and no-silent-fresh-prime on the restore path.
- Fixture-home isolation guard: a fresh-prime that would clobber a
  live rig's home dir is refused loudly.
- Liveness PID-verify: live seat distinguished from dead-PID ghost.
- Daemon event-loop health + TerminalSessionBroker resilience across
  daemon restarts.
- Startup-proof: challenge-verified orientation read.

Deny-by-default rig-send reversal: only needs_input (a real interactive
picker on the target pane) hard-refuses; unknown / stale / missing /
busy advise-and-send. --dangerously-interact --reason override
unchanged. Removes the friction bridge that routine coordination hit
under the 0.4.1 posture.

New CLI: rig auth secret-boundary hardening (fd-first: open the fd +
operate on the fd, never re-resolve the path — closes the check-then-
use gap under interruption / concurrent-legitimate-rig-process
scenarios; TOCTOU class closed as a consequence; leak-hunt regression
against the real credential file).

rig send unified targeting: multi-recipient list + --pod + --rig;
backward-compatible single-send.

Codex activity-signal hardening: idle Codex takes normal sends; genuine
prompt still blocks; hook-trust autoclear on the restore path for
fully-unattended Codex restore.

Recovery: seat-handover full-cycle (delivers captured context to a
fresh successor via the shipped restore-packet write +
deliverInitialSessionPrompt; loud-unwind both lanes on failure); seat-
forking closeout; idle-gate watchdog wakes an idle seat holding a
claimable gate.

Wave-2 UI: rig-status + launch-control on the workspace; switch-client
view-retarget; dashboard theming (Vellum Dark opt-in via Tailwind
darkMode selector; light byte-identical).

Hardening + bug pile-ins: session-admin mutation auth-guard;
rig queue show bounded body preview; manual configurable compaction
trigger + same-seat guard.

Doctrine: mission-slice-sop skill ships.

Migrations: additive only. 045_resume_verification,
046_seat_identity_verdicts, 047_events_node_type_index. Existing v0.4.2
databases upgrade by running rig daemon start.

Behavior change (rig send default posture): unknown / stale / missing /
busy no longer default-block. If call sites relied on 0.4.1 default-
block, add an explicit guard.

See CHANGELOG.md and docs/releases/v0.4.3.md.
2026-07-03 16:04:22 -07:00

116 lines
4.2 KiB
TypeScript

import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { Command } from "commander";
import { startupProofCommand, resolveStartupProofEndpoint, submitStartupProof } from "../src/commands/startup-proof.js";
function captureLogs(fn: () => Promise<void>): Promise<{ logs: string[]; errors: string[]; exitCode: number | undefined }> {
return new Promise(async (resolve) => {
const logs: string[] = [];
const errors: string[] = [];
const origLog = console.log;
const origErr = console.error;
const origExit = process.exitCode;
process.exitCode = undefined;
console.log = (...args: unknown[]) => logs.push(args.join(" "));
console.error = (...args: unknown[]) => errors.push(args.join(" "));
try {
await fn();
} finally {
console.log = origLog;
console.error = origErr;
}
const exitCode = process.exitCode;
process.exitCode = origExit;
resolve({ logs, errors, exitCode });
});
}
describe("rig startup-proof", () => {
beforeEach(() => vi.restoreAllMocks());
afterEach(() => vi.restoreAllMocks());
it("resolves endpoint and token from the activity endpoint file", () => {
const root = mkdtempSync(join(tmpdir(), "openrig-startup-proof-"));
try {
mkdirSync(root, { recursive: true });
writeFileSync(join(root, "activity-endpoint.json"), JSON.stringify({ baseUrl: "http://127.0.0.1:17433", token: "tok-file" }));
expect(resolveStartupProofEndpoint({ env: { OPENRIG_HOME: root } })).toEqual({
baseUrl: "http://127.0.0.1:17433",
token: "tok-file",
});
} finally {
rmSync(root, { recursive: true, force: true });
}
});
it("posts startup_proof through the authenticated activity hook", async () => {
const fetchImpl = vi.fn(async () => new Response(JSON.stringify({
ok: true,
oriented: "verified",
nodeId: "node-1",
challengeId: "challenge-1",
}), { status: 200, headers: { "content-type": "application/json" } })) as unknown as typeof fetch;
const result = await submitStartupProof(
{ challengeId: "challenge-1", answer: "answer-1" },
{
fetchImpl,
env: {
OPENRIG_URL: "http://127.0.0.1:7433",
OPENRIG_ACTIVITY_HOOK_TOKEN: "tok-env",
OPENRIG_SESSION_NAME: "dev-qa@test-rig",
OPENRIG_NODE_ID: "node-1",
OPENRIG_RUNTIME: "codex",
},
},
);
expect(result).toMatchObject({ ok: true, oriented: "verified", nodeId: "node-1" });
expect(fetchImpl).toHaveBeenCalledWith("http://127.0.0.1:7433/api/activity/hooks", expect.objectContaining({
method: "POST",
headers: expect.objectContaining({ authorization: "Bearer tok-env" }),
}));
const body = JSON.parse((fetchImpl.mock.calls[0]?.[1] as RequestInit).body as string);
expect(body).toMatchObject({
eventFamily: "startup_proof",
sessionName: "dev-qa@test-rig",
nodeId: "node-1",
runtime: "codex",
challengeId: "challenge-1",
answer: "answer-1",
});
});
it("CLI submit prints verified result without exposing the bearer token", async () => {
const fetchImpl = vi.fn(async () => new Response(JSON.stringify({
ok: true,
oriented: "verified",
nodeId: "node-1",
challengeId: "challenge-1",
}), { status: 200, headers: { "content-type": "application/json" } })) as unknown as typeof fetch;
const program = new Command();
program.exitOverride();
program.addCommand(startupProofCommand({
fetchImpl,
env: {
OPENRIG_URL: "http://127.0.0.1:7433",
OPENRIG_ACTIVITY_HOOK_TOKEN: "tok-secret",
OPENRIG_NODE_ID: "node-1",
OPENRIG_RUNTIME: "claude-code",
},
}));
const { logs, exitCode } = await captureLogs(async () => {
await program.parseAsync(["node", "rig", "startup-proof", "submit", "--challenge-id", "challenge-1", "--answer", "answer-1"]);
});
const output = logs.join("\n");
expect(exitCode).toBeUndefined();
expect(output).toContain("startup_proof: verified");
expect(output).toContain("node_id: node-1");
expect(output).not.toContain("tok-secret");
});
});