Skip to content

chore(repo): Build and publish native passkeys binaries on production releases#8955

Open
wobsoriano wants to merge 5 commits into
mainfrom
rob/electron-passkeys-ci-cd
Open

chore(repo): Build and publish native passkeys binaries on production releases#8955
wobsoriano wants to merge 5 commits into
mainfrom
rob/electron-passkeys-ci-cd

Conversation

@wobsoriano

@wobsoriano wobsoriano commented Jun 22, 2026

Copy link
Copy Markdown
Member

Description

Follow-up to #8786 (the Electron SDK scaffold). That PR added @clerk/electron-passkeys to the monorepo but deliberately shipped no native binaries. This PR adds the release pipeline that builds and publishes them.

On a production release where @clerk/electron-passkeys is bumped, the native .node binaries (macOS arm64/x64, Windows arm64/x64) are built fresh on native runners, assembled into the per-platform packages, and published in lockstep with the wrapper.

Canary and snapshot releases exclude these packages

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features
    • Added native passkey (WebAuthn) support to Clerk's Electron SDK with prebuilt binaries for macOS (arm64, x64) and Windows (arm64, x64).

@vercel

vercel Bot commented Jun 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Jun 23, 2026 12:40am
swingset Ready Ready Preview, Comment Jun 23, 2026 12:40am

Request Review

@changeset-bot

changeset-bot Bot commented Jun 22, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3fcfb27

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@clerk/electron-passkeys Patch
@clerk/electron Patch
@clerk/electron-passkeys-darwin-arm64 Patch
@clerk/electron-passkeys-darwin-x64 Patch
@clerk/electron-passkeys-win32-arm64-msvc Patch
@clerk/electron-passkeys-win32-x64-msvc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 39b0981a-cfc8-4d58-8a75-28eecbddd83d

📥 Commits

Reviewing files that changed from the base of the PR and between 9a80889 and 3fcfb27.

📒 Files selected for processing (1)
  • .changeset/electron-passkeys-native-binaries.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/electron-passkeys-native-binaries.md

📝 Walkthrough

Walkthrough

Adds a native binary CI pipeline for @clerk/electron-passkeys. A new reusable GitHub Actions workflow builds .node binaries for macOS and Windows targets. The release workflow gains detection, gating, and artifact download steps. New scripts handle publish detection and binary verification. Snapshot and canary flows exclude electron-passkeys packages.

Changes

Electron Passkeys Native Binary Pipeline

Layer / File(s) Summary
Package predicate and changeset wiring
scripts/common.mjs, .changeset/config.json, .changeset/electron-passkeys-native-binaries.md
Adds isElectronPasskeysPackage predicate, populates the changeset fixed array with all five electron-passkeys platform package variants, and adds the patch-level changeset entry for native binary support.
Snapshot and canary exclusion
scripts/snapshot.mjs, scripts/canary.mjs
Both scripts import isElectronPasskeysPackage and filter matching packages from the workspace package lists used to generate snapshot and canary releases.
Binary verification script and tests
scripts/check-electron-passkeys-binaries.mjs, scripts/check-electron-passkeys-binaries.test.mjs
Exports findMissingBinaries to locate platform directories with a count other than exactly one .node file, a CLI main() that exits 1 on mismatch, and a Vitest suite covering the zero, one, and multiple file cases.
Publish detection script
scripts/detect-electron-passkeys-publish.mjs
Reads the local package version, queries npm view for the published version, and outputs should-build=true|false for CI consumption.
Native build CI workflow
.github/workflows/electron-passkeys.yml
Defines a reusable workflow with a matrix build job (macOS aarch64/x86_64, Windows x86_64/aarch64) that compiles the Rust native module, runs host-native smoke tests, and uploads per-target artifacts; a package job then assembles and verifies platform npm packages.
Release workflow gating and artifact download
.github/workflows/release.yml
Adds detect-native and build-native jobs that gate the release job, and inserts conditional steps in release to download electron-passkeys-npm and verify binaries before publishing.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • dstaley
  • jacekradko

Poem

🐇 Hop, hop, little binaries fly,
Arm64 and x64 reaching the sky!
macOS munching, Windows compiling away,
Native passkeys arrive fresh today.
No toolchain needed—just install and play! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: implementing a native binary release pipeline for electron-passkeys. It accurately reflects the primary objective of adding CI/CD automation to build and publish native binaries on production releases.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

Comment thread .github/workflows/electron-passkeys.yml Fixed
Comment thread .github/workflows/electron-passkeys.yml Fixed
@pkg-pr-new

