Coverage
every category held in a system needs a rule (category-wide or system-specific); undeclared categories and systems are reported; unused categories are noted.
GitHub Packages · MIT · Node ≥ 18
Lint your data-retention policy as code: every data category gets a period, a legal basis and an action at expiry.
Lint a declarative data-retention policy (YAML or JSON): missing or invalid periods, indefinite retention, conflicting rules, data categories held in systems with no rule, unknown categories/systems, missing legal basis, expiry action, trigger and owner, over-long periods, overdue reviews. SARIF, GitHub Action. Zero deps.
1 Point the @mrlouiswright scope at GitHub Packages in .npmrc
@mrlouiswright:registry=https://npm.pkg.github.com2 Install
npm i -D @mrlouiswright/retention-wardenPublished to GitHub Packages, not npmjs.com. GitHub Packages needs a GitHub token with read:packages to install, even for public packages: add //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} to .npmrc or run npm login --registry=https://npm.pkg.github.com.
$ npx retention-warden test/fixtures/bad/retention.ymlretention-warden — test/fixtures/bad/retention.ymlpolicy test/fixtures/bad/retention.yml HIGH test/fixtures/bad/retention.yml:12 "chat" is held in postgres but no rule covers it [retention-category-unmapped]HIGH test/fixtures/bad/retention.yml:21 Rules #1 and #2 disagree for account: P2Y/delete vs P10Y/delete [retention-conflict]HIGH test/fixtures/bad/retention.yml:32 marketing is kept indefinitely [retention-indefinite]HIGH test/fixtures/bad/retention.yml:36 Period "soon" for invoices in s3 is not understood [retention-period-invalid]MEDIUM test/fixtures/bad/retention.yml:13 System "postgres" holds undeclared category "marketing" [retention-category-unknown]MEDIUM test/fixtures/bad/retention.yml:22 account kept 10y, over maxPeriod 5y [retention-exceeds-max]
GDPR's storage-limitation principle, the UK GDPR and most security questionnaires ask the same thing: how long do you keep each kind of personal data, why, and what happens afterwards? The answer usually lives in a spreadsheet that drifts away from the systems it describes. retention-warden reads a small, declarative retention.yml (categories, systems and rules), checks it is complete and consistent, and fails CI when someone adds a new data category without a rule or sets an over-long or indefinite period.
CLI, library and GitHub Action. Node.js 18+, zero runtime dependencies, runs offline. By Louis Wright.
every category held in a system needs a rule (category-wide or system-specific); undeclared categories and systems are reported; unused categories are noted.
ISO 8601 (P30D, P6M, P2Y) or plain words (90 days, 6 years); invalid periods, missing periods and indefinite retention of personal data (without justification) are high severity.
defaults.maxPeriod and defaults.specialMaxPeriod (for special: true categories such as health data).
conflicting rules for the same category and system, and exact duplicates.
legal basis, action at expiry (delete, anonymise, archive, review, ...), trigger (when the clock starts), owner, and a reviewed date checked against reviewEveryMonths (default 12).
findings carry the line in your YAML file, so SARIF annotations land on the right rule.
# Example
npx retention-warden# Example
npx retention-warden policies/retention.yml --fail-on medium# Example
npx retention-warden . --max-period P7Y --special-max-period P1Y# Example
npx retention-warden --format sarif > retention.sarifpermissions:
contents: read
security-events: write # only needed for the SARIF upload
jobs:
retention-warden:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with: { persist-credentials: false }
- uses: MrLouisWright/retention-warden@v1
with:
path: .
fail-on: high
sarif: retention-warden.sarif
- uses: github/codeql-action/upload-sarif@v3
if: always()
with: { sarif_file: retention-warden.sarif }
| Flag | Description |
|---|---|
| Policy | |
--max-period <p> | Longest allowed period, e.g. P7Y (overrides defaults.maxPeriod) |
--review-every-months <n> | Review interval (default 12) |
| Common | |
-c, --config <file> | JSON config (default: .retention-warden.json or "retentionWarden" in package.json) |
-f, --format <fmt> | text (default) | json | sarif | markdown |
--json <file> | Also write a JSON report |
--sarif <file> | Also write SARIF 2.1.0 |
--markdown <file> | Also write Markdown (e.g. for a job summary) |
--fail-on <sev> | critical | high | medium | low | info | none (default: high) |
--list-rules | Print rules and default severities |
--no-fixes | Hide fix suggestions in text output |
--no-color | Disable colours |
Full reference, config file format and API in the README.
Support this project
I build free, open-source tools that help developers ship safer websites. Every coffee helps keep them maintained, documented and free for everyone.
Buy me a coffee (opens Stripe in a new tab)Secure checkout by Stripe