Skip to content

ci: harden release workflow - #3

Merged
ragnorc merged 3 commits into
mainfrom
ci/release-workflow
May 14, 2026
Merged

ci: harden release workflow#3
ragnorc merged 3 commits into
mainfrom
ci/release-workflow

Conversation

@ragnorc

@ragnorc ragnorc commented May 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces the stub release workflow with one that meets the bar to actually ship @modernrelay/omnigraph + @modernrelay/omnigraph-mcp.

Before: SDK-only publish, drift+build only, every tag → `latest`, no provenance.
After: both packages, full CI gate, dist-tag derived from semver, npm provenance, manual approval gate.

What changes

  • Full gate on the tag SHA — `check-drift`, `check-coverage`, `build`, `typecheck`, `test`. A stale CI run on the branch can't bless a release.
  • Tag/manifest version assertion — fails if `v0.4.0` is pushed while a manifest still says `0.3.0`.
  • Dist-tag derivation: `-alpha.`/`-beta.`/`-rc.` → `next`, otherwise `latest`. Pre-releases stop clobbering stable.
  • MCP publish added, after the SDK (workspace:* pointer resolves at rewrite time).
  • npm provenance via `--provenance` plus `id-token: write`. Consumers get a verifiable attestation linking the npm tarball to this workflow run.
  • `.npmrc` written directly — pnpm publish doesn't always honor setup-node's `registry-url` token plumbing.
  • `release` Environment gate — a stray `v*` tag push requires manual approval before it ships.

README gains a `Releasing` section: one-time setup (NPM_TOKEN secret, `release` Environment) and the recipe to cut a release.

One-time setup before the first release

  1. `gh secret set NPM_TOKEN` with an Automation token from npmjs.com.
  2. Repo Settings → Environments → create `release` with required reviewers.
  3. If the `@modernrelay` scope doesn't exist yet on npm, do one manual publish locally to claim it.

Test plan

  • YAML parses (Python yaml.safe_load)
  • Dist-tag regex verified against `0.4.0-alpha.1`, `-beta.2`, `-rc.1`, `0.4.0`, `1.0.0`
  • Dry-run the publish locally before tagging:
    ```
    pnpm --filter @modernrelay/omnigraph publish --dry-run --no-git-checks --tag next
    pnpm --filter @modernrelay/omnigraph-mcp publish --dry-run --no-git-checks --tag next
    ```
  • First real run will be the alpha cut (`v0.4.0-alpha.1`).

🤖 Generated with Claude Code


Open in Devin Review

Note

Medium Risk
Touches the release/publish pipeline and npm authentication/provenance, so misconfiguration could block releases or publish under the wrong dist-tag despite limited code impact.

Overview
Upgrades .github/workflows/release.yml from a basic publish step to a gated, manual-approval release job that reruns the full CI suite on the tag SHA before publishing.

The workflow now verifies the v* tag matches both package versions, derives the npm dist-tag (next for prereleases, otherwise latest), writes an explicit npm auth .npmrc, and publishes both @modernrelay/omnigraph and @modernrelay/omnigraph-mcp with --provenance (OIDC id-token: write).

README.md adds a Releasing section documenting one-time setup (NPM token + release environment) and the annotated-tag release procedure.

Reviewed by Cursor Bugbot for commit 1bd444f. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Hardened the release workflow to safely publish both @modernrelay/omnigraph and @modernrelay/omnigraph-mcp with full CI gating, correct dist-tags (any SemVer prerelease → next), npm provenance, and annotated-tag docs so git push --follow-tags triggers releases. Added a concise Releasing guide to the README.

  • New Features

    • Run full gate on the tag SHA: drift, coverage, build, typecheck, test.
    • Fail if the v* tag version doesn’t match both package versions.
    • Derive npm dist-tag: any SemVer prerelease (-...) → next; else latest (ignores +meta).
    • Publish both packages in order (SDK first, then MCP).
    • Add npm provenance via --provenance and id-token: write.
    • Write .npmrc with NPM_TOKEN to ensure pnpm publish auth.
    • Require manual approval via the release GitHub Environment.
    • Use and document annotated tags so --follow-tags pushes the release tag.
  • Migration

    • Add NPM_TOKEN repo secret (Automation token recommended).
    • Create a release Environment with required reviewers.

Written for commit 1bd444f. Summary will update on new commits.

The original release.yml only published the SDK, ran a thin gate
(check-drift + build), pushed every tag to `latest`, and skipped npm
provenance despite having `id-token: write`. Replace with a workflow
that:

- Runs the full CI gate (check-drift, check-coverage, build, typecheck,
  test) on the tag SHA — a stale CI run on the branch cannot bless a
  release.
- Asserts the git tag matches both packages' manifest versions, so a
  v0.4.0 tag with a still-0.3.0 manifest fails fast.
- Derives the npm dist-tag from the tag name: -alpha/-beta/-rc go to
  `next`, everything else to `latest`. Avoids clobbering `latest` with
  pre-releases.
- Publishes both `@modernrelay/omnigraph` and the MCP package, in order
  (SDK first so the MCP's `workspace:*` resolves at rewrite time).
- Adds `--provenance` for a verifiable supply-chain attestation linking
  the npm tarball to this workflow run.
- Writes `.npmrc` directly instead of relying on setup-node's
  registry-url, which pnpm publish doesn't always honor.
- Gates on a `release` GitHub Environment so a stray `v*` tag push
  requires a manual approval before anything ships.

README gains a `Releasing` section with the one-time setup (NPM_TOKEN,
Environment) and the steps to cut a release.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 144b85860f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/release.yml Outdated
run: |
set -euo pipefail
ver="${GITHUB_REF_NAME#v}"
if [[ "$ver" =~ -(alpha|beta|rc)\. ]]; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Route all prerelease tags to next

The dist-tag check only matches prereleases that contain -alpha., -beta., or -rc.; valid semver prereleases like v1.2.3-alpha (no dot) fall through to latest. In that case, a prerelease publish would incorrectly move npm’s stable latest tag, which is exactly what this workflow is trying to prevent.

Useful? React with 👍 / 👎.

cubic-dev-ai[bot]

This comment was marked as resolved.

ragnorc added 2 commits May 14, 2026 11:21
git push --follow-tags only pushes annotated tags reachable from the
pushed commits; lightweight tags (the default for `git tag <name>`) are
skipped, so the release command in the README would not trigger the
tag-driven release workflow. Switch to `git tag -a -m` in both the
README recipe and the release.yml header comment.
The previous regex only matched `-(alpha|beta|rc)\.`, so valid SemVer
prereleases without a dot (`v1.2.3-alpha`, `v1.2.3-rc`) or with other
labels (`v1.2.3-0`, `v1.2.3-next`) would fall through to `latest` —
the exact behavior this step was meant to prevent.

Match SemVer 2.0 instead: any `-` after the version is a prerelease.
Strip build metadata (`+...`) first so a stray `+sha` can't sneak a
prerelease past as `latest`. Verified by hand against `-alpha`,
`-alpha.1`, `-beta.2`, `-rc`, `-rc.1`, `-0`, `-next`, plain `X.Y.Z`,
`X.Y.Z+meta`, and `X.Y.Z-alpha+meta`.
@ragnorc
ragnorc merged commit 892758c into main May 14, 2026
5 checks passed
@ragnorc ragnorc mentioned this pull request May 14, 2026
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant