diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 85e3c26d..59781a96 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -44,22 +44,27 @@ jobs:
# -short skips 3 known-slow stress tests in pkg/daemon and
# pkg/daemon/udpio; everything else runs.
#
- # Both hosted runners have started handing out a $RUNNER_TEMP
- # (/Users/runner/work/_temp on macOS, /home/runner/work/_temp on
- # ubuntu) whose ACLs make t.TempDir() fail with "mkdir ...:
- # permission denied" — a recurring GitHub-runner issue (seen on
- # #304/#306/#308 for macOS and now hitting ubuntu too). A writable
- # subdir under it inherits the same restriction, so redirecting
- # TMPDIR *into* $RUNNER_TEMP is not enough; it must point at a
- # freshly-created dir outside that tree. Create one under /tmp
- # (writable by the test process on both Linux and macOS), chmod it
- # so t.TempDir()'s sub-dirs are creatable, and point $TMPDIR there
- # for THIS run block so go test's os.TempDir() -> t.TempDir()
- # lands somewhere writable. No job/step-level `env: TMPDIR:` is set
- # anywhere in this workflow, so nothing overrides this export.
+ # t.TempDir() flakes with "mkdir
//001: permission
+ # denied" on the hosted runners when $TMPDIR points into /tmp.
+ # /tmp (and /private/tmp on macOS) is world-writable with the
+ # sticky bit (mode 1777); the runner's extra sandbox layer
+ # (sandbox-exec on macOS, AppArmor on ubuntu) intermittently
+ # denies the nested mkdir Go does for each parallel sub-test there,
+ # which is why #316's `mktemp -d /tmp/...` + chmod 777 still failed
+ # on #302/#321/#325 (and started hitting ubuntu too). The fix is to
+ # keep temp OUT of the sticky /tmp tree and use a plain, per-user,
+ # runner-owned directory instead:
+ # * macOS: the OS-native DARWIN_USER_TEMP_DIR (/var/folders/.../T)
+ # — a per-user temp with no sticky bit and no sandbox quirk.
+ # * Linux: a fresh dir under the runner-owned $RUNNER_TEMP.
+ # No job/step-level `env: TMPDIR:` is set anywhere in this
+ # workflow, so nothing overrides this export.
run: |
- TMPDIR="$(mktemp -d /tmp/gotmpXXXXXX 2>/dev/null || mktemp -d "${RUNNER_TEMP:-.}/gotmpXXXXXX")"
- chmod 777 "$TMPDIR"
+ if [ "${RUNNER_OS}" = "macOS" ]; then
+ TMPDIR="$(getconf DARWIN_USER_TEMP_DIR)"
+ else
+ TMPDIR="$(mktemp -d "${RUNNER_TEMP:-/tmp}/gotmpXXXXXX")"
+ fi
export TMPDIR
echo "using TMPDIR=$TMPDIR"
go test -short -count=1 -timeout 600s ./pkg/... ./cmd/... ./internal/...