Skip to content

ci(release): add musl Linux targets for Alpine compatibility#452

Merged
jdx merged 3 commits intomainfrom
claude/hungry-payne-e4d09f
Apr 29, 2026
Merged

ci(release): add musl Linux targets for Alpine compatibility#452
jdx merged 3 commits intomainfrom
claude/hungry-payne-e4d09f

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented Apr 29, 2026

Summary

  • Adds x86_64-unknown-linux-musl and aarch64-unknown-linux-musl to the release build matrix in .github/workflows/release.yml.
  • Resolves #428 — the existing gnu-only Linux binaries fail on Alpine with cannot execute: required file not found (missing libudev.so.1, glibc symbol __res_init).

Why

Alpine and other musl-based distros can't run glibc-linked binaries — even with gcompat, some glibc-only symbols like __res_init aren't satisfied. Shipping native musl artifacts is the standard fix.

No source changes needed: openssl-sys and dbus are already vendored for Linux at Cargo.toml:82-86, and cross (already in use for the gnu targets) supports musl out of the box and produces statically linked binaries. taiki-e/upload-rust-binary-action handles musl artifact naming transparently.

Notes for reviewer

  • The keychain provider (via keyring crate's sync-secret-service feature) compiles fine on musl with vendored dbus. At runtime on a headless Alpine container it'll fail to find a session bus — but that's the existing behavior on any headless Linux, not a musl-specific regression. Alpine users who need a keychain-equivalent should use age/pass/cloud providers.
  • If the vendored dbus/openssl-sys build fails on the cross musl images (cmake/pkg-config not present), the fallback is a Cross.toml at the repo root with a pre-build step to install them. Not added preemptively — try the simpler change first.

Test plan

  • Release workflow builds both new musl targets cleanly (uses dry-run: true already, so it builds without uploading until a real tag is pushed).
  • Pull a fnox-*-x86_64-unknown-linux-musl.tar.gz artifact from the workflow run and verify it executes inside alpine:3:
    docker run --rm -v "$PWD:/work" alpine:3 sh -c 'cd /work && tar xzf fnox-*-x86_64-unknown-linux-musl.tar.gz && ./fnox --version'
    
  • Once merged, the next v* tag will publish musl binaries alongside the gnu ones — update the discussion to point Alpine users at the new artifacts.

🤖 Generated with Claude Code


Note

Medium Risk
Moderate build/release pipeline change plus conditional compilation that removes the fido2 provider on musl targets; risk is mainly missed cfg sync causing build failures or provider-list drift on certain targets.

Overview
Adds x86_64-unknown-linux-musl and aarch64-unknown-linux-musl to the GitHub Actions release build matrix so tagged releases also produce musl-compatible Linux binaries.

To make musl builds succeed, the PR gates the ctap-hid-fido2 dependency and the fido2 provider behind cfg(not(target_env = "musl")), and updates provider code generation/tests to skip providers/fido2.toml when targeting musl so generated enums/instantiation remain consistent.

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

Adds x86_64-unknown-linux-musl and aarch64-unknown-linux-musl to the
release build matrix. The existing gnu-only Linux binaries fail on Alpine
(missing libudev.so.1, glibc symbol __res_init), as reported in #428.

Both targets use the existing `cross` build-tool. openssl-sys and dbus are
already vendored for Linux in Cargo.toml, so no source changes are needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jdx jdx force-pushed the claude/hungry-payne-e4d09f branch from b321bc4 to 9c668a1 Compare April 29, 2026 20:11
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds the communique tool to the mise.toml configuration and introduces a mise.lock file specifying platform-specific binaries for version 1.0.1. Review feedback highlights that the musl platform entries in the lockfile incorrectly reference GNU binaries, which will lead to execution failures on Alpine Linux. Furthermore, there is a discrepancy between the PR description and the actual changes, as intended workflow updates are missing and the tool addition is not mentioned in the summary.

I am having trouble creating individual review comments. Click here to see my feedback.

mise.lock (12-15)

high

The linux-arm64-musl platform entry is incorrectly pointing to the GNU binary (communique-aarch64-unknown-linux-gnu.tar.gz). This will cause execution failures on Alpine Linux due to the missing glibc dependency, which contradicts the primary goal of this PR. Please verify if a native musl build is available for communique v1.0.1 or if this is an erroneous fallback in the lockfile generation.

mise.lock (22-25)

high

The linux-x64-musl platform entry is incorrectly pointing to the GNU binary (communique-x86_64-unknown-linux-gnu.tar.gz). This will fail on musl-based distributions like Alpine. If communique does not support musl, this entry should be removed or updated to a compatible artifact to avoid providing a broken binary to users in those environments.

mise.toml (6)

high

The pull request description states that x86_64-unknown-linux-musl and aarch64-unknown-linux-musl are being added to the release build matrix in .github/workflows/release.yml, but that file is not included in the current diff. Additionally, the addition of communique to the tools list is not mentioned in the PR summary. Please ensure all intended changes are committed and the description is updated to reflect the tool addition.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 29, 2026

Greptile Summary

This PR adds x86_64-unknown-linux-musl and aarch64-unknown-linux-musl targets to the release matrix and gates the FIDO2 provider behind cfg(not(target_env = "musl")) throughout the codebase, since ctap-hid-fido2 → hidapi → libudev cannot be statically linked on musl.

The implementation is thorough: the Cargo dependency is conditioned via [target.'cfg(...)'.dependencies], the build script skips fido2.toml on musl using CARGO_CFG_TARGET_ENV, the ProviderType::Fido2 variant and its match arm in add.rs are both cfg-gated, the fido2 module is conditionally compiled out of src/providers/mod.rs, and the test in mod.rs mirrors the exclusion with cfg!(). The previous thread concern about Cross.toml missing musl entries is moot because libudev is no longer a dependency on musl at all.

Confidence Score: 5/5

Safe to merge — all cfg-gates are consistent across Cargo.toml, build script, source, and tests; no outstanding issues remain.

No P0 or P1 issues found. The fido2 exclusion is applied consistently in every required location (dependency declaration, build codegen, provider module, CLI enum variant, match arm, and test). The previous thread's Cross.toml concern is resolved because libudev is no longer pulled in on musl. The test fix using cfg!() is a compile-time evaluation, which is correct.

No files require special attention.

Important Files Changed

Filename Overview
.github/workflows/release.yml Adds x86_64 and aarch64 musl targets to the release matrix; both use cross on ubuntu-latest, consistent with the existing gnu targets.
Cargo.toml Moves ctap-hid-fido2 = "3" into a [target.'cfg(not(target_env = "musl"))'.dependencies] section; correctly prevents the libudev transitive dependency on musl.
build/generate_providers.rs Reads CARGO_CFG_TARGET_ENV and skips fido2.toml when targeting musl; ensures all generated provider files exclude FIDO2 on musl at build time.
src/commands/provider/add.rs Gates the ProviderType::Fido2 match arm behind #[cfg(not(target_env = "musl"))]; match remains exhaustive on musl because the variant itself is also cfg-gated out.
src/commands/provider/mod.rs Gates ProviderType::Fido2 enum variant behind #[cfg(not(target_env = "musl"))] and fixes the provider-types test by filtering fido2 via cfg!() macro to match build-script behaviour.
src/providers/mod.rs Gates pub mod fido2 and its use import in providers_instantiate behind #[cfg(not(target_env = "musl"))]; consistent with the build-script exclusion.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Release Matrix] --> B{target_env}
    B -->|gnu| C[x86_64/aarch64-linux-gnu\ncross + libudev-dev via Cross.toml]
    B -->|musl| D[x86_64/aarch64-linux-musl\ncross, no libudev needed]

    D --> E{build/generate_providers.rs\nCARGO_CFG_TARGET_ENV == musl?}
    E -->|yes| F[Skip fido2.toml\nGenerate providers without FIDO2]
    E -->|no| G[Include fido2.toml\nGenerate all providers]

    F --> H[Cargo.toml\ncfg-not-musl dep:\nctap-hid-fido2 excluded]
    F --> I[src/providers/mod.rs\ncfg-gate: pub mod fido2 excluded]
    F --> J[src/commands/provider/mod.rs\ncfg-gate: ProviderType::Fido2 excluded]
    F --> K[src/commands/provider/add.rs\ncfg-gate: Fido2 match arm excluded]

    G --> L[All providers compiled\nincluding FIDO2]
Loading

Reviews (3): Last reviewed commit: "test(musl): exclude fido2 from provider/..." | Re-trigger Greptile

Comment on lines +40 to +45
- target: x86_64-unknown-linux-musl
os: ubuntu-latest
build-tool: cross
- target: aarch64-unknown-linux-musl
os: ubuntu-latest
build-tool: cross
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 Missing Cross.toml entries for musl targets

The repo's Cross.toml installs libudev-dev before building the gnu targets because ctap-hid-fido2 (via hidapi) requires udev on Linux. The new musl targets have no corresponding pre-build entries, and there's no musl-compatible static libudev available — apt-installing libudev-dev inside a musl cross image would link the glibc variant and break the static build. Unless ctap-hid-fido2/hidapi is conditionally excluded for *-musl targets (e.g. via a Cargo feature flag or cfg target), these matrix jobs will fail at link time with the same missing-udev error the gnu targets had before Cross.toml was added.

Fix in Claude Code

ctap-hid-fido2 → hidapi → libudev cannot be statically linked into musl
binaries (apt-installing libudev-dev inside a cross musl image links the
glibc variant and breaks the static build). On musl targets:

- Move ctap-hid-fido2 to a target-specific dep (cfg(not(target_env = "musl")))
- Gate `pub mod fido2;` and the fido2 import in providers/mod.rs
- Gate ProviderType::Fido2 and its add-command match arm
- Skip providers/fido2.toml in the build-script codegen so the generated
  ProviderConfig and dispatch tables don't reference it

Verified `cargo tree --target x86_64-unknown-linux-musl` no longer pulls
ctap-hid-fido2 or hidapi, while the gnu target tree is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jdx
Copy link
Copy Markdown
Owner Author

jdx commented Apr 29, 2026

Addressed Greptile P1: musl builds now exclude the fido2 provider so they don't pull ctap-hid-fido2hidapi → libudev (which can't be statically linked into a musl binary — apt-installing libudev-dev in a cross musl image links the glibc variant).