pkg-pr-new Bot commented Jun 22, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@8955

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@8955

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@8955

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@8955

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@8955

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@8955

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@8955

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@8955

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@8955

@clerk/express

npm i https://pkg.pr.new/@clerk/express@8955

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@8955

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8955

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@8955

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@8955

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@8955

@clerk/react

npm i https://pkg.pr.new/@clerk/react@8955

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@8955

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@8955

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@8955

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@8955

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8955

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@8955

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@8955

commit: 3fcfb27

@wobsoriano wobsoriano changed the title chore(repo): Build and publish native binaries on production releases chore(repo): Build and publish native passkeys binaries on production releases Jun 22, 2026
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Comment thread .changeset/config.json
Comment on lines +11 to +19
"fixed": [
[
"@clerk/electron-passkeys",
"@clerk/electron-passkeys-darwin-arm64",
"@clerk/electron-passkeys-darwin-x64",
"@clerk/electron-passkeys-win32-arm64-msvc",
"@clerk/electron-passkeys-win32-x64-msvc"
]
],

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

all five packages must publish at the same version number. The four platform packages are optionalDependencies of the wrapper at an exact version, and napi-rs's native loader matches the .node binary by the package version it was built with

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this workflow builds the native Rust addon for @clerk/electron-passkeys, then assembles the per-platform npm packages and uploads them as a single artifact. It's called by release.yml when a version bump to @clerk/electron-passkeys is detected

Comment on lines +108 to +113
- name: Download electron-passkeys native binaries
if: ${{ needs.detect-native.outputs.should-build == 'true' }}
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: electron-passkeys-npm
path: packages/electron-passkeys/npm

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Binaries land here before changesets/action runs so npm publish picks themup

@wobsoriano wobsoriano marked this pull request as ready for review June 23, 2026 00:33

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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/electron-passkeys.yml:
- Around line 11-20: The workflow file has a duplicate permissions key defined
in the YAML structure, which causes a parsing error. Remove the second
permissions block that only contains contents: read and keep only the first
permissions block that includes both contents: read and actions: read. This will
resolve the YAML syntax error and allow the workflow to parse correctly.

In @.github/workflows/release.yml:
- Around line 46-52: Navigate to the `.github/workflows/electron-passkeys.yml`
reusable workflow file and locate the duplicate `permissions` key that is
causing the YAML parsing error. Remove one of the duplicate `permissions` blocks
so that only a single `permissions` definition remains in the file. This will
resolve the syntax error and allow the workflow call in the build-native job to
execute successfully.

In `@scripts/check-electron-passkeys-binaries.mjs`:
- Around line 27-45: The main function lacks error handling for the
findMissingBinaries call, which means any thrown errors will result in unhandled
rejections instead of GitHub annotations. Wrap the await
findMissingBinaries(npmDir) call in a try-catch block and use console.error with
the ::error:: format to report caught exceptions. Additionally, the error
message template is inaccurate as it always says "empty package" regardless of
the count value; update the message logic to correctly indicate that the issue
is having an incorrect number of binaries (not exactly 1), adjusting the text
appropriately when count is greater than 1 versus when count is 0.
🪄 Autofix (Beta)

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: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 935b7c82-ea09-45c8-a2d9-eae66f8d7961

📥 Commits

Reviewing files that changed from the base of the PR and between 52d310c and 9a80889.

📒 Files selected for processing (10)
  • .changeset/config.json
  • .changeset/electron-passkeys-native-binaries.md
  • .github/workflows/electron-passkeys.yml
  • .github/workflows/release.yml
  • scripts/canary.mjs
  • scripts/check-electron-passkeys-binaries.mjs
  • scripts/check-electron-passkeys-binaries.test.mjs
  • scripts/common.mjs
  • scripts/detect-electron-passkeys-publish.mjs
  • scripts/snapshot.mjs

Comment on lines +11 to +20
permissions:
contents: read
actions: read

concurrency:
group: electron-passkeys-${{ github.head_ref || github.ref }}
cancel-in-progress: true

permissions:
contents: read

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Duplicate permissions key causes YAML syntax error.

The workflow defines permissions twice (lines 11-12 and 19-20), which violates YAML syntax and will cause the workflow to fail parsing.

🐛 Proposed fix

Remove the duplicate permissions block:

 permissions:
   contents: read
   actions: read

 concurrency:
   group: electron-passkeys-${{ github.head_ref || github.ref }}
   cancel-in-progress: true

-permissions:
-  contents: read
-
 jobs:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
