fix(ci): confine the sweep self-test to its own run
CI / verify (pull_request) Successful in 1m10s
CI / infrastructure-smoke (pull_request) Successful in 42s
CI / package-release (pull_request) Successful in 49s
CI / migration-smoke (pull_request) Successful in 2m21s
CI / image-build (pull_request) Successful in 59s
CI / deploy-smoke (same-origin) (pull_request) Successful in 52s
CI / deploy-smoke (split) (pull_request) Successful in 2m35s
CI / package-publication (pull_request) Successful in 1m3s

scripts/test-ci-sweep.sh proves the stale sweep by running
`ci-sweep.sh --stale --max-age-seconds 0` on the runner's shared Docker
daemon. With a zero threshold that removes every `ekklesia-ci-` stack on
the daemon, not just the test's own: any job running at that moment
loses its containers, networks, and volumes. It reported "CI sweep
checks passed" while doing it. Core's infrastructure-smoke job runs the
self-test on every run, and twice tore down Signage's integration stack
mid-scenario (Zayin/Signage run 288: its first attempt, and the second
one during connectivity-blip).

`ci-sweep.sh --stale` now takes `--prefix P`, which narrows the sweep to
stacks whose names begin with P and must itself begin with the CI
prefix, so it can only narrow a sweep, never widen one. The self-test
confines every stale sweep to its own fake run and proves that another
run's stack survives even the zero threshold. The workflow's own sweeps
are unchanged.

Regression: a bystander stack from another run in the self-test, and a
Docker-free guard that every stale sweep in the self-test is confined
and the workflow's keep the default threshold.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ekklesia
2026-10-13 22:46:38 -05:00
co-authored by Claude Opus 5.5
parent 437720f228
commit 94fa7a17a8
3 changed files with 60 additions and 7 deletions
+14 -2
View File
@@ -5,6 +5,11 @@
# bash scripts/ci-sweep.sh --stale [--max-age-seconds N] any CI stack older than N (default 3 h)
# bash scripts/ci-sweep.sh --job this job's own stacks, at any age
#
# `--stale --prefix P` narrows the sweep to stacks whose names begin with P, which must itself begin
# with the CI prefix: it can only ever narrow a sweep, never widen one. scripts/test-ci-sweep.sh
# confines its short thresholds with it, because the daemon is shared and another job's live stack
# may be on it right now.
#
# Every CI script already removes its own stack in an EXIT trap, but a trap never runs when the runner
# kills the job container: a cancelled or superseded job (the server honours `concurrency`), or
# the runner's own time limit. So each workflow job that starts stacks ends with `--job` in an
@@ -31,9 +36,10 @@ source "$repository_root/scripts/lib/ci-project.sh"
compose_label="com.docker.compose.project"
mode=""
max_age_seconds="${EKKLESIA_CI_SWEEP_MAX_AGE_SECONDS:-10800}"
narrow_prefix=""
usage() {
echo "usage: ci-sweep.sh --stale [--max-age-seconds N] | --job" >&2
echo "usage: ci-sweep.sh --stale [--max-age-seconds N] [--prefix P] | --job" >&2
exit 2
}
@@ -48,11 +54,17 @@ while (($# > 0)); do
max_age_seconds="$2"
shift
;;
--prefix)
[[ "${2:-}" == "$EKKLESIA_CI_PREFIX"?* ]] || usage
narrow_prefix="$2"
shift
;;
*) usage ;;
esac
shift
done
[[ -n "$mode" ]] || usage
[[ -z "$narrow_prefix" || "$mode" == stale ]] || usage
if [[ "$mode" == job ]]; then
[[ -n "${GITHUB_RUN_ID:-}" ]] || {
@@ -62,7 +74,7 @@ if [[ "$mode" == job ]]; then
prefix="$(ci_job_prefix)"
cutoff=""
else
prefix="$EKKLESIA_CI_PREFIX"
prefix="${narrow_prefix:-$EKKLESIA_CI_PREFIX}"
cutoff="$(($(date +%s) - max_age_seconds))"
fi