/** * The fail-closed SecurityAuditGate (spec-20260712-security-audit-agent-team, * sprint 3, ADR-2). * * Thin wrapper over runSecurityAudit (sprint 2): the gate owns the * Promise.race time-box, the rejection→'audit-error'/'timeout' mapping, the * parsed:false→'audit-error' elevation, and the best-effort store guard * (sc-3-6). It does NOT re-run or re-derive any auditor logic — the verdict * comes straight from `result.verdict` (already computed via deriveVerdict * inside runSecurityAudit). * * evaluateSecurityGate NEVER throws. Every failure mode (timeout, thrown * audit error, unparseable output) resolves to `blocked:true` — an * incomplete audit is never treated as clean (fail-closed). * * Sprint 6 additionally emits critical/important findings into the priority * hub AFTER the verdict is computed and OUTSIDE the Promise.race time-box * below, so a slow or failing hub ingest can never flip the verdict or * manufacture a false timeout (see emitFindingsToHub). */ import type { BoberConfig } from "../config/schema.js"; import type { SprintContract } from "../contracts/sprint-contract.js"; import type { EvaluationRunResult } from "../evaluators/registry.js"; import type { SecurityAuditResult } from "./security-audit-types.js"; import type { SecurityFindingSink } from "./security-hub.js"; export interface SecurityGateInput { contract: SprintContract; evaluation: EvaluationRunResult; projectRoot: string; config: BoberConfig; /** Injected hub sink (tests only) — default binds ingestFinding to a real FactStore. */ findingSink?: SecurityFindingSink; } export type SecurityGateReason = "critical-finding" | "timeout" | "audit-error" | "clean" | "disabled"; export interface SecurityGateVerdict { blocked: boolean; reason: SecurityGateReason; result?: SecurityAuditResult; } /** * Evaluate the security gate for a sprint that just passed evaluation. * * Never throws. Resolution mapping: * - `config.security` absent or `enabled !== true` → `{blocked:false, reason:'disabled'}` * WITHOUT invoking the audit at all. * - `runSecurityAudit` rejects (any error) → `{blocked:true, reason:'audit-error'}`. * - The Promise.race timeout (`config.security.timeoutMs`) fires first → * `{blocked:true, reason:'timeout'}`. * - `result.parsed === false` (unparseable auditor output) → * `{blocked:true, reason:'audit-error', result}` — checked BEFORE * `result.verdict` so a parse failure is never mistaken for a genuine * critical finding. * - `result.verdict === 'blocked'` (a real critical finding) → * `{blocked:true, reason:'critical-finding', result}`. * - Otherwise → `{blocked:false, reason:'clean', result}`. * * A `saveSecurityAudit` persistence failure is caught, logged, and never * changes the already-computed verdict in either direction (sc-3-6). */ export declare function evaluateSecurityGate(input: SecurityGateInput): Promise; /** * Render a blocked SecurityGateVerdict into feedback strings for the * generator's next retry iteration (ADR-5), phrased for a fixer. Pure * function — no side effects, no I/O. * * Returns `[]` for a non-blocked verdict. Returns a single generic message * when there is no `result` to enumerate findings from (a `timeout` or a * rejected `audit-error` never resolves a SecurityAuditResult). Otherwise * returns a summary line followed by one line per critical finding, capped * to MAX_RENDERED_FINDINGS. */ export declare function renderSecurityFeedback(verdict: SecurityGateVerdict): string[]; //# sourceMappingURL=security-gate.d.ts.map