permissions:
contents: read
actions: read
concurrency:
group: electron-passkeys-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
permissions:
contents: read
actions: read
concurrency:
group: electron-passkeys-${{ github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
🧰 Tools
🪛 actionlint (1.7.12)

[error] 19-19: key "permissions" is duplicated in "workflow" section. previously defined at line:11,col:1

(syntax-check)

🪛 YAMLlint (1.37.1)

[error] 19-19: duplication of key "permissions" in mapping

(key-duplicates)

🤖 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/electron-passkeys.yml around lines 11 - 20, The workflow
file has a duplicate permissions key defined in the YAML structure, which causes
a parsing error. Remove the second permissions block that only contains
contents: read and keep only the first permissions block that includes both
contents: read and actions: read. This will resolve the YAML syntax error and
allow the workflow to parse correctly.

Source: Linters/SAST tools

Comment on lines +46 to +52
build-native:
name: Build electron-passkeys native binaries
needs: detect-native
if: ${{ needs.detect-native.outputs.should-build == 'true' }}
permissions:
contents: read
uses: ./.github/workflows/electron-passkeys.yml

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Workflow call will fail due to syntax error in electron-passkeys.yml.

The reusable workflow .github/workflows/electron-passkeys.yml contains a duplicate permissions key (already flagged in that file), which will cause this workflow call to fail during YAML parsing.

This will be resolved once the duplicate permissions block is removed from electron-passkeys.yml.

🧰 Tools
🪛 actionlint (1.7.12)

[error] 52-52: error while parsing reusable workflow "./.github/workflows/electron-passkeys.yml": yaml: unmarshal errors: line 19: mapping key "permissions" already defined at line 11

(workflow-call)

🤖 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 around lines 46 - 52, Navigate to the
`.github/workflows/electron-passkeys.yml` reusable workflow file and locate the
duplicate `permissions` key that is causing the YAML parsing error. Remove one
of the duplicate `permissions` blocks so that only a single `permissions`
definition remains in the file. This will resolve the syntax error and allow the
workflow call in the build-native job to execute successfully.

Source: Linters/SAST tools

Comment on lines +27 to +45
async function main() {
const npmDir = process.argv[2] || DEFAULT_NPM_DIR;
const missing = await findMissingBinaries(npmDir);

if (missing.length > 0) {
for (const { dir, count } of missing) {
console.error(
`::error::${dir} has ${count} .node binaries (expected exactly 1); publishing it would ship an empty package`,
);
}

process.exit(1);
}

console.log('All electron-passkeys platform packages contain exactly one .node binary.');
}

if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
await main();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Handle CLI read errors explicitly and fix inaccurate failure text.

If findMissingBinaries() throws (e.g., missing/unreadable directory), the script currently fails with an unhandled rejection instead of a GitHub annotation. Also, Line 34 always says “empty package,” which is incorrect when count > 1.

Suggested patch
 async function main() {
-  const npmDir = process.argv[2] || DEFAULT_NPM_DIR;
-  const missing = await findMissingBinaries(npmDir);
+  const npmDir = process.argv[2] || DEFAULT_NPM_DIR;
+  let missing;
+  try {
+    missing = await findMissingBinaries(npmDir);
+  } catch (error) {
+    const message = error instanceof Error ? error.message : String(error);
+    console.error(`::error::Failed to scan ${npmDir}: ${message}`);
+    process.exit(1);
+  }

   if (missing.length > 0) {
     for (const { dir, count } of missing) {
       console.error(
-        `::error::${dir} has ${count} .node binaries (expected exactly 1); publishing it would ship an empty package`,
+        count === 0
+          ? `::error::${dir} has 0 .node binaries (expected exactly 1); publishing it would ship an empty package`
+          : `::error::${dir} has ${count} .node binaries (expected exactly 1); publishing it would ship an invalid package`,
       );
     }

     process.exit(1);
   }
🤖 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 `@scripts/check-electron-passkeys-binaries.mjs` around lines 27 - 45, The main
function lacks error handling for the findMissingBinaries call, which means any
thrown errors will result in unhandled rejections instead of GitHub annotations.
Wrap the await findMissingBinaries(npmDir) call in a try-catch block and use
console.error with the ::error:: format to report caught exceptions.
Additionally, the error message template is inaccurate as it always says "empty
package" regardless of the count value; update the message logic to correctly
indicate that the issue is having an incorrect number of binaries (not exactly
1), adjusting the text appropriately when count is greater than 1 versus when
count is 0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants