base-rs
CI License: AGPL-3.0-or-later Reproducible builds Rust 1.96.0
Architecture-independent starting point for our Rust projects. It is empty on purpose — a hello-world library + binary — but already wired into the org-wide reproducible-build toolchain: pinned compiler, vendored dependencies, a digest-pinned Docker build, and a Codeberg CI pipeline that proves the build is bit-for-bit reproducible. Copy it, rename the package, start writing code.
Suitable as a base for Linux services, WebRTC/UC backends, CLI tools,
host-tested embedded cores — anything std.
Quick start
# day-to-day development (native, offline against vendor/)
cargo run # -> Hello, world! — built reproducibly from base-rs.
cargo run -- Stewie # -> Hello, Stewie! ...
cargo test # unit tests (in src/lib.rs) + integration tests (tests/)
# reproducible release build in the pinned Docker image -> ./out/
scripts/build.sh
scripts/build.sh --verify # build twice and confirm the hashes match
Layout
base-rs/
├── .cargo/config.toml # offline vendored-sources + --remap-path-prefix
├── .dockerignore # keeps target/ & out/ out of the build context
├── .gitignore # ignores target/out; KEEPS Cargo.lock + vendor/
├── .woodpecker.yml # Codeberg CI: fmt + clippy + test + verify-reproducible
├── Cargo.lock # committed: exact versions + checksums
├── Cargo.toml # AGPL, pinned rust-version, RE-friendly release profile
├── Dockerfile # alpine@sha256 + rustup(sha256) + fixed clock/locale
├── LICENSE # GNU AGPL-3.0-or-later
├── README.md
├── rust-toolchain.toml # channel = "1.96.0"
├── scripts/build.sh # one-shot reproducible build + --verify
├── src/
│ ├── lib.rs # the logic — host-testable everywhere (unit tests here)
│ └── main.rs # thin binary shell over the library
├── tests/
│ └── integration.rs # exercises the public API as an external crate
└── vendor/ # vendored crate sources (empty until you add a dep)
The library-holds-the-logic, binary-is-a-shell split is deliberate: it keeps every line unit-testable on the host even when the real deployment target is a microcontroller or a WASM/WebRTC runtime.
Reproducible builds
The goal is bit-for-bit reproducibility: anyone, on any machine, can rebuild
the exact same artifact bytes and verify a release was not tampered with. This
repo implements the seven org rules (see the org-wide REPRODUCIBLE-BUILDS.md):
| Rule | How it's done here |
|---|---|
| Build only in Docker, base pinned by digest | Dockerfile: FROM alpine@sha256:48b0309... (multi-arch index digest) |
| Pin the Rust toolchain | rust-toolchain.toml channel 1.96.0; rustup-init pinned by version and sha256 (per arch) in the Dockerfile |
| Vendor everything; build offline & locked | vendor/ + committed Cargo.lock; .cargo/config.toml replaces crates-io with vendored-sources; build is --offline --locked |
| Fix clock, locale, paths | SOURCE_DATE_EPOCH=1781395200, TZ=UTC, LC_ALL=C, --remap-path-prefix=/build=. |
| Fix the release profile | [profile.release] in Cargo.toml (codegen-units = 1, ...) |
Export from a scratch stage; record hashes |
final FROM scratch AS artifacts, emits SHA256SUMS |
| Verify, don't assume | scripts/build.sh --verify and the CI verify-reproducible step build twice and cmp |
Reverse-engineerable on purpose
Unlike most release profiles, this one keeps the binary easy to inspect:
strip = false,debug = "full"→ full symbol names + DWARF line tables stay in the binary, so it reads almost like source under a debugger.lto = false,opt-level = 1→ light optimisation, no cross-crate inlining, so function boundaries survive in the disassembly.
This is a deliberate deviation from the org default (strip = true). It does
not cost reproducibility — determinism comes from codegen-units = 1, the
fixed clock, and path remapping, not from stripping. Want the small, stripped
variant instead? Set strip = true / debug = false and re---verify.
Adding a dependency
Dependencies are taken newest-then-frozen:
cargo add <crate> # newest version
cargo update # newest compatible across the tree
cargo vendor vendor # mirror sources into vendor/ (locked by Cargo.lock)
git add Cargo.toml Cargo.lock vendor/
scripts/build.sh --verify
New versions only ever enter through such a deliberate re-vendor commit, never
silently — --offline --locked fails the build otherwise.
CI
.woodpecker.yml runs on Codeberg CI (Woodpecker) on
every push / PR / tag, in the same digest-pinned rust:1.96.0-alpine image:
- check —
cargo fmt --check,cargo clippy -D warnings,cargo test. - verify-reproducible — builds the release binary twice and fails unless the two hashes are identical.