Screenshots from the Rust build; system-roots feature for macOS cross-builds
docs/guide/img is re-shot from the 0.6 binary. TLS roots come from the operating system by default; build.sh cross-builds macOS on Linux without that feature (no Apple SDK), trusting the bundled Mozilla roots. Lock tests wait for the reader to report it is blocked rather than assuming how long unlocking takes on a busy machine. Co-Authored-By: Claude <noreply@anthropic.com>
@@ -25,7 +25,13 @@ serde_json = "1"
|
|||||||
jiff = "0.2"
|
jiff = "0.2"
|
||||||
tar = { version = "0.4.46", default-features = false }
|
tar = { version = "0.4.46", default-features = false }
|
||||||
flate2 = { version = "1.1", default-features = false, features = ["rust_backend"] }
|
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]
|
[dev-dependencies]
|
||||||
aes = "0.9"
|
aes = "0.9"
|
||||||
|
|||||||
@@ -134,8 +134,9 @@ for the passphrase.
|
|||||||
|
|
||||||
## Network
|
## Network
|
||||||
|
|
||||||
Downloads verify TLS certificates (rustls with the platform verifier; it is
|
Downloads verify TLS certificates (rustls with the operating system's trust
|
||||||
never disabled), follow at most 10 redirects (http and https only; for
|
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
|
`mirror`, only to the same host), and are bounded by connect, response and
|
||||||
whole-request deadlines and a byte budget counted after decompression. See
|
whole-request deadlines and a byte budget counted after decompression. See
|
||||||
`vault(1)` for the defaults and flags.
|
`vault(1)` for the defaults and flags.
|
||||||
|
|||||||
@@ -14,7 +14,9 @@
|
|||||||
#
|
#
|
||||||
# How each target is built, and what the host needs:
|
# How each target is built, and what the host needs:
|
||||||
# zig cargo-zigbuild and zig on PATH (Linux, Windows GNU ABI)
|
# 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)
|
# cross `cross` and Docker (FreeBSD)
|
||||||
# A requested target the host cannot build is reported, the others are still
|
# 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
|
# 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; }
|
{ echo "SKIPPED $want: needs cargo-zigbuild and zig" >&2; return 1; }
|
||||||
cmd=(cargo zigbuild) ;;
|
cmd=(cargo zigbuild) ;;
|
||||||
mac)
|
mac)
|
||||||
[[ $HOST_OS == Darwin ]] || { echo "SKIPPED $want: needs a Mac with Xcode" >&2; return 1; }
|
if [[ $HOST_OS == Darwin ]]; then
|
||||||
cmd=(cargo build) ;;
|
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)
|
cross)
|
||||||
command -v cross >/dev/null && command -v docker >/dev/null ||
|
command -v cross >/dev/null && command -v docker >/dev/null ||
|
||||||
{ echo "SKIPPED $want: needs cross and docker" >&2; return 1; }
|
{ echo "SKIPPED $want: needs cross and docker" >&2; return 1; }
|
||||||
|
|||||||
@@ -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/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/386 | i686-pc-windows-gnu | static CRT | zig | build only |
|
||||||
| windows/arm64 | aarch64-pc-windows-gnullvm | 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/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 (Xcode) | CI only (macos-15 job, not yet run) |
|
| 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/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 |
|
| 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
|
process spins). `build.sh` and `packaging/package.sh` build that target
|
||||||
with `--cfg getrandom_backend="linux_raw"`, which makes the `getrandom`
|
with `--cfg getrandom_backend="linux_raw"`, which makes the `getrandom`
|
||||||
crate issue the system call itself; with that flag the binary passes.
|
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
|
## No longer released
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 525 KiB After Width: | Height: | Size: 604 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 191 KiB After Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 180 KiB After Width: | Height: | Size: 195 KiB |
@@ -135,9 +135,14 @@ impl Client {
|
|||||||
Some(p) => Some(ureq::Proxy::new(p).map_err(|_| "invalid proxy setting in the environment".to_string())?),
|
Some(p) => Some(ureq::Proxy::new(p).map_err(|_| "invalid proxy setting in the environment".to_string())?),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
let tls = ureq::tls::TlsConfig::builder()
|
// The operating system's trust store; builds without the
|
||||||
.root_certs(ureq::tls::RootCerts::PlatformVerifier)
|
// `system-roots` feature (macOS binaries cross-built without
|
||||||
.build();
|
// 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 l = &self.limits;
|
||||||
let cfg = ureq::Agent::config_builder()
|
let cfg = ureq::Agent::config_builder()
|
||||||
.tls_config(tls)
|
.tls_config(tls)
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ fn hold_lock(e: &Env, bin: &str) -> Child {
|
|||||||
c.stdin.as_mut().unwrap().write_all(b"\0").unwrap();
|
c.stdin.as_mut().unwrap().write_all(b"\0").unwrap();
|
||||||
// Wait until the lock file is held exclusively: probe with our own
|
// Wait until the lock file is held exclusively: probe with our own
|
||||||
// fcntl lock attempt from this process.
|
// fcntl lock attempt from this process.
|
||||||
let deadline = Instant::now() + Duration::from_secs(20);
|
let deadline = Instant::now() + Duration::from_secs(120);
|
||||||
loop {
|
loop {
|
||||||
if locked_exclusively(&e.dir.join("store/.lock")) {
|
if locked_exclusively(&e.dir.join("store/.lock")) {
|
||||||
return c;
|
return c;
|
||||||
@@ -350,13 +350,32 @@ fn lock_contention(holder: &str, waiter: &str) {
|
|||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap();
|
.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");
|
assert!(w.try_wait().unwrap().is_none(), "reader did not wait for the writer");
|
||||||
h.kill().unwrap(); // death releases the lock
|
h.kill().unwrap(); // death releases the lock
|
||||||
let _ = h.wait();
|
let _ = h.wait();
|
||||||
let o = w.wait_with_output().unwrap();
|
let o = w.wait_with_output().unwrap();
|
||||||
assert!(o.status.success());
|
assert!(o.status.success(), "reader failed after the writer died");
|
||||||
assert!(String::from_utf8_lossy(&o.stderr).contains("waiting for another vault process to finish"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
|||||||