agentic/code/frameworks/security-engineering/skills/pnpm-release-age-gate/SKILL.md
Configure pnpm's minimumReleaseAge gate (7-day default, 10-day high-sensitivity) plus blockExoticSubdeps for workspace-scope dep-source enforcement. Includes Corepack detection and lockfile-caveat warning.
npx skillsauth add jmagly/aiwg pnpm-release-age-gateInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill when a user has chosen pnpm as their package manager
and wants to apply the same release-age-gate hardening that
npm-release-age-gate provides for npm. pnpm is often the preferred
baseline for new projects because minimumReleaseAge AND
blockExoticSubdeps can be enforced at the workspace level — npm
has no equivalent for the latter.
pnpm --version)package.json exists at repo rootIf pnpm is below v9.0, the skill should refuse to proceed and direct
the user to upgrade — minimumReleaseAge was introduced in v9.0 and
older versions silently ignore it.
Add the gate to .npmrc at repo root:
# Refuse dependency versions published less than 7 days ago.
# pnpm interprets the value in MINUTES. 10080 = 7 days; 14400 = 10 days.
# Defends against newly-published malicious versions.
minimum-release-age=10080
# Reject git+, tarball-URL, file:, link: sources — these bypass
# registry signature verification (companion to npm-supply-chain-audit
# dep-source policy).
block-exotic-subdeps=true
Add the gate to pnpm-workspace.yaml:
packages:
- 'packages/*'
- 'apps/*'
# Workspace-scope release-age enforcement.
# Value is in MINUTES. 10080 = 7 days; 14400 = 10 days.
minimumReleaseAge: 10080
# Reject non-registry dep sources fleet-wide.
blockExoticSubdeps: true
Workspace-scope is the pnpm advantage over npm — every nested package inherits the gate without per-package config.
pnpm config set minimum-release-age 10080 # minutes — 7 days
pnpm config set block-exotic-subdeps true
Use this only when the entire dev machine should apply the gate across all projects. Per-repo config (Option A or B) is preferred — it travels with the repo and works in CI without machine setup.
pnpm uses minutes for minimumReleaseAge:
| Days | Minutes value |
|---|---|
| 1 | 1440 |
| 7 (recommended default) | 10080 |
| 10 (high-sensitivity profile) | 14400 |
| 14 | 20160 |
| 30 | 43200 |
This differs from npm (min-release-age in days) and Bun
(install.minimumReleaseAge in seconds). Document the unit
inline when committing the config so future readers don't misread it.
The gate must be active before pnpm install or pnpm update
resolves dependencies. If the existing pnpm-lock.yaml was generated
without the gate, the gate is checked on the NEXT resolution pass —
not retroactively against the lockfile.
To apply the gate retroactively:
# Force re-resolution with the gate active
rm pnpm-lock.yaml
pnpm install
This is destructive to existing pins and may pull in newer intermediate versions. Coordinate with the team before running.
Check whether the project pins a pnpm version via Corepack:
node -p "require('./package.json').packageManager"
Output like [email protected] means Corepack will use that exact version
in CI. The skill should:
corepack use pnpm@latest
# writes packageManager to package.json
Genuine emergency overrides:
# One-off install bypassing the gate
pnpm install <pkg>@<version> --ignore-min-release-age
# Permanently allow a specific package (rare; record rationale in
# a SECURITY-OVERRIDE.md or equivalent)
Document every override with reason + sunset date. Overrides should be reviewed quarterly.
Add a verification step to the publish/build workflow:
- name: Verify pnpm gate active
run: |
set -euo pipefail
AGE=$(pnpm config get minimum-release-age 2>/dev/null || echo "0")
EXOTIC=$(pnpm config get block-exotic-subdeps 2>/dev/null || echo "false")
if [ "$AGE" -lt 10080 ] || [ "$EXOTIC" != "true" ]; then
echo "✗ pnpm gate not configured to baseline (minimumReleaseAge≥10080, blockExoticSubdeps=true)"
exit 1
fi
echo "✓ pnpm gate active: $AGE minutes, blockExoticSubdeps=$EXOTIC"
.npmrc OR pnpm-workspace.yaml for minimumReleaseAge and blockExoticSubdepspackage.json packageManager field for Corepack pinpnpm-lock.yaml was generated AFTER the gate was committed (timestamp check)When auditing an existing pnpm project, produce a structured report
at .aiwg/security/working/pnpm-release-age-audit.md:
# pnpm Release-Age Gate Audit
**pnpm version**: <version> (Corepack pinned: yes/no)
**Workspace shape**: single-package / multi-package
**Gate active**: yes (10080 min) / yes (custom: <value>) / no
**blockExoticSubdeps**: true / false / unset
## Findings
### <severity> — <description>
- File: <path>
- Issue: <what's wrong>
- Fix: <exact change>
## Clean Checks
- ...
## Recommendations
- ...
npm-release-age-gate skill — npm equivalentyarn-release-age-gate skill — Yarn equivalentbun-release-age-gate skill — Bun equivalentnpm-supply-chain-audit skill — companion auditsupply-chain-hardening-quickstart skill — orchestratorminimumReleaseAge: https://pnpm.io/settings#minimumreleaseageblockExoticSubdeps: https://pnpm.io/settings#blockexoticsubdepsdata-ai
Report which research-corpus radar sidecars are overdue for refresh. Computes staleness (days since last refresh vs the cadence window) for every radar, sorted most-overdue-first. Runs via `aiwg corpus radar-status`.
data-ai
Aggregate research-corpus radar sidecars into a corpus or per-cluster freshness report — totals, overdue count, per-cluster / per-GRADE / per-trajectory breakdowns, an overdue table, and per-radar rationale snippets. Runs via `aiwg corpus radar-report`.
testing
Scaffold radar/freshness sidecars for research-corpus REFs. Pulls title/authors from the citation sidecar and GRADE from the analysis doc, defaults the refresh cadence from GRADE and the cluster from a corpus-local map, and stamps documentation/radar/REF-XXX-radar.md. Runs via `aiwg corpus radar-init`.
data-ai
Compute an entity's publication trajectory — per-year paper counts, topic drift, hot-streak detection (≥3 consecutive A-grade years), and career phase. Runs via `aiwg corpus profile-temporal`.