From 8ad8ae1077378e983ef0f6e60e8646f67b2418aa Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Wed, 15 Apr 2026 21:20:06 -0700 Subject: [PATCH] fix(ci): explicitly disable osxkeychain credsStore for self-hosted runner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #273 tried to fix the macOS Keychain -25308 error by pointing DOCKER_CONFIG at a per-run temp dir with `{"auths": {}}`. That was necessary but not sufficient: Docker on macOS inherits `osxkeychain` as the default credsStore even when config.json doesn't declare one (comes from Docker Desktop's bundled binding), so the login-action still tried to call /usr/local/bin/docker-credential-osxkeychain which fails with -25308 from the non-interactive launchd session. Evidence: after #273, publish-platform-image still failed on every main merge with: error saving credentials: error storing credentials - err: exit status 1, out: `User interaction is not allowed. (-25308)` Fix: write a config.json that explicitly sets `credsStore: ""` and clears `credHelpers`, forcing Docker to store creds in the inline `auths` map of this disposable config.json instead of reaching for the keychain. Also print config.json at diagnostic time so a future regression surfaces in the log instead of at login. No runtime / test impact — this only changes what the runner writes to the workflow's temp DOCKER_CONFIG directory. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/publish-platform-image.yml | 32 +++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/.github/workflows/publish-platform-image.yml b/.github/workflows/publish-platform-image.yml index 6c530584..4c70297e 100644 --- a/.github/workflows/publish-platform-image.yml +++ b/.github/workflows/publish-platform-image.yml @@ -43,23 +43,41 @@ jobs: # is the macOS Keychain, which raises # error storing credentials - err: exit status 1, out: # `User interaction is not allowed. (-25308)` - # without an unlocked desktop session. Point DOCKER_CONFIG at a - # per-run temp dir so the login step writes a plain config.json - # that never touches the keychain. Plus diagnostics: print the - # docker path so a future EACCES on /usr/local/bin/docker - # surfaces in the log instead of via a cryptic docker-login - # failure mid-step. + # without an unlocked desktop session. + # + # Point DOCKER_CONFIG at a per-run temp dir. IMPORTANT: writing + # `{"auths": {}}` alone is NOT enough — Docker on macOS picks up + # `osxkeychain` as the default credential store even when + # config.json doesn't declare one, inheriting from Docker + # Desktop's bundled credsStore binding. We must explicitly set + # `credsStore` to an empty string AND clear `credHelpers` so the + # login step writes credentials into the auths map of this + # disposable config.json rather than reaching for the keychain. + # (First tried in #273 without the empty-credsStore line; #319 + # + #322 merges showed it still regressed.) + # + # Plus diagnostics: print the docker path so a future EACCES on + # /usr/local/bin/docker surfaces in the log instead of via a + # cryptic docker-login failure mid-step. shell: bash run: | set -euo pipefail mkdir -p "${RUNNER_TEMP}/docker-config" - echo '{"auths": {}}' > "${RUNNER_TEMP}/docker-config/config.json" + cat > "${RUNNER_TEMP}/docker-config/config.json" <<'JSON' + { + "auths": {}, + "credsStore": "", + "credHelpers": {} + } + JSON echo "DOCKER_CONFIG=${RUNNER_TEMP}/docker-config" >> "${GITHUB_ENV}" echo "=== Runner docker diagnostics ===" echo "PATH=$PATH" command -v docker || echo "(docker not in PATH — the runner is missing the Docker CLI or it's not symlinked to a visible location)" docker --version 2>&1 || true ls -la /usr/local/bin/docker /opt/homebrew/bin/docker 2>&1 || true + echo "=== config.json after setup ===" + cat "${RUNNER_TEMP}/docker-config/config.json" - name: Set up QEMU # Required on the Apple-silicon self-hosted runner — Fly tenant machines