Changes in 3e0c397:

  • Cargo.toml: moved ctap-hid-fido2 to [target.'cfg(not(target_env = "musl"))'.dependencies]
  • src/providers/mod.rs: gated pub mod fido2; and the fido2 import
  • src/commands/provider/{mod.rs,add.rs}: gated ProviderType::Fido2 variant and its match arm
  • build/generate_providers.rs: skip providers/fido2.toml when CARGO_CFG_TARGET_ENV=musl so the generated ProviderConfig enum and dispatch tables don't reference it

Verified locally:

$ cargo tree --target x86_64-unknown-linux-musl --prefix none | grep -E 'ctap|hidapi|udev'
(no matches)

$ cargo tree --target x86_64-unknown-linux-gnu --prefix none | grep -E 'ctap|hidapi|udev'
ctap-hid-fido2 v3.5.9
hidapi v2.6.5

So musl builds shouldn't need the libudev pre-build step that the gnu targets use. No Cross.toml change required for the new musl entries.

Trade-off: musl binaries won't have the fido2 provider. That seems acceptable since musl/Alpine deployments are typically headless containers without USB hardware-key access; users who need fido2 on musl can build from source on a glibc host or wait for a future libusb-static backend.

Re Gemini's review — those comments are reviewing the stale chore: add communique 1.0.1 commit that was on the branch base before I rebased onto current main. The current diff on the PR is just the release.yml matrix change + the fido2 gating. Re-running the review should clear those.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3e0c397. Configure here.

