Repository navigation
Conversation
If the BuildKit root is already a mountpoint (e.g. a dedicated volume), use it as-is instead of shadowing it. Otherwise keep the existing 3 GB tmpfs mount required for the native overlayfs snapshotter on the overlayfs rootfs.
rgarcia
marked this pull request as ready for review
August 2, 2026 02:20
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Mount detection misses init volumes
- Mount-point detection now matches both the guest path and its pre-chroot
/overlay/newroot/...mount entry so attached BuildKit volumes are recognized and tmpfs is not mounted over them.
- Mount-point detection now matches both the guest path and its pre-chroot
Or push these changes by commenting:
@cursor push b6c7734af7
Preview (b6c7734af7)
diff --git a/lib/builds/builder_agent/main.go b/lib/builds/builder_agent/main.go
--- a/lib/builds/builder_agent/main.go
+++ b/lib/builds/builder_agent/main.go
@@ -941,20 +941,38 @@
}
// isMountPoint reports whether path is a mountpoint according to /proc/self/mounts.
+// In exec mode, init mounts guest volumes before chroot at /overlay/newroot/<path>,
+// so check both the guest path and its pre-chroot namespace path.
func isMountPoint(path string) (bool, error) {
data, err := os.ReadFile("/proc/self/mounts")
if err != nil {
return false, err
}
+ candidates := mountPathCandidates(path, "")
+ if processRoot, err := os.Readlink("/proc/self/root"); err == nil {
+ candidates = mountPathCandidates(path, processRoot)
+ }
for _, line := range strings.Split(string(data), "\n") {
fields := strings.Fields(line)
- if len(fields) >= 2 && fields[1] == path {
- return true, nil
+ if len(fields) >= 2 {
+ if _, ok := candidates[fields[1]]; ok {
+ return true, nil
+ }
}
}
return false, nil
}
+func mountPathCandidates(path string, processRoot string) map[string]struct{} {
+ candidates := map[string]struct{}{
+ filepath.Clean(path): {},
+ }
+ if processRoot != "" {
+ candidates[filepath.Clean(filepath.Join(processRoot, path))] = struct{}{}
+ }
+ return candidates
+}
+
func extractDigest(metadataPath string) (string, error) {
data, err := os.ReadFile(metadataPath)
if err != nil {
diff --git a/lib/builds/builder_agent/main_test.go b/lib/builds/builder_agent/main_test.go
--- a/lib/builds/builder_agent/main_test.go
+++ b/lib/builds/builder_agent/main_test.go
@@ -55,3 +55,10 @@
require.ErrorContains(t, err, "mount failed")
}
+
+func TestMountPathCandidatesIncludesChrootMountPath(t *testing.T) {
+ candidates := mountPathCandidates("/var/lib/buildkit", "/overlay/newroot")
+
+ assert.Contains(t, candidates, "/var/lib/buildkit")
+ assert.Contains(t, candidates, "/overlay/newroot/var/lib/buildkit")
+}You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit 7114b82. Configure here.
rgarcia
force-pushed
the
hypeship/buildkit-mounted-root
branch
from
August 3, 2026 17:50
7114b82 to
b66a729
Compare
Contributor
Author
|
Closing in favor of a fresh first-class Builder resource stack. Useful implementation and test work from this PR will be selectively reapplied in smaller reviewable layers. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Problem
The builder agent unconditionally mounts a 3 GB tmpfs at
/var/lib/buildkit(needed because the VM rootfs is overlayfs, and BuildKit's native overlayfs snapshotter can't create whiteout devices on a nested overlayfs). This hard-caps BuildKit's snapshot storage: any build whose layer data exceeds 3 GB fails, and because it's tmpfs, that storage also competes with the build's RAM budget.Reproduced locally with a Dockerfile writing 3×1.2 GB layers:
Fix
If
/var/lib/buildkitis already a mountpoint (e.g. a dedicated volume attached to the builder VM), use it directly. Otherwise the tmpfs fallback is preserved exactly (samemount -t tmpfs -o size=3Gcommand, same error messages) — the unmounted path is byte-for-byte the current behavior.Changes
runBuildintoensureBuildkitRoot(root, isMounted, mountTmpfs)with the mount check and tmpfs command injected, so both paths are testable without privileged mounts.isMountPointchecks/proc/self/mounts;mountBuildkitTmpfsruns the unchanged tmpfs mount command.ensureBuildkitRoot.No changes to the host manager, API, volume attachment, registry behavior, or default runtime behavior.
Verification
Ran the same 3.6 GB build end-to-end with a 15 GB ext4 volume pre-attached at
/var/lib/buildkit:This also confirms the whiteout concern doesn't apply to the mounted path: BuildKit's native overlayfs snapshotter runs fine on an ext4 block volume.
Caveat: hypeman itself can't attach a volume there today —
isSystemDirectoryrejects/var/...mount paths, so the end-to-end test required temporarily attaching the volume fromexecuteBuildand carving out/var/lib/buildkitfrom that guard. Wiring up the host side (volume attach + guard exception) is follow-up work; until then this path is only reachable via out-of-band orchestration.Security considerations
The agent trusts whatever is mounted at
/var/lib/buildkit, so the follow-up wiring MUST attach a fresh per-build volume, deleted with the VM. Sharing the snapshotter root across builds/tenants would enable cross-tenant cache poisoning (BuildKit caches RUN steps) and disclosure of prior builds' layers/source. Cross-tenant cache sharing already has a safe, scoped mechanism (registry-basedcache_scopeimport/export). Documented onensureBuildkitRoot.Tests
go test ./lib/builds/builder_agent/— new tests: already-mounted root is accepted without attempting tmpfs; unmounted root mounts tmpfs; mount failure propagates.go test ./lib/builds/...andgo build ./...pass.Note
Medium Risk
Changes privileged mount behavior on builder VMs; wrong or shared mounts at
/var/lib/buildkitcould affect build isolation until host volume wiring is in place.Overview
BuildKit snapshot storage no longer always gets a 3 GB tmpfs at
/var/lib/buildkit. If that path is already a mountpoint (e.g. a dedicated block volume), the agent uses it as-is and skips tmpfs, avoiding the layer-size cap and RAM pressure from large builds.Unmounted path is unchanged:
ensureBuildkitRootstill creates the directory and runs the samemount -t tmpfs -o size=3GviamountBuildkitTmpfs, with the nested-overlayfs rationale kept on the helper. Mount detection usesisMountPointreading/proc/self/mounts.Tests inject
isMountedandmountTmpfsto cover already-mounted (no tmpfs), unmounted (tmpfs + mkdir), and mount failure propagation.Reviewed by Cursor Bugbot for commit b66a729. Bugbot is set up for automated code reviews on this repo. Configure here.