Skip to content

ci: automate releases with release-please and npm trusted publishing - #1

Merged
jlucaso1 merged 1 commit into
mainfrom
ci/automated-release
Aug 6, 2026
Merged

ci: automate releases with release-please and npm trusted publishing#1
jlucaso1 merged 1 commit into
mainfrom
ci/automated-release

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Releases here are manual today, and dist/ is gitignored while being the only thing files ships — so the published tarball is whatever the maintainer's disk happened to hold at publish time. The publish job now builds the wasm package from source on a GitHub runner and ships that.

How it works

release-please keeps a release PR up to date from the conventional commits already used in this repo. Merging that PR tags the release, and only that tag triggers a publish — the version bump stays reviewable instead of firing on every merge to main.

The publish job authenticates to npm over OIDC (trusted publishing) rather than a stored token. Provenance attestations are attached automatically, so no --provenance flag and no NODE_AUTH_TOKEN anywhere.

Also fixes: CI was not running

CI still triggered on master, which stopped being the default branch when the repository moved to the oxidezap org. No workflow runs for a pull request against main — including this one until it lands. Retargeted to main.

Choices worth flagging

  • release-please over semantic-release — semantic-release publishes straight off the merge, with no reviewable bump.
  • Actions pinned to commit SHAs — this workflow is the publish path, so a moving tag on a third-party action would be a supply-chain hole. Note ci.yml still uses dtolnay/rust-toolchain@master, a moving branch ref; left alone here to keep this PR to the release path.
  • npm-publish environment — already created on the repo. Add required reviewers there to gate releases; the same name scopes the OIDC trust on npm.
  • 45 min timeout on publish — the wasm release build plus wasm-opt took ~4 min locally, and a cold Rust cache on a runner is slower.

Required before this can publish

One-time trusted publisher setup on npmjs.com for @oxidezap/whatsapp-rust-bridge, naming this repository, release.yml, and the npm-publish environment. Until that exists the publish step fails — nothing else in CI is affected.

The manifest pins 0.6.0, matching what is on main and on npm. The three old v1.0.0-alpha.* tags predate the current line and are ignored, since the manifest is the source of truth.


Summary by cubic

Automates releases with release-please and npm trusted publishing; builds the wasm package on GitHub runners for consistent tarballs. CI now runs on main and cancels superseded runs.

  • New Features

    • release-please keeps a release PR; only the merged tag publishes. Optional GitHub App token avoids “Approve and run”; falls back to GITHUB_TOKEN.
    • Trusted publishing to npm via OIDC with provenance; no NODE_AUTH_TOKEN.
    • Tag verification builds/tests from source (wasm-pack, bun); publish rebuilds dist/ with pinned npm@11.19.0.
    • Only feat/fix/perf commits release; use fix(deps) for dependency bumps.
    • Removed the broken Node benchmark step from CI.
  • Migration

    • Set up trusted publishing on npm for @oxidezap/whatsapp-rust-bridge with this repo, release.yml, and the npm-publish environment.

Written for commit 647018d. Summary will update on new commits.

Review in cubic

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds release-please metadata and a GitHub Actions release workflow. Releases run from main, build and test the package, then publish tagged releases to npm through OIDC trusted publishing.

Changes

Release automation

Layer / File(s) Summary
Release metadata
.release-please-manifest.json, release-please-config.json
Defines version 0.6.0, changelog settings, tag format, version bump rules, and commit categories.
Release preparation
.github/workflows/ci.yml, .github/workflows/release.yml
Updates CI branch filters to main. Adds release-please execution, permissions, concurrency, and release outputs.
Tagged package publication
.github/workflows/release.yml
Checks out release tags, installs pinned Rust/WASM and Node tooling, builds and tests the package, and publishes to npm with OIDC trusted publishing.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions
  participant releasePlease
  participant BuildTooling
  participant npmRegistry
  GitHubActions->>releasePlease: prepare release on main
  releasePlease-->>GitHubActions: return release status and tag
  GitHubActions->>BuildTooling: install tools, build package, run tests
  BuildTooling-->>GitHubActions: return build and test results
  GitHubActions->>npmRegistry: publish tagged package with OIDC
Loading

Poem

A rabbit checks the release gate,
Tags hop forward, neat and straight.
Rust and WASM build with care,
Tests report from everywhere.
OIDC carries the bun—
The npm release is done!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: automating releases with release-please and npm trusted publishing.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 5-7: Add workflow-level concurrency configuration in the CI
workflow so runs for the same pull request share a group and newer commits
cancel superseded runs; preserve existing branch triggers and enable
cancellation of in-progress runs.

