Skip to content

ci(docker): portable multi-arch image, unprivileged runtime, GHCR publish - #927

Merged
jlucaso1 merged 7 commits into
mainfrom
claude/whatsapp-rust-dockerfile-mfinvt
Jun 30, 2026
Merged

ci(docker): portable multi-arch image, unprivileged runtime, GHCR publish#927
jlucaso1 merged 7 commits into
mainfrom
claude/whatsapp-rust-dockerfile-mfinvt

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes correctness/security issues in the Dockerfile and adds a workflow that builds and publishes a single multi-arch image to GHCR.

Dockerfile

  • Drop -C target-cpu=native. A published image must run on any host of its arch; native tuned the binary to the build machine's CPU, risking SIGILL on older/different hosts and meaning nothing under emulated cross-arch builds — it directly contradicted the musl-portability rationale in the header. RUSTFLAGS is now just -Zshare-generics=y.
  • Fix the cargo-chef cache. The dependency layer is now cooked with --example demo, matching the final build. The demo example pulls env_logger (a dev-dependency), so without matching flags those deps recompiled after the source COPY instead of landing in the cached layer.
  • Run unprivileged. The runtime stage now runs as USER 65532:65532. /data and /tmp are staged as empty dirs and copied with COPY --chown=65532:65532 (numeric uid → reliable, works on buildkit and the legacy builder). A fresh named volume inherits /data's ownership, so the SQLite DB stays writable.
  • Provide /tmp. scratch ships no /tmp; added one plus ENV TMPDIR=/tmp for any SQLite temp files.

CI — .github/workflows/docker.yml

  • Triggers on push to main, v* tags, and manual workflow_dispatch.
  • Builds linux/amd64 and linux/arm64 on native runners (ubuntu-latest + ubuntu-24.04-arm) — not QEMU, which would be far too slow for this build-std + fat-LTO build.
  • Each arch pushes by digest; a merge job assembles a single multi-arch manifest and publishes to ghcr.io/oxidezap/whatsapp-rust with branch/tag/semver/sha tags plus latest on the default branch. Per-arch gha cache scopes.

One manifest, one URL

The image is published as a single manifest list, so consumers pull one reference and Docker resolves the right arch automatically:

docker pull ghcr.io/oxidezap/whatsapp-rust:latest   # → amd64 or arm64 per host

Notes / to verify

  • The ubuntu-24.04-arm runners are free for public repos but must be enabled in the org's Actions settings.
  • No docker build was run in the dev environment (no daemon); first real validation happens when the workflow runs — it can be triggered manually via the Actions tab after merge.

🤖 Generated with Claude Code


Generated by Claude Code

Review in cubic

…lish

- Drop `-C target-cpu=native`: a published image must run on any host of its
  arch, so keep the portable musl baseline. native risked SIGILL on
  older/different CPUs and is meaningless under emulated cross-arch builds.
- Cook the dependency layer with `--example demo` so the example's dev-deps
  (env_logger, …) land in the cached layer instead of recompiling after COPY.
- Run as unprivileged uid 65532 with writable /data (named-volume ownership)
  and /tmp for SQLite temp files, staged via COPY --chown.
- Add docker.yml: build linux/amd64 + linux/arm64 on native runners, push by
  digest, merge into one manifest, publish to GHCR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0161LFHLPTdCNyianZFH8dor
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jlucaso1, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 26 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

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

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 96723937-1a52-4279-aa56-b08dcc52cd5c

📥 Commits

Reviewing files that changed from the base of the PR and between a362145 and c8cbee1.

📒 Files selected for processing (2)
  • .github/workflows/release.yml
  • Dockerfile
📝 Walkthrough

Walkthrough

Adds a Docker workflow that builds amd64 and arm64 images, merges them into a multi-arch manifest on ghcr.io, and wires release version output into reusable publishing. The Dockerfile now builds for a derived Rust target triple, drops target-cpu=native, and runs the final image as an unprivileged user with writable /data and /tmp.

Changes

Docker build and publish flow