Comment thread src/commands/provider/mod.rs
provider_add_types_match_provider_definitions reads providers/*.toml
from disk and asserts the names match ProviderType::value_variants().
Since the Fido2 variant is cfg-gated out on musl but fido2.toml is still
on disk, the assertion failed. Mirror the gate in the test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jdx jdx merged commit 275e079 into main Apr 29, 2026
17 checks passed
@jdx jdx deleted the claude/hungry-payne-e4d09f branch April 29, 2026 20:45
jdx pushed a commit that referenced this pull request May 2, 2026
### 🚜 Refactor

- extract providers and core types into fnox-core crate by
[@jdx](https://github.com/jdx) in
[#458](#458)

### 📚 Documentation

- prefix star count with ★ glyph and populate it on deploy by
[@jdx](https://github.com/jdx) in
[#447](#447)
- add favicons and web app manifest by [@jdx](https://github.com/jdx) in
[#448](#448)

### 🔍 Other Changes

- **(docs)** remove shrill.en.dev analytics script by
[@jdx](https://github.com/jdx) in
[#457](#457)
- **(release)** add musl Linux targets for Alpine compatibility by
[@jdx](https://github.com/jdx) in
[#452](#452)
- add plausible analytics by [@jdx](https://github.com/jdx) in
[#451](#451)
- bump hk to 1.44.3 by [@jdx](https://github.com/jdx) in
[#454](#454)

### 📦️ Dependency Updates

- update autofix-ci/action action to v1.3.4 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#455](#455)
- update apple-actions/import-codesign-certs action to v7 by
[@renovate[bot]](https://github.com/renovate[bot]) in
[#456](#456)
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