[INL-3675] feat: add dev release workflow for PR-based npm publishing#4233
[INL-3675] feat: add dev release workflow for PR-based npm publishing#4233Jack Waller (Jack-Waller) wants to merge 3 commits intomainfrom
Conversation
Adds a workflow_dispatch workflow that validates PR security, builds the package from a PR branch, and publishes a dev release to npm. Includes composite actions for PR security validation and idempotent PR commenting. INL-3675 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| run: | | ||
| cd dist | ||
| npm version $DEV_VERSION --no-git-tag-version | ||
| npm publish --tag dev |
Check notice
Code scanning / zizmor
prefer trusted publishing for authentication Note
There was a problem hiding this comment.
I'm happy accepting this now, as setting up OIDC for backpack publishing is beyond the scope of this incident.
|
Visit https://backpack.github.io/storybook-prs/4233 to see this build running in a browser. |
|
Visit https://backpack.github.io/storybook-prs/4233 to see this build running in a browser. |
| CACHE_NAME: node-modules-cache | ||
| PR_COMMENT_MARKER: "<!-- backpack-dev-release -->" | ||
|
|
||
| permissions: {} |
There was a problem hiding this comment.
Top-level permissions: {} revokes all default token permissions at the workflow level. Each job then re-declares only what it needs (e.g. contents: read, pull-requests: write), following least-privilege.
| - name: Determine dev version | ||
| id: version | ||
| run: | | ||
| BASE_VERSION=$(git describe --tags --abbrev=0 --exclude='*-*' HEAD) |
There was a problem hiding this comment.
Version format: x.y.z-dev-v<run_id>.<attempt>
git describe --exclude='*-*' skips any existing pre-release tags and finds the latest stable release tag. The run ID + attempt number guarantees uniqueness even across retries of the same workflow run.
| - name: Get PR data | ||
| id: get-pr-data | ||
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | ||
| env: |
There was a problem hiding this comment.
All ${{ }} expressions are passed via env blocks rather than inlined in run: scripts. This is a security best practice — it prevents script injection if any output value contains shell metacharacters or malicious payloads. The JS steps already use process.env for the same reason.
| description: The pull request number to comment on | ||
| required: true | ||
| marker: | ||
| description: HTML comment marker used to identify and update existing comments |
There was a problem hiding this comment.
The marker is a hidden HTML comment embedded in the body. On subsequent runs, the action searches for an existing comment containing this marker and updates it in-place rather than creating duplicates. This keeps PR comment threads clean across retries and re-runs.
| DevRelease: | ||
| name: Build and publish dev release | ||
| runs-on: ubuntu-latest | ||
| environment: Publishing |
There was a problem hiding this comment.
Publishing environment gates this job behind environment protection rules. The NPM_TOKEN secret is scoped to this environment, so it's never exposed to the security-check or reporting jobs.
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| ref: ${{ needs.SecurityCheck.outputs.pr_sha }} |
There was a problem hiding this comment.
Checkout at the validated SHA (needs.SecurityCheck.outputs.pr_sha) rather than the branch ref. This prevents a TOCTOU race where the branch could be force-pushed between the security check and the build.
| with: | ||
| ref: ${{ needs.SecurityCheck.outputs.pr_sha }} | ||
| persist-credentials: false | ||
| fetch-depth: 0 |
There was a problem hiding this comment.
fetch-depth: 0 is needed for git describe in the version step.
| name: Report results on PR | ||
| runs-on: ubuntu-latest | ||
| needs: [SecurityCheck, DevRelease] | ||
| if: always() && needs.SecurityCheck.result == 'success' |
There was a problem hiding this comment.
always() ensures this job runs even if DevRelease fails, but the needs.SecurityCheck.result == 'success' condition skips it if the PR itself failed validation (no point commenting if we already posted a failure comment in SecurityCheck).
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| persist-credentials: false | ||
| sparse-checkout: .github/actions |
There was a problem hiding this comment.
Sparse checkout — only .github/actions is checked out here. This job doesn't need the full repo; it only needs the composite actions to run the security validation. Keeps the checkout fast and avoids exposing source code in a job that doesn't need it.
| pr_number: ${{ inputs.pr_number }} | ||
|
|
||
| - name: Add or update failure comment on PR | ||
| if: failure() |
There was a problem hiding this comment.
Failure comment on security check. The if: failure() condition means this only runs when the validation step fails. It posts a comment to the PR so the author gets feedback without having to dig through workflow logs.
There was a problem hiding this comment.
Pull request overview
Adds a dev release workflow that enables publishing pre-release npm packages from open pull requests, allowing contributors to test unreleased changes in downstream projects before merging.
Changes:
- New workflow_dispatch workflow for PR-based npm publishing with security validation
- Composite action for PR security validation (same-repo branches, user permissions)
- Composite action for creating/updating PR comments with workflow status
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
.github/workflows/dev-release.yml |
Main workflow orchestrating security checks, build, npm publish, and PR comment reporting |
.github/actions/pr-security-validation/action.yml |
Validates PR is open, from same repository, and user has write access |
.github/actions/upsert-pr-comment/action.yml |
Creates or updates a single PR comment identified by HTML marker |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
What
Adds a
workflow_dispatchdev release workflow that publishes pre-release npm packages from open pull requests. This enables contributors to test unreleased changes in downstream projects before merging.Took heavy inspiration from Global Components' dev release workflow and backpack's release workflow.
New files
.github/workflows/dev-release.yml— Orchestrates the full pipeline: security validation, build, npm publish, and PR comment reporting..github/actions/pr-security-validation/action.yml— Composite action that validates the PR is open, from the same repository (not a fork), and the triggering user has write access..github/actions/upsert-pr-comment/action.yml— Composite action that creates or updates a single PR comment identified by a hidden HTML marker, keeping comment threads tidy.Why
Currently there is no way to test a Backpack change in a consuming application without merging and releasing. A dev release workflow lets engineers publish a tagged pre-release (
x.y.z-dev-v<run>.<attempt>) from any open PR, significantly shortening the feedback loop.We need this to safely roll out a potential backpack fix, #4231, which is needed for INL-3675.
Security considerations
${{ }}expressions in bash steps are passed viaenvblocks to prevent script injection.contents: read,pull-requests: write).Publishingenvironment withNPM_TOKENfrom repository secrets.References
Checklist
skip-changeloglabel appropriate (no consumer-facing changes)