Layer / File(s) Summary
Workflow triggers and settings
.github/workflows/docker.yml
Defines the Docker workflow name, push/tag/manual triggers, concurrency group, reusable-workflow input, and registry/image environment variables.
Parallel per-architecture build
.github/workflows/docker.yml
Runs matrix builds for amd64 and arm64 on different runners, scopes Buildx cache per platform pair, pushes per-arch digests, and uploads each digest as an artifact.
Multi-arch manifest merge
.github/workflows/docker.yml
Downloads the digest artifacts, regenerates tags from metadata, logs in to the registry, creates a combined manifest with Buildx imagetools, and inspects the pushed image tag.
Release version wiring
.github/workflows/release.yml
The release job exports the computed version, and a new publish job invokes the reusable Docker workflow after release completion with package write permissions.
Portable Rust build inputs
Dockerfile
Removes -C target-cpu=native, keeps -Zshare-generics=y, derives the Rust target triple into /rust-target, and uses it for cargo chef cook and the final cargo build with --example demo.
Writable scratch runtime
Dockerfile
Documents the /data volume ownership requirement, creates writable /data and /tmp directories in scratch, copies them with --chown=65532:65532, sets TMPDIR=/tmp, and runs the image as USER 65532:65532.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

  • oxidezap/whatsapp-rust#300: Changes .github/workflows/release.yml in the same release-version plumbing path used to drive Docker publishing here.
  • oxidezap/whatsapp-rust#461: Overlaps with the Dockerfile build stages, cargo-chef caching, and final artifact copy into the runtime image.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the Docker portability, unprivileged runtime, and GHCR publishing changes.
Description check ✅ Passed The description matches the Dockerfile and workflow changes and is directly related to the pull request.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/whatsapp-rust-dockerfile-mfinvt

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.

@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown

📦 Binary size report

Metric main PR Δ
bin size (stripped) 10.11 MiB 10.11 MiB 0
bin .text 8.16 MiB 8.16 MiB 0
bin allocated (text+data+bss) 10.11 MiB 10.11 MiB 0
llvm-lines wacore 644,533 644,533 0
llvm-lines wacore copies 17,879 17,879 0
llvm-lines whatsapp-rust lib 658,435 658,435 0
llvm-lines whatsapp-rust lib copies 20,447 20,447 0
deps crates (Cargo.lock) 466 466 0
.text per crate
Crate main PR Δ
.text whatsapp_rust 1.49 MiB 1.49 MiB 0
.text wacore 527.81 KiB 527.81 KiB 0
.text wacore_binary 155.84 KiB 155.84 KiB 0
.text wacore_libsignal 165.86 KiB 165.86 KiB 0
.text wacore_appstate 144.24 KiB 144.24 KiB 0
.text wacore_noise 27.71 KiB 27.71 KiB 0
.text waproto 871.99 KiB 871.99 KiB 0
.text whatsapp_rust_sqlite_storage 475.72 KiB 475.72 KiB 0
.text whatsapp_rust_tokio_transport 43.67 KiB 43.67 KiB 0
.text whatsapp_rust_ureq_http_client 8.81 KiB 8.81 KiB 0
.text std 998.85 KiB 998.85 KiB 0
.text other deps 3.28 MiB 3.28 MiB 0
Top movers (cargo-bloat attribution)
Crate main PR Δ
regex_automata 2.90 KiB 1.39 KiB -1.50 KiB (-51.84%)
prost 370.63 KiB 371.90 KiB +1.26 KiB (+0.34%)

Baseline: 44aafc5a3 (latest main run) · Head: 31410a2a0 · Graphs

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

🤖 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 `@Dockerfile`:
- Line 58: Preserve the failure from rustc when writing the target in the
Dockerfile build step: the current RUN command in the rustc -vV / sed / test
sequence hides rustc status behind the pipe, so rewrite the logic in the same
Docker layer without piping and make the failure path explicit. Use the existing
rustc -vV target extraction step to store the host target directly, then
validate the output separately so Hadolint no longer flags the instruction.
🪄 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 UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 49d6c878-9b22-42a0-afb6-d5f51d4f3529

📥 Commits

Reviewing files that changed from the base of the PR and between 44aafc5 and a81fca4.

📒 Files selected for processing (2)
  • .github/workflows/docker.yml
  • Dockerfile

Comment thread Dockerfile Outdated
Piping rustc -vV into sed let sed's exit status drive the layer, masking a
rustc failure. Write the version to a temp file first so the failure path is
explicit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0161LFHLPTdCNyianZFH8dor
@codspeed-hq

codspeed-hq Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 179 untouched benchmarks


