Skip to content

Add Justfile and Docker reproducible build#132

Merged
kwsantiago merged 7 commits intomainfrom
Justfile-and-Docker
Jan 22, 2026
Merged

Add Justfile and Docker reproducible build#132
kwsantiago merged 7 commits intomainfrom
Justfile-and-Docker

Conversation

@wksantiago
Copy link
Contributor

@wksantiago wksantiago commented Jan 22, 2026

Summary

  • Add Dockerfile.reproducible for deterministic firmware builds
  • Add Justfile with build, test, and verification commands
  • Add REPRODUCIBILITY.md documentation
  • Pin all dependencies to specific versions/commits

Test plan

  • Run just test to verify native tests pass
  • Run just docker-build to build firmware
  • Compare output hashes across builds

Verification Results

Native Tests: 11/11 passing (test_storage, test_secure_element, test_secresult, test_hw_entropy, test_psbt_fraud, test_integration, test_self_test, test_hw_entropy_sha256, test_session, test_anti_glitch, test_psbt_fraud_integration)

Docker Build: Successful - produces keep.bin (897KB), keep-merged.bin (962KB)

Reproducibility: Verified - consecutive builds produce identical hashes:

keep.bin: 743d46586ba53e9d73d16c4b6978684de8ec97f55bbc27901d0d085ba20ee245
keep-merged.bin: 5c9a744905c2dcaf169b5861c65c9357cf8ee20afe02a6c91f981e5d7348c59d

Summary by CodeRabbit

  • New Features

    • Added reproducible firmware builds with Docker support for consistent artifacts
    • Introduced automated workflow commands for building, flashing, testing, fuzzing, and verification
  • Documentation

    • Added comprehensive reproducibility guide with artifact verification procedures
  • Chores

    • Updated build artifact ignore patterns and license configurations

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 22, 2026

Warning

Rate limit exceeded

@kwsantiago has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 1 minutes and 46 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Walkthrough

Adds reproducible firmware build infrastructure and developer automation: a multi-stage reproducible Docker build, a comprehensive Justfile with build/test/verify/fuzz targets, reproducibility documentation, .gitignore additions, and SPDX annotations in REUSE.toml.

Changes

Cohort / File(s) Summary
Reproducible Docker build
Dockerfile.reproducible
New multi-stage Dockerfile that pins toolchain and repos, builds firmware in a builder stage, merges binaries with esptool, computes SHA256 checksums, and exports artifacts to /out.
Developer automation (Just targets)
Justfile
New Justfile adding many targets (default, build, flash, monitor, flash-monitor, test, fuzz(target,duration), docs, clean, docker-build, verify-sha(expected), verify-release(version), verify-device, ci) with env-driven behavior, parameter validation, and verification workflows.
Documentation
REPRODUCIBILITY.md
New reproducibility doc describing requirements, quick start, docker-build usage, output artifacts, and manual and automated verification steps.
Ignore rules
.gitignore
Adds fuzz/build/ and output/ to ignored paths.
License metadata
REUSE.toml
Adds SPDX annotations for Justfile and Dockerfile*, removes an obsolete line, and adds trailing newline.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Dev as Developer
  participant Local as Local host / just
  participant Docker as Docker builder
  participant Git as External repos
  participant IDF as ESP-IDF toolchain
  participant Out as /out artifacts

  Dev->>Local: run `just docker-build` (or `docker build`)
  Local->>Docker: start builder stage (Dockerfile.reproducible)
  Docker->>Git: clone pinned repos (secp256k1-frost, libnostr-c, noscrypt, libwally-core)
  Docker->>IDF: invoke build (idf.py / cmake) with SOURCE_DATE_EPOCH
  IDF-->>Docker: produce firmware binaries (keep.bin, bootloader.bin, ...)
  Docker->>Docker: merge binaries (esptool) -> keep-merged.bin
  Docker->>Docker: compute SHA256 checksums
  Docker->>Out: place artifacts and checksums into `/out`
  Docker-->>Local: export final image containing `/out`
  Local-->>Dev: artifacts available for verify-release / verify-device
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I nudge the build, I stamp the time,
I gather bins in perfect line.
Docker stews and checksums hum,
Repro carrots ready — here they come! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding a Justfile and Docker reproducible build setup, which are the primary additions across multiple files in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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 and usage tips.

