From df2c95a82db4fec31a52876841f8f7fb9202b524 Mon Sep 17 00:00:00 2001 From: Landon Cox Date: Tue, 30 Jun 2026 13:30:18 -0700 Subject: [PATCH 1/2] fix: skip /etc bind mounts when sysroot-stage is active (arc-dind) When runnerTopology is 'arc-dind', the sysroot-stage container already provides a complete /etc from the build-tools image. Bind-mounting the host's /etc files on top fails on split-fs because the Docker daemon cannot resolve runner filesystem paths (e.g., /etc/ld.so.cache doesn't exist on the Alpine-based DinD daemon). Return an empty array from buildEtcMounts() when isSysrootEnabled() is true, since the sysroot volume already has all needed /etc content. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/services/agent-volumes/etc-mounts.test.ts | 22 +++++++++++++++++++ src/services/agent-volumes/etc-mounts.ts | 8 +++++++ 2 files changed, 30 insertions(+) diff --git a/src/services/agent-volumes/etc-mounts.test.ts b/src/services/agent-volumes/etc-mounts.test.ts index f3b467a92..e4b688980 100644 --- a/src/services/agent-volumes/etc-mounts.test.ts +++ b/src/services/agent-volumes/etc-mounts.test.ts @@ -16,6 +16,28 @@ function createMinimalConfig(overrides: Partial = {}): WrapperCon } describe('buildEtcMounts', () => { + describe('arc-dind with sysroot-stage', () => { + it('returns empty array when runnerTopology is arc-dind (sysroot provides /etc)', () => { + const config = createMinimalConfig({ runnerTopology: 'arc-dind' }); + const mounts = buildEtcMounts(config); + expect(mounts).toEqual([]); + }); + + it('still mounts /etc files when runnerTopology is standard', () => { + const config = createMinimalConfig({ runnerTopology: 'standard' }); + const mounts = buildEtcMounts(config); + expect(mounts.length).toBeGreaterThan(0); + expect(mounts).toContain('/etc/ld.so.cache:/host/etc/ld.so.cache:ro'); + }); + + it('still mounts /etc files when runnerTopology is undefined', () => { + const config = createMinimalConfig({ runnerTopology: undefined }); + const mounts = buildEtcMounts(config); + expect(mounts.length).toBeGreaterThan(0); + expect(mounts).toContain('/etc/ld.so.cache:/host/etc/ld.so.cache:ro'); + }); + }); + describe('non-DinD mode', () => { it('mounts /etc/passwd and /etc/group directly', () => { const config = createMinimalConfig({ dockerHostPathPrefix: undefined }); diff --git a/src/services/agent-volumes/etc-mounts.ts b/src/services/agent-volumes/etc-mounts.ts index 4b7fcc70f..66ec65741 100644 --- a/src/services/agent-volumes/etc-mounts.ts +++ b/src/services/agent-volumes/etc-mounts.ts @@ -3,6 +3,7 @@ import * as path from 'path'; import { WrapperConfig } from '../../types'; import { shouldUseDockerHostStaging, stageHostFile, getDockerHostStageRoot } from './docker-host-staging'; import { getSafeHostUid, getSafeHostGid } from '../../host-identity'; +import { isSysrootEnabled } from '../sysroot-service'; /** * Synthesize a minimal /etc/passwd or /etc/group file in the staging directory. @@ -58,6 +59,13 @@ function resolveUniqueName(content: string, preferredName: string, id: string): } export function buildEtcMounts(config: WrapperConfig): string[] { + // When sysroot-stage is active (arc-dind), the sysroot volume already provides + // a complete /etc from the build-tools image. Bind-mounting the host's /etc files + // on top would fail on split-fs (Docker daemon can't resolve runner paths). + if (isSysrootEnabled(config)) { + return []; + } + const mounts: string[] = [ '/etc/ssl:/host/etc/ssl:ro', '/etc/ca-certificates:/host/etc/ca-certificates:ro', From b8af93a4fc217ae6ff2e0ba80d1f0b8fb3667c7b Mon Sep 17 00:00:00 2001 From: Landon Cox Date: Tue, 30 Jun 2026 13:42:05 -0700 Subject: [PATCH 2/2] test: rename sysroot gating suite Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/services/agent-volumes/etc-mounts.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/agent-volumes/etc-mounts.test.ts b/src/services/agent-volumes/etc-mounts.test.ts index e4b688980..6dd0b54a0 100644 --- a/src/services/agent-volumes/etc-mounts.test.ts +++ b/src/services/agent-volumes/etc-mounts.test.ts @@ -16,7 +16,7 @@ function createMinimalConfig(overrides: Partial = {}): WrapperCon } describe('buildEtcMounts', () => { - describe('arc-dind with sysroot-stage', () => { + describe('sysroot gating by runnerTopology', () => { it('returns empty array when runnerTopology is arc-dind (sysroot provides /etc)', () => { const config = createMinimalConfig({ runnerTopology: 'arc-dind' }); const mounts = buildEtcMounts(config);