@norskvideo/ctl-dev-kit 0.1.85 → 0.1.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/flake.nix +9 -0
- package/conventions/build-docs.yml +102 -21
- package/conventions/build-image.yml +204 -52
- package/conventions/checks.yml +153 -39
- package/conventions/integration.yml +102 -13
- package/conventions/publish-docs.yml +102 -21
- package/conventions/smoke.yml +102 -13
- package/conventions/sync-ctl-packages.yml +51 -13
- package/conventions/sync-dev-kit.yml +102 -26
- package/conventions/upgrade-latest.yml +102 -26
- package/conventions/workflow-shell.ts +106 -0
- package/package.json +1 -1
package/conventions/checks.yml
CHANGED
|
@@ -30,23 +30,61 @@ jobs:
|
|
|
30
30
|
drift:
|
|
31
31
|
runs-on: x64
|
|
32
32
|
steps:
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
40
|
-
# from a root container FIRST, and the checkout can clean properly again.
|
|
41
|
-
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
42
|
-
# fall through without failing the job.
|
|
43
|
-
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
33
|
+
# Runs BEFORE checkout, and does two things: points the harness's temp base
|
|
34
|
+
# out of the workspace for every later step in this job, and clears whatever
|
|
35
|
+
# the old repo-local default left behind on this runner. The body carries the
|
|
36
|
+
# why. It fails the job only when legacy litter survives -- which would take
|
|
37
|
+
# the checkout down a step later anyway, but report nothing useful.
|
|
38
|
+
- name: Route test-temp out of the workspace (pre-checkout)
|
|
44
39
|
run: |
|
|
45
40
|
set -uo pipefail
|
|
41
|
+
# These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
|
|
42
|
+
# HOST daemon has not seen before is created by dockerd, as ROOT, on the
|
|
43
|
+
# host -- even when the launch passes --container-user (reproduced
|
|
44
|
+
# 2026-09-04). The harness's default base is repo-local for an OrbStack
|
|
45
|
+
# inotify constraint that binds macOS dev and nothing here, so every run
|
|
46
|
+
# seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
|
|
47
|
+
# cannot remove. That took commentary's checks AND integration red on
|
|
48
|
+
# 2026-09-03. Use the sanctioned override, per-run and outside the
|
|
49
|
+
# checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
|
|
50
|
+
base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
|
|
51
|
+
mkdir -p "$base"
|
|
52
|
+
echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
|
|
53
|
+
# Yesterday's bases hold dockerd-created root dirs, so a non-root rm
|
|
54
|
+
# EACCESes. They cannot wedge a checkout, but they do fill the disk.
|
|
55
|
+
for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
|
|
56
|
+
docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
|
|
57
|
+
done
|
|
58
|
+
# LEGACY: a runner that ran the old default still carries a workspace
|
|
59
|
+
# test-temp, and a checkout with clean:true dies on it. Reap the holders
|
|
60
|
+
# first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
|
|
61
|
+
# RESTARTING leaked container re-creates the path as root seconds after
|
|
62
|
+
# any clean. Match on mount SOURCE, not a label: the holders are untracked
|
|
63
|
+
# by construction, because a killed run labels nothing.
|
|
46
64
|
tt="$GITHUB_WORKSPACE/test-temp"
|
|
47
65
|
[ -d "$tt" ] || exit 0
|
|
48
|
-
|
|
49
|
-
|
|
66
|
+
stuck=""
|
|
67
|
+
for c in $(docker ps -aq 2>/dev/null || true); do
|
|
68
|
+
if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
|
|
69
|
+
stuck="$stuck $c"
|
|
70
|
+
fi
|
|
71
|
+
done
|
|
72
|
+
if [ -n "$stuck" ]; then
|
|
73
|
+
echo "reaping containers holding mounts under $tt:$stuck"
|
|
74
|
+
docker rm -f $stuck || true
|
|
75
|
+
fi
|
|
76
|
+
# The DIRECTORY, not just its contents: an empty but root-owned base
|
|
77
|
+
# still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
|
|
78
|
+
# container unlink the leaf.
|
|
79
|
+
docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
|
|
80
|
+
sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
|
|
81
|
+
# Fail HERE if it survived. The checkout fails on it either way, but
|
|
82
|
+
# reports only an EACCES rmdir with no clue what was holding the path.
|
|
83
|
+
if [ -e "$tt" ]; then
|
|
84
|
+
echo "::error::$tt survived the pre-checkout clean"
|
|
85
|
+
ls -lan "$tt" || true
|
|
86
|
+
exit 1
|
|
87
|
+
fi
|
|
50
88
|
|
|
51
89
|
- uses: actions/checkout@v5
|
|
52
90
|
with:
|
|
@@ -68,23 +106,61 @@ jobs:
|
|
|
68
106
|
quality:
|
|
69
107
|
runs-on: x64
|
|
70
108
|
steps:
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
|
|
77
|
-
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
78
|
-
# from a root container FIRST, and the checkout can clean properly again.
|
|
79
|
-
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
80
|
-
# fall through without failing the job.
|
|
81
|
-
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
109
|
+
# Runs BEFORE checkout, and does two things: points the harness's temp base
|
|
110
|
+
# out of the workspace for every later step in this job, and clears whatever
|
|
111
|
+
# the old repo-local default left behind on this runner. The body carries the
|
|
112
|
+
# why. It fails the job only when legacy litter survives -- which would take
|
|
113
|
+
# the checkout down a step later anyway, but report nothing useful.
|
|
114
|
+
- name: Route test-temp out of the workspace (pre-checkout)
|
|
82
115
|
run: |
|
|
83
116
|
set -uo pipefail
|
|
117
|
+
# These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
|
|
118
|
+
# HOST daemon has not seen before is created by dockerd, as ROOT, on the
|
|
119
|
+
# host -- even when the launch passes --container-user (reproduced
|
|
120
|
+
# 2026-09-04). The harness's default base is repo-local for an OrbStack
|
|
121
|
+
# inotify constraint that binds macOS dev and nothing here, so every run
|
|
122
|
+
# seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
|
|
123
|
+
# cannot remove. That took commentary's checks AND integration red on
|
|
124
|
+
# 2026-09-03. Use the sanctioned override, per-run and outside the
|
|
125
|
+
# checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
|
|
126
|
+
base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
|
|
127
|
+
mkdir -p "$base"
|
|
128
|
+
echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
|
|
129
|
+
# Yesterday's bases hold dockerd-created root dirs, so a non-root rm
|
|
130
|
+
# EACCESes. They cannot wedge a checkout, but they do fill the disk.
|
|
131
|
+
for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
|
|
132
|
+
docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
|
|
133
|
+
done
|
|
134
|
+
# LEGACY: a runner that ran the old default still carries a workspace
|
|
135
|
+
# test-temp, and a checkout with clean:true dies on it. Reap the holders
|
|
136
|
+
# first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
|
|
137
|
+
# RESTARTING leaked container re-creates the path as root seconds after
|
|
138
|
+
# any clean. Match on mount SOURCE, not a label: the holders are untracked
|
|
139
|
+
# by construction, because a killed run labels nothing.
|
|
84
140
|
tt="$GITHUB_WORKSPACE/test-temp"
|
|
85
141
|
[ -d "$tt" ] || exit 0
|
|
86
|
-
|
|
87
|
-
|
|
142
|
+
stuck=""
|
|
143
|
+
for c in $(docker ps -aq 2>/dev/null || true); do
|
|
144
|
+
if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
|
|
145
|
+
stuck="$stuck $c"
|
|
146
|
+
fi
|
|
147
|
+
done
|
|
148
|
+
if [ -n "$stuck" ]; then
|
|
149
|
+
echo "reaping containers holding mounts under $tt:$stuck"
|
|
150
|
+
docker rm -f $stuck || true
|
|
151
|
+
fi
|
|
152
|
+
# The DIRECTORY, not just its contents: an empty but root-owned base
|
|
153
|
+
# still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
|
|
154
|
+
# container unlink the leaf.
|
|
155
|
+
docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
|
|
156
|
+
sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
|
|
157
|
+
# Fail HERE if it survived. The checkout fails on it either way, but
|
|
158
|
+
# reports only an EACCES rmdir with no clue what was holding the path.
|
|
159
|
+
if [ -e "$tt" ]; then
|
|
160
|
+
echo "::error::$tt survived the pre-checkout clean"
|
|
161
|
+
ls -lan "$tt" || true
|
|
162
|
+
exit 1
|
|
163
|
+
fi
|
|
88
164
|
|
|
89
165
|
- uses: actions/checkout@v5
|
|
90
166
|
with:
|
|
@@ -160,23 +236,61 @@ jobs:
|
|
|
160
236
|
if: ${{ !cancelled() && github.event_name == 'push' }}
|
|
161
237
|
runs-on: x64
|
|
162
238
|
steps:
|
|
163
|
-
#
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
#
|
|
168
|
-
|
|
169
|
-
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
170
|
-
# from a root container FIRST, and the checkout can clean properly again.
|
|
171
|
-
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
172
|
-
# fall through without failing the job.
|
|
173
|
-
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
239
|
+
# Runs BEFORE checkout, and does two things: points the harness's temp base
|
|
240
|
+
# out of the workspace for every later step in this job, and clears whatever
|
|
241
|
+
# the old repo-local default left behind on this runner. The body carries the
|
|
242
|
+
# why. It fails the job only when legacy litter survives -- which would take
|
|
243
|
+
# the checkout down a step later anyway, but report nothing useful.
|
|
244
|
+
- name: Route test-temp out of the workspace (pre-checkout)
|
|
174
245
|
run: |
|
|
175
246
|
set -uo pipefail
|
|
247
|
+
# These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
|
|
248
|
+
# HOST daemon has not seen before is created by dockerd, as ROOT, on the
|
|
249
|
+
# host -- even when the launch passes --container-user (reproduced
|
|
250
|
+
# 2026-09-04). The harness's default base is repo-local for an OrbStack
|
|
251
|
+
# inotify constraint that binds macOS dev and nothing here, so every run
|
|
252
|
+
# seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
|
|
253
|
+
# cannot remove. That took commentary's checks AND integration red on
|
|
254
|
+
# 2026-09-03. Use the sanctioned override, per-run and outside the
|
|
255
|
+
# checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
|
|
256
|
+
base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
|
|
257
|
+
mkdir -p "$base"
|
|
258
|
+
echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
|
|
259
|
+
# Yesterday's bases hold dockerd-created root dirs, so a non-root rm
|
|
260
|
+
# EACCESes. They cannot wedge a checkout, but they do fill the disk.
|
|
261
|
+
for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
|
|
262
|
+
docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
|
|
263
|
+
done
|
|
264
|
+
# LEGACY: a runner that ran the old default still carries a workspace
|
|
265
|
+
# test-temp, and a checkout with clean:true dies on it. Reap the holders
|
|
266
|
+
# first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
|
|
267
|
+
# RESTARTING leaked container re-creates the path as root seconds after
|
|
268
|
+
# any clean. Match on mount SOURCE, not a label: the holders are untracked
|
|
269
|
+
# by construction, because a killed run labels nothing.
|
|
176
270
|
tt="$GITHUB_WORKSPACE/test-temp"
|
|
177
271
|
[ -d "$tt" ] || exit 0
|
|
178
|
-
|
|
179
|
-
|
|
272
|
+
stuck=""
|
|
273
|
+
for c in $(docker ps -aq 2>/dev/null || true); do
|
|
274
|
+
if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
|
|
275
|
+
stuck="$stuck $c"
|
|
276
|
+
fi
|
|
277
|
+
done
|
|
278
|
+
if [ -n "$stuck" ]; then
|
|
279
|
+
echo "reaping containers holding mounts under $tt:$stuck"
|
|
280
|
+
docker rm -f $stuck || true
|
|
281
|
+
fi
|
|
282
|
+
# The DIRECTORY, not just its contents: an empty but root-owned base
|
|
283
|
+
# still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
|
|
284
|
+
# container unlink the leaf.
|
|
285
|
+
docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
|
|
286
|
+
sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
|
|
287
|
+
# Fail HERE if it survived. The checkout fails on it either way, but
|
|
288
|
+
# reports only an EACCES rmdir with no clue what was holding the path.
|
|
289
|
+
if [ -e "$tt" ]; then
|
|
290
|
+
echo "::error::$tt survived the pre-checkout clean"
|
|
291
|
+
ls -lan "$tt" || true
|
|
292
|
+
exit 1
|
|
293
|
+
fi
|
|
180
294
|
|
|
181
295
|
- uses: actions/checkout@v5
|
|
182
296
|
with:
|
|
@@ -70,17 +70,61 @@ jobs:
|
|
|
70
70
|
- runner: '["x64"]'
|
|
71
71
|
runs-on: ${{ fromJSON(matrix.runner) }}
|
|
72
72
|
steps:
|
|
73
|
-
# BEFORE checkout:
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
|
|
73
|
+
# Runs BEFORE checkout, and does two things: points the harness's temp base
|
|
74
|
+
# out of the workspace for every later step in this job, and clears whatever
|
|
75
|
+
# the old repo-local default left behind on this runner. The body carries the
|
|
76
|
+
# why. It fails the job only when legacy litter survives -- which would take
|
|
77
|
+
# the checkout down a step later anyway, but report nothing useful.
|
|
78
|
+
- name: Route test-temp out of the workspace (pre-checkout)
|
|
78
79
|
run: |
|
|
79
80
|
set -uo pipefail
|
|
81
|
+
# These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
|
|
82
|
+
# HOST daemon has not seen before is created by dockerd, as ROOT, on the
|
|
83
|
+
# host -- even when the launch passes --container-user (reproduced
|
|
84
|
+
# 2026-09-04). The harness's default base is repo-local for an OrbStack
|
|
85
|
+
# inotify constraint that binds macOS dev and nothing here, so every run
|
|
86
|
+
# seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
|
|
87
|
+
# cannot remove. That took commentary's checks AND integration red on
|
|
88
|
+
# 2026-09-03. Use the sanctioned override, per-run and outside the
|
|
89
|
+
# checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
|
|
90
|
+
base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
|
|
91
|
+
mkdir -p "$base"
|
|
92
|
+
echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
|
|
93
|
+
# Yesterday's bases hold dockerd-created root dirs, so a non-root rm
|
|
94
|
+
# EACCESes. They cannot wedge a checkout, but they do fill the disk.
|
|
95
|
+
for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
|
|
96
|
+
docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
|
|
97
|
+
done
|
|
98
|
+
# LEGACY: a runner that ran the old default still carries a workspace
|
|
99
|
+
# test-temp, and a checkout with clean:true dies on it. Reap the holders
|
|
100
|
+
# first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
|
|
101
|
+
# RESTARTING leaked container re-creates the path as root seconds after
|
|
102
|
+
# any clean. Match on mount SOURCE, not a label: the holders are untracked
|
|
103
|
+
# by construction, because a killed run labels nothing.
|
|
80
104
|
tt="$GITHUB_WORKSPACE/test-temp"
|
|
81
105
|
[ -d "$tt" ] || exit 0
|
|
82
|
-
|
|
83
|
-
|
|
106
|
+
stuck=""
|
|
107
|
+
for c in $(docker ps -aq 2>/dev/null || true); do
|
|
108
|
+
if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
|
|
109
|
+
stuck="$stuck $c"
|
|
110
|
+
fi
|
|
111
|
+
done
|
|
112
|
+
if [ -n "$stuck" ]; then
|
|
113
|
+
echo "reaping containers holding mounts under $tt:$stuck"
|
|
114
|
+
docker rm -f $stuck || true
|
|
115
|
+
fi
|
|
116
|
+
# The DIRECTORY, not just its contents: an empty but root-owned base
|
|
117
|
+
# still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
|
|
118
|
+
# container unlink the leaf.
|
|
119
|
+
docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
|
|
120
|
+
sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
|
|
121
|
+
# Fail HERE if it survived. The checkout fails on it either way, but
|
|
122
|
+
# reports only an EACCES rmdir with no clue what was holding the path.
|
|
123
|
+
if [ -e "$tt" ]; then
|
|
124
|
+
echo "::error::$tt survived the pre-checkout clean"
|
|
125
|
+
ls -lan "$tt" || true
|
|
126
|
+
exit 1
|
|
127
|
+
fi
|
|
84
128
|
|
|
85
129
|
- uses: actions/checkout@v5
|
|
86
130
|
with:
|
|
@@ -288,16 +332,61 @@ jobs:
|
|
|
288
332
|
if: ${{ !cancelled() && github.event_name != 'repository_dispatch' }}
|
|
289
333
|
runs-on: x64
|
|
290
334
|
steps:
|
|
291
|
-
#
|
|
292
|
-
#
|
|
293
|
-
#
|
|
294
|
-
|
|
335
|
+
# Runs BEFORE checkout, and does two things: points the harness's temp base
|
|
336
|
+
# out of the workspace for every later step in this job, and clears whatever
|
|
337
|
+
# the old repo-local default left behind on this runner. The body carries the
|
|
338
|
+
# why. It fails the job only when legacy litter survives -- which would take
|
|
339
|
+
# the checkout down a step later anyway, but report nothing useful.
|
|
340
|
+
- name: Route test-temp out of the workspace (pre-checkout)
|
|
295
341
|
run: |
|
|
296
342
|
set -uo pipefail
|
|
343
|
+
# These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
|
|
344
|
+
# HOST daemon has not seen before is created by dockerd, as ROOT, on the
|
|
345
|
+
# host -- even when the launch passes --container-user (reproduced
|
|
346
|
+
# 2026-09-04). The harness's default base is repo-local for an OrbStack
|
|
347
|
+
# inotify constraint that binds macOS dev and nothing here, so every run
|
|
348
|
+
# seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
|
|
349
|
+
# cannot remove. That took commentary's checks AND integration red on
|
|
350
|
+
# 2026-09-03. Use the sanctioned override, per-run and outside the
|
|
351
|
+
# checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
|
|
352
|
+
base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
|
|
353
|
+
mkdir -p "$base"
|
|
354
|
+
echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
|
|
355
|
+
# Yesterday's bases hold dockerd-created root dirs, so a non-root rm
|
|
356
|
+
# EACCESes. They cannot wedge a checkout, but they do fill the disk.
|
|
357
|
+
for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
|
|
358
|
+
docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
|
|
359
|
+
done
|
|
360
|
+
# LEGACY: a runner that ran the old default still carries a workspace
|
|
361
|
+
# test-temp, and a checkout with clean:true dies on it. Reap the holders
|
|
362
|
+
# first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
|
|
363
|
+
# RESTARTING leaked container re-creates the path as root seconds after
|
|
364
|
+
# any clean. Match on mount SOURCE, not a label: the holders are untracked
|
|
365
|
+
# by construction, because a killed run labels nothing.
|
|
297
366
|
tt="$GITHUB_WORKSPACE/test-temp"
|
|
298
367
|
[ -d "$tt" ] || exit 0
|
|
299
|
-
|
|
300
|
-
|
|
368
|
+
stuck=""
|
|
369
|
+
for c in $(docker ps -aq 2>/dev/null || true); do
|
|
370
|
+
if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
|
|
371
|
+
stuck="$stuck $c"
|
|
372
|
+
fi
|
|
373
|
+
done
|
|
374
|
+
if [ -n "$stuck" ]; then
|
|
375
|
+
echo "reaping containers holding mounts under $tt:$stuck"
|
|
376
|
+
docker rm -f $stuck || true
|
|
377
|
+
fi
|
|
378
|
+
# The DIRECTORY, not just its contents: an empty but root-owned base
|
|
379
|
+
# still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
|
|
380
|
+
# container unlink the leaf.
|
|
381
|
+
docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
|
|
382
|
+
sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
|
|
383
|
+
# Fail HERE if it survived. The checkout fails on it either way, but
|
|
384
|
+
# reports only an EACCES rmdir with no clue what was holding the path.
|
|
385
|
+
if [ -e "$tt" ]; then
|
|
386
|
+
echo "::error::$tt survived the pre-checkout clean"
|
|
387
|
+
ls -lan "$tt" || true
|
|
388
|
+
exit 1
|
|
389
|
+
fi
|
|
301
390
|
|
|
302
391
|
- uses: actions/checkout@v5
|
|
303
392
|
with:
|
|
@@ -42,36 +42,117 @@ jobs:
|
|
|
42
42
|
publish:
|
|
43
43
|
runs-on: x64
|
|
44
44
|
steps:
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
- name:
|
|
45
|
+
# Runs BEFORE checkout, and does two things: points the harness's temp base
|
|
46
|
+
# out of the workspace for every later step in this job, and clears whatever
|
|
47
|
+
# the old repo-local default left behind on this runner. The body carries the
|
|
48
|
+
# why. It fails the job only when legacy litter survives -- which would take
|
|
49
|
+
# the checkout down a step later anyway, but report nothing useful.
|
|
50
|
+
- name: Route test-temp out of the workspace (pre-checkout)
|
|
51
51
|
run: |
|
|
52
52
|
set -uo pipefail
|
|
53
|
+
# These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
|
|
54
|
+
# HOST daemon has not seen before is created by dockerd, as ROOT, on the
|
|
55
|
+
# host -- even when the launch passes --container-user (reproduced
|
|
56
|
+
# 2026-09-04). The harness's default base is repo-local for an OrbStack
|
|
57
|
+
# inotify constraint that binds macOS dev and nothing here, so every run
|
|
58
|
+
# seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
|
|
59
|
+
# cannot remove. That took commentary's checks AND integration red on
|
|
60
|
+
# 2026-09-03. Use the sanctioned override, per-run and outside the
|
|
61
|
+
# checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
|
|
62
|
+
base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
|
|
63
|
+
mkdir -p "$base"
|
|
64
|
+
echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
|
|
65
|
+
# Yesterday's bases hold dockerd-created root dirs, so a non-root rm
|
|
66
|
+
# EACCESes. They cannot wedge a checkout, but they do fill the disk.
|
|
67
|
+
for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
|
|
68
|
+
docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
|
|
69
|
+
done
|
|
70
|
+
# LEGACY: a runner that ran the old default still carries a workspace
|
|
71
|
+
# test-temp, and a checkout with clean:true dies on it. Reap the holders
|
|
72
|
+
# first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
|
|
73
|
+
# RESTARTING leaked container re-creates the path as root seconds after
|
|
74
|
+
# any clean. Match on mount SOURCE, not a label: the holders are untracked
|
|
75
|
+
# by construction, because a killed run labels nothing.
|
|
53
76
|
tt="$GITHUB_WORKSPACE/test-temp"
|
|
54
77
|
[ -d "$tt" ] || exit 0
|
|
55
|
-
|
|
56
|
-
|
|
78
|
+
stuck=""
|
|
79
|
+
for c in $(docker ps -aq 2>/dev/null || true); do
|
|
80
|
+
if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
|
|
81
|
+
stuck="$stuck $c"
|
|
82
|
+
fi
|
|
83
|
+
done
|
|
84
|
+
if [ -n "$stuck" ]; then
|
|
85
|
+
echo "reaping containers holding mounts under $tt:$stuck"
|
|
86
|
+
docker rm -f $stuck || true
|
|
87
|
+
fi
|
|
88
|
+
# The DIRECTORY, not just its contents: an empty but root-owned base
|
|
89
|
+
# still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
|
|
90
|
+
# container unlink the leaf.
|
|
91
|
+
docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
|
|
92
|
+
sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
|
|
93
|
+
# Fail HERE if it survived. The checkout fails on it either way, but
|
|
94
|
+
# reports only an EACCES rmdir with no clue what was holding the path.
|
|
95
|
+
if [ -e "$tt" ]; then
|
|
96
|
+
echo "::error::$tt survived the pre-checkout clean"
|
|
97
|
+
ls -lan "$tt" || true
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
57
100
|
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
|
|
64
|
-
# time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
|
|
65
|
-
# from a root container FIRST, and the checkout can clean properly again.
|
|
66
|
-
# Best-effort by construction: no docker, no test-temp, or a failed run all
|
|
67
|
-
# fall through without failing the job.
|
|
68
|
-
- name: Clear stale root-owned test-temp (pre-checkout)
|
|
101
|
+
# Runs BEFORE checkout, and does two things: points the harness's temp base
|
|
102
|
+
# out of the workspace for every later step in this job, and clears whatever
|
|
103
|
+
# the old repo-local default left behind on this runner. The body carries the
|
|
104
|
+
# why. It fails the job only when legacy litter survives -- which would take
|
|
105
|
+
# the checkout down a step later anyway, but report nothing useful.
|
|
106
|
+
- name: Route test-temp out of the workspace (pre-checkout)
|
|
69
107
|
run: |
|
|
70
108
|
set -uo pipefail
|
|
109
|
+
# These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
|
|
110
|
+
# HOST daemon has not seen before is created by dockerd, as ROOT, on the
|
|
111
|
+
# host -- even when the launch passes --container-user (reproduced
|
|
112
|
+
# 2026-09-04). The harness's default base is repo-local for an OrbStack
|
|
113
|
+
# inotify constraint that binds macOS dev and nothing here, so every run
|
|
114
|
+
# seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
|
|
115
|
+
# cannot remove. That took commentary's checks AND integration red on
|
|
116
|
+
# 2026-09-03. Use the sanctioned override, per-run and outside the
|
|
117
|
+
# checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
|
|
118
|
+
base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
|
|
119
|
+
mkdir -p "$base"
|
|
120
|
+
echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
|
|
121
|
+
# Yesterday's bases hold dockerd-created root dirs, so a non-root rm
|
|
122
|
+
# EACCESes. They cannot wedge a checkout, but they do fill the disk.
|
|
123
|
+
for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
|
|
124
|
+
docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
|
|
125
|
+
done
|
|
126
|
+
# LEGACY: a runner that ran the old default still carries a workspace
|
|
127
|
+
# test-temp, and a checkout with clean:true dies on it. Reap the holders
|
|
128
|
+
# first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
|
|
129
|
+
# RESTARTING leaked container re-creates the path as root seconds after
|
|
130
|
+
# any clean. Match on mount SOURCE, not a label: the holders are untracked
|
|
131
|
+
# by construction, because a killed run labels nothing.
|
|
71
132
|
tt="$GITHUB_WORKSPACE/test-temp"
|
|
72
133
|
[ -d "$tt" ] || exit 0
|
|
73
|
-
|
|
74
|
-
|
|
134
|
+
stuck=""
|
|
135
|
+
for c in $(docker ps -aq 2>/dev/null || true); do
|
|
136
|
+
if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
|
|
137
|
+
stuck="$stuck $c"
|
|
138
|
+
fi
|
|
139
|
+
done
|
|
140
|
+
if [ -n "$stuck" ]; then
|
|
141
|
+
echo "reaping containers holding mounts under $tt:$stuck"
|
|
142
|
+
docker rm -f $stuck || true
|
|
143
|
+
fi
|
|
144
|
+
# The DIRECTORY, not just its contents: an empty but root-owned base
|
|
145
|
+
# still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
|
|
146
|
+
# container unlink the leaf.
|
|
147
|
+
docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
|
|
148
|
+
sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
|
|
149
|
+
# Fail HERE if it survived. The checkout fails on it either way, but
|
|
150
|
+
# reports only an EACCES rmdir with no clue what was holding the path.
|
|
151
|
+
if [ -e "$tt" ]; then
|
|
152
|
+
echo "::error::$tt survived the pre-checkout clean"
|
|
153
|
+
ls -lan "$tt" || true
|
|
154
|
+
exit 1
|
|
155
|
+
fi
|
|
75
156
|
|
|
76
157
|
- uses: actions/checkout@v5
|
|
77
158
|
with:
|