@schalkneethling/calavera-skill-npm-publishing-best-practices 0.2.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Schalk Neethling
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://calavera.schalkneethling.com/schemas/calavera-artifact.schema.json",
|
|
3
|
+
"schemaVersion": 1,
|
|
4
|
+
"id": "skill-npm-publishing-best-practices",
|
|
5
|
+
"type": "skill",
|
|
6
|
+
"displayName": "npm publishing best practices",
|
|
7
|
+
"payload": "payload/npm-publishing-best-practices",
|
|
8
|
+
"compatibility": {
|
|
9
|
+
"calavera": ">=2.2.0 <3"
|
|
10
|
+
}
|
|
11
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@schalkneethling/calavera-skill-npm-publishing-best-practices",
|
|
3
|
+
"version": "0.2.0-next.1",
|
|
4
|
+
"description": "npm publishing best practices artifact for Calavera.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+ssh://git@github.com/schalkneethling/create-project-calavera.git",
|
|
9
|
+
"directory": "packages/artifacts/skill-npm-publishing-best-practices"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"calavera-artifact.json",
|
|
13
|
+
"payload"
|
|
14
|
+
],
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": "./calavera-artifact.json",
|
|
18
|
+
"./package.json": "./package.json"
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public",
|
|
22
|
+
"provenance": true
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: npm-package-publishing
|
|
3
|
+
description: >
|
|
4
|
+
Audit and improve the security posture of npm package publishing: account security, npm trusted
|
|
5
|
+
publishing strategy, GitHub repository hardening, token removal, release governance, dependency
|
|
6
|
+
update policy, provenance, and supply-chain risk. Use when the user asks about npm publishing best
|
|
7
|
+
practices, publishing security, OIDC/trusted publishing strategy, npm token hygiene, release
|
|
8
|
+
automation posture, Changesets versus changelog strategies, publint, provenance, or auditing an
|
|
9
|
+
existing publishing pipeline. For writing or debugging the concrete GitHub Actions publish
|
|
10
|
+
workflow file, use the npm-trusted-publishing-github-workflow skill instead.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# npm Package Publishing — Best Practices
|
|
14
|
+
|
|
15
|
+
Based on the [e18e publishing guide](https://e18e.dev/docs/publishing.html). Reference it for
|
|
16
|
+
the canonical source; this skill distils the actionable steps.
|
|
17
|
+
|
|
18
|
+
## Agent Workflow
|
|
19
|
+
|
|
20
|
+
1. Inspect the repository before recommending changes:
|
|
21
|
+
- `package.json`
|
|
22
|
+
- lockfiles and `packageManager`
|
|
23
|
+
- `.npmrc`, `.yarnrc.yml`, `.github/workflows/*`
|
|
24
|
+
- release tooling such as Changesets, changelogithub, semantic-release, or release-it
|
|
25
|
+
- existing npm/GitHub tokens or `NODE_AUTH_TOKEN` usage in workflows
|
|
26
|
+
2. Classify the request:
|
|
27
|
+
- **Audit**: report risks by severity, with file and line references where possible.
|
|
28
|
+
- **Implementation**: make scoped repository changes, then run relevant validation.
|
|
29
|
+
- **Strategy**: explain tradeoffs and identify user-only settings.
|
|
30
|
+
3. Separate agent-doable work from user-only UI work. Do not claim account, npmjs.com, or GitHub
|
|
31
|
+
settings are configured unless verified by authenticated tool/API access.
|
|
32
|
+
4. For concrete GitHub Actions publish workflow creation or CI failure debugging, hand off to the
|
|
33
|
+
`npm-trusted-publishing-github-workflow` skill.
|
|
34
|
+
|
|
35
|
+
## Freshness Rule
|
|
36
|
+
|
|
37
|
+
Before changing trusted publishing requirements, supported CI providers, npm CLI minimums, Node.js
|
|
38
|
+
minimums, provenance behavior, or GitHub release/security settings, verify the current official npm
|
|
39
|
+
and GitHub documentation when browsing is available. These requirements change over time.
|
|
40
|
+
|
|
41
|
+
## Responsibility Split
|
|
42
|
+
|
|
43
|
+
Agent can usually:
|
|
44
|
+
|
|
45
|
+
- Edit `.github/workflows/*`.
|
|
46
|
+
- Add or update repository package-manager config such as `.npmrc` or `.yarnrc.yml`.
|
|
47
|
+
- Remove `NODE_AUTH_TOKEN` usage from publish steps when trusted publishing is used.
|
|
48
|
+
If private dependencies require registry auth during install, keep that token scoped to read-only
|
|
49
|
+
install steps only.
|
|
50
|
+
- Add Dependabot/Renovate config.
|
|
51
|
+
- Run `publint`, workflow linting, tests, package builds, and other local validation.
|
|
52
|
+
- Report exact user steps for npm/GitHub settings.
|
|
53
|
+
|
|
54
|
+
User or authenticated UI/API access required:
|
|
55
|
+
|
|
56
|
+
- Enable npm/GitHub 2FA.
|
|
57
|
+
- Configure npm trusted publisher settings on npmjs.com.
|
|
58
|
+
- Set package publishing access to require 2FA and disallow tokens.
|
|
59
|
+
- Enable GitHub repository/org Actions restrictions.
|
|
60
|
+
- Configure branch/tag rulesets and immutable releases.
|
|
61
|
+
- Remove repository/org secrets when the agent lacks GitHub settings access.
|
|
62
|
+
|
|
63
|
+
## Non-Negotiables
|
|
64
|
+
|
|
65
|
+
- Do not add `NODE_AUTH_TOKEN` to publish steps when trusted publishing is available.
|
|
66
|
+
Use OIDC for publishing; if private dependencies require install auth, use a read-only token only
|
|
67
|
+
for the install step.
|
|
68
|
+
- Do not store npm publish tokens in GitHub Actions secrets for OIDC-capable publishing.
|
|
69
|
+
- Do not run install lifecycle scripts in release workflows unless the user explicitly accepts the
|
|
70
|
+
risk.
|
|
71
|
+
- Do not show tag-pinned actions as compliant with SHA pinning; resolve all third-party and
|
|
72
|
+
GitHub-owned actions to full commit SHAs. Tag-based refs such as `@v6` or `@v7` weaken
|
|
73
|
+
supply-chain integrity and violate pinned-action policy.
|
|
74
|
+
- Do not create or edit GitHub Actions workflows without explicit least-privilege `permissions:`
|
|
75
|
+
for `GITHUB_TOKEN`. Set a restrictive top-level default such as `contents: read`, then grant
|
|
76
|
+
elevated scopes only on the jobs that need them.
|
|
77
|
+
- Do not use `actions/checkout` with default credential persistence. Always set
|
|
78
|
+
`persist-credentials: false`; if a job must push to git, provide an explicit, narrowly scoped
|
|
79
|
+
credential only for that push step.
|
|
80
|
+
- Do not say npm/GitHub account settings are complete unless they were actually checked.
|
|
81
|
+
- Do not use self-hosted runners for npm trusted publishing unless official npm docs currently
|
|
82
|
+
support them.
|
|
83
|
+
|
|
84
|
+
> **Package manager note.** The example install and configuration commands in this skill use `npm`
|
|
85
|
+
> to match the e18e source material, but should be adapted to whichever package manager the project
|
|
86
|
+
> already uses — `pnpm`, `yarn`, `bun`, etc. Adapt commands accordingly:
|
|
87
|
+
>
|
|
88
|
+
> | npm | pnpm | yarn |
|
|
89
|
+
> | --------------------------------- | ------------------------------------------------- | ------------------------------------------------- |
|
|
90
|
+
> | `npm ci --ignore-scripts` | `pnpm install --frozen-lockfile --ignore-scripts` | `yarn install --frozen-lockfile --ignore-scripts` |
|
|
91
|
+
> | `npm i -g npm@12.0.1` | `pnpm add -g pnpm@11.13.1` | `yarn set version 4.17.1` |
|
|
92
|
+
> | `ignore-scripts=true` in `.npmrc` | `ignore-scripts=true` in `.npmrc` | `enableScripts: false` in `.yarnrc.yml` |
|
|
93
|
+
>
|
|
94
|
+
> Detect the project's package manager by checking for a lockfile (`pnpm-lock.yaml`,
|
|
95
|
+
> `yarn.lock`, `bun.lock`) or a `packageManager` field in `package.json` before
|
|
96
|
+
> generating any commands or workflow steps.
|
|
97
|
+
>
|
|
98
|
+
> Section 2.2's trusted-publishing requirement is npm-specific: the publish step must run with a
|
|
99
|
+
> supported Node.js version and npm CLI version even when the rest of the workflow uses another
|
|
100
|
+
> package manager.
|
|
101
|
+
>
|
|
102
|
+
> For pnpm projects on GitHub Actions, prefer the Marketplace action
|
|
103
|
+
> [`pnpm/setup`](https://github.com/marketplace/actions/setup-pnpm-with-runtime) to set up pnpm and
|
|
104
|
+
> the JavaScript runtime in one step. It installs pnpm from `@pnpm/exe`, can read
|
|
105
|
+
> `devEngines.runtime` from `package.json`, and replaces the separate
|
|
106
|
+
> `pnpm/action-setup` + `actions/setup-node` pattern. In release workflows, pin `pnpm/setup` to a
|
|
107
|
+
> full commit SHA, set `install: false`, and run the explicit hardened install command yourself so
|
|
108
|
+
> flags like `--frozen-lockfile --ignore-scripts` remain visible.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 1 · Prerequisites
|
|
113
|
+
|
|
114
|
+
### 1.1 · Enforce 2FA everywhere
|
|
115
|
+
|
|
116
|
+
| Account | Location | Recommended method |
|
|
117
|
+
| ------- | -------------------------------------- | ---------------------------------------------------------------------------- |
|
|
118
|
+
| npm | Account → Security | Security key (YubiKey, Touch ID, Windows Hello); fallback: authenticator app |
|
|
119
|
+
| GitHub | Settings → Password and authentication | Same priority order |
|
|
120
|
+
|
|
121
|
+
Use a password manager with generated passwords for both accounts.
|
|
122
|
+
|
|
123
|
+
### 1.2 · Harden GitHub Actions settings
|
|
124
|
+
|
|
125
|
+
`Settings → Actions → General`:
|
|
126
|
+
|
|
127
|
+
- ✅ Require actions to be pinned to a **full-length commit SHA**
|
|
128
|
+
- ✅ Require approval for first-time contributors
|
|
129
|
+
- ✅ Set default workflow permissions to **"Read repository contents and packages"**
|
|
130
|
+
|
|
131
|
+
> If the repository belongs to an organisation, apply these settings at org level for consistency
|
|
132
|
+
> across all repositories.
|
|
133
|
+
|
|
134
|
+
### 1.3 · Configure branch protection
|
|
135
|
+
|
|
136
|
+
`Settings → Branches` → create a ruleset for `main`:
|
|
137
|
+
|
|
138
|
+
- ✅ Require a pull request before merging
|
|
139
|
+
- ✅ Require at least 1 approval
|
|
140
|
+
- ✅ Dismiss stale approvals when new commits are pushed
|
|
141
|
+
- ✅ Require approval of the most recent reviewable push
|
|
142
|
+
|
|
143
|
+
### 1.4 · Remove legacy npm tokens
|
|
144
|
+
|
|
145
|
+
`Settings → Secrets & Variables → Actions`: remove npm publish tokens. Retain any read-only
|
|
146
|
+
registry credential required for private installs, scoped to install steps only.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 2 · Trusted Publishing (OIDC)
|
|
151
|
+
|
|
152
|
+
Trusted publishing means GitHub Actions authenticates directly with npm via OIDC — no npm token
|
|
153
|
+
ever touches the repository.
|
|
154
|
+
|
|
155
|
+
### 2.1 · Configure on npmjs.com
|
|
156
|
+
|
|
157
|
+
1. Open your package page → **Settings** tab → **Trusted Publishing** section.
|
|
158
|
+
2. Add a trusted publisher:
|
|
159
|
+
- **Organisation / user**: your GitHub org or username
|
|
160
|
+
- **Repository**: the repository name
|
|
161
|
+
- **Workflow filename**: e.g. `publish.yml`
|
|
162
|
+
3. Check **"Require two-factor authentication and disallow tokens"** — this forces manual publishes
|
|
163
|
+
to use 2FA as well.
|
|
164
|
+
|
|
165
|
+
> For bulk configuration across many packages, use
|
|
166
|
+
> [`open-packages-on-npm`](https://github.com/antfu/open-packages-on-npm) to open each package
|
|
167
|
+
> in a new tab, then the
|
|
168
|
+
> [npm-trusted-publisher userscript](https://github.com/sxzz/userscripts/blob/main/src/npm-trusted-publisher.md)
|
|
169
|
+
> to configure them rapidly.
|
|
170
|
+
|
|
171
|
+
### 2.2 · npm CLI version requirement
|
|
172
|
+
|
|
173
|
+
The publish step **must** use npm CLI ≥ 11.5.1 for automatic OIDC trusted publishing.
|
|
174
|
+
Node.js 22.14.0 or newer can use trusted publishing when the workflow installs npm CLI 11.5.1 or
|
|
175
|
+
newer before publishing:
|
|
176
|
+
|
|
177
|
+
```yaml
|
|
178
|
+
- run: npm i -g npm@12.0.1
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 3 · Standard Publish Workflow
|
|
184
|
+
|
|
185
|
+
Use the [e18e setup-publish template](https://github.com/e18e/setup-publish/blob/main/templates/default.yml)
|
|
186
|
+
as your base, or scaffold it with:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
npx @e18e/setup-publish@1.1.0
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### 3.1 · Job structure
|
|
193
|
+
|
|
194
|
+
The workflow **must** separate build from publish. This ensures publish permissions (the OIDC
|
|
195
|
+
token) are never exposed to build-time code.
|
|
196
|
+
|
|
197
|
+
```text
|
|
198
|
+
test → build → publish
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 3.2 · Non-negotiable workflow constraints
|
|
202
|
+
|
|
203
|
+
| Constraint | Why |
|
|
204
|
+
| ------------------------------------------------------ | ----------------------------------------------------------- |
|
|
205
|
+
| All actions pinned to full-length commit SHA | Prevents supply-chain attacks via mutable tags |
|
|
206
|
+
| Explicit least-privilege `GITHUB_TOKEN` permissions | Avoids inheriting broad repository defaults |
|
|
207
|
+
| `actions/checkout` uses `persist-credentials: false` | Reduces token exposure to later workflow steps |
|
|
208
|
+
| `npm ci --ignore-scripts` (or `--ignore-scripts` flag) | Prevents malicious lifecycle scripts running during install |
|
|
209
|
+
| Build and publish in **separate jobs** | Isolates publish permissions from arbitrary build code |
|
|
210
|
+
|
|
211
|
+
Always include a top-level `permissions:` block with the workflow-wide minimum, usually
|
|
212
|
+
`contents: read`. Add job-level permissions only when a job requires more access; for npm trusted
|
|
213
|
+
publishing, `id-token: write` belongs on the publish job only.
|
|
214
|
+
|
|
215
|
+
Every checkout step must disable persisted credentials:
|
|
216
|
+
|
|
217
|
+
```yaml
|
|
218
|
+
- uses: actions/checkout@<full-length-commit-sha>
|
|
219
|
+
with:
|
|
220
|
+
persist-credentials: false
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
This is especially important for jobs that build packages or upload artifacts, because later steps
|
|
224
|
+
should not inherit a repository token unless they explicitly need one.
|
|
225
|
+
|
|
226
|
+
### 3.3 · Suppress lifecycle scripts project-wide
|
|
227
|
+
|
|
228
|
+
Add to `.npmrc` in the repository:
|
|
229
|
+
|
|
230
|
+
```ini
|
|
231
|
+
ignore-scripts=true
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Also apply globally on developer machines:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
npm config set -g ignore-scripts true
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 3.4 · Creating a release
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
git tag v1.0.0
|
|
244
|
+
git push origin v1.0.0
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Then in GitHub UI: **Releases → Draft a new release** → choose the tag → **Generate release notes**
|
|
248
|
+
→ **Publish release**. This triggers the workflow.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## 4 · Alternative Workflow Strategies
|
|
253
|
+
|
|
254
|
+
### 4.1 · Changesets (recommended for teams)
|
|
255
|
+
|
|
256
|
+
Use the [changesets template](https://github.com/e18e/setup-publish/blob/main/templates/changesets.yml).
|
|
257
|
+
|
|
258
|
+
- Merged PRs automatically update a release pull request
|
|
259
|
+
- Changelog is generated by changesets and included in the release PR
|
|
260
|
+
- Releasing = merging the generated release PR — no manual tagging
|
|
261
|
+
|
|
262
|
+
### 4.2 · changelogithub (changelog from commit messages)
|
|
263
|
+
|
|
264
|
+
Use the [changelogithub template](https://github.com/e18e/setup-publish/blob/main/templates/changelogithub.yml).
|
|
265
|
+
|
|
266
|
+
- Tags are still pushed manually
|
|
267
|
+
- GitHub release + changelog are created automatically on tag push
|
|
268
|
+
- Package is published on tag push
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## 5 · Ongoing Maintenance
|
|
273
|
+
|
|
274
|
+
### 5.1 · Keep dependencies updated
|
|
275
|
+
|
|
276
|
+
Set up **Dependabot** or **Renovate** to receive automated PRs for dependency updates,
|
|
277
|
+
addressing security vulnerabilities promptly.
|
|
278
|
+
|
|
279
|
+
### 5.2 · Keep GitHub Actions updated
|
|
280
|
+
|
|
281
|
+
All third-party and GitHub-owned actions must be pinned to a full commit SHA, not a tag. Tag refs
|
|
282
|
+
such as `@v6` or `@v7` are mutable and must not be committed to workflow files. To migrate existing
|
|
283
|
+
workflows and keep them current:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
npx actions-up@1.16.0
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Run this periodically, or let Dependabot/Renovate manage action updates once SHAs are in place.
|
|
290
|
+
|
|
291
|
+
### 5.3 · Lint workflows for vulnerabilities
|
|
292
|
+
|
|
293
|
+
[`zizmor`](https://github.com/zizmorcore/zizmor) detects template injection vulnerabilities and
|
|
294
|
+
excessive permission scopes in GitHub workflow files:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
zizmor .github/workflows/publish.yml
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Integrate this into CI or run it before merging workflow changes.
|
|
301
|
+
|
|
302
|
+
### 5.4 · Validate package.json and exports
|
|
303
|
+
|
|
304
|
+
[`publint`](https://publint.dev) checks for common publishing issues: missing files, incorrect
|
|
305
|
+
`exports` fields, wrong `main`/`module` paths, and more.
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
npx publint@0.3.21
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Review the [full list of publint rules](https://publint.dev/rules) to understand what it checks.
|
|
312
|
+
Run this locally before tagging a release.
|
|
313
|
+
|
|
314
|
+
### 5.5 · Visualise dependency changes
|
|
315
|
+
|
|
316
|
+
[`multiocular`](https://github.com/multiocular-com/multiocular) shows exactly what code changed
|
|
317
|
+
between dependency versions, helping catch unexpected changes or potential security issues.
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## 6 · Further Security Hardening
|
|
322
|
+
|
|
323
|
+
### 6.1 · Use a GitHub environment (important for shared repos)
|
|
324
|
+
|
|
325
|
+
Without a GitHub environment, **any account with write access can trigger a publish** by creating
|
|
326
|
+
a branch and modifying the release workflow — bypassing code review entirely.
|
|
327
|
+
|
|
328
|
+
`Settings → Environments`:
|
|
329
|
+
|
|
330
|
+
1. Create an environment named `publish`.
|
|
331
|
+
2. **Do not** allow administrator bypass of protection rules.
|
|
332
|
+
3. Limit deployment to explicit branch names only (e.g. `main`, `v1`). Do not use wildcards.
|
|
333
|
+
Remove stale branches promptly.
|
|
334
|
+
4. Update the publish job in `publish.yml`:
|
|
335
|
+
|
|
336
|
+
```yaml
|
|
337
|
+
jobs:
|
|
338
|
+
publish:
|
|
339
|
+
environment: publish
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
5. Update the npm trusted publisher settings on `npmjs.com` to include the environment name.
|
|
343
|
+
|
|
344
|
+
> Optionally configure the `publish` environment to require **manual approval** before the job
|
|
345
|
+
> proceeds — providing a human gate even if malicious code reaches a release branch.
|
|
346
|
+
|
|
347
|
+
### 6.2 · Consider hardware security keys _(optional)_
|
|
348
|
+
|
|
349
|
+
Physical security keys (YubiKey, etc.) are significantly more resistant to phishing and credential
|
|
350
|
+
theft than authenticator apps or SMS. They are worth recommending but should never be enforced —
|
|
351
|
+
not everyone has access to one, and a good authenticator app is a perfectly reasonable alternative.
|
|
352
|
+
Mention this as a suggestion, not a requirement.
|
|
353
|
+
|
|
354
|
+
### 6.3 · Protect all long-lived branches and tags
|
|
355
|
+
|
|
356
|
+
Apply branch protection rules to every long-lived branch. Protect release tags separately with a
|
|
357
|
+
tag ruleset; branch protection does not apply to tags.
|
|
358
|
+
|
|
359
|
+
### 6.4 · Enable immutable releases
|
|
360
|
+
|
|
361
|
+
Enable [GitHub immutable releases](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/immutable-releases)
|
|
362
|
+
to prevent modification or deletion of tags and releases after creation.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## 7 · Sole Maintainer Considerations
|
|
367
|
+
|
|
368
|
+
There is an [open feature request](https://github.com/orgs/community/discussions/174507) to
|
|
369
|
+
support 2FA for GitHub environment approvals. Until that lands, trusted publishing carries a risk
|
|
370
|
+
for solo maintainers: a leaked GitHub token could be used to publish through the trusted workflow
|
|
371
|
+
without a 2FA challenge.
|
|
372
|
+
|
|
373
|
+
**Recommendation for sole maintainers**: consider publishing locally with `npm publish` and
|
|
374
|
+
2FA-protected npm access until environment-level 2FA approval is supported. Continue to follow
|
|
375
|
+
all other security recommendations in this document regardless.
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Audit Output Format
|
|
380
|
+
|
|
381
|
+
For audits, lead with findings:
|
|
382
|
+
|
|
383
|
+
- **P0/P1/P2/P3** severity.
|
|
384
|
+
- File and line when repo-local.
|
|
385
|
+
- Risk.
|
|
386
|
+
- Recommended fix.
|
|
387
|
+
- Whether the agent can implement it now or the user must configure it externally.
|
|
388
|
+
|
|
389
|
+
Then include:
|
|
390
|
+
|
|
391
|
+
- Validation run.
|
|
392
|
+
- Remaining user-only checklist.
|
|
393
|
+
- Suggested next change.
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## Quick Reference Checklist
|
|
398
|
+
|
|
399
|
+
Use this when setting up a new package or auditing an existing one.
|
|
400
|
+
|
|
401
|
+
### Account security
|
|
402
|
+
|
|
403
|
+
- [ ] npm 2FA enabled (security key preferred)
|
|
404
|
+
- [ ] GitHub 2FA enabled (security key preferred)
|
|
405
|
+
- [ ] Password manager in use
|
|
406
|
+
|
|
407
|
+
### Repository settings
|
|
408
|
+
|
|
409
|
+
- [ ] Actions pinned to full-length commit SHAs (enforced in settings)
|
|
410
|
+
- [ ] First-time contributor approval required
|
|
411
|
+
- [ ] Default workflow permissions set to read-only
|
|
412
|
+
- [ ] `main` branch protected (PR + review required)
|
|
413
|
+
- [ ] Release tags protected by a tag ruleset
|
|
414
|
+
- [ ] No publish-capable npm tokens in repository secrets
|
|
415
|
+
|
|
416
|
+
### Trusted publishing
|
|
417
|
+
|
|
418
|
+
- [ ] OIDC trusted publisher configured on npmjs.com
|
|
419
|
+
- [ ] "Require 2FA, disallow tokens" enabled on npm
|
|
420
|
+
- [ ] Publish step uses npm CLI ≥ 11.5.1 and a Node.js version supported by official npm docs
|
|
421
|
+
- [ ] GitHub environment (`publish`) configured with branch restrictions
|
|
422
|
+
|
|
423
|
+
### Workflow hygiene
|
|
424
|
+
|
|
425
|
+
- [ ] Build and publish are separate jobs
|
|
426
|
+
- [ ] Workflows declare explicit least-privilege `GITHUB_TOKEN` permissions
|
|
427
|
+
- [ ] Every `actions/checkout` step sets `persist-credentials: false`
|
|
428
|
+
- [ ] `npm ci --ignore-scripts` used in all install steps
|
|
429
|
+
- [ ] `ignore-scripts=true` in `.npmrc`
|
|
430
|
+
- [ ] `zizmor` passes on all workflow files
|
|
431
|
+
|
|
432
|
+
### Package quality
|
|
433
|
+
|
|
434
|
+
- [ ] `npx publint@0.3.21` passes with no errors
|
|
435
|
+
- [ ] Dependabot or Renovate configured
|
|
436
|
+
- [ ] `actions-up` run to migrate to SHA-pinned actions
|