Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions .github/workflows/publish-js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
# Triggered alongside publish.yml on GitHub Release or manual dispatch.
# Adapted from https://github.com/pydantic/monty CI JS-building pattern.
#
# Prerequisites:
# - NPM_TOKEN secret with publish access (GitHub Settings > Secrets > Actions)
# - id-token: write permission for npm provenance (OIDC attestation)
# Auth: npm trusted publishing (GitHub OIDC), no NPM_TOKEN secret.
# - npmjs.com @everruns/bashkit > Settings > Trusted publisher:
# GitHub Actions, everruns/bashkit, workflow publish-js.yml, no environment
# - release-js needs id-token: write; npm >= 11.5.1 exchanges the OIDC token
# for a short-lived publish token and attaches provenance automatically
# - setup-node has no registry option: it would write an .npmrc carrying a
# placeholder auth token

name: Publish JS

Expand Down Expand Up @@ -509,7 +513,18 @@ jobs:
node-version: "24.22.1"
cache: pnpm
cache-dependency-path: crates/bashkit-js/pnpm-lock.yaml
registry-url: "https://registry.npmjs.org"

- name: Require npm with trusted publishing (>= 11.5.1)
# npm trusted publishing (GitHub OIDC -> short-lived publish token)
# landed in npm 11.5.1. Upgrade to a pinned release if the bundled
# npm is older, then assert.
run: |
npm_ok() {
node -e 'const [a,b,c]=process.argv[1].split(".").map(Number);process.exit(a>11||(a==11&&(b>5||(b==5&&c>=1)))?0:1)' "$(npm --version)"
}
npm_ok || npm install -g npm@11.6.2
npm_ok || { echo "::error::npm $(npm --version) lacks trusted publishing"; exit 1; }
echo "npm $(npm --version)"

- name: Install dependencies
run: pnpm install --frozen-lockfile
Expand Down Expand Up @@ -558,8 +573,6 @@ jobs:
echo "Publishing with dist-tag: $TAG"
python3 "$GITHUB_WORKSPACE/scripts/publish_npm.py" --tag "$TAG"
working-directory: crates/bashkit-js
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Verify npm publish
run: |
Expand Down
24 changes: 18 additions & 6 deletions .github/workflows/publish-wasm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
# publishes to npm. Triggered alongside publish.yml on GitHub Release.
#
# Prerequisites:
# - NPM_TOKEN secret with publish access
# - id-token: write permission for npm provenance (OIDC attestation)
# - npm trusted publishing (GitHub OIDC), no NPM_TOKEN secret:
# npmjs.com @everruns/bashkit-wasm > Settings > Trusted publisher:
# GitHub Actions, everruns/bashkit, workflow publish-wasm.yml, no environment
# - id-token: write on publish-wasm; npm >= 11.5.1 (OIDC token exchange +
# automatic provenance)
#
# Derive the bindgen CLI from Cargo.lock; never duplicate its schema version.

Expand Down Expand Up @@ -110,7 +113,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # npm provenance
id-token: write # npm trusted publishing + provenance
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -129,7 +132,18 @@ jobs:
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
with:
node-version: "24.22.1"
registry-url: "https://registry.npmjs.org"

- name: Require npm with trusted publishing (>= 11.5.1)
# npm trusted publishing (GitHub OIDC -> short-lived publish token)
# landed in npm 11.5.1. Upgrade to a pinned release if the bundled
# npm is older, then assert.
run: |
npm_ok() {
node -e 'const [a,b,c]=process.argv[1].split(".").map(Number);process.exit(a>11||(a==11&&(b>5||(b==5&&c>=1)))?0:1)' "$(npm --version)"
}
npm_ok || npm install -g npm@11.6.2
npm_ok || { echo "::error::npm $(npm --version) lacks trusted publishing"; exit 1; }
echo "npm $(npm --version)"

- name: Download pkg
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
Expand Down Expand Up @@ -161,5 +175,3 @@ jobs:
TAG="${{ steps.dist-tag.outputs.tag }}"
echo "Publishing @everruns/bashkit-wasm with dist-tag: $TAG"
python3 "$GITHUB_WORKSPACE/scripts/publish_npm.py" --tag "$TAG"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
19 changes: 14 additions & 5 deletions knowledge/operations/release-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,8 @@ Trigger: Release published (parallel). Builds native NAPI-RS bindings
(macOS x86_64/aarch64, Linux x86_64/aarch64, Windows x86_64,
wasm32-wasip1-threads), tests on Node 20/22/24 (Node 20 runs the
runtime-compat suite, not the ava suites, since ava >= 8 needs Node 22.20+),
publishes to npm. Secret:
`NPM_TOKEN` (Automation token); provenance via `id-token: write` OIDC +
`--provenance`, same pattern as everruns/sdk. JS package version is synced
publishes to npm via npm trusted publishing (GitHub OIDC, `id-token: write`,
npm >= 11.5.1, provenance automatic); no `NPM_TOKEN`. JS package version is synced
from the workspace `Cargo.toml` by `build.rs` updating `package.json`.

