diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb1c8c6..ec73883 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,21 +68,20 @@ jobs: run: | rustup target add x86_64-unknown-linux-musl aarch64-unknown-linux-musl i686-unknown-linux-musl \ arm-unknown-linux-musleabihf armv7-unknown-linux-musleabihf riscv64gc-unknown-linux-musl \ - loongarch64-unknown-linux-musl powerpc64le-unknown-linux-musl powerpc64-unknown-linux-gnu \ - s390x-unknown-linux-gnu x86_64-pc-windows-gnu i686-pc-windows-gnu aarch64-pc-windows-gnullvm wasm32-wasip1 \ - x86_64-unknown-freebsd i686-unknown-freebsd x86_64-unknown-netbsd x86_64-unknown-illumos x86_64-pc-solaris + loongarch64-unknown-linux-musl powerpc64le-unknown-linux-musl \ + s390x-unknown-linux-gnu x86_64-pc-windows-gnu i686-pc-windows-gnu aarch64-pc-windows-gnullvm \ + x86_64-unknown-freebsd i686-unknown-freebsd - name: build run: | # Everything but macOS, which the test job builds on a Mac. TARGETS="linux/amd64 linux/arm64 linux/386 linux/armv6 linux/armv7 linux/riscv64 linux/loong64 \ - linux/ppc64le linux/ppc64 linux/s390x android/arm64 windows/amd64 windows/386 windows/arm64 \ - freebsd/amd64 freebsd/386 netbsd/amd64 illumos/amd64 solaris/amd64 wasip1/wasm" ./build.sh + linux/ppc64le linux/s390x windows/amd64 windows/386 windows/arm64 freebsd/amd64 freebsd/386" ./build.sh - name: run builds under qemu, cross-checked with the Go oracle run: | - sudo apt-get update -q && sudo apt-get install -yq qemu-user libc6-s390x-cross libc6-ppc64-cross + sudo apt-get update -q && sudo apt-get install -yq qemu-user libc6-s390x-cross (cd oracle/go && go build -o ../../target/vault-go .) for t in "arm64 qemu-aarch64" "armv7 qemu-arm" "riscv64 qemu-riscv64" "ppc64le qemu-ppc64le" \ - "s390x qemu-s390x -L /usr/s390x-linux-gnu" "ppc64 qemu-ppc64 -L /usr/powerpc64-linux-gnu"; do + "s390x qemu-s390x -L /usr/s390x-linux-gnu"; do EMU="${t#* }" scripts/smoke.sh "dist/vault-linux-${t%% *}" target/vault-go done - uses: actions/upload-artifact@v4 diff --git a/README.md b/README.md index 72aa72f..cf41266 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ TARGETS="linux/amd64 windows/amd64" ./build.sh `build.sh` cross-compiles with `cargo-zigbuild` and `zig` (Linux, statically linked with musl, and Windows), on a Mac for macOS, and with `cross` and -Docker for the BSDs, illumos and Solaris. It names binaries as before +Docker for FreeBSD. The release covers Linux, Windows, macOS and FreeBSD. It names binaries as before (`vault-linux-arm64`, `vault-windows-amd64.exe`, …), builds 32-bit ARM Linux for both armv6 and armv7, and writes `dist/SHA256SUMS`. `docs/PLATFORMS.md` lists every target, how it is built and tested, and the Go targets Rust @@ -103,9 +103,7 @@ Commands that change the vault take an exclusive lock on `DIR/.lock`, and commands that read it take a shared one. A second process waits, and says so, until the first finishes. The operating system releases the lock if a process dies; the locks are the same ones the Go version used, so old and -new versions exclude each other. WebAssembly (WASI) has no file locks, so -there the lock file itself is the lock. After a crash there you remove it -by hand; the error message names it. +new versions exclude each other. Adding a name that already exists replaces it. `get` never replaces an existing file (or symlink) and writes nothing until the whole file has diff --git a/build.sh b/build.sh index 43c4540..16c2a30 100755 --- a/build.sh +++ b/build.sh @@ -9,16 +9,13 @@ # release builds from the pinned toolchain (rust-toolchain.toml) and the # locked dependencies (Cargo.lock), with build paths remapped so the output # does not depend on where the tree lives. Linux binaries are static (musl) -# except s390x and ppc64, which link glibc dynamically; static linking is +# except s390x, which links glibc dynamically; static linking is # checked. SHA256SUMS is written next to the binaries. # # How each target is built, and what the host needs: # zig cargo-zigbuild and zig on PATH (Linux, Windows GNU ABI) # mac a Mac with Xcode (macOS) -# cross `cross` and Docker (FreeBSD, NetBSD, illumos, Solaris, -# and big-endian ppc64, which zig -# links for the wrong ABI) -# cargo nothing extra (WASI) +# cross `cross` and Docker (FreeBSD) # A requested target the host cannot build is reported, the others are still # built, and the script exits non-zero. See docs/PLATFORMS.md for the Go # targets with no Rust equivalent; asking for one is an error. @@ -40,9 +37,7 @@ table() { linux/riscv64 riscv64gc-unknown-linux-musl zig linux/loong64 loongarch64-unknown-linux-musl zig linux/ppc64le powerpc64le-unknown-linux-musl zig - linux/ppc64 powerpc64-unknown-linux-gnu cross linux/s390x s390x-unknown-linux-gnu zig - android/arm64 aarch64-unknown-linux-musl zig windows/amd64 x86_64-pc-windows-gnu zig windows/386 i686-pc-windows-gnu zig windows/arm64 aarch64-pc-windows-gnullvm zig @@ -50,19 +45,15 @@ table() { darwin/arm64 aarch64-apple-darwin mac freebsd/amd64 x86_64-unknown-freebsd cross freebsd/386 i686-unknown-freebsd cross - netbsd/amd64 x86_64-unknown-netbsd cross - illumos/amd64 x86_64-unknown-illumos cross - solaris/amd64 x86_64-pc-solaris cross - wasip1/wasm wasm32-wasip1 cargo EOF } -# Go targets that Rust cannot build with a stable toolchain (no prebuilt -# standard library, or no Rust target at all). See docs/PLATFORMS.md. -unsupported="aix/ppc64 dragonfly/amd64 freebsd/arm freebsd/arm64 freebsd/riscv64 js/wasm -linux/mips linux/mipsle linux/mips64 linux/mips64le netbsd/386 netbsd/arm netbsd/arm64 -openbsd/386 openbsd/amd64 openbsd/arm openbsd/arm64 openbsd/ppc64 openbsd/riscv64 -plan9/386 plan9/amd64 plan9/arm" +# Go-era targets no longer released (the release covers Linux, Windows, +# macOS and FreeBSD). See docs/PLATFORMS.md for why each was dropped. +unsupported="aix/ppc64 android/arm64 dragonfly/amd64 freebsd/arm freebsd/arm64 freebsd/riscv64 +illumos/amd64 js/wasm linux/mips linux/mipsle linux/mips64 linux/mips64le linux/ppc64 +netbsd/386 netbsd/amd64 netbsd/arm netbsd/arm64 openbsd/386 openbsd/amd64 openbsd/arm +openbsd/arm64 openbsd/ppc64 openbsd/riscv64 plan9/386 plan9/amd64 plan9/arm solaris/amd64 wasip1/wasm" out=${OUT:-dist} jobs=${JOBS:-1} @@ -89,7 +80,7 @@ build_one() { row=$(table | awk -v t="$want" '$1 == t') if [[ -z $row ]]; then if grep -qw -- "$want" <<<"$unsupported"; then - echo "UNSUPPORTED $want: no stable Rust target; see docs/PLATFORMS.md" >&2 + echo "UNSUPPORTED $want: not released; see docs/PLATFORMS.md" >&2 else echo "UNKNOWN $want" >&2 fi @@ -98,7 +89,6 @@ build_one() { read -r _ triple method <<<"$row" os=${want%/*} [[ $os == windows ]] && ext=.exe - [[ $os == wasip1 ]] && ext=.wasm name=vault-${want/\//-}$ext tdir=$root/target [[ $JOBS_N != 1 ]] && tdir=$CARGO_TARGET_DIR_BASE/$triple @@ -114,7 +104,6 @@ build_one() { command -v cross >/dev/null && command -v docker >/dev/null || { echo "SKIPPED $want: needs cross and docker" >&2; return 1; } cmd=(cross build) ;; - cargo) cmd=(cargo build) ;; esac local flags=$RUSTFLAGS # zig's musl getrandom() never reaches the kernel on riscv64 (it spins); @@ -126,7 +115,6 @@ build_one() { return 1 fi bin=$tdir/$triple/release/vault$ext - [[ $os == wasip1 ]] && bin=$tdir/$triple/release/vault.wasm cp -- "$bin" "$OUT_DIR/$name" if [[ $triple == *-musl* ]] && command -v file >/dev/null; then file -L "$OUT_DIR/$name" | grep -q 'static' || { echo "FAILED $want: not statically linked" >&2; return 1; } diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index 70c1ed5..22b38e4 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -92,8 +92,8 @@ Command line: - `ls`/`list` piped into a reader that stops early end quietly with status 141, as Go's did by `SIGPIPE`. -Platforms: see `PLATFORMS.md`. Some targets Go built have no stable Rust -equivalent; they are listed there and need a decision before release. +Platforms: releases now cover Linux, Windows, macOS and FreeBSD (16 +binaries, down from 43); `PLATFORMS.md` lists what was dropped and why. ## Unchanged on purpose diff --git a/docs/PLATFORMS.md b/docs/PLATFORMS.md index 12320c3..3634a86 100644 --- a/docs/PLATFORMS.md +++ b/docs/PLATFORMS.md @@ -1,8 +1,8 @@ # Platforms The Go version was built for every target of `go tool dist list` that needs -no cgo: 43 binaries. Rust supports fewer operating systems and CPUs with a -prebuilt, stable standard library. This is the target-by-target record: +no cgo: 43 binaries. The Rust release is narrower by decision (Linux, +Windows, macOS, FreeBSD): 16 binaries. This is the target-by-target record: how each is built, and how far it has actually been verified. "Runtime" means a binary was executed; "build" means it only compiled and linked. @@ -14,7 +14,10 @@ x86-64. `scripts/smoke.sh` is the runtime check: create a key and vault, store files across object boundaries, read them back, then have the Go oracle read what that binary wrote and the binary read what the oracle wrote. -## Supported +## Released + +The release covers Linux, Windows, macOS and FreeBSD (a decision made during +the port: the Go release's more exotic targets are no longer built). | Go name | Rust target | Linking | Built by | Verified | | --- | --- | --- | --- | --- | @@ -23,63 +26,42 @@ what that binary wrote and the binary read what the oracle wrote. | linux/386 | i686-unknown-linux-musl | static | zig | runtime: smoke test under qemu-i386, cross-checked | | linux/armv6 | arm-unknown-linux-musleabihf | static | zig | runtime: smoke test under qemu-arm, cross-checked | | linux/armv7 | armv7-unknown-linux-musleabihf | static | zig | runtime: smoke test under qemu-arm, cross-checked | -| linux/riscv64 | riscv64gc-unknown-linux-musl | static | zig | runtime: smoke test under qemu-riscv64, cross-checked; unit tests under qemu (see note 1) | +| linux/riscv64 | riscv64gc-unknown-linux-musl | static | zig | runtime: smoke test and crypto unit tests under qemu-riscv64, cross-checked (note 1) | | linux/loong64 | loongarch64-unknown-linux-musl | static | zig | runtime: smoke test under qemu-loongarch64, cross-checked | | linux/ppc64le | powerpc64le-unknown-linux-musl | static | zig | runtime: smoke test under qemu-ppc64le, cross-checked | | linux/s390x | s390x-unknown-linux-gnu | glibc, dynamic | zig | runtime: smoke test under qemu-s390x (big-endian) with an Ubuntu glibc sysroot, cross-checked | -| linux/ppc64 | powerpc64-unknown-linux-gnu | glibc, dynamic | cross (Docker) | see note 2 | -| android/arm64 | aarch64-unknown-linux-musl | static | zig | build only on Android; it is the linux/arm64 binary (see note 3) | | windows/amd64 | x86_64-pc-windows-gnu | static CRT | zig | build; tests cross-compile cleanly; runtime in CI only (windows-2025 job, not yet run) | | windows/386 | i686-pc-windows-gnu | static CRT | zig | build only | | windows/arm64 | aarch64-pc-windows-gnullvm | static CRT | zig | build only | | darwin/amd64 | x86_64-apple-darwin | system | a Mac (Xcode) | CI only (macos-15-intel job, not yet run) | | darwin/arm64 | aarch64-apple-darwin | system | a Mac (Xcode) | CI only (macos-15 job, not yet run) | -| freebsd/amd64 | x86_64-unknown-freebsd | system | cross (Docker) | see note 4 | -| freebsd/386 | i686-unknown-freebsd | system | cross (Docker) | see note 4 | -| netbsd/amd64 | x86_64-unknown-netbsd | system | cross (Docker) | see note 4 | -| illumos/amd64 | x86_64-unknown-illumos | system | cross (Docker) | see note 4 | -| solaris/amd64 | x86_64-pc-solaris | system | cross (Docker) | see note 4 | -| wasip1/wasm | wasm32-wasip1 | n/a | cargo | build only; no agent, no terminal prompts (passphrase from the environment), lock file instead of locks | +| freebsd/amd64 | x86_64-unknown-freebsd | system | cross 0.2.5 (Docker) | build only (no emulator) | +| freebsd/386 | i686-unknown-freebsd | system | cross 0.2.5 (Docker) | build only | -Feature notes: the `unlock` agent works on Unix only (Linux, macOS, the BSDs, -illumos, Solaris); Windows asks for the passphrase every time. Full agent -hardening (`PR_SET_DUMPABLE`) is Linux-only; elsewhere the agent locks its -memory and disables core dumps. See `SECURITY.md`. +Feature notes: the `unlock` agent works on Linux, macOS and FreeBSD; +Windows asks for the passphrase every time. Full agent hardening +(`PR_SET_DUMPABLE`) is Linux-only; elsewhere the agent locks its memory and +disables core dumps. See `SECURITY.md`. 1. zig's bundled musl `getrandom()` never reaches the kernel on riscv64 (the process spins). `build.sh` and `packaging/package.sh` build that target with `--cfg getrandom_backend="linux_raw"`, which makes the `getrandom` crate issue the system call itself; with that flag the binary passes. -2. zig links big-endian ppc64 for the ELFv2 ABI (`/lib64/ld64.so.2`), but - big-endian glibc distributions use ELFv1 (`ld64.so.1`), so the zig build - would not start there. `build.sh` builds it with `cross` (GCC toolchain) - instead. -3. Go's android/arm64 binary was a static Linux binary used in Termux; this - is the same. Name resolution for `add URL`/`mirror` reads - `/etc/resolv.conf`, which Android does not have, so those two commands - may fail to resolve hosts there; everything else is unaffected. -4. Built with `cross` 0.2.5 images; not executed (no emulator). The - dependency graph supports these systems (rustix, ring, getrandom). -## Not supported +## No longer released -These Go targets have no Rust target with a prebuilt standard library on the -stable toolchain (Rust tier 3, built only with nightly `-Zbuild-std`, or no -Rust target at all). Building them would need a nightly toolchain and -untested standard libraries, which this project does not ship. - -| Go name | Rust status | +| Go name | Why | | --- | --- | -| aix/ppc64 | tier 3 (powerpc64-ibm-aix) | -| dragonfly/amd64 | tier 3 | -| freebsd/arm, freebsd/arm64, freebsd/riscv64 | tier 3 | -| netbsd/386, netbsd/arm, netbsd/arm64 | tier 3 | -| openbsd/386, amd64, arm, arm64, ppc64, riscv64 | tier 3 (OpenBSD packages Rust itself; building in an OpenBSD VM would work) | -| linux/mips, mipsle, mips64, mips64le | tier 3 since Rust 1.72 | -| plan9/386, amd64, arm | no Rust target | -| js/wasm | wasm32-unknown-unknown has no filesystem or OS access; not meaningful for vault | +| android/arm64 | was a copy of the static Linux arm64 binary; that binary still runs in Termux, but `add URL`/`mirror` need `/etc/resolv.conf` | +| linux/ppc64 (big-endian) | zig links it for the ELFv2 loader that BE distributions lack; built with `cross` instead, even a hello-world crashes at start-up under qemu-ppc64, so it cannot be verified | +| linux/mips, mipsle, mips64, mips64le | Rust tier 3 (no stable std) since 1.72 | +| netbsd/amd64 | builds only with a newer sysroot than cross 0.2.5 provides (std needs `libexecinfo`); netbsd/386, arm, arm64 are tier 3 | +| openbsd/* | Rust tier 3; OpenBSD packages Rust itself, so a native build there would work | +| freebsd/arm, arm64, riscv64 | Rust tier 3 | +| dragonfly/amd64, aix/ppc64 | Rust tier 3 | +| illumos/amd64, solaris/amd64 | outside the chosen matrix (illumos builds with cross; Solaris has no cross 0.2.5 image) | +| wasip1/wasm | outside the chosen matrix (it builds; no agent, no prompts) | +| js/wasm | no filesystem in the browser target | +| plan9/* | no Rust target | -Dropping these is a scope change from the Go release (43 binaries) and needs -an explicit decision before a release: either accept the narrower matrix, -or add nightly/native builds for chosen targets (OpenBSD in a VM is the most -practical). +Asking `build.sh` for any of these reports it and fails. diff --git a/docs/guide/vault-guide.tex b/docs/guide/vault-guide.tex index c0560c0..adb09b0 100644 --- a/docs/guide/vault-guide.tex +++ b/docs/guide/vault-guide.tex @@ -221,16 +221,15 @@ Linux PC or server & almost everything & vault-linux-amd64 \\ Linux on ARM64 & Pi 4/5 (64-bit OS), Graviton, Ampere & vault-linux-arm64 \\ Raspberry Pi, 32-bit & Pi 2, 3, 4 on a 32-bit OS & vault-linux-armv7 \\ Raspberry Pi Zero / 1 & the tiny older ones & vault-linux-armv6 \\ -Android & in Termux & vault-android-arm64 \\ -FreeBSD, NetBSD & amd64 (FreeBSD also 386) & vault-freebsd-amd64 etc. \\ -Something exotic & RISC-V, POWER, s390x, LoongArch, illumos, Solaris & see \cmd{dist/} \\ +Android & in Termux: the Linux ARM64 file & vault-linux-arm64 \\ +FreeBSD & amd64 or 386 & vault-freebsd-amd64 etc. \\ +Something exotic & RISC-V, POWER (little-endian), s390x, LoongArch & see \cmd{dist/} \\ \end{vtable} \begin{squirrel} -The release covers some twenty platforms, from Windows on ARM to IBM -mainframes, and even WebAssembly. A few that the older Go builds reached, -such as Plan~9, OpenBSD and MIPS, have no stable Rust toolchain yet; -\file{docs/PLATFORMS.md} keeps the list. Will you ever need +The release covers sixteen builds for Linux, Windows, macOS and FreeBSD, +from Windows on ARM to IBM mainframes. The older Go builds reached further, +to Plan~9 and WebAssembly; \file{docs/PLATFORMS.md} says why those went. Will you ever need \file{vault-linux-s390x}? Almost certainly not. Is it pleasing that it exists? Extremely. \end{squirrel} @@ -290,8 +289,8 @@ so Gatekeeper quarantines it. Once you've checked the SHA-256, clear the flag: \subsection{Android (Termux)} \begin{shell} -$ curl -LO https://.../vault-android-arm64 -$ chmod +x vault-android-arm64 && mv vault-android-arm64 $PREFIX/bin/vault +$ curl -LO https://.../vault-linux-arm64 +$ chmod +x vault-linux-arm64 && mv vault-linux-arm64 $PREFIX/bin/vault \end{shell} \section{Did it work?} @@ -311,8 +310,7 @@ $ ./build.sh # every platform it can, into ./dist, with SH \end{shell} \cmd{build.sh} cross-compiles Linux and Windows with \cmd{cargo-zigbuild} -and \cmd{zig}, macOS on a Mac, and the BSDs, illumos and Solaris with -\cmd{cross} and Docker; it says which targets your machine can't build. +and \cmd{zig}, macOS on a Mac, and FreeBSD with \cmd{cross} and Docker; it says which targets your machine can't build. 32-bit ARM Linux gets two builds, armv6 and armv7. Want just a few? Set \env{TARGETS}. Want them somewhere else? Set \env{OUT}. @@ -1080,8 +1078,7 @@ who's slow at typing never blocks you. \textbf{What if vault crashes while holding the lock?} On Linux, macOS, the BSDs and Windows, the operating system drops the lock the moment the process dies. Nothing to clean up. Older Go builds of vault use the very same locks, -so mixing versions is safe. On WebAssembly, which has no file locks, vault -uses a \file{.lock} file instead. If one's ever left behind, +so mixing versions is safe. If one's ever left behind, vault tells you after a minute exactly which file to delete. \end{whyso} @@ -1335,7 +1332,6 @@ could not read passphrase (set VAULT\_PASSPHRASE\ldots) & No terminal to ask on, agent did not start: \ldots & \cmd{unlock} couldn't start its helper. The reason follows; commands still work, asking for the passphrase. \\ nothing was unlocked & \cmd{vault lock} found nothing to lock. Not an error. \\ waiting for another vault process to finish & Not an error. Another command is writing; this one continues when it's done. \\ -vault still locked after a minute\ldots & WebAssembly only. If nothing else is running, delete the file it names. \\ cannot lock the vault: \ldots & The lock file couldn't be opened or locked; the reason follows. Check the vault folder's permissions. \\ \ldots\ changed while being added & The file was being written while vault read it. Nothing was stored; try again when it's finished. \\ \ldots\ changed after it was stored; not deleting it & \cmd{migrate} stored the file, but it changed before it could be deleted. The original is kept; the vault has the version it read. \\