Skip to content

Commit 52460cc

Browse files
committed
chore: automate npm publishing with OIDC
1 parent e2be313 commit 52460cc

10 files changed

Lines changed: 68 additions & 21 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@ jobs:
1313
publish:
1414
runs-on: ubuntu-latest
1515
environment: npm
16-
env:
17-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
1816
steps:
19-
- uses: actions/checkout@v4
20-
- uses: actions/setup-node@v4
17+
- uses: actions/checkout@v6
18+
- uses: actions/setup-node@v6
2119
with:
22-
node-version: 22
23-
cache: npm
20+
node-version: 24
2421
registry-url: https://registry.npmjs.org
22+
package-manager-cache: false
23+
- run: npm install --global npm@latest
2524
- run: npm ci
2625
- run: npm run verify
2726
- run: node scripts/publish-workspace-if-needed.mjs beatapi-client

‎CHANGELOG.md‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ and this project uses [Semantic Versioning](https://semver.org/).
77

88
## [Unreleased]
99

10+
## [0.1.1] - 2026-07-20
11+
12+
### Changed
13+
14+
- Publish both npm packages from GitHub Actions through npm Trusted Publishing
15+
and short-lived OIDC credentials instead of a long-lived automation token.
16+
- Add an approval-gated `npm` deployment environment and automatic npm
17+
provenance for future releases.
18+
- Normalize the CLI binary path in the published package metadata.
19+
1020
## [0.1.0] - 2026-07-17
1121

1222
### Added
@@ -20,5 +30,6 @@ and this project uses [Semantic Versioning](https://semver.org/).
2030
- Structured errors, request IDs, bounded retries, CI, package checks, and npm
2131
release automation.
2232

23-
[Unreleased]: https://github.com/BeatAPI/beatapi-cli/compare/v0.1.0...HEAD
33+
[Unreleased]: https://github.com/BeatAPI/beatapi-cli/compare/v0.1.1...HEAD
34+
[0.1.1]: https://github.com/BeatAPI/beatapi-cli/compare/v0.1.0...v0.1.1
2435
[0.1.0]: https://github.com/BeatAPI/beatapi-cli/releases/tag/v0.1.0

‎docs/releasing.md‎

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,20 @@
66
2. Log in to npm with the BeatAPI publishing account.
77
3. Publish or reserve both package names: `beatapi-client` and `beatapi`.
88
4. In GitHub, create an environment named `npm`.
9-
5. Add an environment secret named `NPM_TOKEN` with publish access to both
10-
packages. Keep required reviewer protection enabled for production releases.
9+
5. Add the publishing owner as a required reviewer for the `npm` environment
10+
and allow release tags matching `v*`.
11+
6. On npmjs.com, configure a GitHub Actions Trusted Publisher separately for
12+
`beatapi-client` and `beatapi` with these exact values:
13+
- organization: `BeatAPI`;
14+
- repository: `beatapi-cli`;
15+
- workflow filename: `release.yml`;
16+
- environment: `npm`;
17+
- allowed action: `npm publish`.
18+
19+
The release workflow uses npm Trusted Publishing over OIDC. It intentionally
20+
does not store or reference a long-lived `NPM_TOKEN`. GitHub grants the workflow
21+
a short-lived identity for each approved release, and npm automatically records
22+
provenance for public packages published from the public repository.
1123

1224
The package names were unregistered when this repository was prepared. npm
1325
names are first-come, first-served, so reserve them before announcing the
@@ -30,6 +42,11 @@ release.
3042
10. Run `beatapi --version`, `beatapi --help`, and an authenticated
3143
`beatapi auth status` smoke test.
3244

45+
The workflow installs the current npm CLI on Node.js 24 because Trusted
46+
Publishing requires npm 11.5.1 or newer and Node.js 22.14.0 or newer. Do not add
47+
an `NPM_TOKEN` fallback: a missing OIDC trust relationship should fail closed
48+
instead of silently using a persistent credential.
49+
3350
## Rollback
3451

3552
npm package versions are immutable. If a release is defective:

‎package-lock.json‎

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "beatapi-cli-workspace",
3-
"version": "0.1.0",
3+
"version": "0.1.1",
44
"private": true,
55
"description": "Official TypeScript client and CLI for BeatAPI AI video workflows.",
66
"type": "module",

‎packages/cli/package.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"name": "beatapi",
3-
"version": "0.1.0",
3+
"version": "0.1.1",
44
"description": "Command-line interface for BeatAPI AI music video and ecommerce video workflows.",
55
"type": "module",
66
"bin": {
7-
"beatapi": "./dist/bin.js"
7+
"beatapi": "dist/bin.js"
88
},
99
"main": "./dist/index.js",
1010
"types": "./dist/index.d.ts",
@@ -19,7 +19,7 @@
1919
"test": "tsx --test test/*.test.ts"
2020
},
2121
"dependencies": {
22-
"beatapi-client": "0.1.0",
22+
"beatapi-client": "0.1.1",
2323
"cross-keychain": "1.1.0"
2424
},
2525
"engines": {

‎packages/cli/src/cli.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
import { promptSecret as defaultPromptSecret } from "./prompt.js";
1919
import { persistWebhookSecret } from "./webhook-secrets.js";
2020

21-
export const VERSION = "0.1.0";
21+
export const VERSION = "0.1.1";
2222

2323
const HELP = `BeatAPI CLI ${VERSION}
2424

‎packages/client/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "beatapi-client",
3-
"version": "0.1.0",
3+
"version": "0.1.1",
44
"description": "Type-safe JavaScript and TypeScript client for the BeatAPI async video API.",
55
"type": "module",
66
"main": "./dist/index.js",

‎scripts/package-smoke.mjs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ try {
4545
"utf8",
4646
),
4747
);
48-
if (installedPackage.version !== "0.1.0") {
48+
if (installedPackage.version !== "0.1.1") {
4949
throw new Error("Installed CLI package version did not match the release.");
5050
}
5151

‎test/release-workflow.test.mjs‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import assert from "node:assert/strict";
2+
import { readFile } from "node:fs/promises";
3+
import test from "node:test";
4+
5+
const workflow = await readFile(
6+
new URL("../.github/workflows/release.yml", import.meta.url),
7+
"utf8",
8+
);
9+
10+
test("publishes both packages through approval-gated OIDC", () => {
11+
assert.match(workflow, /id-token:\s*write/);
12+
assert.match(workflow, /environment:\s*npm/);
13+
assert.match(workflow, /node-version:\s*24/);
14+
assert.match(workflow, /npm install --global npm@latest/);
15+
assert.match(
16+
workflow,
17+
/publish-workspace-if-needed\.mjs beatapi-client[\s\S]*publish-workspace-if-needed\.mjs beatapi/,
18+
);
19+
assert.doesNotMatch(workflow, /NPM_TOKEN|NODE_AUTH_TOKEN/);
20+
});

0 commit comments

Comments
 (0)