Merge branch 'rust-port': screenshots and macOS cross-build support

This commit is contained in:
Andy Dixon
2026-10-08 18:28:04 +01:00
21 changed files with 62 additions and 15 deletions
+7 -1
View File
@@ -25,7 +25,13 @@ serde_json = "1"
jiff = "0.2"
tar = { version = "0.4.46", default-features = false }
flate2 = { version = "1.1", default-features = false, features = ["rust_backend"] }
ureq = { version = "3.4", default-features = false, features = ["rustls", "platform-verifier", "gzip"] }
ureq = { version = "3.4", default-features = false, features = ["rustls", "gzip"] }
[features]
default = ["system-roots"]
# Verify TLS certificates against the operating system's trust store. Off,
# the bundled Mozilla roots are used (for cross-built macOS binaries).
system-roots = ["ureq/platform-verifier"]
[dev-dependencies]
aes = "0.9"
+3 -2
View File
@@ -134,8 +134,9 @@ for the passphrase.
## Network
Downloads verify TLS certificates (rustls with the platform verifier; it is
never disabled), follow at most 10 redirects (http and https only; for
Downloads verify TLS certificates (rustls with the operating system's trust
store; macOS binaries cross-built on Linux use the bundled Mozilla roots
instead, see `docs/PLATFORMS.md`; verification is never disabled), follow at most 10 redirects (http and https only; for
`mirror`, only to the same host), and are bounded by connect, response and
whole-request deadlines and a byte budget counted after decompression. See
`vault(1)` for the defaults and flags.
+13 -3
View File
@@ -14,7 +14,9 @@
#
# 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)
# mac a Mac with Xcode, or zig (macOS; zig builds trust the
# bundled Mozilla roots, not the
# keychain)
# 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
@@ -98,8 +100,16 @@ build_one() {
{ echo "SKIPPED $want: needs cargo-zigbuild and zig" >&2; return 1; }
cmd=(cargo zigbuild) ;;
mac)
[[ $HOST_OS == Darwin ]] || { echo "SKIPPED $want: needs a Mac with Xcode" >&2; return 1; }
cmd=(cargo build) ;;
if [[ $HOST_OS == Darwin ]]; then
cmd=(cargo build)
elif command -v cargo-zigbuild >/dev/null && command -v zig >/dev/null; then
# Without Apple's SDK there is no Security framework to link, so
# the cross-built binary trusts the bundled Mozilla roots rather
# than the macOS keychain.
cmd=(cargo zigbuild --no-default-features)
else
echo "SKIPPED $want: needs a Mac, or cargo-zigbuild and zig" >&2; return 1
fi ;;
cross)
command -v cross >/dev/null && command -v docker >/dev/null ||
{ echo "SKIPPED $want: needs cross and docker" >&2; return 1; }
+8 -2
View File
@@ -33,8 +33,8 @@ the port: the Go release's more exotic targets are no longer built).
| 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) |
| darwin/amd64 | x86_64-apple-darwin | system | a Mac, or zig (note 2) | build only from Linux; tested in CI on macos-15-intel |
| darwin/arm64 | aarch64-apple-darwin | system | a Mac, or zig (note 2) | build only from Linux; tested in CI on macos-15 |
| 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 |
@@ -47,6 +47,12 @@ disables core dumps. See `SECURITY.md`.
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. Without Apple's SDK there is no Security framework to link, so `build.sh`
on Linux cross-builds macOS with `--no-default-features`: those binaries
verify TLS for `add URL` and `mirror` against the bundled Mozilla roots
instead of the macOS keychain (so a corporate CA added to the keychain is
not trusted). Built on a Mac, or through Homebrew
(`brew install andydixon/tap/vault`), they use the keychain.
## No longer released
Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 KiB

After

Width:  |  Height:  |  Size: 604 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 195 KiB

+8 -3
View File
@@ -135,9 +135,14 @@ impl Client {
Some(p) => Some(ureq::Proxy::new(p).map_err(|_| "invalid proxy setting in the environment".to_string())?),
None => None,
};
let tls = ureq::tls::TlsConfig::builder()
.root_certs(ureq::tls::RootCerts::PlatformVerifier)
.build();
// The operating system's trust store; builds without the
// `system-roots` feature (macOS binaries cross-built without
// Apple's SDK) use the bundled Mozilla roots instead.
#[cfg(feature = "system-roots")]
let roots = ureq::tls::RootCerts::PlatformVerifier;
#[cfg(not(feature = "system-roots"))]
let roots = ureq::tls::RootCerts::WebPki;
let tls = ureq::tls::TlsConfig::builder().root_certs(roots).build();
let l = &self.limits;
let cfg = ureq::Agent::config_builder()
.tls_config(tls)
+23 -4
View File
@@ -313,7 +313,7 @@ fn hold_lock(e: &Env, bin: &str) -> Child {
c.stdin.as_mut().unwrap().write_all(b"\0").unwrap();
// Wait until the lock file is held exclusively: probe with our own
// fcntl lock attempt from this process.
let deadline = Instant::now() + Duration::from_secs(20);
let deadline = Instant::now() + Duration::from_secs(120);
loop {
if locked_exclusively(&e.dir.join("store/.lock")) {
return c;
@@ -350,13 +350,32 @@ fn lock_contention(holder: &str, waiter: &str) {
.stderr(Stdio::piped())
.spawn()
.unwrap();
std::thread::sleep(Duration::from_millis(1500));
// Wait (however long unlocking takes on a busy machine) until the
// reader says it is blocked on the lock, and is still running.
let mut err = w.stderr.take().unwrap();
let (tx, rx) = std::sync::mpsc::channel();
std::thread::spawn(move || {
use std::io::Read;
let mut all = Vec::new();
let mut buf = [0u8; 256];
while let Ok(n) = err.read(&mut buf) {
if n == 0 {
break;
}
all.extend_from_slice(&buf[..n]);
if String::from_utf8_lossy(&all).contains("waiting for another vault process to finish") {
let _ = tx.send(());
}
}
});
rx.recv_timeout(Duration::from_secs(120))
.expect("reader never reported waiting for the lock");
std::thread::sleep(Duration::from_millis(300));
assert!(w.try_wait().unwrap().is_none(), "reader did not wait for the writer");
h.kill().unwrap(); // death releases the lock
let _ = h.wait();
let o = w.wait_with_output().unwrap();
assert!(o.status.success());
assert!(String::from_utf8_lossy(&o.stderr).contains("waiting for another vault process to finish"));
assert!(o.status.success(), "reader failed after the writer died");
}
#[cfg(unix)]