Dependency Admission / Firewall Events
Dependency Admission evaluates new dependencies and dependency version changes before they enter a repository or build.
The firewall proxy still exists, but the default product posture is not "block every risky package in the current backlog." The useful enforcement point is the delta: packages newly added in a PR, packages upgraded in a lockfile, and packages that would be denied if introduced today.
It reuses existing dpndncY signals:
- OSV vulnerability lookup
- registry trust checks
- prior dependency review records
- tenant admission policy
- unverified upgrade candidates
#Decisions
Every package/version receives one decision:
allow- no policy violation detectedwarn- risk exists, but build can continue by defaultreview- manual approval recommendedblock- dependency should not be installed or merged
Default posture:
mode: observe- block-level policy findings are shown as review decisions until a tenant explicitly switches to enforcement.failOn: block- CI and proxy enforcement only fail on block-level decisions by default.
Default block-level rules are intentionally narrow:
- prior dependency review blocked the same version
- package/version is not present in the expected registry
- registry trust check classifies package as untrusted
- likely typosquatting risk is detected
- CISA KEV signal is present and a verified fixed version exists
- license is explicitly blocklisted
Default review rules:
- package is suspicious or newly published
- registry status cannot be verified
- critical vulnerability has no fixed version
- critical vulnerability has a verified fixed version
- CISA KEV signal is present but no verified fix exists
- high vulnerability has a fixed version
#UI
The feature is visible in two places:
/app?page=firewallshows the tenant-wide Firewall Events audit log with blocked, review, warn, and allow decisions from proxy, CLI, CI, and API checks.- Each scan result has a
Dependencies -> Admissionsubview. It compares the scan to the previous run and shows only new packages, version changes, and unchanged packages that would be denied if introduced today.
Admins can allowlist or blocklist packages directly from the tenant-wide event log. They can also lock a scan as the target's admission baseline or create scan-scoped temporary exceptions from a scan's Admission table. Recorded events keep the policy reason, risk signals, unverified upgrade candidates, and exception metadata when an exception allowed the package.
The Firewall Events page also shows:
- active temporary exceptions
- recent policy-impact simulation
- admission metrics aggregated from recent events
#PR / CI Admission Path
Use the dependency review CI script as the main enforcement path for normal teams. It compares changed manifests between a base and head ref, evaluates new packages through Dependency Admission, and runs package-diff review for version upgrades:
node scripts/dependency-review-ci.jsRelevant environment variables:
DPNDNCY_SERVER_URL
DPNDNCY_API_TOKEN
DPNDNCY_TENANT_ID
DPNDNCY_REVIEW_BASE_REF
DPNDNCY_REVIEW_HEAD_REF
DPNDNCY_ADMISSION_FAIL_ON=block
DPNDNCY_REVIEW_FAIL_ON_RISK=HIGH
DPNDNCY_REVIEW_FAIL_ON_BLOCKING=trueThis keeps existing backlog noise out of the gate. CI fails only when the PR introduces a dependency that meets the configured admission or upgrade-review threshold.
#API
Evaluate one package:
POST /api/firewall/evaluate
Content-Type: application/json
{
"ecosystem": "npm",
"name": "express",
"version": "4.18.2",
"source": "package-lock.json"
}Evaluate a lockfile-sized batch:
POST /api/firewall/evaluate-batch
Content-Type: application/json
{
"packages": [
{ "ecosystem": "npm", "name": "express", "version": "4.18.2" },
{ "ecosystem": "pypi", "name": "requests", "version": "2.31.0" }
]
}Evaluate manifest content server-side:
POST /api/firewall/evaluate-manifest
Content-Type: application/json
{
"path": "package-lock.json",
"content": "{...}"
}Policy and audit routes:
GET /api/firewall/policies
POST /api/firewall/policies
POST /api/firewall/override
GET /api/firewall/eventsAdmission diff, exceptions, and impact routes:
GET /api/scans/:id/admission-diff
POST /api/scans/:id/admission-baseline
GET /api/admission/baselines
GET /api/admission/exceptions?active=true
POST /api/admission/exceptions
DELETE /api/admission/exceptions/:id
GET /api/admission/metrics
GET /api/admission/policy-simulator?limit=8&maxPackages=80Temporary exception example:
POST /api/admission/exceptions
Content-Type: application/json
{
"ecosystem": "npm",
"packageName": "express",
"version": "4.18.2",
"scopeType": "scan",
"scopeId": "scan-id",
"ttlDays": 14,
"reason": "Approved for release candidate validation"
}Scope types are tenant, project, repo, and scan. Non-tenant scopes require a scopeId. Exceptions are temporary and capped at 180 days.
#CLI
CI enforcement:
dpndncy firewall check .
dpndncy firewall check package-lock.json --fail-on review
dpndncy firewall check requirements.txt --jsonExit codes:
0- no dependency meets the fail threshold1- one or more dependencies met the fail threshold2- configuration, parsing, or API error
Supported local files:
package-lock.jsonnpm-shrinkwrap.jsonpnpm-lock.yamlyarn.lockpackage.jsonrequirements.txtpyproject.tomlpoetry.lockCargo.lockcomposer.lockgo.modpom.xmlbuild.gradleandbuild.gradle.ktspackages.lock.json,packages.config, and*.csprojGemfile.lock
#Registry Proxy
npm:
registry=http://localhost:3001/api/firewall/npm/
//localhost:3001/api/firewall/npm/:_authToken=${DPNDNCY_TOKEN}PyPI simple index:
pip install --index-url http://localhost:3001/api/firewall/pypi/simple requestsAdditional proxy roots:
Maven /api/firewall/maven/<group>/<artifact>/<version>/<file>
NuGet /api/firewall/nuget/v3-flatcontainer/<package>/<version>/<file>
Cargo /api/firewall/cargo/api/v1/crates/<crate>/<version>/download
Composer /api/firewall/composer/p2/<vendor>/<package>.json
RubyGems /api/firewall/rubygems/gems/<gem>-<version>.gem
Go /api/firewall/go/<module>/@v/<version>.zip
Pub /api/firewall/pub/api/packages/<package>/versions/<version>
CRAN /api/firewall/cran/src/contrib/<package>_<version>.tar.gz
Conda /api/firewall/conda/pkgs/main/<subdir>/<package>-<version>-<build>.conda
CPAN /api/firewall/cpan/authors/id/.../<dist>-<version>.tar.gz
OPAM /api/firewall/opam/packages/<package>/<package>.<version>/opam
CocoaPods /api/firewall/cocoapods/Specs/.../<pod>/<version>/<pod>.podspec.json
SwiftPM /api/firewall/swiftpm/<scope>/<package>/releases/<version>
PEAR /api/firewall/pear/get/<package>-<version>.tgzThe proxy uses the same evaluator. If the tenant policy is in enforce mode and a request meets the policy fail threshold, the proxy returns 403 with the firewall decision and unverified upgrade candidates. In default observe mode, those same signals are recorded for review without breaking installs.
For ecosystems whose registry metadata contains direct artifact URLs, the firewall rewrites those URLs back through dpndncY so clients cannot bypass enforcement after metadata resolution:
- npm
dist.tarball - PyPI simple-index file links
- Composer
dist.url - Pub
archive_url
The upstream registry base URLs can be overridden with environment variables:
FIREWALL_MAVEN_BASE
FIREWALL_NUGET_BASE
FIREWALL_CARGO_BASE
FIREWALL_CARGOSTATIC_BASE
FIREWALL_COMPOSER_BASE
FIREWALL_RUBYGEMS_BASE
FIREWALL_GO_BASE
FIREWALL_PUB_BASE
FIREWALL_CRAN_BASE
FIREWALL_CONDA_BASE
FIREWALL_CPAN_BASE
FIREWALL_OPAM_BASE
FIREWALL_COCOAPODS_BASE
FIREWALL_SWIFTPM_BASE
FIREWALL_PEAR_BASE#Storage
The firewall adds:
dependency_firewall_policiesdependency_firewall_eventsdependency_firewall_cachedependency_admission_exceptionsdependency_admission_baselines
Events are the audit trail for who requested a package, which policy applied, and why the dependency was allowed, warned, reviewed, or blocked.
#Upgrade candidates and evidence
candidateVersions are advisory/registry suggestions requiring a rescan; candidateVersionStatus is unverified. The legacy safeVersions array is empty until independent validation exists. Fix-dependent policy conditions correlate the fix with the same advisory. Prior reviews apply only to the requested version. Evaluator decisions are not automatically DSSE-signed.