fix: use one workflow for npm trusted publishing
This commit is contained in:
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -1,6 +1,6 @@
|
|||||||
# Replace @dotta if a different maintainer or team should own release infrastructure.
|
# Replace @dotta if a different maintainer or team should own release infrastructure.
|
||||||
|
|
||||||
.github/workflows/release-*.yml @dotta
|
.github/workflows/release.yml @dotta
|
||||||
scripts/release*.sh @dotta
|
scripts/release*.sh @dotta
|
||||||
scripts/release-*.mjs @dotta
|
scripts/release-*.mjs @dotta
|
||||||
scripts/create-github-release.sh @dotta
|
scripts/create-github-release.sh @dotta
|
||||||
|
|||||||
94
.github/workflows/release-canary.yml
vendored
94
.github/workflows/release-canary.yml
vendored
@@ -1,94 +0,0 @@
|
|||||||
name: Release Canary
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: release-canary-master
|
|
||||||
cancel-in-progress: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
verify:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 30
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup pnpm
|
|
||||||
uses: pnpm/action-setup@v4
|
|
||||||
with:
|
|
||||||
version: 9.15.4
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: pnpm
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --no-frozen-lockfile
|
|
||||||
|
|
||||||
- name: Typecheck
|
|
||||||
run: pnpm -r typecheck
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
run: pnpm test:run
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: pnpm build
|
|
||||||
|
|
||||||
publish:
|
|
||||||
needs: verify
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 45
|
|
||||||
environment: npm-canary
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup pnpm
|
|
||||||
uses: pnpm/action-setup@v4
|
|
||||||
with:
|
|
||||||
version: 9.15.4
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: pnpm
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --no-frozen-lockfile
|
|
||||||
|
|
||||||
- name: Configure git author
|
|
||||||
run: |
|
|
||||||
git config user.name "github-actions[bot]"
|
|
||||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
||||||
|
|
||||||
- name: Publish canary
|
|
||||||
env:
|
|
||||||
GITHUB_ACTIONS: "true"
|
|
||||||
run: ./scripts/release.sh canary --skip-verify
|
|
||||||
|
|
||||||
- name: Push canary tag
|
|
||||||
run: |
|
|
||||||
tag="$(git tag --points-at HEAD | grep '^canary/v' | head -1)"
|
|
||||||
if [ -z "$tag" ]; then
|
|
||||||
echo "Error: no canary tag points at HEAD after release." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
git push origin "refs/tags/${tag}"
|
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
name: Release Stable
|
name: Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
source_ref:
|
source_ref:
|
||||||
@@ -19,11 +22,97 @@ on:
|
|||||||
default: false
|
default: false
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: release-stable
|
group: release-${{ github.event_name }}-${{ github.ref }}
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
verify:
|
verify_canary:
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 30
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 9.15.4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 24
|
||||||
|
cache: pnpm
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --no-frozen-lockfile
|
||||||
|
|
||||||
|
- name: Typecheck
|
||||||
|
run: pnpm -r typecheck
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: pnpm test:run
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: pnpm build
|
||||||
|
|
||||||
|
publish_canary:
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
needs: verify_canary
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
environment: npm-canary
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 9.15.4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 24
|
||||||
|
cache: pnpm
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --no-frozen-lockfile
|
||||||
|
|
||||||
|
- name: Configure git author
|
||||||
|
run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
|
- name: Publish canary
|
||||||
|
env:
|
||||||
|
GITHUB_ACTIONS: "true"
|
||||||
|
run: ./scripts/release.sh canary --skip-verify
|
||||||
|
|
||||||
|
- name: Push canary tag
|
||||||
|
run: |
|
||||||
|
tag="$(git tag --points-at HEAD | grep '^canary/v' | head -1)"
|
||||||
|
if [ -z "$tag" ]; then
|
||||||
|
echo "Error: no canary tag points at HEAD after release." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
git push origin "refs/tags/${tag}"
|
||||||
|
|
||||||
|
verify_stable:
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
permissions:
|
permissions:
|
||||||
@@ -59,9 +148,9 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: pnpm build
|
run: pnpm build
|
||||||
|
|
||||||
preview:
|
preview_stable:
|
||||||
if: inputs.dry_run
|
if: github.event_name == 'workflow_dispatch' && inputs.dry_run
|
||||||
needs: verify
|
needs: verify_stable
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
permissions:
|
permissions:
|
||||||
@@ -98,9 +187,9 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
./scripts/release.sh "${args[@]}"
|
./scripts/release.sh "${args[@]}"
|
||||||
|
|
||||||
publish:
|
publish_stable:
|
||||||
if: ${{ !inputs.dry_run }}
|
if: github.event_name == 'workflow_dispatch' && !inputs.dry_run
|
||||||
needs: verify
|
needs: verify_stable
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
environment: npm-stable
|
environment: npm-stable
|
||||||
@@ -9,8 +9,7 @@ This document covers the GitHub and npm setup required for the current Paperclip
|
|||||||
|
|
||||||
Repo-side files that depend on this setup:
|
Repo-side files that depend on this setup:
|
||||||
|
|
||||||
- `.github/workflows/release-canary.yml`
|
- `.github/workflows/release.yml`
|
||||||
- `.github/workflows/release-stable.yml`
|
|
||||||
- `.github/CODEOWNERS`
|
- `.github/CODEOWNERS`
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
@@ -24,8 +23,7 @@ Before touching GitHub or npm settings, merge the release automation code so the
|
|||||||
|
|
||||||
Required files:
|
Required files:
|
||||||
|
|
||||||
- `.github/workflows/release-canary.yml`
|
- `.github/workflows/release.yml`
|
||||||
- `.github/workflows/release-stable.yml`
|
|
||||||
- `.github/CODEOWNERS`
|
- `.github/CODEOWNERS`
|
||||||
|
|
||||||
## 2. Configure npm Trusted Publishing
|
## 2. Configure npm Trusted Publishing
|
||||||
@@ -46,21 +44,26 @@ For each package:
|
|||||||
2. go to the package settings / publishing access area
|
2. go to the package settings / publishing access area
|
||||||
3. add a trusted publisher for the GitHub repository `paperclipai/paperclip`
|
3. add a trusted publisher for the GitHub repository `paperclipai/paperclip`
|
||||||
|
|
||||||
### 2.2. Add two trusted publisher entries per package
|
### 2.2. Add one trusted publisher entry per package
|
||||||
|
|
||||||
Because npm trusted publishing is tied to the workflow filename, configure both:
|
npm currently allows one trusted publisher configuration per package.
|
||||||
|
|
||||||
- workflow: `.github/workflows/release-canary.yml`
|
Configure:
|
||||||
- workflow: `.github/workflows/release-stable.yml`
|
|
||||||
|
- workflow: `.github/workflows/release.yml`
|
||||||
|
|
||||||
Repository:
|
Repository:
|
||||||
|
|
||||||
- `paperclipai/paperclip`
|
- `paperclipai/paperclip`
|
||||||
|
|
||||||
Branch expectations:
|
Environment name:
|
||||||
|
|
||||||
- canary workflow should only ever run from `master`
|
- leave the npm trusted-publisher environment field blank
|
||||||
- stable workflow is manual but should also be restricted to `master` by GitHub environment policy
|
|
||||||
|
Why:
|
||||||
|
|
||||||
|
- the single `release.yml` workflow handles both canary and stable publishing
|
||||||
|
- GitHub environments `npm-canary` and `npm-stable` still enforce different approval rules on the GitHub side
|
||||||
|
|
||||||
### 2.3. Verify trusted publishing before removing old auth
|
### 2.3. Verify trusted publishing before removing old auth
|
||||||
|
|
||||||
@@ -167,8 +170,7 @@ If `@dotta` is not the right reviewer identity in the public repo, change it bef
|
|||||||
|
|
||||||
These files should always trigger code owner review:
|
These files should always trigger code owner review:
|
||||||
|
|
||||||
- `.github/workflows/release-canary.yml`
|
- `.github/workflows/release.yml`
|
||||||
- `.github/workflows/release-stable.yml`
|
|
||||||
- `scripts/release.sh`
|
- `scripts/release.sh`
|
||||||
- `scripts/release-lib.sh`
|
- `scripts/release-lib.sh`
|
||||||
- `scripts/release-package-map.mjs`
|
- `scripts/release-package-map.mjs`
|
||||||
@@ -198,7 +200,7 @@ This keeps LLM spending intentional and avoids a high-value token sitting in Act
|
|||||||
After setup:
|
After setup:
|
||||||
|
|
||||||
1. merge a harmless commit to `master`
|
1. merge a harmless commit to `master`
|
||||||
2. open the `Release Canary` workflow run
|
2. open the `Release` workflow run triggered by that push
|
||||||
3. confirm it passes verification
|
3. confirm it passes verification
|
||||||
4. confirm publish succeeds under the `npm-canary` environment
|
4. confirm publish succeeds under the `npm-canary` environment
|
||||||
5. confirm npm now shows a new `canary` release
|
5. confirm npm now shows a new `canary` release
|
||||||
@@ -215,7 +217,7 @@ npx paperclipai@canary onboard
|
|||||||
After at least one good canary exists:
|
After at least one good canary exists:
|
||||||
|
|
||||||
1. prepare `releases/vYYYY.M.D.md` on the source commit you want to promote
|
1. prepare `releases/vYYYY.M.D.md` on the source commit you want to promote
|
||||||
2. open `Actions` -> `Release Stable`
|
2. open `Actions` -> `Release`
|
||||||
3. run it with:
|
3. run it with:
|
||||||
- `source_ref`: the tested commit SHA or canary tag source commit
|
- `source_ref`: the tested commit SHA or canary tag source commit
|
||||||
- `stable_date`: leave blank or set the intended UTC date
|
- `stable_date`: leave blank or set the intended UTC date
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ Canaries only cover the first two surfaces plus an internal traceability tag.
|
|||||||
|
|
||||||
### Canary
|
### Canary
|
||||||
|
|
||||||
Every push to `master` runs [`.github/workflows/release-canary.yml`](../.github/workflows/release-canary.yml).
|
Every push to `master` runs the canary path inside [`.github/workflows/release.yml`](../.github/workflows/release.yml).
|
||||||
|
|
||||||
It:
|
It:
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ npx paperclipai@canary onboard
|
|||||||
|
|
||||||
### Stable
|
### Stable
|
||||||
|
|
||||||
Use [`.github/workflows/release-stable.yml`](../.github/workflows/release-stable.yml) from the Actions tab.
|
Use [`.github/workflows/release.yml`](../.github/workflows/release.yml) from the Actions tab with the manual `workflow_dispatch` inputs.
|
||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
|
|
||||||
|
|||||||
@@ -158,20 +158,17 @@ This is the cleanest answer to the open-repo security concern.
|
|||||||
|
|
||||||
### Concrete controls
|
### Concrete controls
|
||||||
|
|
||||||
#### 1. Split canary and stable into separate workflow files
|
#### 1. Use one release workflow file
|
||||||
|
|
||||||
Do not use one workflow file for both.
|
Use one workflow filename for both canary and stable publishing:
|
||||||
|
|
||||||
Recommended:
|
- `.github/workflows/release.yml`
|
||||||
|
|
||||||
- `.github/workflows/release-canary.yml`
|
|
||||||
- `.github/workflows/release-stable.yml`
|
|
||||||
|
|
||||||
Why:
|
Why:
|
||||||
|
|
||||||
- npm trusted publishing is configured per workflow filename
|
- npm trusted publishing is configured per workflow filename
|
||||||
- canary and stable need different blast radii
|
- npm currently allows one trusted publisher configuration per package
|
||||||
- stable should have stronger GitHub environment rules than canary
|
- GitHub environments can still provide separate canary/stable approval rules inside the same workflow
|
||||||
|
|
||||||
#### 2. Use separate GitHub environments
|
#### 2. Use separate GitHub environments
|
||||||
|
|
||||||
@@ -438,7 +435,7 @@ That is acceptable if canaries stay clearly separate:
|
|||||||
|
|
||||||
### Phase 1: Security foundation
|
### Phase 1: Security foundation
|
||||||
|
|
||||||
1. Create `release-canary.yml` and `release-stable.yml`
|
1. Create `release.yml`
|
||||||
2. Configure npm trusted publishers for all public packages
|
2. Configure npm trusted publishers for all public packages
|
||||||
3. Create `npm-canary` and `npm-stable` environments
|
3. Create `npm-canary` and `npm-stable` environments
|
||||||
4. Add `CODEOWNERS` protection for release files
|
4. Add `CODEOWNERS` protection for release files
|
||||||
|
|||||||
Reference in New Issue
Block a user