Fix Docker builds under rootless daemons and expose git metadata to build containers
Two fixes from the vm4006 rollout (docs/plan/16-git-in-docker-builds.md): Rootless daemons map the host user to container root, so running the build container as --user <host-uid> put it into the subuid range and it could not even create .gradle in a fresh worktree (legacy only worked because its ownership-repair chown had accidentally moved build/ and .gradle/ into subuid ownership in its reused primary checkout). The container now always runs as --user 0: the unprivileged host user under rootless, real root under rootful where the ownership repair still applies; under rootless it degenerates to 0:0. Git now works inside build containers: the primary .git is mounted read-only with .git/gittally/ masked by an empty tmpfs (git.token and the control token stay unreachable, the workspace bind resurfaces only the build's own worktree) and the worktree admin dir mounted read-write for index-refreshing commands. Verified on vm4006: git log/status succeed, the machine config is invisible, ref writes fail on the read-only mount. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
800fcae2f7
commit
8b71d0db8e
@@ -126,7 +126,7 @@ class DockerBuildRunnerTest : FunSpec() {
|
||||
script shouldContain "exit \$build_exit"
|
||||
}
|
||||
|
||||
test("a rootless socket runs the container as the host user without group-add") {
|
||||
test("a rootless socket runs the container as root (the host user) without group-add or host-id chown") {
|
||||
every { socketLocator.locate("1000") } returns
|
||||
DockerSocket(Paths.get("/run/user/1000/docker.sock"), rootless = true, gid = 998L)
|
||||
|
||||
@@ -134,8 +134,42 @@ class DockerBuildRunnerTest : FunSpec() {
|
||||
|
||||
val args = captured.single()
|
||||
args shouldContain "/run/user/1000/docker.sock:/var/run/docker.sock"
|
||||
args[args.indexOf("--user") + 1] shouldBe "1000"
|
||||
args[args.indexOf("--user") + 1] shouldBe "0"
|
||||
args shouldNotContain "--group-add"
|
||||
// container root already is the host user — the repair chown must not target the host ids,
|
||||
// which would push the worktree files into the subuid range
|
||||
args[args.size - 3] shouldBe "0"
|
||||
args[args.size - 2] shouldBe "0"
|
||||
verify {
|
||||
commandRunner.runOrThrow(
|
||||
match { it.take(2) == listOf("docker", "run") && it.takeLast(2) == listOf("0", "0") },
|
||||
repoDir,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
test("exposes git metadata read-only with the gittally dir masked for a worktree workspace") {
|
||||
val gitDir = repoDir.resolve(".git")
|
||||
val adminDir = gitDir.resolve("worktrees/workspace")
|
||||
Files.createDirectories(adminDir)
|
||||
Files.createDirectories(gitDir.resolve("gittally"))
|
||||
Files.createDirectories(workspace)
|
||||
Files.writeString(workspace.resolve(".git"), "gitdir: $adminDir\n")
|
||||
|
||||
runner.start("./gradlew test", workspace, mapOf("branch" to "main"), repoDir, dockerBranchConfig())
|
||||
|
||||
val args = captured.single()
|
||||
args shouldContain "$gitDir:$gitDir:ro"
|
||||
args[args.indexOf("--tmpfs") + 1] shouldBe "${gitDir.resolve("gittally")}"
|
||||
args shouldContain "$adminDir:$adminDir"
|
||||
}
|
||||
|
||||
test("mounts no git metadata when the workspace is not a worktree") {
|
||||
runner.start("./gradlew test", workspace, mapOf("branch" to "main"), repoDir, dockerBranchConfig())
|
||||
|
||||
val args = captured.single()
|
||||
args shouldNotContain "--tmpfs"
|
||||
args.none { it.endsWith(":ro") } shouldBe true
|
||||
}
|
||||
|
||||
test("host network keeps Testcontainers on localhost without add-host") {
|
||||
|
||||
Reference in New Issue
Block a user