import { describe, expect, test } from "bun:test"; import { parseSecretSyncOptions } from "./agentrun/control-plane"; import type { SecretSyncOptions } from "./agentrun/options"; import { compactAgentRunSecretSyncPayload, renderAgentRunSecretSyncResult } from "./agentrun/secret-sync-output"; import { confirmedSecretSyncPlan } from "./agentrun/trigger"; const options = (output: SecretSyncOptions["output"], overrides: Partial = {}): SecretSyncOptions => ({ confirm: false, dryRun: true, node: "NC01", lane: "nc01-v02", secretIds: [], full: false, raw: false, output, ...overrides, }); function blockedFixture(): Record { const planItems = Array.from({ length: 13 }, (_, index) => { const id = index === 11 ? "tool-github-ssh-private-key" : index === 12 ? "tool-github-ssh-known-hosts" : `fixture-secret-${index}`; return { id, namespace: "agentrun-v02", secret: index >= 11 ? "agentrun-v01-tool-github-ssh" : `fixture-target-${index}`, key: index === 11 ? "id_ed25519" : index === 12 ? "known_hosts" : `key-${index}`, sourceMode: "file", sourcePath: "/root/.unidesk/.state/secrets/", present: true, sourceFilePresent: true, fingerprint: `sha256:${String(index).padStart(64, "a")}`, valueBytes: 120 + index, degradedReason: null, valuesPrinted: false, }; }); return { ok: false, command: "agentrun control-plane secret-sync", mode: "dry-run-blocked-before-mutation", status: "blocked", mutation: false, blockedBeforeMutation: true, secretSyncStarted: false, target: { node: "NC01", lane: "nc01-v02", namespace: "agentrun-v02", valuesPrinted: false }, degradedReason: "provider-secret-activation-fence-unavailable", plan: { secretCount: planItems.length, items: planItems, omittedCount: 0, valuesPrinted: false }, activationPreflight: { ok: false, status: "blocked", reason: "provider-secret-activation-fence-unavailable", targetSecretCount: 1, targetSecrets: [{ namespace: "agentrun-v02", name: "agentrun-v01-provider-codex", desiredKeys: ["auth.json", "config.toml"], queryOk: true, present: true, mutationCount: 1, noOp: false, mutations: [{ id: "provider-codex-config", key: "config.toml", desiredFingerprintSuffix: "aaaaaaaaaaaa", runtimeFingerprintSuffix: "bbbbbbbbbbbb", changeKind: "change-key", valuesPrinted: false, }], valuesPrinted: false, }], activationRiskCount: 1, activationRisks: [{ pod: "agentrun-runner-rjob_fixture-pod", jobName: "agentrun-runner-rjob_fixture", phase: "Pending", runId: "run_fixture", commandId: "cmd_fixture", runnerJobId: "rjob_fixture", waitingReasons: ["CreateContainerConfigError"], classification: "nonterminal-runner-required-provider-secret-missing", dependencies: [{ source: "volume-secret", name: "agentrun-v01-provider-codex", affectedDesiredKeys: ["config.toml"], mutationKinds: ["change-key"], reason: "nonterminal-runner-provider-secret-mutation", valuesPrinted: false, }], valuesPrinted: false, }], requiresManagerFence: true, targetSecretObservationComplete: true, runnerObservationComplete: true, allObservationsComplete: true, providerSecretMutationCount: 1, providerSecretDataNoOp: false, providerSecretMutationAuthorized: false, managerAuthority: { owner: "agentrun-manager-provider-activation-fence", atomicFenceAvailable: false, mutationAuthorized: false, noOpOnly: true, trackingIssue: "https://github.com/pikasTech/agentrun/issues/284", valuesPrinted: false, }, capture: { stdoutTail: "FULL_PROBE_BODY_ONLY_VISIBLE_WITH_EXPLICIT_FULL", valuesPrinted: false, }, valuesPrinted: false, }, execution: { providerSecretClassification: "exact-target-ref", providerSecretWriteBlockedCount: 2, secretSyncStarted: false, valuesPrinted: false, }, next: { observeRunners: "bun scripts/cli.ts agentrun control-plane cleanup-runners --node NC01 --lane nc01-v02 --dry-run", retryAfterManagerFence: "bun scripts/cli.ts agentrun control-plane secret-sync --node NC01 --lane nc01-v02 --confirm", }, valuesPrinted: false, }; } describe("AgentRun secret-sync bounded output", () => { test("confirmed sync reports all written secrets without stale provider classification", () => { const items = [{ id: "provider-gpt-pika-auth-json" }, { id: "provider-gpt-pika-config" }]; expect(confirmedSecretSyncPlan(items, 2)).toEqual({ secretCount: 2, items, writableSecretCount: 2, valuesPrinted: false, }); }); test("parses compact machine output and explicit disclosure options", () => { expect(parseSecretSyncOptions(["--node", "NC01", "--lane", "nc01-v02", "--dry-run", "-o", "yaml"])).toEqual({ confirm: false, dryRun: true, node: "NC01", lane: "nc01-v02", secretIds: [], full: false, raw: false, output: "yaml", }); expect(parseSecretSyncOptions(["--node", "NC01", "--lane", "nc01-v02", "--secret-id", "tool-github-ssh-private-key", "--full", "--output=json"])).toMatchObject({ secretIds: ["tool-github-ssh-private-key"], full: true, raw: false, output: "json", }); expect(parseSecretSyncOptions(["--node", "NC01", "--lane", "nc01-v02", "--raw"])).toMatchObject({ full: true, raw: true }); expect(() => parseSecretSyncOptions(["--node", "NC01", "--lane", "nc01-v02", "-o", "wide"])).toThrow("must be one of human,json,yaml"); }); test("uses one bounded Secret-safe projection for human, JSON, and YAML", () => { const fixture = blockedFixture(); const compact = compactAgentRunSecretSyncPayload(fixture); const human = renderAgentRunSecretSyncResult(fixture, options("human")).renderedText; const jsonText = renderAgentRunSecretSyncResult(fixture, options("json")).renderedText; const yamlText = renderAgentRunSecretSyncResult(fixture, options("yaml")).renderedText; const json = JSON.parse(jsonText) as Record; const yaml = Bun.YAML.parse(yamlText) as Record; expect(json).toEqual(compact); expect(yaml).toEqual(json); expect(json.kind).toBe("AgentRunSecretSyncPlan"); expect(json.status).toMatchObject({ status: "blocked", reason: "provider-secret-activation-fence-unavailable", mutation: false, valuesPrinted: false }); expect(json.plan.secretCount).toBe(13); expect(json.plan.omittedCount).toBe(0); expect(json.plan.items.some((item: Record) => item.id === "tool-github-ssh-private-key")).toBe(true); expect(json.plan.items.some((item: Record) => item.id === "tool-github-ssh-known-hosts")).toBe(true); expect(json.activationFence).toMatchObject({ kind: "ProviderSecretActivationFence", identity: "providersecretactivationfence/NC01/nc01-v02", status: "blocked", reason: "provider-secret-activation-fence-unavailable", resourceCount: 1, valuesPrinted: false, }); expect(json.activationFence.resources[0]).toMatchObject({ identity: "runnerjob/rjob_fixture", status: "Pending", runId: "run_fixture", commandId: "cmd_fixture", runnerJobId: "rjob_fixture", }); expect(json.activationFence.resources[0].drillDown.map((item: Record) => item.identity)).toEqual([ "runnerjob/rjob_fixture", "command/cmd_fixture", "run/run_fixture", ]); expect(json.next.secretById).toContain("--secret-id --dry-run -o json"); expect(human).toContain("ACTIVATION FENCE"); expect(human).toContain("runnerjob/rjob_fixture"); expect(human).toContain("tool-github-ssh-private-key"); expect(human).toContain("VALUES PRINTED false"); for (const output of [human, jsonText, yamlText]) { expect(Buffer.byteLength(output, "utf8")).toBeLessThan(10_240); expect(output).not.toContain("FULL_PROBE_BODY_ONLY_VISIBLE_WITH_EXPLICIT_FULL"); expect(output).not.toContain("/root/.unidesk/.state/secrets/"); } }); test("keeps exhaustive probe details behind explicit full or raw", () => { const fixture = blockedFixture(); const full = renderAgentRunSecretSyncResult(fixture, options("json", { full: true })).renderedText; const raw = renderAgentRunSecretSyncResult(fixture, options("human", { full: true, raw: true })).renderedText; expect(JSON.parse(full)).toEqual(fixture); expect(JSON.parse(raw)).toEqual(fixture); expect(full).toContain("FULL_PROBE_BODY_ONLY_VISIBLE_WITH_EXPLICIT_FULL"); expect(raw).toContain("FULL_PROBE_BODY_ONLY_VISIBLE_WITH_EXPLICIT_FULL"); }); });