Skip to content

Commit 8cf646f

Browse files
committed
ci: PR-based alpha release with OIDC trusted publishing
Replace the direct-push + NPM_TOKEN alpha release with a resium-style, credential-free flow: - release_alpha_prepare.yml (new): workflow_dispatch bumps the alpha prerelease version, commits it to a release/alpha-<version> branch, and opens a PR into alpha. GITHUB_TOKEN only. - release_alpha.yml (rewritten): on merge of a release/alpha-* PR, builds, pushes the v<version> tag, and runs npm publish --provenance --tag alpha via OIDC trusted publishing. GITHUB_TOKEN (tag) + OIDC (publish). Tag and publish are combined into one merge-triggered job so no privileged token is needed to cross-trigger publishing. No NPM_TOKEN, no PAT, no GitHub App, and no branch-protection bypass. The bump never pushes directly to the protected alpha branch. npm Trusted Publisher stays registered as workflow release_alpha.yml. beta/latest still use npm_release.yml + NPM_TOKEN and are unaffected.
1 parent a907bdf commit 8cf646f

2 files changed

Lines changed: 141 additions & 16 deletions

File tree

Lines changed: 79 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,82 @@
1+
# Tags and publishes an alpha release when its release PR is merged.
2+
#
3+
# Triggered when a `release/alpha-*` PR (opened by "Prepare Alpha Release") is
4+
# merged into `alpha`. It builds, pushes the `v<version>` tag, and publishes
5+
# @reearth/core to the npm `alpha` dist-tag.
6+
#
7+
# Publishing is secured via npm Trusted Publishing (OIDC): no NPM_TOKEN, no PAT,
8+
# no GitHub App. Auth is a short-lived OIDC handshake and every publish carries
9+
# a provenance attestation (verify with `npm audit signatures`).
10+
#
11+
# Tag + publish are combined into this single job on purpose: a tag pushed by
12+
# GITHUB_TOKEN does not trigger other workflows, so publishing here (rather than
13+
# in a separate `on: push: tags` workflow) is what lets us avoid a privileged
14+
# token entirely.
15+
#
16+
# npm Trusted Publisher (one-time, already configured on npmjs.com):
17+
# @reearth/core -> repo reearth/core, workflow release_alpha.yml, action
18+
# "npm publish". Keep this file named release_alpha.yml so that stays valid.
19+
#
20+
# beta/latest still publish via npm_release.yml + NPM_TOKEN and are unaffected.
21+
22+
name: Release Alpha
23+
124
on:
2-
push:
3-
branches: alpha
4-
paths-ignore:
5-
- "package.json"
6-
workflow_dispatch:
25+
pull_request:
26+
types: [closed]
27+
28+
permissions:
29+
contents: write # push the version tag
30+
id-token: write # OIDC token for npm Trusted Publishing + provenance
731