In @.github/workflows/release.yml:
- Around line 55-57: Update the checkout step using the actions/checkout
configuration to disable persisting the GitHub token in Git configuration by
setting persist-credentials to false, while preserving the existing tag ref.
- Around line 72-83: Pin the release toolchain versions in the Bun setup,
NODE_VERSION configuration, and npm installation command: replace bun-version
latest, the floating Node version 24, and npm@latest with exact reviewed
versions. Ensure all three versions are explicitly maintained in NODE_VERSION or
the npm install command so release behavior changes only through repository
updates.
- Line 85: Update the release workflow’s dependency installation step from plain
`bun install` to frozen-lockfile mode, using `bun ci` or `bun install
--frozen-lockfile`, so it fails when package.json and bun.lock are out of sync.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c90978c5-95b7-4f7c-b108-1e3673f9ad32

📥 Commits

Reviewing files that changed from the base of the PR and between c78ad1d and aa038d5.

📒 Files selected for processing (4)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • .release-please-manifest.json
  • release-please-config.json

Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/release.yml
Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml Outdated
- name: Ensure npm supports trusted publishing
run: npm install -g npm@latest

- run: bun install

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "Committed Bun lockfiles:"
fd -HI -t f '^(bun\.lock|bun\.lockb)$' . -E .git -E node_modules || true

echo "Release install configuration:"
rg -n -C 2 'bun install|bun-version' .github/workflows/release.yml

Repository: oxidezap/whatsapp-rust-bridge

Length of output: 618


🌐 Web query:

Bun install locked dependency verification frozen-lockfile documentation

💡 Result:

The --frozen-lockfile flag in Bun is used to ensure reproducible installations by strictly enforcing that the project's dependencies match the existing lockfile [1][2]. Key behaviors and details: - Enforcement: When --frozen-lockfile is used, Bun installs the exact versions specified in the bun.lock file [1][3]. If the project's package.json file disagrees with the lockfile (e.g., due to added, removed, or modified dependencies), Bun will exit with an error [1][2][4]. - CI/CD Usage: The command bun ci is equivalent to running bun install --frozen-lockfile [1][2]. It is the recommended approach for continuous integration environments to ensure the installed environment exactly matches the committed lockfile [1]. - Prerequisites: For these commands to function, the bun.lock file must be committed to version control [1][2]. - Evolution and Fixes: Recent updates have improved the accuracy of the frozen-lockfile check [5][4]. Bun now correctly fails in edge cases where package.json changes (such as adding a direct dependency that was previously only a transitive one) might have previously allowed the installation to proceed [4]. In summary, --frozen-lockfile acts as a guardrail against dependency drift, ensuring that the dependency tree remains immutable during installation unless the lockfile is explicitly updated [1][4].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "Workflow install context:"
sed -n '68,92p' .github/workflows/release.yml | cat -n -v

echo "Other bun install usages:"
rg -n -C 1 '\bbun (ci|install)( --frozen-lockfile)?\b|frozen-lockfile' .github . --glob '!node_modules/**' || true

Repository: oxidezap/whatsapp-rust-bridge

Length of output: 1644


Enable frozen lockfile mode for the release install.

The release workflow has bun.lock, but .github/workflows/release.yml:85 runs plain bun install. Use bun ci or bun install --frozen-lockfile so the build fails when package.json and bun.lock are out of sync instead of resolving a new dependency graph before publishing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml at line 85, Update the release workflow’s
dependency installation step from plain `bun install` to frozen-lockfile mode,
using `bun ci` or `bun install --frozen-lockfile`, so it fails when package.json
and bun.lock are out of sync.

@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: aa038d5174

ℹ️ 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".

