fix(ci): hash the served index.html byte stream in CloudFront verify (SH-300) (#186)
Some checks failed
Frontend checks / Build and test (push) Has been cancelled
Frontend checks / governance (push) Has been cancelled
Frontend checks / Visual regression (push) Has been cancelled
Deploy dev content / Deploy shoc-frontend-new-dev through Terraform (push) Has been cancelled

Capturing the curl body in "$(...)" strips the trailing newline, so the
served sha256 never matched dist/index.html and every release and rollback
verify polled to the budget and failed. Hash the response stream directly
and give the test fixture a trailing newline so the suite covers it.
This commit is contained in:
Adam Moussa 2026-09-11 17:10:51 -04:00 • committed by GitHub
parent c30e8aa74b
commit 29aecff2bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 11 additions and 8 deletions

View file

@ -8,7 +8,9 @@ CURRENT="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-2-1"
PREVIOUS="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-1-1"
NEW_HASH="1111111111111111111111111111111111111111111111111111111111111111"
OLD_HASH="0000000000000000000000000000000000000000000000000000000000000000"
INDEX_HTML='<!doctype html><html><head><script type="module" src="/assets/app.js"></script></head><body></body></html>'
# Vite writes index.html with a trailing newline. Keep it in the fixture so
# the expected hash covers every served byte, exactly like dist/index.html.
INDEX_HTML=$'<!doctype html><html><head><script type="module" src="/assets/app.js"></script></head><body></body></html>\n'
INDEX_HASH="$(printf '%s' "${INDEX_HTML}" | python3 -c 'import hashlib,sys; print(hashlib.sha256(sys.stdin.buffer.read()).hexdigest())')"
failures=0
@ -75,12 +77,12 @@ if [[ "${url}" == *"/assets/"* ]]; then
[[ -z "${output}" ]] && printf '%s' "${body}"
exit 0
fi
body="$(cat "${state_dir}/index.html")"
# Serve index.html byte-for-byte, trailing newline included, like real curl.
[[ -n "${dump}" ]] && printf 'HTTP/1.1 200 OK\nCache-Control: no-cache,no-store,must-revalidate\n\n' > "${dump}"
if [[ -n "${output}" ]]; then
printf '%s' "${body}" > "${output}"
cat "${state_dir}/index.html" > "${output}"
else
printf '%s' "${body}"
cat "${state_dir}/index.html"
fi
exit 0
CURL

View file

@ -80,10 +80,11 @@ observe() {
last_status="$(printf '%s\n' "${parsed}" | sed -n '1p')"
last_paths="$(printf '%s\n' "${parsed}" | sed -n '2p' | tr '\037' ' ')"
last_path_ok="$(printf '%s\n' "${parsed}" | sed -n '3p')"
local body
body="$(curl -fsS --max-time 30 "${SITE_URL}/" || true)"
if [[ -n "${body}" ]]; then
last_hash="$(printf '%s' "${body}" | sha256_of)"
# Hash the response stream directly. Capturing the body in "$(...)" strips
# trailing newlines, so the hash never matched dist/index.html.
local hash
if hash="$(curl -fsS --max-time 30 "${SITE_URL}/" | sha256_of)" && [[ -n "${hash}" ]]; then
last_hash="${hash}"
else
last_hash="unreachable"
fi