A version number is pushed once, and every build addresses its CSS differently
gates / gates (push) Failing after 44s
gates / gates (push) Failing after 44s
MEASURED FIRST (audits/app-page-2026-10-15b/P0/VERDICT.md). The tab bar rendered unstyled through
the public address for one reason, and it was not the box: exactly one guest runs 0.315.0 and it
runs the registry's current digest (8887343011d6, identical to the registry's). The floor is still
0.314.0, so nothing else could have taken it.
What it was, in four measured facts:
1. the stylesheet URL is /static/style.css?v={{.Version}} -> ?v=0.315.0 for all THREE different
0.315.0 builds (e66d466, fe0228c, db52f5a), the first of which had no .app-tabs rules at all;
2. the origin sends NO validator at all (ETag present = 0, Last-Modified present = 0), so a
cached copy cannot be revalidated - it can only expire;
3. Cloudflare caches that URL (cf-cache-status HIT, age climbing) and rewrites the browser TTL
from the origin's 3600 to 14400 - four hours;
4. the session's first request returned cf-cache-status EXPIRED, which only happens when the edge
holds an entry that has aged out.
Origin, edge and box now agree byte-for-byte. The stale object itself is gone - that first probe
forced its revalidation - and the REPORT says so rather than claiming a HIT nobody can reproduce.
THE FIX IS IN TWO PARTS, NEITHER OF WHICH IS PURGING A CACHE:
build.sh refuses to push a version that already exists, before building, for --push and
--multiarch. A registry that cannot be asked is a refusal too: proving the tag is new is the point,
and "I could not ask" is not that proof. Local builds are untouched - reusing a version while
iterating is normal. scripts/test_build_push_once.sh drives the real build.sh with a fake docker on
PATH over six cases; red-proved twice (check deleted -> a present tag builds and pushes; an
unreachable registry treated as absent -> two cases fail).
assetTag() now hashes version + GitCommit + BuildTime, and EVERY shell's stylesheet link uses it
(seven of the nine asked for ?v={{.Version}}; only the two stranger-facing share pages already had
it). It stays opaque and 8 hex, because the share pages are reached by a capability URL and naming
the build to whoever holds one is a gift to somebody hunting a known fault. Cache-Control is
unchanged: the new address is the fix, not a shorter cache.
The parity harness normalises the asset tag on BOTH sides of the comparison, as it already does for
the per-session CSRF token, so all 148 fixtures stay byte-identical on disk and stop depending on
which build rendered them. The same normalisation is applied at the second comparison site in
i18n_wiring_test.go, which had the same assumption.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117kRTSgs3rJWUFGxyoWN6Y
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
#!/bin/bash
|
||||
# A VERSION NUMBER IS PUSHED ONCE — the test for build.sh's registry check (v0.316.0).
|
||||
#
|
||||
# WHY IT EXISTS: 0.315.0 was built and pushed three times from three different commits. A box that
|
||||
# pulled between the first and the last runs different code under the same number and will never
|
||||
# fetch the fix, because to the box that number is already current. The check in build.sh is the
|
||||
# mechanism; this is the test that it convicts.
|
||||
#
|
||||
# HOW IT TESTS WITHOUT A REGISTRY: a fake `docker` is put first on PATH. Every case drives the REAL
|
||||
# build.sh, so the test cannot pass while the check has been deleted — which is the red-proof.
|
||||
# Nothing is ever pushed: the fake refuses `build` and `push` loudly, so a build that got past the
|
||||
# check would fail the test rather than reach the network.
|
||||
#
|
||||
# Run from controller/: bash scripts/test_build_push_once.sh
|
||||
set -u
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
BUILD_SH="$(dirname "$HERE")/build.sh"
|
||||
fails=0; ran=0
|
||||
|
||||
[[ -f "$BUILD_SH" ]] || { echo "FAIL: build.sh not found at $BUILD_SH"; exit 1; }
|
||||
|
||||
# A fake `docker` whose answer to `manifest inspect` is set by FAKE_MODE.
|
||||
make_fake_docker() {
|
||||
local dir="$1"
|
||||
mkdir -p "$dir"
|
||||
cat > "$dir/docker" <<'FAKE'
|
||||
#!/bin/bash
|
||||
case "$1 $2" in
|
||||
"manifest inspect")
|
||||
case "${FAKE_MODE}" in
|
||||
present) echo '{"schemaVersion":2}'; exit 0 ;;
|
||||
absent) echo "manifest unknown: manifest unknown" >&2; exit 1 ;;
|
||||
down) echo "Get \"https://gitea.dooplex.hu/v2/\": dial tcp: connection refused" >&2; exit 1 ;;
|
||||
denied) echo "unauthorized: authentication required" >&2; exit 1 ;;
|
||||
esac ;;
|
||||
"build "*|"buildx "*|"push "*)
|
||||
echo "FAKE-DOCKER-REACHED: $*" ; exit 0 ;;
|
||||
esac
|
||||
# anything else (version checks etc.) succeeds quietly
|
||||
exit 0
|
||||
FAKE
|
||||
chmod +x "$dir/docker"
|
||||
}
|
||||
|
||||
# Run build.sh with the fake docker, from a throwaway cwd, and capture everything.
|
||||
run_build() {
|
||||
local mode="$1"; shift
|
||||
local tmp; tmp="$(mktemp -d)"
|
||||
make_fake_docker "$tmp/bin"
|
||||
FAKE_MODE="$mode" PATH="$tmp/bin:$PATH" bash "$BUILD_SH" "$@" >"$tmp/out" 2>&1
|
||||
rc=$?
|
||||
out="$(cat "$tmp/out")"
|
||||
rm -rf "$tmp"
|
||||
return $rc
|
||||
}
|
||||
|
||||
check() {
|
||||
local name="$1" want_rc="$2" want_text="$3" forbid_text="${4:-}"
|
||||
ran=$((ran+1))
|
||||
if [[ "$rc" != "$want_rc" ]]; then
|
||||
fails=$((fails+1)); echo " FAIL $name: exit $rc, want $want_rc"
|
||||
echo "$out" | tail -6 | sed 's/^/ /'; return
|
||||
fi
|
||||
if [[ -n "$want_text" ]] && ! grep -qi -- "$want_text" <<<"$out"; then
|
||||
fails=$((fails+1)); echo " FAIL $name: output does not contain '$want_text'"
|
||||
echo "$out" | tail -6 | sed 's/^/ /'; return
|
||||
fi
|
||||
if [[ -n "$forbid_text" ]] && grep -qi -- "$forbid_text" <<<"$out"; then
|
||||
fails=$((fails+1)); echo " FAIL $name: output contains '$forbid_text', which must not happen"
|
||||
echo "$out" | tail -6 | sed 's/^/ /'; return
|
||||
fi
|
||||
echo " ok $name"
|
||||
}
|
||||
|
||||
echo "build.sh — a version number is pushed once"
|
||||
|
||||
# 1. The tag is already in the registry -> refuse, before building, and push nothing.
|
||||
run_build present 0.999.0 --push
|
||||
check "--push, tag present -> refuses" 1 "already exists in the registry" "FAKE-DOCKER-REACHED"
|
||||
|
||||
# 2. The tag is new -> say so and carry on INTO the build.
|
||||
# The exit code is deliberately not asserted: past the check, build.sh runs the real build steps,
|
||||
# which cannot complete in a test sandbox. What matters is that the check let it through, so the
|
||||
# assertion is its verdict line plus the ABSENCE of a refusal.
|
||||
run_build absent 0.999.0 --push
|
||||
check "--push, tag absent -> proceeds" "$rc" "is not present in the registry" "already exists in the registry"
|
||||
|
||||
# 3. --multiarch gets the same refusal (the task's edge case).
|
||||
run_build present 0.999.0 --multiarch
|
||||
check "--multiarch, tag present -> refuses" 1 "already exists in the registry" "FAKE-DOCKER-REACHED"
|
||||
|
||||
# 4. The registry cannot be asked -> refuse. "I could not ask" is not proof the tag is new.
|
||||
run_build down 0.999.0 --push
|
||||
check "--push, registry unreachable -> refuses" 1 "Could not establish whether" "FAKE-DOCKER-REACHED"
|
||||
|
||||
# 5. An auth failure is just as unanswered as a network failure.
|
||||
run_build denied 0.999.0 --push
|
||||
check "--push, auth failure -> refuses" 1 "Could not establish whether" "FAKE-DOCKER-REACHED"
|
||||
|
||||
# 6. A LOCAL build is untouched — reusing a version while iterating is the normal case, and the
|
||||
# check must not even run (no registry question is asked, so `present` must not refuse).
|
||||
run_build present 0.999.0
|
||||
check "local build, tag present -> not refused" 0 "" "already exists in the registry"
|
||||
|
||||
echo
|
||||
if [[ $fails -eq 0 ]]; then
|
||||
echo "all $ran cases behaved — a pushed version cannot be overwritten"
|
||||
exit 0
|
||||
fi
|
||||
echo "$fails of $ran cases FAILED"
|
||||
exit 1
|
||||
Reference in New Issue
Block a user