From 690d19c9c1a55a4cc5f8417daafe3d0101c51a25 Mon Sep 17 00:00:00 2001 From: Aditya Garud <153842990+yashranaway@users.noreply.github.com> Date: Thu, 6 Aug 2026 09:40:31 +0000 Subject: [PATCH] fix(test): hand E2E evidence back to the right user under rootless Docker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Linux E2E passes under rootless Docker, but its evidence came back unreadable, and the run ended on sha256sum failing to open the manifest it had just written. The container writes evidence as its own non-root user. restore_evidence_owner chowned that back to $(id -u) from inside the container, which is correct only because rootful Docker maps uid to uid — the mapping CI runs under, which is why this was never noticed. Rootless inverts it: container root maps to the invoking user, and every other container id maps to a subuid the user cannot read. Chowning to 1004 there produces another subuid, not the caller. Detect the daemon mode and chown to 0:0 when rootless. Rootful behaviour, and therefore CI, is unchanged. Verified locally on rootless: evidence lands owned by the invoking user with 0600 intact, sha256sum -c passes, and the suite's own mode assertions still hold. CONTRIBUTING notes that rootless is supported. --- CONTRIBUTING.md | 4 ++++ apps/headless/Tests/linux-docker.sh | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e024539..af5abb1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,6 +43,10 @@ Platform notes: - **Linux** builds need only Docker: `pnpm build:linux` compiles inside `swift:6.1-bookworm` and emits a tarball. Chromium must be non-Snap — the runtime rejects Snap launchers before starting, by design. +- **Rootless Docker works**, including the E2E: Chromium's nested namespace + sandbox runs fine, and the harness detects the daemon mode so exported QA + evidence comes back owned by you. Nothing binds a host port, so the suites + cannot collide with other services on a shared machine. - `pnpm test:e2e:mac` opens real windows and mutates `com.headless.app` user defaults. Don't run it in a background session or on a machine where that matters. diff --git a/apps/headless/Tests/linux-docker.sh b/apps/headless/Tests/linux-docker.sh index 69146fa..58e126a 100755 --- a/apps/headless/Tests/linux-docker.sh +++ b/apps/headless/Tests/linux-docker.sh @@ -8,9 +8,19 @@ EVIDENCE_ROOT="${HEADLESS_EVIDENCE_ROOT:-$PWD/build/qa-evidence}" mkdir -p "$EVIDENCE_ROOT" EVIDENCE_DIR="$(mktemp -d "$EVIDENCE_ROOT/linux.XXXXXX")" chmod 0777 "$EVIDENCE_DIR" +# The container writes evidence as its own non-root user, which lands on the +# host as an id this user cannot read. Which id to hand it back to depends on +# how the daemon maps them: rootful Docker maps uid to uid, so the invoking +# user's id is correct, while rootless maps container root to the invoking user +# and every other container id to an unreadable subuid. +if docker info --format '{{join .SecurityOptions ","}}' 2>/dev/null | grep -q rootless; then + EVIDENCE_OWNER="0:0" +else + EVIDENCE_OWNER="$(id -u):$(id -g)" +fi restore_evidence_owner() { docker run --rm --user root -v "$EVIDENCE_DIR:/evidence" \ - headless-p1-test chown -R "$(id -u):$(id -g)" /evidence >/dev/null 2>&1 || true + headless-p1-test chown -R "$EVIDENCE_OWNER" /evidence >/dev/null 2>&1 || true chmod 0700 "$EVIDENCE_DIR" >/dev/null 2>&1 || true } file_mode() {