# Dependency security clearance The required Security workflow evaluates JavaScript vulnerability evidence offline and evaluates Go vulnerabilities against the current source. Before that gate, the workflow separately prepares the ignored generated Go source needed by source-aware `govulncheck` with `task db:generate`, `task config:generate`, and `task ui-signals:generate`; this step does not run a JavaScript audit or advisory query, or refresh the controlled evidence. The default `task security:dependencies` command reads `.security/javascript-vulnerability-evidence.json`; it does not refresh that document or call a live JavaScript audit. The evidence must cover exactly five JavaScript graphs: - root `package.json` + `bun.lock`; - `desktop/package.json` + `desktop/bun.lock`; - `deploy/compose/qualification/package.json` + `deploy/compose/qualification/bun.lock`; - `internal/app/testing/maliciousinstance/electron/package.json` + `internal/app/testing/maliciousinstance/electron/bun.lock`; - `pkg/apigen/typespec/package.json` + `pkg/apigen/typespec/package-lock.json`. Each manifest and lockfile is bound by a SHA-256 identity in the evidence. Generation and expiry timestamps are UTC, and the evidence lifetime is bounded to at most 7 days (168 hours). Future-dated, stale, malformed, missing, or mismatched evidence fails closed. The same required task performs a live, source-aware Go `govulncheck` scan for every maintained Go module, so a Go feed/tool outage also remains a gate failure. Before those scans, the evaluator provisions the pinned `govulncheck@v1.6.0` binary once into a private temporary directory and verifies its `-version` identity. Provisioning accepts only Go module download-progress diagnostics; the scanner's own stderr remains forbidden. The evaluator requires a source-mode symbol scan, validates every module-, package-, and symbol-level record, and blocks every callable symbol finding. Module-only and import-only records remain non-reachable notices; an ambiguous trace or mismatched scan precision fails closed. The evidence names the npm advisory API as its provider and records the exact Bun or npm scanner identity and version used for each graph. Treat every evidence change as a security-policy input: review the refresh command, scanner identities, timestamps, file digests, and normalized findings alongside the manifest or lockfile change that required the refresh. JavaScript evidence is refreshed only by the separate task: ```sh task security:dependencies:evidence:refresh ``` That task invokes the same repository-owned tool with `-refresh-javascript-evidence` and is the live registry path. Bun may retry one process-wide exact recognized transport failure, using a fresh process after a five-second backoff. Critical findings, malformed or unknown output, another transport failure, and retry exhaustion fail without another retry. npm audit has no retry. A complete authoritative refresh, including one that records a blocking finding, atomically replaces the evidence document; an operationally failed or unavailable refresh does not replace it. An outage cannot create or extend evidence, and previously reviewed evidence remains usable only until its explicit bounded expiry. The retained compatibility report is separate from the checked-in JavaScript evidence and remains a live scanner path. Its commands still require the scanners, Node, and Task as described below; they must not be treated as an offline version of the required Security workflow. It is generated by the repository-native tool: ```sh go run ./internal/app/tools/dependencyreport report \ --output dependency-security-report.json go run ./internal/app/tools/dependencyreport check \ --input dependency-security-report.json ``` The equivalent `task security:report` and `task security:report:check` tasks may be used in CI. Generation requires a clean checkout and all four scanners, Node, and Task. A missing tool, scanner error, malformed result, missing lock graph, edited graph, commit mismatch, or expired waiver fails closed. Scanner errors and vulnerable graphs replace any older report with explicit uncleared diagnostics while still returning non-zero. When a failure occurs before complete evidence can be assembled, generation removes an older report rather than leaving stale clearance. The `--allow-dirty` flag is reserved for diagnostics and still cannot produce cleared evidence. Each report includes its schema version and UTC generation time, source commit and dirty state, Node and Task versions, scanner/runtime versions and exact normalized commands, the Go vulnerability database timestamp when supplied by govulncheck, scanner environment controls, SHA-256 digests of all required module lock/manifests, the presence and SHA-256 digest of the repository waiver policy, normalized results, and severity/package counts. The Go scanner uses a 4 GiB soft memory limit so the full source analysis remains viable on standard CI runners. `check` recomputes the digests, toolchain, scans, summaries, and clearance before accepting the artifact. For Go, module-only and import-only advisories are retained as non-reachable notices, deduplicated by advisory and module. They do not satisfy the scanner's definition of affected code and therefore do not require a waiver. A finding with a symbol-level call trace is recorded as reachable and blocks clearance. ## Runtime OS packages The production server image combines a digest-pinned Debian base with the dated sources in `deploy/container/debian-bookworm.sources`. Both the Debian and Debian security suites use one immutable snapshot timestamp. APT binds each source to the Debian archive keyring, verifies signed repository metadata and package hashes, and therefore resolves direct and transitive packages from a frozen package universe on both release architectures. The bootstrap CA bundle comes from the separately digest-pinned Go builder before APT connects to the HTTPS snapshot. The distroless public-site runtime installs no OS packages. The authoring qualification image derives from the server runtime and inherits its frozen sources. The malicious-browser proof image is test-only, and the Ubuntu host bootstrap is an installation-time patching boundary: it intentionally consumes the current signed Ubuntu 24.04 repositories and enables unattended upgrades rather than becoming part of the immutable application image. To refresh runtime packages, choose a reviewed snapshot containing the intended security updates, update the snapshot timestamp and the pinned runtime base digest together, build both `linux/amd64` and `linux/arm64`, inspect the installed package inventory, and rerun container vulnerability and provenance checks. Do not point a release build back at a moving mirror. ## Waivers Waivers are optional JSON in `security/dependency-waivers.json`. Reports bind the exact repository policy, including its absence; alternate or report-only waiver sources are rejected. Every waiver must match an observed advisory and dependency and must include an owner, reachability assessment, compensating control, creation time, and a future expiry. Unused, malformed, future-dated, or expired waivers are rejected. ```json [ { "advisory": "GHSA-example", "dependency": "example-package", "owner": "security@example.com", "reachability": "The vulnerable code path is not shipped.", "compensating_control": "Pinned transitive version and regression test.", "created": "2026-08-01T00:00:00Z", "expiry": "2026-09-01T00:00:00Z" } ] ``` The report is cleared only when every scan passes or every observed finding is covered by a valid waiver. Do not hand-edit a report; `check` compares its normalized scan results with a fresh scan of the same checkout. ## Verification Run the report and then its check from the same clean commit. Both commands must exit successfully, and the JSON must contain `"clearance": {"cleared": true}`. Review the uploaded artifact's commit and lockfile digests before retaining it as release evidence. If a scan, digest, commit, graph, or waiver check fails, fix the dependency or waiver and regenerate the artifact; do not reuse a previous report.