/** * `agent-bober security-audit [target]` — on-demand stack-aware security audit. * * Synthesizes a lightweight SprintContract-shaped descriptor from the target * path (or the working tree when omitted), runs the same `runSecurityAudit` * core the in-pipeline gate uses (with `evaluation=null` for standalone * mode), persists the artifact via `saveSecurityAudit` (called internally by * the core), prints a human-readable findings summary, and exits with a * CI-friendly code driven by `security.standaloneBlockOn`. * * Threshold semantics (sc-4-2) are CLI-local by design: `thresholdVerdict` * lives HERE, never in `security-gate.ts`. The pipeline gate's critical-only * veto (ADR-2) stays structurally untouched — this command reads * `security.standaloneBlockOn` to decide its OWN exit code only. * * Exit codes: 0 = pass, 2 = blocked-by-threshold OR fail-closed (audit threw, * or the auditor's output could not be parsed). 1 is reserved for Commander's * own usage errors and for unexpected errors resolving config/project root. * * Clock discipline: `new Date().toISOString()` is called ONLY at the * `.action()` boundary — never inside `runStandaloneSecurityAudit` — mirrors * `research.ts`'s "stamp wall-clock time at handler boundary" convention. * Hub emission (sprint 6) reuses `deps.now` for the same reason — it is * never re-stamped inside this module. * * Error handling: CLI handlers MUST NOT throw. They set `process.exitCode` * and return on all errors (mirrors `research.ts` / `do.ts`). */ import type { Command } from "commander"; import type { BoberConfig } from "../../config/schema.js"; import type { SprintContract } from "../../contracts/sprint-contract.js"; import type { ReviewResult } from "../../orchestrator/code-reviewer-agent.js"; import type { SecurityAuditResult } from "../../orchestrator/security-audit-types.js"; import { runSecurityAudit } from "../../orchestrator/security-auditor-agent.js"; import type { SecurityFindingSink } from "../../orchestrator/security-hub.js"; /** * Decide whether the standalone CLI should block (exit 2) given a review and * the configured `standaloneBlockOn` threshold. Pure function — no I/O. * * `critical` findings always block, regardless of threshold. `important` * findings only block when `standaloneBlockOn === "important"`. `minor` * findings never block. This is intentionally a *superset* of the pipeline * gate's critical-only veto (`deriveVerdict`) — it must never be imported * into `security-gate.ts` or `pipeline.ts` (sc-4-4 is verified structurally). */ export declare function thresholdVerdict(review: ReviewResult, standaloneBlockOn: "critical" | "important"): boolean; /** * Build a synthetic SprintContract-shaped descriptor for the standalone * audit. The `contractId` is timestamped (`security-audit-`) so it can * never collide with a pipeline sprint's `sprint-*` contractId, and so the * fs-safe sanitization in `security-audit-state.ts` produces a stable, * readable artifact filename. */ export declare function buildAuditDescriptor(target: string | undefined, now: string): SprintContract; /** Injectable deps so tests never spawn a process or hit a real provider. */ export interface StandaloneAuditDeps { projectRoot: string; config: BoberConfig; target?: string; /** ISO timestamp, stamped ONCE at the `.action` boundary. */ now: string; /** Default = the real `runSecurityAudit` core; tests inject a fake. */ runAudit?: typeof runSecurityAudit; /** Injected hub sink (tests only) — default binds ingestFinding to a real FactStore. */ findingSink?: SecurityFindingSink; } export interface StandaloneAuditOutcome { result?: SecurityAuditResult; exitCode: 0 | 2; } /** * Run a standalone security audit and compute the CI exit code. * * `config.security` may be absent — that is legal for standalone mode (the * explicit CLI invocation IS the opt-in; nonGoals[0]). When absent, the * section is synthesized via `SecuritySectionSchema.parse({})` so the audit * still runs with schema defaults (sc-4-3). * * Fail-closed (sc-4-2): a thrown audit error, or `result.parsed === false`, * always exits 2 — checked BEFORE the threshold, so an empty fallback review * (which `thresholdVerdict` alone would read as "clean") never yields a * false pass. */ export declare function runStandaloneSecurityAudit(deps: StandaloneAuditDeps): Promise; export interface SecurityAuditOverrides { runAudit?: typeof runSecurityAudit; } export declare function registerSecurityAuditCommand(program: Command, overrides?: SecurityAuditOverrides): void; //# sourceMappingURL=security-audit.d.ts.map