# dependency-cve canary fixtures Planted-vulnerable-dependency corpus for `checkers/dependency-cve.sh --canary` (offline, no network/token). The checker asserts the total vulnerable-dependency count equals `EXPECTED_VULN_COUNT` (anti-complacency floor, design §6.4). If extraction or matching regresses (a parser stops firing, or the advisory match breaks), the count drops and the canary FAILS (exit 3). ## Offline advisory source OSV needs the network, so the canary CANNOT call `api.osv.dev`. Instead, `--canary` (and the `--advisories-file PATH` override) makes the checker consult the local `osv-advisories.json` fixture INSTEAD of the network — keyed by `ECOSYSTEM|package|version`. This keeps the canary fully offline and deterministic. The fixture mirrors real advisory ids/summaries/fixed-versions so a finding looks like a live one, but nothing is fetched. ## Fixture repos (each a real git checkout; `dotgit/` is renamed to `.git/` at run time) The git metadata is shipped as `dotgit/` (not `.git/`) so these commit into the orchestrator repo WITHOUT becoming nested submodules — the SAME trick `compliance-drift` fixtures use. The checker copies each fixture to a temp area and renames `dotgit` → `.git` before scanning. | Fixture | Ecosystem | Pinned deps | Vulnerable match | Count | |---|---|---|---|---| | `vuln-py-repo` | PyPI (`requirements.txt`) | `flask==2.0.1`, `jinja2==2.11.2`, `requests==2.31.0` | `jinja2==2.11.2` → `GHSA-g3rq-g295-4j3m` | 1 | | `vuln-js-repo` | npm (`package-lock.json`) | `lodash 4.17.15`, `left-pad 1.3.0` | `lodash 4.17.15` → `GHSA-p6mc-m468-83gw` | 1 | | `clean-repo` | PyPI (`requirements.txt`) | `requests==2.31.0`, `urllib3==2.2.1` | none (no advisory entry) | 0 | Total = **2** (`EXPECTED_VULN_COUNT`). Two ecosystems are exercised (PyPI + npm) so a regression in either parser is caught. When you add/remove a parser, a fixture, or an advisory entry, update the fixture(s), `osv-advisories.json`, and `EXPECTED_VULN_COUNT` in the same commit (the canary edit is itself caught on the next run — design §6.4). **Manifest naming:** the dependency manifests are stored with a `.fixture` suffix (`requirements.txt.fixture`, `package-lock.json.fixture`) so GitHub's dependency graph / the `dependency-review` CI action does NOT parse the deliberately-vulnerable canary pins as real project dependencies (which would fail the PR gate). The checker's `--canary` materialization strips the `.fixture` suffix in its temp work area before scanning, so the per-ecosystem parsers still dispatch on the real names. Keep this suffix on any new manifest fixture.