Comparing claude/whatsapp-rust-dockerfile-mfinvt (c8cbee1) with main (44aafc5)

Open in CodSpeed

@cubic-dev-ai cubic-dev-ai 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.

1 issue found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/docker.yml">

<violation number="1" location=".github/workflows/docker.yml:1">
P2: Net-new workflow pins Docker and artifact actions to stale major versions. Start with current releases (setup-buildx@v4, login@v4, metadata@v6, build-push@v7, upload-artifact@v7, download-artifact@v8) for Node.js 24 compatibility and latest fixes.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread .github/workflows/docker.yml

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

ℹ️ 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 Dockerfile Outdated
claude added 2 commits June 30, 2026 03:12
cargo-chef 0.1.77's `cook` CLI defines `--examples` (plural bool) but not
`--example <name>`, so `--example demo` aborted the dependency layer with a
clap unexpected-argument error. Under default features `--examples` builds only
demo (the other examples gate on extra features), and dev-deps are per-package,
so the demo's dev-deps still land in the cached layer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0161LFHLPTdCNyianZFH8dor
setup-buildx@v4, login@v4, metadata@v6, build-push@v7, upload-artifact@v7,
download-artifact@v8 — current releases (verified), for Node 24 runtime and
latest fixes. Only stable, still-supported inputs are used.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0161LFHLPTdCNyianZFH8dor

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

🤖 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 `@Dockerfile`:
- Around line 63-65: The Dockerfile’s cargo-chef cache step is using an invalid
specific example argument with cargo chef cook, so update the `RUN cargo chef
cook` invocation to use the supported `--examples` flag instead of `--example
demo`. Keep the existing `cargo chef cook`, `--release`, `--recipe-path`, and
target handling intact, and adjust this layer so it matches the
example-dependency caching behavior needed before the final build.
🪄 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 UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2a6edf9e-92d8-4ada-b51d-25f560bdc9b6

📥 Commits

Reviewing files that changed from the base of the PR and between a81fca4 and a27bd69.

📒 Files selected for processing (1)
  • Dockerfile

Comment thread Dockerfile Outdated

@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: 33dfdfac57

ℹ️ 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/docker.yml
A v* tag pushed by release.yml with GITHUB_TOKEN can't trigger docker.yml's tag
event (GitHub suppresses workflow runs from token-pushed refs), so semver image
tags were never produced by automated releases. Make docker.yml callable via
workflow_call with a version input and invoke it from release.yml after the
GitHub release, tagging the image :<version>. Push-to-main keeps publishing
:latest/:sha on its own. Concurrency now keys on event_name so a main push
can't cancel a release's build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0161LFHLPTdCNyianZFH8dor

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

🤖 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/release.yml:
- Around line 108-110: The reusable workflow call needs an explicit note
explaining why it requests packages: write. Update the permissions block in the
release workflow near the reusable workflow invocation to document that the
called workflow logs into GHCR and pushes the manifest, so reviewers and
security tooling can see the purpose of the package-write grant. Keep the
permission values unchanged and add the explanation close to the permissions
declaration for easy discovery.
🪄 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 UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3a35d332-0e88-4335-840e-3db2fdb76f59

📥 Commits

Reviewing files that changed from the base of the PR and between 33dfdfa and a362145.

📒 Files selected for processing (2)
  • .github/workflows/docker.yml
  • .github/workflows/release.yml

Comment thread .github/workflows/release.yml

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread .github/workflows/release.yml
…mor)

zizmor's undocumented-permissions flags permission grants without a rationale;
note that the called docker.yml logs into GHCR and pushes the manifest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0161LFHLPTdCNyianZFH8dor

@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: 53d311e31d

ℹ️ 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 Dockerfile
…umes

Dropping to uid 65532 can't write a whatsapp-data volume that an older
root-running image populated; Docker won't re-chown an existing named volume.
Auto-migration isn't possible on scratch (no shell/su-exec), so document the
one-time chown via a throwaway image. Fresh volumes inherit 65532 and are
unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0161LFHLPTdCNyianZFH8dor
@jlucaso1
jlucaso1 merged commit 645e2ba into main Jun 30, 2026
14 checks passed
@jlucaso1
jlucaso1 deleted the claude/whatsapp-rust-dockerfile-mfinvt branch June 30, 2026 03:52
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.

2 participants