Skip to content

Commit d3d5590

Browse files
andrasbacsaiclaude
andcommitted
fix(builder): use buildah images to read digest, avoid sandbox remount
`buildah inspect --format '{{.FromImageDigest}}'` opens the overlay store for read, which includes a MS_PRIVATE remount of `/var/lib/containers/storage/overlay`. That fails inside the `systemd-run` sandbox coold spawns the builder under: remount /var/lib/containers/storage/overlay, flags: 0x40000: invalid argument `buildah images --format '{{.Digest}}' <tag>` returns the same sha256:... digest string without triggering the remount, confirmed on a live Hetzner VM inside the equivalent `systemd-run` unit. Also pin `--storage-driver overlay` to match the driver passed to `bud` so a non-default `/etc/containers/storage.conf` can't silently send the digest lookup to a different store. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 7d3e52b commit d3d5590

1 file changed

Lines changed: 24 additions & 30 deletions

File tree

builder-core/src/static_build.rs

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -77,37 +77,31 @@ pub async fn run(
7777
emit(sink, "build", "build complete", 80);
7878

7979
emit(sink, "store", "reading image digest", 90);
80-
// Match `bud`'s explicit storage driver so a non-default system
81-
// `storage.conf` doesn't send inspect to a different store than the one
82-
// bud just wrote to. Retry a few times with backoff to absorb overlay
83-
// lock contention that can briefly follow `bud` on slower hosts.
84-
let mut last_err = String::new();
85-
let mut digest = String::new();
86-
for attempt in 0..3u32 {
87-
let out = Command::new("buildah")
88-
.args([
89-
"--storage-driver",
90-
"overlay",
91-
"inspect",
92-
"--format",
93-
"{{.FromImageDigest}}",
94-
&req.target_image,
95-
])
96-
.output()
97-
.await
98-
.map_err(|e| err(500, "store", format!("buildah inspect spawn: {e}")))?;
99-
if out.status.success() {
100-
digest = String::from_utf8_lossy(&out.stdout).trim().to_owned();
101-
break;
102-
}
103-
last_err = String::from_utf8_lossy(&out.stderr).trim().to_owned();
104-
info!(%attempt, %last_err, "buildah inspect non-zero, retrying");
105-
tokio::time::sleep(std::time::Duration::from_millis(400 * (attempt as u64 + 1))).await;
106-
}
107-
if digest.is_empty() {
108-
return Err(err(500, "store", format!("buildah inspect failed: {last_err}")));
80+
// `buildah inspect` remounts the overlay store with MS_PRIVATE, which
81+
// fails inside the systemd-run sandbox coold wraps the builder in
82+
// (`remount /var/lib/containers/storage/overlay, flags: 0x40000:
83+
// invalid argument`). `buildah images` reads metadata without
84+
// remounting, so use it instead. `--storage-driver overlay` matches
85+
// the driver explicitly passed to `bud` so a non-default
86+
// `storage.conf` can't send us to a different store.
87+
let images_out = Command::new("buildah")
88+
.args([
89+
"--storage-driver",
90+
"overlay",
91+
"images",
92+
"--format",
93+
"{{.Digest}}",
94+
&req.target_image,
95+
])
96+
.output()
97+
.await
98+
.map_err(|e| err(500, "store", format!("buildah images spawn: {e}")))?;
99+
if !images_out.status.success() {
100+
let stderr = String::from_utf8_lossy(&images_out.stderr).trim().to_owned();
101+
return Err(err(500, "store", format!("buildah images failed: {stderr}")));
109102
}
110-
if !digest.starts_with("sha256:") {
103+
let digest = String::from_utf8_lossy(&images_out.stdout).trim().to_owned();
104+
if digest.is_empty() || !digest.starts_with("sha256:") {
111105
return Err(err(500, "store", format!("unexpected digest format: {digest:?}")));
112106
}
113107

0 commit comments

Comments
 (0)