832
jobs:
9-
release:
10-
permissions:
11-
contents: write
12-
uses: reearth/core/.github/workflows/npm_release.yml@beta
13-
with:
14-
branch: alpha
15-
tag: alpha
16-
version-args: --preid alpha prerelease
17-
secrets:
18-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
19-
PAT: ${{ secrets.PAT }}
33+
publish:
34+
name: Tag and publish alpha
35+
runs-on: ubuntu-latest
36+
# Only for merged release PRs into alpha (not every closed PR).
37+
if: >-
38+
github.event.pull_request.merged == true &&
39+
github.event.pull_request.base.ref == 'alpha' &&
40+
startsWith(github.event.pull_request.head.ref, 'release/alpha-')
41+
steps:
42+
- uses: actions/checkout@v4
43+
with:
44+
ref: ${{ github.event.pull_request.merge_commit_sha }}
45+
- uses: actions/setup-node@v4
46+
with:
47+
# Trusted Publishing requires Node >=22.14 and npm >=11.5.1.
48+
node-version: 22
49+
registry-url: "https://registry.npmjs.org"
50+
- name: Activate npm via corepack
51+
# Node 22 ships npm 10.x; Trusted Publishing needs >=11.5.1. corepack
52+
# fetches a fresh npm binary, avoiding the broken self-upgrade path.
53+
run: |
54+
corepack enable npm
55+
corepack prepare npm@11.5.1 --activate
56+
npm --version
57+
- name: Run install
58+
run: yarn install --frozen-lockfile
59+
- name: Build
60+
run: yarn build
61+
- name: Verify tag matches package.json version
62+
id: version
63+
run: |
64+
VERSION=$(node -p "require('./package.json').version")
65+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
66+
echo "tag=v$VERSION" >> "$GITHUB_OUTPUT"
67+
echo "Publishing @reearth/core@$VERSION"
68+
- name: Create and push tag
69+
run: |
70+
TAG="${{ steps.version.outputs.tag }}"
71+
if git ls-remote --exit-code --tags origin "refs/tags/${TAG}" >/dev/null 2>&1; then
72+
echo "Tag ${TAG} already exists; skipping tag push."
73+
else
74+
git config user.name "github-actions[bot]"
75+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
76+
git tag -a "${TAG}" -m "${TAG}"
77+
git push origin "${TAG}"
78+
fi
79+
- name: Publish to npm with provenance (OIDC)
80+
# No NPM_TOKEN: auth is the OIDC handshake configured as a Trusted
81+
# Publisher on npmjs.com. --access public because @reearth/core is scoped.
82+
run: npm publish --provenance --access public --tag alpha
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Prepares an alpha release.
2+
#
3+
# Dispatch this workflow on the `alpha` branch. It bumps the alpha prerelease
4+
# version, commits it to a `release/alpha-<version>` branch, and opens a PR
5+
# into `alpha`. Merging that PR triggers release_alpha.yml, which tags the
6+
# release and publishes to npm (dist-tag `alpha`) via OIDC.
7+
#
8+
# Uses only the built-in GITHUB_TOKEN: no PAT, no GitHub App. The version bump
9+
# never touches the protected `alpha` branch directly; it goes through the PR,
10+
# so no branch-protection bypass is required.
11+
12+
name: Prepare Alpha Release
13+
14+
on:
15+
workflow_dispatch:
16+
17+
permissions:
18+
contents: write # push the release/alpha-* branch
19+
pull-requests: write # open the release PR
20+
21+
jobs:
22+
prepare:
23+
name: Open alpha release PR
24+
runs-on: ubuntu-latest
25+
if: github.ref == 'refs/heads/alpha'
26+
steps:
27+
- uses: actions/checkout@v4
28+
- uses: actions/setup-node@v4
29+
with:
30+
node-version: 22
31+
- name: Set up git user
32+
run: |
33+
git config user.name "github-actions[bot]"
34+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
35+
- name: Run install
36+
run: yarn install --frozen-lockfile
37+
- name: Bump alpha prerelease version
38+
id: bump
39+
# --no-git-tag-version: we commit the bump onto the release branch
40+
# ourselves; the tag is created later by the publish workflow. This
41+
# still runs the preversion (yarn test run) and version (yarn build)
42+
# npm scripts, so tests and the build gate the bump.
43+
run: |
44+
npm version --preid alpha prerelease --no-git-tag-version
45+
echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
46+
- name: Create release branch and PR
47+
env:
48+
VERSION: ${{ steps.bump.outputs.version }}
49+
GH_TOKEN: ${{ github.token }}
50+
run: |
51+
BRANCH="release/alpha-${VERSION}"
52+
git checkout -b "$BRANCH"
53+
git add package.json
54+
git commit -m "chore: release ${VERSION}"
55+
git push origin "$BRANCH"
56+
gh pr create \
57+
--base alpha \
58+
--head "$BRANCH" \
59+
--title "chore: release ${VERSION}" \
60+
--body "Prepares alpha release \`${VERSION}\`.
61+
62+
Merging this PR tags \`v${VERSION}\` and publishes \`@reearth/core@${VERSION}\` to the npm \`alpha\` dist-tag via OIDC trusted publishing (with provenance)."

0 commit comments

Comments
 (0)