Policy Configuration
npmvc-policy.json controls what gets checked and how strictly.
Quick start: presets
Use npmvc install-hook --preset strict|balanced|permissive to generate a policy. The fields below are documented for hand-tuning.
Full schema
{
"enforcement": "block | warn | off",
"transitive": true,
"minAge": "7d",
"perPackage": { "left-pad": "30d" },
"unattested": "warn | block | allow",
"unattestedMinAge": "30d",
"trustedIssuers": ["https://npmvc.com/trust-root.json", "did:key:z6Mk..."],
"trustedAuditIssuers": ["did:key:z6MkSCANNER..."],
"auditMaxAge": "180d",
"attestationSources": ["local", "registry"],
"requireAuditWithin": "90d",
"registry": "https://npmvc.com",
"allowPrivateRegistry": false,
"publisherContinuity": {
"required": true,
"onUnauthorizedChange": "block | warn",
"pinned": { "express": "did:key:z6Mk..." }
},
"revocation": {
"required": true,
"checkVia": "webvh | none",
"registryUrl": "https://npmvc.com",
"maxCacheAge": "10m"
},
"waivers": [{
"package": "legacy-dep",
"versionRange": "*",
"reason": "reviewed manually",
"expiresAt": "2027-01-01"
}],
"lifecycleScripts": {
"postInstall": "forbidden | whitelisted | allowed",
"whitelist": ["esbuild", "sharp"]
},
"licenses": {
"allowed": ["MIT", "Apache-2.0", "ISC"],
"denied": ["AGPL-3.0", "SSPL-1.0"]
}
}enforcement
block (default) — exit non-zero on any failure, sonpm install aborts. warn — report but allow. off — skip checks entirely.
minAge
Reject versions published less than this duration ago. Formats: 7d, 24h, 30m, 1y. Falls back to a verified PublishTimestampCredential when the public npm registry can't be reached.
unattested
Packages with no attestation bundle. allow accepts silently; warn logs (default); block fails. Block is only practical when every dep is attested.
trustedIssuers
Allowlist of DIDs that may sign Provenance / SBOM / Lifecycle credentials. Entries beginning with https:// are treated as signed trust-root URLs: the fetched document must carry an Ed25519 signature from the pinned root DID before its issuers are added.
trustedAuditIssuers + auditMaxAge
Audit credentials count toward coverage only if their issuer DID is in trustedAuditIssuers (empty = accept any) and they're no older than auditMaxAge.
attestationSources
Where to look up envelopes, in order. local reads node_modules/<pkg>/.npmvc/attestations.jsonld; registry fetches from policy.registry. Pre-install needs registry because node_modules doesn't exist yet.
publisherContinuity
Detect when a package's publisher DID changes. pinned maps package names to expected DIDs. did:webvh DIDs sharing the same SCID prefix count as the same identity (legitimate key rotation is allowed).
revocation
When required, the engine fetches the registry's revoked-credential list once per evaluation and refuses any envelope whose credential ID is on it.
allowPrivateRegistry
By default, policy.registry URLs must be https:// and not point at private IPs / metadata endpoints. Self-hosted setups flip this to true.
waivers
Explicit exceptions for reviewed packages. Downgrades failures to warnings. Supports expiresAt.
lifecycleScripts
forbidden — fail on any install script. whitelisted — allow named packages. allowed — no restriction.
licenses
SPDX license filtering. allowed is a whitelist; denied is a blacklist.