- Rust 70.2%
- Zig 28.7%
- Shell 0.9%
- Dockerfile 0.2%
|
|
||
|---|---|---|
| .cargo | ||
| .forgejo/workflows | ||
| .gear | ||
| docs | ||
| examples | ||
| src | ||
| tests | ||
| vendor | ||
| zig-src | ||
| .dockerignore | ||
| .gitignore | ||
| build.zig | ||
| build.zig.zon | ||
| Cargo.lock | ||
| Cargo.toml | ||
| crucible.spec | ||
| README.md | ||
Crucible
Crucible is an experimental ALT Linux RPM build tool. The current reference implementation is written in Rust; an in-place Zig 0.16.0 migration is being developed alongside it without replacing the Rust baseline. Crucible bootstraps an ALT apt-rpm root filesystem, creates a private writable copy for every build, and executes rpmbuild with explicit read-only input and writable output mounts.
Implemented behavior
- Exact HTTPS apt-rpm targets for Sisyphus and p11, including
noarchand ALT signing-key selectors. - Fail-closed rootfs creation: incomplete bootstraps have no ready marker and are never reused.
- Per-build rootfs copies and direct
rpmbuildargument execution (no shell interpolation). - User, mount, PID, UTS, IPC, and optional network namespaces where the kernel permits them.
- CPU/file/process/address-space rlimits, wall-clock timeout, concurrent output draining, and process-group termination.
- A constrained subset of Gear rules: copy/compress/tar/zip/diff.
tags,type, andspecsubstare rejected. - Managed rootfs, cache, and repository names are restricted to one safe path component.
- Bash and zsh completion generation.
The following are not claimed as complete: cgroups v2, seccomp, overlayfs snapshots, recursive Gear dependency builds, SRPM input, hooks in the build lifecycle, cache reuse in the build command, fakeroot credential emulation, and an ALT apt-rpm-compatible local repository generator. The repository command requires a successful external createrepo_c/createrepo invocation.
Requirements
- Linux host with
curl, GNUtar, and access toregistry.altlinux.org. Docker, Podman, and host ALT tools are not required; Crucible downloads and verifies the officialsisyphus/altorp11/altOCI layers itself. - Linux namespaces enabled; unprivileged mode requires user namespaces.
- Rust 1.85 or newer. The RPM build is locked and offline, so crate sources must already be vendored or present in Cargo's source cache.
- Zig 0.16.0 for the migration skeleton. It has no external Zig dependencies.
Build and checks
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets
cargo build --locked --offline
The migration-oriented Rust behavior corpus, exact golden outputs, security fixtures, and the optional privileged Docker namespace fixture are documented in docs/CONFORMANCE.md.
The Zig migration binary is deliberately installed under a separate name and does not replace the Rust CLI. Its current safe subset includes the typed configuration model, default/system/user/project/environment/CLI precedence, status, config show, config validate, and Rust-compatible golden diagnostics for invalid environment values, chroot styles, and conflicting build modes. The Zig library also consumes Ember's locked alt:p11/crucible-build package-origin profile through either a direct Zig provider or the checked Ember C ABI v3. Cache identity includes profile, profile version, and the exact repository-lock SHA-256; incomplete or mismatched roots fail closed and are never reused. The Zig sandbox API provides typed privileged/rootless policy, direct Linux user/PID/mount/UTS/IPC/network namespace setup, private mounts, pivot_root, and canonical-path-checked build binds. It is exercised by the local-only disposable Docker suite described in ADR-0003, but is not yet wired into the Zig build CLI.
The Zig source_input library parses the typed RPM preamble needed by the next build slice, stages regular spec/source/patch files through directory handles without following symlinks, and produces an rpmbuild argv containing target-visible /build/... paths only. Its intentionally small Gear subset supports only one spec: rule and exact repository-root files in copy: rules. Globs, nested paths, optional rules, tags, type, excludes, archive generation, compression, diff, and specsubst fail explicitly; source archives are copied as opaque regular files and are never extracted. The boundary and non-compatibility statement are recorded in ADR-0004.
zig fmt --check build.zig zig-src
zig build test --summary all
zig build -Doptimize=ReleaseSafe
tests/conformance/docker-zig/run.sh
./zig-out/bin/crucible-zig --version
./zig-out/bin/crucible-zig --help
./zig-out/bin/crucible-zig --migration-status
./zig-out/bin/crucible-zig --config tests/conformance/fixtures/config/full.toml config show
./zig-out/bin/crucible-zig config validate tests/conformance/fixtures/config/full.toml
The Zig TOML reader intentionally accepts only the typed keys and simple values represented by the conformance configuration; unknown tables/keys, escaped strings, malformed values, unsafe work directories, and unsupported architecture/platform/log values fail closed. All Rust commands outside the subset return an explicit unsupported Rust command ... during migration diagnostic and are not executed. No argument is interpreted by a shell. The root acquisition API and independent Zig/C integration examples are described in ADR-0002; they do not switch the production CLI default.
Pass -Dmigration=true to compile in the migration feature gate. It is disabled by default. The in-place layout, cutover boundary, build contract, and GPL-3.0-or-later licensing decision are recorded in docs/adr/0001-zig-migration-layout-and-license.md.
Basic use
crucible init
crucible build --spec package.spec --output results
crucible build --repo-dir . --output results
crucible completions bash
crucible completions zsh
--offline performs no APT update or download. It reports missing BuildRequires from the per-build rootfs. --bb and --bs are mutually exclusive.
Configuration layers are merged in this order: /etc/crucible/config.toml, user config, project crucible.toml, environment, then CLI flags. Invalid environment values are errors.
Security model and limitations
Rootfs creation pulls an official ALT OCI image over TLS, records its immutable SHA-256 repository digest, installs the CA bundle through the image's signed stock ALT repository, and then switches to HTTPS-only configured repositories. ALT apt-rpm, RPM queries, and package scripts execute inside an OCI container; the host package manager and host ALT vendor files are never used. Build inputs are mounted read-only at /build/input (and generated Gear sources at /build/sources), outputs at /build/output, and the build tree is /build/rpm. Host absolute paths are never handed to rpmbuild inside the sandbox.
Namespace and mount availability depends on the host kernel and runner privileges. Crucible fails when required setup fails. The Zig runner accepts only read-only /build/input and /build/sources plus read-write /build/output, all sourced from an explicit non-root host-workspace boundary; it rejects broad/out-of-boundary sources and symlink-aliased targets before namespace setup, does not import rootfs submounts, and closes inherited host descriptors. Do not use Rust chroot_style = "none" for untrusted builds; it is a debugging mode and provides no isolation.
CI
The repository uses its Forgejo runner workflow for the ALT p11 self-build. The ignored privileged integration test can also be enabled on a Linux host with mount/PID namespace privileges and network access.
License: GPL-3.0-or-later.