Skip to content

Commit e76650e

Browse files
committed
docs: document npm E403 fix (Classic token), missing PyPI OIDC, v0.2.0 workarounds
1 parent 41408d7 commit e76650e

1 file changed

Lines changed: 69 additions & 4 deletions

File tree

docs/07-cicd-publishing.md

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,38 @@ brew install edgeparse
8080

8181
---
8282

83+
## ⚠️ What's Missing / Must Be Configured Before Next Release
84+
85+
| Item | Status | Action Required |
86+
|------|--------|----------------|
87+
| **npm — Classic Automation Token** | ❌ Not done | Current `NPM_TOKEN` is a Granular token scoped only to `edgeparse`. Replace with a **Classic Automation token** so all 6 npm packages can publish. See [npm E403 troubleshooting](#npm-e403-forbidden-on-platform-packages-but-main-package-succeeds). |
88+
| **PyPI — OIDC Trusted Publisher** | ❌ Not done | `release-python.yml` uses OIDC. The Trusted Publisher entry must be added at [pypi.org/manage/account/publishing](https://pypi.org/manage/account/publishing/) before CI can publish. See [PyPI OIDC troubleshooting](#pypi-oidc-invalid-publisher--token-request-failed). |
89+
| **npm platform packages — manual publish for v0.2.0** | ⚠️ Workaround needed | Because the token is wrong, the 5 platform packages are NOT on npm at 0.2.0. Either fix the token and re-run the workflow, or publish them manually (see below). |
90+
| **PyPI wheels — manual publish for v0.2.0** | ⚠️ Workaround needed | OIDC not configured. Publish manually with `PYPI_PASSWORD=<api-token> make publish-python` or from the downloaded wheel artifacts. |
91+
92+
### Manual npm publish for v0.2.0 (temporary workaround)
93+
94+
```bash
95+
# 1. Get a Classic Automation token from npmjs.com
96+
export NODE_AUTH_TOKEN=<classic-automation-token>
97+
echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc
98+
99+
# 2. Download built .node artifacts from the GitHub Actions run:
100+
# https://github.com/raphaelmansuy/edgeparse/actions/runs/23481058631
101+
# Download all 5 "node-<platform>" artifacts into sdks/node/npm/
102+
103+
# 3. Publish each platform package
104+
for dir in sdks/node/npm/*/; do
105+
echo "Publishing $dir..."
106+
(cd "$dir" && npm publish --access public) && echo "$dir" || echo "$dir"
107+
done
108+
109+
# 4. Cleanup
110+
rm ~/.npmrc
111+
```
112+
113+
---
114+
83115
## Required Secrets and Environments
84116

85117
### GitHub Repository Secrets
@@ -192,13 +224,14 @@ The npm package is `edgeparse` (unscoped). Platform-specific packages (`edgepars
192224
**Steps (one-time):**
193225

194226
1. Sign in to [npmjs.com](https://www.npmjs.com) as the publisher account.
195-
2. Go to **Account → Access Tokens → Generate New Token → Granular Access Token**.
227+
2. Go to **Account → Access Tokens → Generate New Token → Classic Token**.
228+
- Token type: **Automation** (bypasses 2FA prompts in CI)
196229
- Token name: `edgeparse-github-actions`
197-
- Expiration: 365 days (set a calendar reminder to rotate!)
198-
- Packages and scopes: **Read and write** — all packages belonging to this account
199230
3. Copy the token.
200231
4. Add to GitHub: secret name `NPM_TOKEN`.
201232

233+
> **⚠️ IMPORTANT — Classic token, not Granular token:** A Granular Access Token only grants access to packages you explicitly list at creation time. Publishing 6 packages (`edgeparse` + 5 platform packages) requires either a **Classic Automation token** (access to all packages you own) or a Granular token with all 6 packages listed individually. If you see `E403 Forbidden` on platform packages but the main `edgeparse` publishes fine, your token was created as Granular with only `edgeparse` in scope — recreate it as a Classic Automation token.
234+
202235
> **Token rotation:** npm Granular Access Tokens expire. Rotate before expiry at [npmjs.com → Access Tokens](https://www.npmjs.com/settings/~/tokens).
203236
204237
**Verify locally:**
@@ -411,7 +444,39 @@ edgeparse-core = { path = "../edgeparse-core", version = "0.1.0" }
411444

412445
### npm: E401 Unauthorized
413446

414-
The `NPM_TOKEN` secret is expired or invalid. Generate a new Granular Access Token at [npmjs.com/settings/~/tokens](https://www.npmjs.com/settings/~/tokens) and update the GitHub secret.
447+
The `NPM_TOKEN` secret is expired or invalid. Generate a new Classic Automation token at [npmjs.com/settings/~/tokens](https://www.npmjs.com/settings/~/tokens) and update the GitHub secret.
448+
449+
### npm: E403 Forbidden on platform packages (but main package succeeds)
450+
451+
**Symptom:** `edgeparse@0.2.0` publishes successfully but all 5 platform packages (`edgeparse-darwin-arm64`, `edgeparse-darwin-x64`, etc.) fail with:
452+
```
453+
npm error 403 Forbidden - PUT https://registry.npmjs.org/edgeparse-darwin-arm64
454+
- You may not perform that action with these credentials.
455+
```
456+
457+
**Root cause:** The `NPM_TOKEN` is a **Granular Access Token** scoped to only the `edgeparse` package. Platform packages are not in scope.
458+
459+
**Fix — replace with a Classic Automation Token:**
460+
461+
1. Go to [npmjs.com → Account → Access Tokens](https://www.npmjs.com/settings/~/tokens).
462+
2. Delete or retire the current granular token.
463+
3. Click **Generate New Token → Classic Token** → type **Automation**.
464+
4. Copy the token (shown only once).
465+
5. Go to **GitHub repo → Settings → Secrets and variables → Actions → `NPM_TOKEN` → Update secret**.
466+
6. Re-run the Node.js workflow:
467+
```bash
468+
gh workflow run release-node.yml --field tag_name=v0.2.0
469+
```
470+
471+
> Platform packages that have NEVER been published (`edgeparse-darwin-x64`, `edgeparse-linux-x64-gnu`, etc.) also get E403 with a Granular token because — for packages that don't exist yet — npm still validates scope before creating them.
472+
473+
**Verify your token locally before updating the secret:**
474+
```bash
475+
echo "//registry.npmjs.org/:_authToken=<token>" > /tmp/.npmrc
476+
npm --userconfig /tmp/.npmrc whoami
477+
# Should print your npm username
478+
rm /tmp/.npmrc
479+
```
415480

416481
### npm: "Scope not found"
417482

0 commit comments

Comments
 (0)