Only a run whose ref is the release tag (`refs/tags/vX.Y.Z`, version matching
Expand Down Expand Up @@ -337,7 +336,7 @@ one invariant, since each is a hand-maintained copy of the same set.
Dispatched by `release.yml` from the verified release tag. Builds the
single-threaded `wasm32-unknown-unknown` browser bundle, runs the headless Node
integration suite, and publishes `@everruns/bashkit-wasm` to npm with
provenance. Uses the same `NPM_TOKEN` as `publish-js.yml`; the package version
provenance via npm trusted publishing, same as `publish-js.yml`; the package version
is synced manually from the workspace version during release preparation.

CI and publication both use the `wasm-release` profile and run the package's
Expand Down Expand Up @@ -365,7 +364,17 @@ from `main`; build checkout remains pinned to the tag.

- `CARGO_REGISTRY_TOKEN` (crates.io token, publish scopes) in GitHub Actions secrets.
- PyPI trusted publishing: configure publisher at pypi.org for repo `everruns/bashkit`, workflow `publish-python.yml`, environment `release-python`.
- `NPM_TOKEN` (Automation token) in GitHub Actions secrets; no separate GitHub environment required.
- npm trusted publishing (GitHub OIDC), no npm token secret. On npmjs.com, each
package's Settings > Trusted publisher: GitHub Actions, organization `everruns`,
repository `bashkit`, workflow `publish-js.yml` (`@everruns/bashkit`) or
`publish-wasm.yml` (`@everruns/bashkit-wasm`), environment empty. Publish jobs
need `id-token: write` and npm >= 11.5.1 (the step upgrades to a pinned npm if
Node's bundled one is older). Do not set setup-node `registry-url`: its `.npmrc`
carries a placeholder `NODE_AUTH_TOKEN`. The long-lived `NPM_TOKEN` was rejected
before 0.20.1 and npm reported the auth failure as a 404 on
`@everruns/bashkit-wasm`; an npm publish 404 on an existing package means auth,
check the trusted publisher config first. Guarded by
`scripts/tests/test_release_workflow.py`.

## Post-Release Verification

Expand Down
2 changes: 1 addition & 1 deletion knowledge/runtimes/browser-package.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ not evidence of a divergent published feature selection.
Version tracks the workspace `Cargo.toml` (currently synced by the release
prepare step, same as the other packages). `publish-wasm.yml` triggers on release
published, builds `pkg/`, runs the smoke test, and `npm publish`es
`@everruns/bashkit-wasm` with provenance (`NPM_TOKEN`, `id-token: write`), same
`@everruns/bashkit-wasm` via npm trusted publishing (GitHub OIDC, `id-token: write`), same
pattern as `publish-js.yml`. Browser example smoke testing writes a file under
`/home/user`, reloads the page, and verifies `browserLocal` restores it from
`localStorage`. The text-only example adapter commits only a complete traversal;
Expand Down
17 changes: 17 additions & 0 deletions scripts/tests/test_release_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,23 @@ def test_npm_publish_lanes_share_exact_archive_verification(self) -> None:
with self.subTest(workflow=name):
self.assertIn('python3 "$GITHUB_WORKSPACE/scripts/publish_npm.py" --tag "$TAG"', workflow)

def test_npm_publish_lanes_use_trusted_publishing(self) -> None:
"""npm auth is GitHub OIDC trusted publishing, never a long-lived token.

A rejected NPM_TOKEN made npm answer the 0.20.1 wasm publish with a
misleading 404. setup-node's registry-url writes an .npmrc carrying a
placeholder NODE_AUTH_TOKEN, so it stays off too.
"""
for name, job in (("publish-js.yml", "release-js"), ("publish-wasm.yml", "publish-wasm")):
workflow = (ROOT / ".github/workflows" / name).read_text()
with self.subTest(workflow=name):
self.assertNotIn("secrets.NPM_TOKEN", workflow)
self.assertNotIn("NODE_AUTH_TOKEN", workflow)
self.assertNotIn("registry-url:", workflow)
body = workflow.split(f"\n {job}:\n", 1)[1]
self.assertIn("id-token: write", body.split("\n steps:\n", 1)[0])
self.assertIn("npm install -g npm@11.6.2", body)

def test_web_ci_exercises_release_wasm_optimization(self) -> None:
build_script = (ROOT / "crates/bashkit-wasm/scripts/build.sh").read_text()
ci_workflow = (ROOT / ".github/workflows/ci.yml").read_text()
Expand Down
Loading