Skip to content

Commit abb042c

Browse files
committed
fix: address provider review feedback
1 parent 67485d4 commit abb042c

14 files changed

Lines changed: 225 additions & 47 deletions

deploy.sh

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,14 @@ done
4141
echo "[deploy] staging complete runtime tree for $HOST:$DEST"
4242
REMOTE_STAGE="$(ssh -- "$HOST" "umask 022; mktemp -d '${DEST}.deploy.XXXXXX'")"
4343
case "$REMOTE_STAGE" in
44-
"$DEST".deploy.*) ;;
44+
"$DEST".deploy.*)
45+
remote_stage_suffix="${REMOTE_STAGE#"$DEST".deploy.}"
46+
case "$remote_stage_suffix" in
47+
''|*[!A-Za-z0-9]*)
48+
echo "deploy: remote host returned an unsafe staging path: $REMOTE_STAGE" >&2
49+
exit 1 ;;
50+
esac
51+
;;
4552
*) echo "deploy: remote host returned an unsafe staging path: $REMOTE_STAGE" >&2; exit 1 ;;
4653
esac
4754

@@ -68,7 +75,14 @@ if [ "$dest" != "/usr/local/emhttp/plugins/ci-runner-farm" ]; then
6875
exit 1
6976
fi
7077
case "$stage" in
71-
"$dest".deploy.*) ;;
78+
"$dest".deploy.*)
79+
stage_suffix="${stage#"$dest".deploy.}"
80+
case "$stage_suffix" in
81+
''|*[!A-Za-z0-9]*)
82+
echo "deploy: refusing unexpected staging path: $stage" >&2
83+
exit 1 ;;
84+
esac
85+
;;
7286
*) echo "deploy: refusing unexpected staging path: $stage" >&2; exit 1 ;;
7387
esac
7488
@@ -99,8 +113,8 @@ chown -R root:root "$stage"
99113
find "$stage" -type d -exec chmod 0755 {} +
100114
find "$stage" -type f -exec chmod 0644 {} +
101115
chmod 0755 "$stage/include/runner-farm.sh"
102-
find "$stage/nchan" -type f -exec chmod 0755 {} + 2>/dev/null || true
103-
find "$stage/event" -type f -exec chmod 0755 {} + 2>/dev/null || true
116+
find "$stage/nchan" -type f -exec chmod 0755 {} +
117+
find "$stage/event" -type f -exec chmod 0755 {} +
104118
105119
# Use the exact runtime lock location/fallback used by the installed engine. Hold
106120
# it from the final inactive-state snapshot through the tree swap, preventing a
@@ -261,10 +275,14 @@ esac
261275
backup="${dest}.deploy-backup.$$"
262276
rollback() {
263277
status=$?
278+
if [ "$#" -gt 0 ]; then status="$1"; fi
264279
if [ ! -e "$dest" ] && [ -e "$backup" ]; then mv "$backup" "$dest"; fi
265280
exit "$status"
266281
}
267-
trap rollback ERR HUP INT TERM
282+
trap rollback ERR
283+
trap 'rollback 129' HUP
284+
trap 'rollback 130' INT
285+
trap 'rollback 143' TERM
268286
269287
if [ -e "$dest" ]; then mv "$dest" "$backup"; fi
270288
mv "$stage" "$dest"

install-dev.sh

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@ PY
157157
IFS=$'\t' read -r PACKAGE_FILE PACKAGE_SHA256 PLUGIN_SHA256 MANIFEST_SHA256 <<< "$values"
158158
[ -n "$PACKAGE_FILE" ] && [ -n "$PACKAGE_SHA256" ] && [ -n "$PLUGIN_SHA256" ] && [ -n "$MANIFEST_SHA256" ] \
159159
|| die "bundle validator returned an incomplete result"
160-
PACKAGE="$BUNDLE_DIR/$PACKAGE_FILE"
161160
}
162161

163162
if [ "$ACTION" = install ]; then
@@ -233,6 +232,24 @@ canonical_cfg=/boot/config/plugins/ci-runner-farm
233232
dev_root=/boot/config/ci-runner-farm-dev
234233
rollback="$dev_root/rollback"
235234
artifacts="$dev_root/artifacts"
235+
rollback_tmp=
236+
commit_tmp=
237+
cleanup_install_temps() {
238+
local status=$?
239+
trap - EXIT
240+
case "$rollback_tmp" in
241+
'') ;;
242+
"$dev_root"/.rollback.*) rm -rf -- "$rollback_tmp" || status=1 ;;
243+
*) printf 'install-dev remote: refusing to clean unsafe rollback temporary path: %s\n' "$rollback_tmp" >&2; status=1 ;;
244+
esac
245+
case "$commit_tmp" in
246+
'') ;;
247+
"$artifacts"/.commit.*) rm -f -- "$commit_tmp" || status=1 ;;
248+
*) printf 'install-dev remote: refusing to clean unsafe artifact temporary path: %s\n' "$commit_tmp" >&2; status=1 ;;
249+
esac
250+
exit "$status"
251+
}
252+
trap cleanup_install_temps EXIT
236253
umask 077
237254
mkdir -p "$dev_root"
238255
[ -d "$dev_root" ] && [ ! -L "$dev_root" ] || fail "development state root is unsafe"
@@ -298,6 +315,7 @@ else
298315
find "$rollback_tmp" -type d -exec chmod 0700 {} +
299316
find "$rollback_tmp" -type f -exec chmod 0600 {} +
300317
mv -- "$rollback_tmp" "$rollback"
318+
rollback_tmp=
301319
validate_baseline
302320
fi
303321
@@ -339,18 +357,19 @@ fi
339357
chmod 0700 "$artifacts"
340358
341359
commit_artifact() {
342-
local source="$1" destination="$2" expected="$3" tmp
360+
local source="$1" destination="$2" expected="$3"
343361
if [ -e "$destination" ] || [ -L "$destination" ]; then
344362
regular_file "$destination" || fail "artifact destination is unsafe: $destination"
345363
[ "$(sha256_of "$destination")" = "$expected" ] \
346364
|| fail "artifact basename already exists with different bytes: $destination"
347365
return 0
348366
fi
349-
tmp="$(mktemp "$artifacts/.commit.XXXXXX")"
350-
cp -- "$source" "$tmp"
351-
chmod 0600 "$tmp"
352-
[ "$(sha256_of "$tmp")" = "$expected" ] || fail "artifact changed during commit"
353-
mv -- "$tmp" "$destination"
367+
commit_tmp="$(mktemp "$artifacts/.commit.XXXXXX")"
368+
cp -- "$source" "$commit_tmp"
369+
chmod 0600 "$commit_tmp"
370+
[ "$(sha256_of "$commit_tmp")" = "$expected" ] || fail "artifact changed during commit"
371+
mv -- "$commit_tmp" "$destination"
372+
commit_tmp=
354373
[ "$(sha256_of "$destination")" = "$expected" ] || fail "committed artifact verification failed"
355374
}
356375
@@ -453,7 +472,32 @@ docker_names "GitLab validation jobs" \
453472
all_names="$(docker ps -a --format '{{.Names}}' 2>/dev/null)" \
454473
|| fail "cannot enumerate Docker names for legacy mirror verification"
455474
if printf '%s\n' "$all_names" | grep -qxF ci-runner-mirror; then
456-
fail "fixed-name registry mirror remains after Stop"
475+
legacy_cache_root=/mnt/cache/github-runner
476+
cfg="$canonical_cfg/ci-runner-farm.cfg"
477+
if [ -e "$cfg" ]; then
478+
[ -r "$cfg" ] || fail "cannot read plugin config for legacy mirror verification"
479+
while IFS= read -r line || [ -n "$line" ]; do
480+
case "$line" in ''|\#*) continue ;; esac
481+
[ "${line#*=}" = "$line" ] && continue
482+
key="${line%%=*}"; value="${line#*=}"
483+
key="${key//[[:space:]]/}"
484+
[ "$key" = CACHE_ROOT ] || continue
485+
value="${value%\"}"; value="${value#\"}"
486+
value="${value%\'}"; value="${value#\'}"
487+
legacy_cache_root="$value"
488+
done < "$cfg"
489+
fi
490+
legacy_name="$(docker inspect -f '{{.Name}}' ci-runner-mirror 2>/dev/null)" \
491+
&& legacy_image="$(docker inspect -f '{{.Config.Image}}' ci-runner-mirror 2>/dev/null)" \
492+
&& legacy_source="$(docker inspect -f '{{range .Mounts}}{{if eq .Destination "/var/lib/registry"}}{{.Source}}{{end}}{{end}}' ci-runner-mirror 2>/dev/null)" \
493+
&& legacy_env="$(docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' ci-runner-mirror 2>/dev/null)" \
494+
|| fail "cannot verify fixed-name registry mirror provenance"
495+
if [ "$legacy_name" = /ci-runner-mirror ] \
496+
&& [ "$legacy_image" = registry:2 ] \
497+
&& [ "$legacy_source" = "$legacy_cache_root/registry-mirror" ] \
498+
&& printf '%s\n' "$legacy_env" | grep -qx 'REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io'; then
499+
fail "fixed-name registry mirror remains after Stop"
500+
fi
457501
fi
458502
daemon_status=0
459503
pgrep -f '[r]unner-farm.sh (autoscale-daemon|imageupdate-daemon|reconcile-drain|boot-autostart)' >/dev/null 2>&1 \

