The canary fixtures intentionally pin known-vulnerable deps (jinja2 2.11.2, lodash 4.17.15) so the checker has something to detect. GitHub's dependency graph parsed those fixture manifests as real project deps, failing the dependency-review PR gate (fail-on-severity: high). Store the manifests with a .fixture suffix so the dependency graph ignores them; the --canary materializer strips the suffix in its temp work area before scanning, so detection is unchanged (still 2/2). No advisory allowlist, no change to the shared org reusable workflow — the real gate stays strict for actual deps.
2.6 KiB
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.