v11y-check
v0.11.0
Published
Wrap audit-ci with a richer config model, typed JSON source of truth, and sync workflow
Maintainers
Readme
v11y-check
Wraps audit-ci with a richer config model, typed JSON source of truth, and a sync workflow that automates allowlist management.
Release notes — v0.11.0 (2026-07-13)
🎉 Features
🚨 Breaking: Fail a package that declares types but ships none (#467)
nmr attwnow fails a package that claims to ship type declarations but ships none. Such a package used to pass, leaving every TypeScript consumer of it silently typed asany.A package that ships working declarations found only by sitting beside its JavaScript entry point escapes the check, since it declares nothing. Add a
typesentry to bring it under the check.
Installation
pnpm add -D v11y-checkThe package is v11y-check; the bin is v11y. The package also ships v11y-check as a bin alias, so pnpm exec v11y-check and npx v11y-check continue to work.
Quick start
# Run a vulnerability check with sensible defaults (no config needed)
npx v11y-check check
# Scaffold a starter config and GitHub Actions workflow
npx v11y-check init
# Sync allowlists with current findings
npx v11y-check sync
# Raw audit-ci passthrough
npx v11y-check --rawNo config file is required. When .config/v11y-check.config.json is absent, the tool uses built-in defaults: severityThreshold: 'moderate' for dev, severityThreshold: 'low' for prod, and empty allowlists.
Configuration
The source-of-truth config lives at .config/v11y-check.config.json:
{
"$schema": "https://github.com/williamthorsen/node-monorepo-tools/raw/v11y-check-v<version>/packages/v11y-check/schemas/config.json",
"dev": {
"severityThreshold": "moderate",
"allowlist": [
{
"addedAt": "2026-04-15T09:30:00.000Z",
"id": "GHSA-1234-5678-abcd",
"path": "lodash",
"reason": "Accepted risk: no user input reaches this path",
"url": "https://github.com/advisories/GHSA-1234-5678-abcd"
}
]
},
"prod": {
"severityThreshold": "low",
"allowlist": []
}
}Fields
$schema(optional) — JSON Schema URL for editor autocomplete and validation. Automatically included byinitandsync.dev/prod— Scope-specific settings:severityThreshold(optional) — Fail on advisories at or above this severity. Valid values:'low','moderate','high','critical'. When omitted, audit-ci uses its own defaults.allowlist— Typed advisory entries withid,path,url, and optionalreasonandaddedAt.addedAtis an ISO 8601 UTC datetime (e.g.,2026-04-15T09:30:00.000Z) populated automatically byv11y syncon new entries; existing entries retain whatever value they had. OlderYYYY-MM-DDvalues are still accepted.
CLI reference
Usage: v11y [options]
v11y <command> [options]
Commands:
check (default) Grouped vulnerability check with severity indicators
sync Synchronize allowlists with current audit findings
init Scaffold a starter config file and GitHub Actions workflow
Scope options:
--dev Target dev dependencies only
--prod Target production dependencies only
Other options:
--config <path> Path to config file (default: .config/v11y-check.config.json)
--json Output results as JSON
--raw Run raw audit-ci passthrough
--verbose, -v Show detailed per-vulnerability output
--help, -h Show this help message
--version, -V Show version numberInit options
--dry-run, -n Preview changes without writing files
--force, -f Overwrite existing filesJSON output shape
--json emits one object per requested scope plus a top-level summary block:
{
"prod": { "allowed": [...], "belowThreshold": [...], "stale": [...], "unallowed": [...] },
"dev": { "allowed": [...], "belowThreshold": [...], "stale": [...], "unallowed": [...] },
"summary": { "status": "vulnerabilities-found", "count": 3 }
}summary.status is the highest-severity finding category present across the requested scopes. Below-threshold findings never affect it.
| status | When |
| ---------------------------- | ------------------------------------------------- |
| vulnerabilities-found | At least one unallowed advisory |
| suppressed-vulnerabilities | No unallowed; at least one allowlisted advisory |
| stale-overrides | No advisories; at least one stale allowlist entry |
| none | No findings |
summary.count is the total across the requested scopes for the active category. It is 0 when status is none.
Scaffolded GitHub Actions workflow
v11y init scaffolds .github/workflows/audit.yaml alongside the config file. The workflow is a thin caller that delegates to the versioned reusable workflow published at williamthorsen/node-monorepo-tools/.github/workflows/audit.reusable.yaml@workflow/audit-v1, so your repository tracks the reusable workflow at a stable version tag.
The scaffolded workflow triggers on pull requests to main/next, on a daily schedule, and on manual workflow_dispatch. Commit the file into your repository so the caller runs in CI. If the reusable workflow's caller-side requirements change (for example, the tag bumps), re-run v11y init --force to refresh the file.
Migration from v0.3
v0.4 introduces breaking changes to the config schema:
outDirremoved. Intermediate audit-ci files are now written to a temp directory and cleaned up automatically. RemoveoutDirfrom your config.- Severity booleans replaced by
severityThreshold. Replace"moderate": truewith"severityThreshold": "moderate","high": truewith"severityThreshold": "high", etc. Only one threshold per scope is supported. generatesubcommand removed. Thev11y generatecommand no longer exists. Flat audit-ci configs are now managed internally.- Config is optional. All commands now work without a config file, using built-in defaults.
To migrate an existing config:
- Remove the
outDirfield. - Replace severity booleans with
severityThresholdin each scope. - Optionally add a
$schemafield (runv11y init --forceto regenerate, or add it manually). - Delete any generated
audit-ci.*.jsonfiles that were in your config directory.