src/usr/local/emhttp/plugins/ci-runner-farm/default.Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ RUN printf '%s\n' \
3434
'( while true; do docker info >/dev/null 2>&1 || { rm -f /var/run/docker.pid; service docker start >>/var/log/dockerd.log 2>&1; }; sleep 3; done ) &' \
3535
'# wait for first readiness before the runner accepts jobs' \
3636
'for i in $(seq 1 90); do docker info >/dev/null 2>&1 && break; sleep 1; done' \
37+
'docker info >/dev/null 2>&1 || { echo "Docker did not become ready" >&2; exit 1; }' \
3738
'exec "$@"' \
3839
> /usr/local/bin/wait-docker.sh \
3940
&& chmod +x /usr/local/bin/wait-docker.sh

src/usr/local/emhttp/plugins/ci-runner-farm/default.github.Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ RUN printf '%s\n' \
3434
'( while true; do docker info >/dev/null 2>&1 || { rm -f /var/run/docker.pid; service docker start >>/var/log/dockerd.log 2>&1; }; sleep 3; done ) &' \
3535
'# wait for first readiness before the runner accepts jobs' \
3636
'for i in $(seq 1 90); do docker info >/dev/null 2>&1 && break; sleep 1; done' \
37+
'docker info >/dev/null 2>&1 || { echo "Docker did not become ready" >&2; exit 1; }' \
3738
'exec "$@"' \
3839
> /usr/local/bin/wait-docker.sh \
3940
&& chmod +x /usr/local/bin/wait-docker.sh

src/usr/local/emhttp/plugins/ci-runner-farm/include/providers/github.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ github_registry_credentials() {
163163
}
164164