@@ -0,0 +1,3 @@
{
".": "0.6.0"

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 Set a commit baseline for the first automated release

Because the repository has no v0.6.0 release tag for the manual release at c78ad1d—only older prerelease tags—setting the manifest version alone does not tell release-please where the 0.6.0 history ends. On its first run, it can therefore traverse older commits and immediately propose a version bump and changelog containing work already shipped in 0.6.0. Add bootstrap-sha: c78ad1dbdac07ff8f5ac2c1504c6e83752cf8ea3 (documented as the starting point for commit history) or create the matching release tag before enabling this workflow.

Useful? React with 👍 / 👎.

@jlucaso1
jlucaso1 force-pushed the ci/automated-release branch from aa038d5 to 3212020 Compare August 6, 2026 16:51
@jlucaso1

jlucaso1 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Applied the review findings.

Pinned npm (npm@11.19.0, was @latest) and pinned bun (1.3.14, was latest) — coderabbit Major. Valid on the release path specifically: npm runs the publish with the OIDC token, and bun builds the wasm artifact that ships, so a floating version changes the published bytes with no change to this repo. Left node-version: 24 as a major — it neither performs the publish nor produces the artifact, and pinning every patch adds churn for no reproducibility gain here. ci.yml keeps bun-version: latest on purpose: catching breakage against current bun is the point there.

persist-credentials: false on checkout — the job runs cargo, bun and third-party build scripts while holding publish rights, and nothing talks to the remote after checkout.

concurrency on ci.yml — a wasm release build plus wasm-opt is ~4 min even warm, so superseded runs are worth cancelling.


Not applied: the PAT for release PR checks. GitHub does suppress workflow triggers for GITHUB_TOKEN events, so the release PR opens with no check runs. But main has no branch protection, so nothing is blocked or bypassed today, and the fix costs a long-lived credential — the opposite of what the OIDC publish buys. The publish job rebuilds from source and re-runs the tests against the tag, so nothing ships unverified. Documented in the workflow, with the condition that would change the answer.

Worth noting this PR still shows no CI: ci.yml only triggered on master until this very change, which is part of what it fixes. The first run lands once it is on main.

@jlucaso1
jlucaso1 force-pushed the ci/automated-release branch 4 times, most recently from 9fd6577 to 4a7b5dc Compare August 6, 2026 17:23
@jlucaso1

jlucaso1 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Second round applied.

bootstrap-sha for the first run — applied, and it also caught a live problem in the other repo

This was the sharpest finding of the round. Correct: this repo has no v0.6.0 tag, only stale v1.0.0-alpha.* ones, so release-please would have had no boundary and could have walked old commits into the first changelog.

Set bootstrap-sha: c78ad1dbdac07ff8f5ac2c1504c6e83752cf8ea3 (the manual 0.6.0 release commit), which is top-level in the config, not per package.

Chasing this into baileyrs turned up something worse there: npm has 0.0.32 while main sits at 0.0.34, so two versions were bumped but never published. Its baseline is therefore the last actually-published commit rather than the tip, so the first automated release publishes what is missing and its changelog covers it.

Publish job no longer runs the test suites — applied

Same concern three reviewers raised on the sibling PR: the job holding id-token: write was also running bun install, both test suites and the toolchain, any of which could mint a token and publish under this package identity.

Split into verify (no id-token: fmt, clippy, build, bun test, test:rust) and publish (bun install --ignore-scripts, build, npm publish --ignore-scripts).

Being straight about the limit: the build still runs next to the token, and here that means cargo compiling crates with build scripts. That is unavoidable while dist/ is generated and gitignored — the only way out is handing npm a prebuilt tarball, and npm documents provenance against publishing from the package directory, staying silent on tarballs. Not trading a confirmed provenance guarantee for an unverified one.

Verified locally that bun install --ignore-scripts && bun run build produces the same 5.2 MB wasm artifact.

Also

persist-credentials: false is on both checkouts. chore(deps): bumps of the whatsapp-rust pin would have released nothing, so the header now says to commit those as fix(deps): …, and the decorative deps changelog section is gone.

@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: 4a7b5dcc0f

ℹ️ 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".

- id: release
uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0
with:
token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}

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 Do not fall back to GITHUB_TOKEN for the release PR

When RELEASE_APP_CLIENT_ID is unset and main requires the CI check, this fallback creates the release PR with GITHUB_TOKEN, but the resulting pull_request event cannot start .github/workflows/ci.yml. GitHub documents that events triggered by GITHUB_TOKEN do not create new workflow runs except for workflow_dispatch and repository_dispatch (GitHub Actions documentation); consequently, there is no approval-pending run to click and the release PR remains blocked. Require the App credentials or use another credential capable of triggering the required checks.

Useful? React with 👍 / 👎.


# No NODE_AUTH_TOKEN and no --provenance: trusted publishing authenticates
# over OIDC and attaches provenance on its own.
- run: npm publish --ignore-scripts

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 Run the tarball guard before publishing

When a build change accidentally adds pkg/ content or duplicate large files to the tarball, --ignore-scripts suppresses package lifecycle scripts (npm configuration documentation), so the existing prepack command and its scripts/check-pack.ts publish guard never run. A normal manual npm publish previously executed that guard, whereas this workflow can now publish the malformed package; explicitly invoke the check after the build or allow the relevant lifecycle script to run.

