/** * peaks-security-audit service — independent security audit skill driver. * * Slice v2.12.0 (Group A, Tier 2). The skill is decoupled from the * CLI surface: `peaks security-audit run --rid ...`. * * The service owns: * - 5-state detection of the security-audit runtime * (handoff-missing / template-missing / dispatch-failed / template-malformed / ready) * - Loading + sha256 verification of the slice's prd/handoff-.md * - Loading the project-level security-template.md * - Producing the audit envelope (verdict + violations) to write * to `.peaks/_runtime//audit/security-.md` * * The actual LLM-in-loop audit step is NOT in this service — the * parent LLM (peaks-security-audit skill prompt) reads the template, * runs the audit, and returns a structured envelope. This service * is the pure I/O + validation core; the LLM is the judgement core. * * Why a service (not inlined in the CLI): * - The 5-state detector mirrors the ecc-bridge detectEcc pattern * (slice 7 Group D), keeping the surface uniform * - Future migration to peaks sub-agent dispatch (peaks-rd main * loop can opt to call this service directly without re-implementing * the handoff verification) * * Cross-references: * - PRD: `.peaks/_runtime//prd/handoff.md` (sha256-locked, schemaVersion: 2) * - Template: `.peaks/project-scan/security-template.md` * - Output: `.peaks/_runtime//audit/security-.md` * - Schema: `.peaks/project-scan/audit-output-schema.md` (schemaVersion: 1) */ /** * 5-state detection result. Mirrors `detectEcc` in `services/code-review/ecc-bridge.ts`. * * - `ready` — handoff + template + project all present * - `handoff-missing` — this slice's `.peaks/_runtime//prd/handoff-.md` * - `template-missing` — `.peaks/project-scan/security-template.md` absent * - `dispatch-failed` — parent LLM threw before returning the audit envelope * - `envelope-malformed` — parent LLM returned a value that fails `isSecurityAuditEnvelope` */ export type SecurityAuditDetectState = 'ready' | 'handoff-missing' | 'template-missing' | 'dispatch-failed' | 'envelope-malformed' | 'declaration-missing'; export interface SecurityAuditDetectResult { readonly state: SecurityAuditDetectState; readonly handoffPresent: boolean; readonly templatePresent: boolean; readonly warnings: readonly string[]; readonly nextActions: readonly string[]; } export type SecurityAuditVerdict = 'pass' | 'warn' | 'block'; export interface SecurityAuditViolation { readonly dimension: string; readonly severity: 'CRITICAL' | 'HIGH' | 'MED' | 'LOW'; readonly file: string; readonly line: number; readonly hint: string; } export interface SecurityAuditEnvelope { readonly verdict: SecurityAuditVerdict; readonly violations: ReadonlyArray; readonly summary: string; } /** * Validate a raw value as a SecurityAuditEnvelope. Mirrors the * `isEccEnvelope` strict-shape pattern. */ export declare function isSecurityAuditEnvelope(value: unknown): value is SecurityAuditEnvelope; /** * 5-state detector. The parent skill inspects the state and either * proceeds (when `ready`) or records a degradation note and falls * back (when any other state). * * Soft-fail policy mirrors `detectEcc` (slice 7 Group D): the CLI * never throws; it returns a typed detect result. */ export declare function detectSecurityAudit(input: { readonly projectRoot: string; readonly sessionId: string; /** * The slice whose capsule this run audits. Slice * filename, so a caller that knows it must pass it or the probe resolves * `runSecurityAudit` always did, and `peaks security-audit detect` forwards * its long-standing `--rid` flag as of the post-verification repair round. */ readonly requestId?: string; readonly dispatchError?: unknown; readonly envelope?: unknown; }): SecurityAuditDetectResult; /** * Convenience: run `detectSecurityAudit` + `renderSecurityAuditArtifact` * + `writeSecurityAuditArtifact` in one call. * * Returns `{ detect, artifactPath, violationsCount, verdict }` or * `{ detect, artifactPath: null, ... }` when not ready. */ export declare function runSecurityAudit(input: { readonly projectRoot: string; readonly sessionId: string; readonly rid: string; readonly generatedAt: string; /** Project-relative paths this audit judged; written into the artifact as * the declaration the transition gate reads back. Required — a path that * cannot be hashed is refused, because a declaration naming a file that is * not there cannot be checked later. */ readonly judgedPaths: readonly string[]; readonly dispatchError?: unknown; readonly envelope?: unknown; }): { detect: SecurityAuditDetectResult; artifactPath: string | null; violationsCount: number; verdict: SecurityAuditVerdict | null; };