@wksantiago wksantiago requested a review from kwsantiago January 22, 2026 18:47
@wksantiago wksantiago self-assigned this Jan 22, 2026
@wksantiago wksantiago linked an issue Jan 22, 2026 that may be closed by this pull request
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@Justfile`:
- Around line 105-118: The verify-device target uses GNU-specific stat -c%s to
set SIZE which breaks on macOS; change the SIZE computation in the verify-device
recipe to a cross-platform method (e.g., use "wc -c" or a small portable
python/perl one-liner) so SIZE correctly contains the byte length of
output/keep.bin, ensure you trim whitespace/newline from the command output
before using SIZE in the esptool.py call, and keep the rest of the target (TMP,
trap, DEVICE_HASH/BUILT_HASH comparisons) unchanged.
🧹 Nitpick comments (3)
Dockerfile.reproducible (2)

14-21: Consider shallow clones to reduce build time and layer size.

Using --depth=1 for git clones would significantly reduce download time and layer size since only the specific commit is needed.

♻️ Suggested improvement
-RUN git clone https://github.com/privkeyio/secp256k1-frost.git && \
-    cd secp256k1-frost && git checkout 832bac2dbfaf4c35058cd5dadb0f8fe093cb6c65 && cd .. && \
-    git clone https://github.com/privkeyio/libnostr-c.git && \
-    cd libnostr-c && git checkout 4e8d01b8d20680204429aaf3680d069ec222fdaa && cd .. && \
-    git clone https://github.com/privkeyio/noscrypt.git && \
-    cd noscrypt && git checkout 45fcbef32f958145d6797f384a225c0d43616886 && cd .. && \
-    git clone https://github.com/ElementsProject/libwally-core.git && \
-    cd libwally-core && git checkout 242f841af6819b5d5174da5a9593907f56f1bc89 && cd ..
+RUN git clone --depth=1 https://github.com/privkeyio/secp256k1-frost.git && \
+    cd secp256k1-frost && git fetch --depth=1 origin 832bac2dbfaf4c35058cd5dadb0f8fe093cb6c65 && git checkout FETCH_HEAD && cd .. && \
+    git clone --depth=1 https://github.com/privkeyio/libnostr-c.git && \
+    cd libnostr-c && git fetch --depth=1 origin 4e8d01b8d20680204429aaf3680d069ec222fdaa && git checkout FETCH_HEAD && cd .. && \
+    git clone --depth=1 https://github.com/privkeyio/noscrypt.git && \
+    cd noscrypt && git fetch --depth=1 origin 45fcbef32f958145d6797f384a225c0d43616886 && git checkout FETCH_HEAD && cd .. && \
+    git clone --depth=1 https://github.com/ElementsProject/libwally-core.git && \
+    cd libwally-core && git fetch --depth=1 origin 242f841af6819b5d5174da5a9593907f56f1bc89 && git checkout FETCH_HEAD && cd ..

45-46: Use directory copy instead of wildcard to avoid BuildKit glob expansion issues.

The COPY --from=builder /out/* / syntax with wildcards has documented inconsistencies in BuildKit, including skipped files and non-standard glob expansion behavior. Additionally, wildcards do not copy hidden files (names beginning with .), while copying the directory itself does.

♻️ Suggested fix
 FROM scratch AS export
-COPY --from=builder /out/* /
+COPY --from=builder /out/ /

This syntax copies all contents of /out (including hidden files) into the root of the scratch image without relying on glob expansion.

Justfile (1)

87-103: Add error handling for failed downloads.

If the curl download fails (network error, 404, etc.), the script continues and may produce confusing errors. Consider adding -f flag to curl or explicit error checking.

♻️ Suggested improvement
     TMP=$(mktemp -d)
     trap "rm -rf $TMP" EXIT
-    curl -sL "https://github.com/privkeyio/keep-esp32/releases/download/{{version}}/keep-esp32-firmware-{{version}}.tar.gz" | tar -xz -C "$TMP"
+    curl -sfL "https://github.com/privkeyio/keep-esp32/releases/download/{{version}}/keep-esp32-firmware-{{version}}.tar.gz" -o "$TMP/release.tar.gz" || { echo "Failed to download release {{version}}"; exit 1; }
+    tar -xzf "$TMP/release.tar.gz" -C "$TMP"

@kwsantiago kwsantiago merged commit f77b7e6 into main Jan 22, 2026
9 checks passed
@kwsantiago kwsantiago deleted the Justfile-and-Docker branch January 22, 2026 20:27
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.

Add Justfile and Docker for reproducible builds

2 participants