Useful? React with 👍 / 👎.

@jlucaso1
jlucaso1 force-pushed the ci/automated-release branch from 4a7b5dc to 6577538 Compare August 6, 2026 17:34
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@jlucaso1

jlucaso1 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Third round.

The check-pack finding was a real bug I introduced — applied

Right, and specific: npm publish --ignore-scripts suppresses prepack, which here is bun run scripts/check-pack.ts — the guard that catches a tarball leaking pkg/ or duplicate files. Manual publishes always ran it; this workflow would have skipped it.

I had added the equivalent explicit call in the sibling PR and missed it here. Now invoked directly after the build, before publish. Verified it runs standalone: check-pack: 12 files, no duplicates.

Also applied

issues: write on the release job — release-please labels the release PR, and PR labels go through the issues API. Granted on the App but missing from the job permissions governing the GITHUB_TOKEN fallback.

permission-* scoping on the App token — without those inputs the token inherits everything the App installation holds, and job-level permissions do not constrain it. Pinned to contents / pull-requests / issues.

Not applied

The GITHUB_TOKEN fallback not starting ci.yml is the same point from the previous round, and it is now largely moot: the App is configured on this org, so the fallback is not the live path. It remains documented, along with the condition that would make it matter — required status checks on main.

@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: 65775385e6

ℹ️ 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/ci.yml
branches: [main]
pull_request:
branches: [master]
branches: [main]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Restore the benchmark inputs before enabling main CI

For every PR against main, this newly enabled workflow reaches the existing Run Benchmarks with Node.js 24 step, whose bench:node script invokes benches/binary.ts, signal.ts, curve.ts, and crypto.ts; a repo-wide file search finds no benches/ directory or generated equivalents, and node --expose-gc benches/binary.ts exits with MODULE_NOT_FOUND. Consequently, every otherwise-successful CI run fails at the benchmark step, so restore or remove these benchmark targets before switching the trigger.

AGENTS.md reference: AGENTS.md:L7-L9

Useful? React with 👍 / 👎.

Version bumps and publishes were manual, and dist/ is gitignored while
being the only thing `files` ships — so the published tarball was
whatever a maintainer's disk happened to hold. The publish job now builds
the wasm package from source on a GitHub runner and ships that.

release-please keeps a release PR up to date from the conventional commits
already in use here. Merging it tags the release, and only that tag
triggers a publish, so the bump stays reviewable rather than firing on
every merge to main.

The publish job authenticates over OIDC instead of a stored token, which
npm has offered as trusted publishing since it went GA. Provenance
attestations come along automatically, so no --provenance flag. Actions
are pinned to commit SHAs because this workflow is the publish path.

CI also still triggered on master, which stopped being the default branch
when the repository moved to the oxidezap org, so no workflow ran for a
pull request against main.
@jlucaso1

jlucaso1 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Applied — and this one was the most valuable finding of the whole PR, because it is a failure this PR itself would have introduced.

Verified: benches/ was deleted in 157f43a "chore: final cleanup", while bench:node and the CI step kept pointing at benches/binary.ts, signal.ts, curve.ts, crypto.ts. It never surfaced because the workflow only triggered on master, which is dormant. Retargeting it to main — which is the other half of this PR — would have made every CI run fail on MODULE_NOT_FOUND, at a step after the whole wasm build had already run.

Removed the benchmark step and renamed the job to match, with a comment recording why.

Not touching package.json: the bench and bench:node scripts are still orphaned and are the only two in the repo pointing at missing files. Restoring the benchmarks or dropping the scripts is a call for you to make, not something to fold into a CI PR.

@jlucaso1
jlucaso1 force-pushed the ci/automated-release branch from 6577538 to 647018d Compare August 6, 2026 17:43
@jlucaso1
jlucaso1 merged commit 83938b6 into main Aug 6, 2026
5 of 6 checks passed
@jlucaso1
jlucaso1 deleted the ci/automated-release branch August 7, 2026 03:05
jlucaso1 pushed a commit that referenced this pull request Aug 10, 2026
The round trip compared bytes fields by length, and every bytes sample was
empty, so a codec that kept the tag and replaced the payload passed. Each field
now runs a second sample carrying a value the schema cannot supply by accident,
and bytes are compared element by element.

Reverting the comparison and writing a same-length payload from a bytes encoder
produces: ADVSignedDeviceIdentity.details (#1): wrote {1,127,255}, read back
{0,0,0}. The empty sample stays: it is what proves explicit presence.
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