/** * Certification Drift / Staleness Detection * * Age-staleness (`expires_at`) and code-change drift (`project_hash`) are * already handled by `isCertificationValid()` in `store.ts`. This module adds * the genuinely missing piece: **advisory drift** — new CVEs dropping against * an already-certified dependency set. * * The mechanism: * 1. At finalization, we snapshot the set of dependency-advisory keys into * `CertificationMetadata.advisory_baseline` (see `deriveAdvisoryBaseline`). * 2. On a drift check, we re-run the SCA on the current tree, compute current * advisory keys, and diff against the baseline → `newAdvisories` (present * now, absent at cert time) and `fixedAdvisories` (present at cert time, * gone now). * * An advisory key is `|` — a stable, package-scoped * identifier. When a finding carries CVE IDs we emit one key per CVE so a *new* * CVE against an already-vulnerable package is detected (the persisted cert * findings collapse to `npm-audit:` granularity and drop CVE IDs, which is * why a dedicated baseline is required rather than diffing stored findings). * * @module certification/drift */ import type { DeterministicFinding } from "../scanners/types.js"; /** * Error thrown when a drift check cannot be performed. */ export declare class DriftCheckError extends Error { readonly reason: "scan_failed" | "invalid_input"; constructor(message: string, reason: "scan_failed" | "invalid_input"); } /** * Compute the set of advisory keys for a set of dependency findings. * * One key per CVE (`|`) when CVE IDs are present, otherwise a * single key from the rule ID (`|`). The `did-not-run` coverage * marker is excluded. * * @param findings - Dependency-scanner findings (npm-audit). * @returns Sorted, de-duplicated advisory keys. */ export declare function computeAdvisoryKeys(findings: DeterministicFinding[]): string[]; /** * Derive the advisory baseline for a project by running the dependency audit. * * Called at finalization to snapshot the advisory keys present at cert time. * A scanner-level failure (no successful package audit) yields an empty * baseline — we do not want a transient failure to fabricate a baseline that * makes every future advisory look "already known". * * @param projectPath - Absolute path to the project root (already validated). * @returns Sorted advisory keys, or an empty array if the audit could not run. */ export declare function deriveAdvisoryBaseline(projectPath: string): Promise; /** * Result of an advisory-drift diff. */ export interface AdvisoryDrift { /** Advisory keys present now but absent at cert time. */ newAdvisories: string[]; /** Advisory keys present at cert time but gone now. */ fixedAdvisories: string[]; /** Convenience count of `newAdvisories`. */ newCount: number; /** Convenience count of `fixedAdvisories`. */ fixedCount: number; } /** * Diff a current set of advisory keys against a baseline. * * @param baseline - Advisory keys captured at cert time. * @param current - Advisory keys from the current tree. */ export declare function diffAdvisoryKeys(baseline: string[], current: string[]): AdvisoryDrift; /** * Run a live advisory-drift check against a baseline. * * Re-runs the dependency audit on the current tree and diffs the resulting * advisory keys against `baseline`. * * @param projectPath - Absolute path to the project root (already validated). * @param baseline - Advisory keys captured at cert time. * @returns The advisory drift diff. * @throws DriftCheckError if the dependency audit could not run at all. */ export declare function checkAdvisoryDrift(projectPath: string, baseline: string[]): Promise; //# sourceMappingURL=drift.d.ts.map