forgesworn/anvil
Supply-chain-hardened npm publish for JS/TS libraries. OIDC trusted publishing, SLSA provenance, secret scan, exports check, frozen-vector gate, action-pin auditing. Zero dependencies, pure bash, auditable in thirty minutes.
View on GitHubTrust Signals
- Scorecard Score
- not yet scored
- Maintenance Recency
- Activelast commit Jun 3, 2026
- License
- MIT
Pinned Snippet
uses: forgesworn/anvil@d4294e622932d93957d73e5b1af0267382b6af04 # v0.10.1tags can be moved; commit SHAs can't. why a SHA?
Inputs
| name | description | required | default |
|---|---|---|---|
| node-version | Node version used for npm operations (must ship with npm >= 11.5.x for OIDC trusted publishing) | no | 24.11.0 |
| registry-url | npm registry URL for publishes | no | https://registry.npmjs.org |
| test-command | Command that runs the full test suite | no | npm test |
| vector-test-command | Command for the frozen-vector gate (empty to skip) | no | "" |
| changelog-file | Path to CHANGELOG.md | no | CHANGELOG.md |
| package-json | Path to package.json | no | package.json |
| audit-level | npm audit level (low|moderate|high|critical) | no | low |
| strict-action-pins | If "true" (the default), verify-action-pins fails the release on any unpinned `uses:` reference in .github/workflows. Set to "false" for warn-only mode. forgesworn/anvil is exempt by name. | no | true |
| lifecycle-scripts-policy | How verify-lifecycle-scripts handles preinstall/install/postinstall hooks in the published package. One of: - warn (default): unpermitted hooks are logged but publish continues. - strict: unpermitted hooks fail the release. - off: skip the gate entirely. Install-time hooks run on every consumer's machine when they `npm install` the package — the attack surface used in the April 2026 Bitwarden CLI compromise. Allow specific hooks via `allowed-lifecycle-scripts`. | no | warn |
| allowed-lifecycle-scripts | JSON object mapping hook name (preinstall/install/postinstall) to the exact command string permitted. Anything else warns or fails depending on `lifecycle-scripts-policy`. Empty map (default) means no install hooks are allowed. Example: {"postinstall": "node-gyp rebuild"} | no | {} |
| version-strategy | How version bumps are validated. One of: - manual (default): you bump package.json and tag; the action verifies the tag matches and publishes. - verify: you bump manually, but the action parses conventional commits and fails if your bump is smaller than what the commit history implies (e.g. feat commits but only a patch bump). | no | manual |
| dry-run | If "true", skip the real publish (for smoke-testing) | no | false |
| debug | If "true", run a diagnostic step before publish that dumps npm version, redacted .npmrc, OIDC env vars, and `npm config list`. Off by default. Useful for debugging trusted-publisher setup. | no | false |
Outputs
no outputs