165165
github_build_args() {
166-
local idx="$1" name="${2:-${NAME_PREFIX}-${idx}}" role="${CRF_CONTAINER_ROLE:-runner}"
166+
local idx="$1"
167+
local name="${2:-${NAME_PREFIX}-${idx}}" role="${CRF_CONTAINER_ROLE:-runner}"
167168
ARGS=(
168169
-d --restart=no
169170
--name "$name" --hostname "$name"

src/usr/local/emhttp/plugins/ci-runner-farm/include/providers/gitlab.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,8 @@ gitlab_write_config() {
742742
}
743743

744744
gitlab_build_manager_args() {
745-
local idx="$1" name="${2:-${NAME_PREFIX}-${idx}}" dir sock sockdir socket_mount authdir slot_ca
745+
local idx="$1"
746+
local name="${2:-${NAME_PREFIX}-${idx}}" dir sock sockdir socket_mount authdir slot_ca
746747
gitlab_validate_settings || return 1
747748
gitlab_token_ready || { err "no valid GitLab glrt- runner token configured"; return 1; }
748749
gitlab_write_config "$idx" "$name" || { err "could not write GitLab config for $name"; return 1; }

tests/config-parity.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ declare -A ENG CFGV UIV
4242
# plugin config. PHP's INI scanner accepts `;` comments, not shell-style `#`
4343
# comments on current Unraid releases; catch a file that is textually correct
4444
# for the shell tests but unusable by the webGUI.
45-
command -v php >/dev/null 2>&1 || bad "php is required to validate default.cfg"
46-
if command -v php >/dev/null 2>&1 \
47-
&& ! php -r '$v = parse_ini_file($argv[1]); exit(is_array($v) ? 0 : 1);' "$CFG"; then
45+
if ! command -v php >/dev/null 2>&1; then
46+
bad "php is required to validate default.cfg"
47+
elif ! php -r '$v = parse_ini_file($argv[1]); exit(is_array($v) ? 0 : 1);' "$CFG"; then
4848
bad "default.cfg is not valid for PHP parse_ini_file (and therefore Unraid parse_plugin_cfg)"
4949
fi
5050

tests/deploy-uninstall-safety.sh

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ DEPLOY="deploy.sh"
88
BUILD="build-plg.sh"
99

1010
fail() { printf 'DEPLOY/UNINSTALL SAFETY FAIL: %s\n' "$*" >&2; exit 1; }
11-
first_line() { grep -nF -- "$2" "$1" | head -1 | cut -d: -f1; }
11+
first_line() { grep -nF -- "$2" "$1" | head -1 | cut -d: -f1 || true; }
1212

1313
lock_line="$(first_line "$DEPLOY" 'flock -w 20 8')"
1414
manager_check_line="$(first_line "$DEPLOY" 'owned_managers="$(docker ps -a')"
@@ -24,6 +24,25 @@ grep -qF 'COPYFILE_DISABLE=1 tar --no-xattrs -C "$SRC" -cf - .' "$DEPLOY" \
2424
|| fail "deploy does not suppress macOS AppleDouble metadata at the source"
2525
grep -qF "find \"\$stage\" -name '._*' -print" "$DEPLOY" \
2626
|| fail "deploy does not reject AppleDouble metadata in the staged runtime"
27+
grep -qF 'remote_stage_suffix="${REMOTE_STAGE#"$DEST".deploy.}"' "$DEPLOY" \
28+
&& grep -qF 'stage_suffix="${stage#"$dest".deploy.}"' "$DEPLOY" \
29+
&& [ "$(grep -cF "''|*[!A-Za-z0-9]*)" "$DEPLOY" || true)" -eq 2 ] \
30+
|| fail "deploy does not require a nonempty alphanumeric staging suffix locally and remotely"
31+
for executable_tree in nchan event; do
32+
grep -qxF "find \"\$stage/$executable_tree\" -type f -exec chmod 0755 {} +" "$DEPLOY" \
33+
|| fail "deploy does not propagate $executable_tree permission failures"
34+
done
35+
grep -qF 'trap rollback ERR' "$DEPLOY" \
36+
&& grep -qF 'if [ "$#" -gt 0 ]; then status="$1"; fi' "$DEPLOY" \
37+
|| fail "deploy rollback does not preserve ERR status separately from signals"
38+
for signal_trap in \
39+
"trap 'rollback 129' HUP" \
40+
"trap 'rollback 130' INT" \
41+
"trap 'rollback 143' TERM"
42+
do
43+
grep -qF "$signal_trap" "$DEPLOY" \
44+
|| fail "deploy rollback lacks nonzero signal status: $signal_trap"
45+
done
2746
if sed -n "${lock_line},${swap_line}p" "$DEPLOY" | grep -F 'flock -u 8' >/dev/null; then
2847
fail "deploy releases fleet.lock before the staged tree swap"
2948
fi
@@ -125,9 +144,11 @@ printf '%s\n' "$remove_block" | grep -qF 'if ! rm -rf -- "\$PLGDIR" || [ -e "\$P
125144
printf '%s\n' "$remove_block" | grep -qF 'if ! rm -f -- "\$CFGDIR"/${NAME}-*.tgz; then' \
126145
|| fail "plugin remove action does not fail on cached-package deletion"
127146

128-
runtime_delete_line="$(printf '%s\n' "$remove_block" | grep -nF 'if ! rm -rf -- "\$PLGDIR"' | head -1 | cut -d: -f1)"
129-
package_delete_line="$(printf '%s\n' "$remove_block" | grep -nF 'if ! rm -f -- "\$CFGDIR"/${NAME}-*.tgz' | head -1 | cut -d: -f1)"
130-
success_line="$(printf '%s\n' "$remove_block" | grep -nF 'ci-runner-farm removed. Config + credentials left' | head -1 | cut -d: -f1)"
147+
runtime_delete_line="$(printf '%s\n' "$remove_block" | grep -nF 'if ! rm -rf -- "\$PLGDIR"' | head -1 | cut -d: -f1 || true)"
148+
package_delete_line="$(printf '%s\n' "$remove_block" | grep -nF 'if ! rm -f -- "\$CFGDIR"/${NAME}-*.tgz' | head -1 | cut -d: -f1 || true)"
149+
success_line="$(printf '%s\n' "$remove_block" | grep -nF 'ci-runner-farm removed. Config + credentials left' | head -1 | cut -d: -f1 || true)"
150+
[ -n "$runtime_delete_line" ] && [ -n "$package_delete_line" ] && [ -n "$success_line" ] \
151+
|| fail "could not locate runtime deletion, cached-package deletion, and uninstall success"
131152
[ "$runtime_delete_line" -lt "$success_line" ] && [ "$package_delete_line" -lt "$success_line" ] \
132153
|| fail "plugin remove action can announce success before cleanup completes"
133154

tests/gitlab-runner-lint.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ GITLAB_URL=https://gitlab.example.test
2121
# version/length/CRC separators that originally exposed a stale local parser.
2222
GITLAB_RUNNER_TOKEN=glrt-AAECAwQFBgcICQoLDA0OD286MQpwOjIKdTozCnQ6Mw8.01.170z6aiyq
2323
GITLAB_RUNNER_IMAGE="$(sed -n 's/^GITLAB_RUNNER_IMAGE="\([^"]*\)".*/\1/p' src/usr/local/emhttp/plugins/ci-runner-farm/default.cfg | head -1)"
24+
[ -n "$GITLAB_RUNNER_IMAGE" ] \
25+
|| { echo "gitlab-runner-lint: could not read GITLAB_RUNNER_IMAGE from default.cfg" >&2; exit 1; }
2426
CACHE_ROOT="$tmp/cache"
2527
CACHE_MOUNTS=''
2628
RUNNER_CPUS='2'
@@ -35,8 +37,11 @@ mkdir -p "$CACHE_ROOT"
3537
# can open the configured path as well as parse it.
3638
if [ -r /etc/ssl/certs/ca-certificates.crt ]; then
3739
cp /etc/ssl/certs/ca-certificates.crt "$GITLAB_CA_FILE"
38-
else
40+
elif [ -r /etc/ssl/cert.pem ]; then
3941
cp /etc/ssl/cert.pem "$GITLAB_CA_FILE"
42+
else
43+
echo "gitlab-runner-lint: no host CA bundle found for the self-managed CA case" >&2
44+
exit 1
4045
fi
4146
printf '%s' "$GITLAB_RUNNER_TOKEN" > "$GITLAB_RUNNER_TOKEN_FILE"
4247
reload_secret_files

tests/install-dev-safety.sh

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@ INSTALLER=install-dev.sh
88
fail() { printf 'INSTALL-DEV SAFETY FAIL: %s\n' "$*" >&2; exit 1; }
99
line_of() {
1010
local value
11-
value="$(grep -nF -- "$2" "$1" | head -1 | cut -d: -f1)"
11+
value="$(grep -nF -- "$2" "$1" | head -1 | cut -d: -f1 || true)"
1212
[ -n "$value" ] || fail "missing contract: $2"
1313
printf '%s\n' "$value"
1414
}
1515

1616
bash -n "$INSTALLER" || fail "installer has invalid shell syntax"
17+
missing_line_output="$( (line_of "$INSTALLER" '__install_dev_missing_contract_probe__') 2>&1 || true)"
18+
case "$missing_line_output" in
19+
*'missing contract: __install_dev_missing_contract_probe__'*) ;;
20+
*) fail "line_of suppresses its focused missing-contract diagnostic" ;;
21+
esac
1722

1823
# The local bundle is authenticated before the first remote mutation, and the
1924
# lock-protected live deployment completes before flash state is created.
@@ -37,6 +42,9 @@ do
3742
done
3843
grep -qF 'case "${HOST#root@}"' "$INSTALLER" || fail "host shell syntax is not rejected"
3944
if grep -qF 'set -x' "$INSTALLER"; then fail "installer enables shell tracing"; fi
45+
if grep -qF 'PACKAGE="$BUNDLE_DIR/$PACKAGE_FILE"' "$INSTALLER"; then
46+
fail "installer retains the unused PACKAGE assignment"
47+
fi
4048

4149
# Baseline creation is one-time and copies exactly the public canonical
4250
# descriptor plus the one package it references. It must not sweep or copy the
@@ -53,6 +61,22 @@ for contract in \
5361
do
5462
grep -qF -- "$contract" "$INSTALLER" || fail "missing rollback-baseline contract: $contract"
5563
done
64+
cleanup_function_line="$(line_of "$INSTALLER" 'cleanup_install_temps() {')"
65+
cleanup_trap_line="$(line_of "$INSTALLER" 'trap cleanup_install_temps EXIT')"
66+
rollback_tmp_line="$(line_of "$INSTALLER" ' rollback_tmp="$(mktemp -d "$dev_root/.rollback.XXXXXX")"')"
67+
commit_tmp_line="$(line_of "$INSTALLER" ' commit_tmp="$(mktemp "$artifacts/.commit.XXXXXX")"')"
68+
[ "$cleanup_function_line" -lt "$cleanup_trap_line" ] \
69+
&& [ "$cleanup_trap_line" -lt "$rollback_tmp_line" ] \
70+
&& [ "$cleanup_trap_line" -lt "$commit_tmp_line" ] \
71+
|| fail "temporary-path cleanup is not armed before temporary paths are created"
72+
for contract in \
73+
'"$dev_root"/.rollback.*) rm -rf -- "$rollback_tmp" || status=1' \
74+
'"$artifacts"/.commit.*) rm -f -- "$commit_tmp" || status=1' \
75+
' rollback_tmp=' \
76+
' commit_tmp='
77+
do
78+
grep -qF -- "$contract" "$INSTALLER" || fail "missing temporary cleanup contract: $contract"
79+
done
5680
if grep -Eq 'cp[[:space:]]+-R.*(canonical_cfg|/boot/config/plugins/ci-runner-farm)' "$INSTALLER"; then
5781
fail "installer recursively copies the persistent config/credential directory"
5882
fi
@@ -98,6 +122,22 @@ for resource in \
98122
do
99123
grep -qF -- "$resource" "$INSTALLER" || fail "rollback omits empty check: $resource"
100124
done
125+
for contract in \
126+
'legacy_name="$(docker inspect -f '\''{{.Name}}'\'' ci-runner-mirror 2>/dev/null)"' \
127+
'legacy_image="$(docker inspect -f '\''{{.Config.Image}}'\'' ci-runner-mirror 2>/dev/null)"' \
128+
'legacy_source="$(docker inspect -f '\''{{range .Mounts}}{{if eq .Destination "/var/lib/registry"}}{{.Source}}{{end}}{{end}}'\'' ci-runner-mirror 2>/dev/null)"' \
129+
'REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io' \
130+
'[ "$legacy_name" = /ci-runner-mirror ]' \
131+
'[ "$legacy_image" = registry:2 ]' \
132+
'[ "$legacy_source" = "$legacy_cache_root/registry-mirror" ]'
133+
do
134+
grep -qF -- "$contract" "$INSTALLER" || fail "rollback omits legacy mirror provenance: $contract"
135+
done
136+
legacy_name_line="$(line_of "$INSTALLER" 'legacy_name="$(docker inspect')"
137+
legacy_tuple_line="$(line_of "$INSTALLER" ' if [ "$legacy_name" = /ci-runner-mirror ]')"
138+
legacy_fail_line="$(line_of "$INSTALLER" ' fail "fixed-name registry mirror remains after Stop"')"
139+
[ "$legacy_name_line" -lt "$legacy_tuple_line" ] && [ "$legacy_tuple_line" -lt "$legacy_fail_line" ] \
140+
|| fail "an unrelated fixed-name mirror can still trigger rollback failure before provenance matches"
101141
rollback_block="$(awk '
102142
/^ssh -- "\$HOST" \/bin\/bash -s <<'"'"'REMOTE_ROLLBACK'"'"'$/ { emit=1 }
103143
emit { print }
@@ -120,6 +160,35 @@ fi
120160
# deploy/SSH commands. The remote heredocs are deliberately not executed.
121161
tmp="$(mktemp -d)"
122162
trap 'rm -rf "$tmp"' EXIT
163+
164+
# Execute the install transaction's actual EXIT-trap function against both
165+
# temporary path classes. An implicit set -e failure must retain its non-zero
166+
# status while removing the baseline directory and the artifact staging file.
167+
cleanup_function="$(awk '
168+
/^cleanup_install_temps\(\) \{$/ { emit=1 }
169+
emit { print }
170+
emit && /^}$/ { exit }
171+
' "$INSTALLER")"
172+
[ -n "$cleanup_function" ] || fail "could not extract temporary cleanup function"
173+
cleanup_root="$tmp/cleanup-probe"
174+
cleanup_artifacts="$cleanup_root/artifacts"
175+
cleanup_rollback="$cleanup_root/.rollback.ABC123"
176+
cleanup_commit="$cleanup_artifacts/.commit.ABC123"
177+
mkdir -p "$cleanup_rollback" "$cleanup_artifacts"
178+
printf 'partial artifact\n' >"$cleanup_commit"
179+
cleanup_probe="$tmp/cleanup-probe.sh"
180+
{
181+
printf '%s\n' '#!/usr/bin/env bash' 'set -euo pipefail'
182+
printf '%s\n' 'dev_root="$1"' 'artifacts="$2"' 'rollback_tmp="$3"' 'commit_tmp="$4"'
183+
printf '%s\n' "$cleanup_function"
184+
printf '%s\n' 'trap cleanup_install_temps EXIT' 'false'
185+
} >"$cleanup_probe"
186+
if bash "$cleanup_probe" "$cleanup_root" "$cleanup_artifacts" "$cleanup_rollback" "$cleanup_commit"; then
187+
fail "temporary cleanup probe lost the triggering failure status"
188+
fi
189+
[ ! -e "$cleanup_rollback" ] || fail "rollback temporary directory survived a transaction failure"
190+
[ ! -e "$cleanup_commit" ] || fail "artifact temporary file survived a transaction failure"
191+
123192
repo="$tmp/repo"
124193
mkdir -p "$repo/tmp/dev-package" "$tmp/bin"
125194
cp "$INSTALLER" "$repo/install-dev.sh"

0 commit comments

Comments
 (0)