2026-09-11 13:40:14 -04:00
#!/usr/bin/env bash
# Stubbed aws/curl tests for scripts/verify-cloudfront-release.sh.
set -euo pipefail
ROOT = " $( cd " $( dirname " $0 " ) /.. " && pwd ) "
VERIFY = " ${ ROOT } /scripts/verify-cloudfront-release.sh "
NEW_HASH = "1111111111111111111111111111111111111111111111111111111111111111"
2026-09-11 17:10:51 -04:00
INDEX_HTML = $'<!doctype html><html><head><script type="module" src="/assets/app.js"></script></head><body></body></html>\n'
2026-09-11 13:40:14 -04:00
INDEX_HASH = " $( printf '%s' " ${ INDEX_HTML } " | python3 -c 'import hashlib,sys; print(hashlib.sha256(sys.stdin.buffer.read()).hexdigest())' ) "
failures = 0
assert_exit( ) {
local name = " $1 " expected = " $2 " got = " $3 " log = " $4 "
if [ [ " ${ got } " != " ${ expected } " ] ] ; then
echo " FAIL: ${ name } : expected exit ${ expected } , got ${ got } " >& 2
sed -n '1,80p' " ${ log } " >& 2
failures = $(( failures + 1 ))
else
echo " PASS: ${ name } "
fi
}
make_stubs( ) {
local bin = " $1 "
mkdir -p " ${ bin } "
cat > " ${ bin } /aws " << 'AWS'
#!/usr/bin/env bash
set -euo pipefail
2026-09-18 14:30:20 -04:00
cat " ${ STUB_STATE } /distribution.json "
2026-09-11 13:40:14 -04:00
AWS
cat > " ${ bin } /curl " << 'CURL'
#!/usr/bin/env bash
set -euo pipefail
state_dir = " ${ STUB_STATE } "
method = "GET"
url = ""
dump = ""
output = ""
write_out = ""
args = ( " $@ " )
i = 0
while [ [ $i -lt ${# args [@] } ] ] ; do
arg = " ${ args [ $i ] } "
case " ${ arg } " in
-X) i = $(( i + 1 )) ; method = " ${ args [ $i ] } " ; ;
-D) i = $(( i + 1 )) ; dump = " ${ args [ $i ] } " ; ;
-o) i = $(( i + 1 )) ; output = " ${ args [ $i ] } " ; ;
-w) i = $(( i + 1 )) ; write_out = " ${ args [ $i ] } " ; ;
-H| --max-time| -s| -S| -f| -fsS| -sS) ; ;
http*) url = " ${ arg } " ; ;
esac
i = $(( i + 1 ))
done
if [ [ " ${ method } " = = "OPTIONS" ] ] ; then
[ [ -n " ${ dump } " ] ] && printf 'HTTP/1.1 204 No Content\nAccess-Control-Allow-Origin: https://dev.seahaven.com\n\n' > " ${ dump } "
[ [ -n " ${ write_out } " ] ] && printf '204'
exit 0
fi
if [ [ " ${ url } " = = *"/assets/" * ] ] ; then
[ [ -n " ${ dump } " ] ] && printf 'HTTP/1.1 200 OK\nCache-Control: public,max-age=31536000,immutable\n\n' > " ${ dump } "
2026-09-11 15:38:07 -04:00
if [ [ -f " ${ state_dir } /asset.js " ] ] ; then
body = " $( cat " ${ state_dir } /asset.js " ) "
else
body = 'const api="https://api.dev.seahaven.com/api";'
fi
[ [ -n " ${ output } " ] ] && printf '%s' " ${ body } " > " ${ output } "
[ [ -z " ${ output } " ] ] && printf '%s' " ${ body } "
2026-09-11 13:40:14 -04:00
exit 0
fi
[ [ -n " ${ dump } " ] ] && printf 'HTTP/1.1 200 OK\nCache-Control: no-cache,no-store,must-revalidate\n\n' > " ${ dump } "
if [ [ -n " ${ output } " ] ] ; then
2026-09-11 17:10:51 -04:00
cat " ${ state_dir } /index.html " > " ${ output } "
2026-09-11 13:40:14 -04:00
else
2026-09-11 17:10:51 -04:00
cat " ${ state_dir } /index.html "
2026-09-11 13:40:14 -04:00
fi
exit 0
CURL
chmod +x " ${ bin } /aws " " ${ bin } /curl "
}
dist_json( ) {
local status = " $1 " current_path = " $2 "
python3 -c ' import json,sys
status, path = sys.argv[ 1] , sys.argv[ 2]
print( json.dumps( {
"Distribution" : {
"Status" : status,
"DistributionConfig" : {
"Origins" : { "Items" : [
2026-09-18 14:30:20 -04:00
{ "Id" : "current" , "OriginPath" : path}
2026-09-11 13:40:14 -04:00
] }
}
}
} ) ) ' " ${ status } " " ${ current_path } "
}
2026-09-18 14:30:20 -04:00
# 1. Empty origin, then propagates (InProgress -> Deployed, hash already matches).
2026-09-11 13:40:14 -04:00
{
dir = " $( mktemp -d) "
make_stubs " ${ dir } /bin "
printf '%s' " ${ INDEX_HTML } " > " ${ dir } /index.html "
printf 'InProgress\n' > " ${ dir } /status "
cat > " ${ dir } /bin/aws " << AWS
#!/usr/bin/env bash
set -euo pipefail
status = "\$(cat " ${ dir } /status")"
2026-09-18 14:30:20 -04:00
python3 -c 'import json,sys; print(json.dumps({"Distribution":{"Status":sys.argv[1],"DistributionConfig":{"Origins":{"Items":[{"Id":"current","OriginPath":""}]}}}}))' "\${status}"
2026-09-11 13:40:14 -04:00
echo Deployed > " ${ dir } /status "
AWS
chmod +x " ${ dir } /bin/aws "
export STUB_STATE = " ${ dir } " PATH = " ${ dir } /bin: ${ PATH } "
2026-09-18 14:30:20 -04:00
export DISTRIBUTION_ID = "E2CWLM1AFB964P"
export EXPECTED_INDEX_SHA256 = " ${ INDEX_HASH } "
export SITE_URL = "https://dev.seahaven.com"
export API_URL = "https://api.dev.seahaven.com/api"
2026-09-11 13:40:14 -04:00
export BUDGET = 5 INTERVAL = 0
set +e
bash " ${ VERIFY } " > " ${ dir } /log.txt " 2>& 1
code = $?
set -e
2026-09-18 14:30:20 -04:00
assert_exit "empty-origin-then-propagates" 0 " ${ code } " " ${ dir } /log.txt "
2026-09-11 13:40:14 -04:00
rm -rf " ${ dir } "
}
2026-09-18 14:30:20 -04:00
# 2. Empty origin never propagates (Deployed, stale hash).
2026-09-11 13:40:14 -04:00
{
dir = " $( mktemp -d) "
make_stubs " ${ dir } /bin "
2026-09-18 14:30:20 -04:00
dist_json "Deployed" "" > " ${ dir } /distribution.json "
2026-09-11 13:40:14 -04:00
printf 'stale' > " ${ dir } /index.html "
export STUB_STATE = " ${ dir } " PATH = " ${ dir } /bin: ${ PATH } "
2026-09-18 14:30:20 -04:00
export DISTRIBUTION_ID = "E2CWLM1AFB964P"
export EXPECTED_INDEX_SHA256 = " ${ NEW_HASH } "
export SITE_URL = "https://dev.seahaven.com"
export API_URL = "https://api.dev.seahaven.com/api"
2026-09-11 13:40:14 -04:00
export BUDGET = 2 INTERVAL = 0
set +e
bash " ${ VERIFY } " > " ${ dir } /log.txt " 2>& 1
code = $?
set -e
2026-09-18 14:30:20 -04:00
assert_exit "empty-origin-never-propagates" 1 " ${ code } " " ${ dir } /log.txt "
2026-09-11 13:40:14 -04:00
grep -q "last observed" " ${ dir } /log.txt " || { echo "FAIL: timeout missing last observed state" >& 2; failures = $(( failures + 1 )) ; }
rm -rf " ${ dir } "
}
2026-09-18 14:30:20 -04:00
# 3. Non-empty origin path fails fast.
2026-09-11 13:40:14 -04:00
{
dir = " $( mktemp -d) "
make_stubs " ${ dir } /bin "
2026-09-18 14:30:20 -04:00
dist_json "Deployed" "/releases/deadbeef" > " ${ dir } /distribution.json "
2026-09-11 13:40:14 -04:00
printf '%s' " ${ INDEX_HTML } " > " ${ dir } /index.html "
export STUB_STATE = " ${ dir } " PATH = " ${ dir } /bin: ${ PATH } "
2026-09-18 14:30:20 -04:00
export DISTRIBUTION_ID = "E2CWLM1AFB964P"
export EXPECTED_INDEX_SHA256 = " ${ NEW_HASH } "
export SITE_URL = "https://dev.seahaven.com"
export API_URL = "https://api.dev.seahaven.com/api"
2026-09-11 13:40:14 -04:00
export BUDGET = 2 INTERVAL = 0
set +e
bash " ${ VERIFY } " > " ${ dir } /log.txt " 2>& 1
code = $?
set -e
2026-09-18 14:30:20 -04:00
assert_exit "nonempty-origin-path" 1 " ${ code } " " ${ dir } /log.txt "
grep -q "origin_path" " ${ dir } /log.txt " || { echo "FAIL: nonempty origin path did not name origin_path" >& 2; failures = $(( failures + 1 )) ; }
2026-09-11 13:40:14 -04:00
rm -rf " ${ dir } "
}
2026-09-18 14:30:20 -04:00
# 4. Never Deployed.
2026-09-11 13:40:14 -04:00
{
dir = " $( mktemp -d) "
make_stubs " ${ dir } /bin "
2026-09-18 14:30:20 -04:00
dist_json "InProgress" "" > " ${ dir } /distribution.json "
2026-09-11 13:40:14 -04:00
printf '%s' " ${ INDEX_HTML } " > " ${ dir } /index.html "
export STUB_STATE = " ${ dir } " PATH = " ${ dir } /bin: ${ PATH } "
2026-09-18 14:30:20 -04:00
export DISTRIBUTION_ID = "E2CWLM1AFB964P"
export EXPECTED_INDEX_SHA256 = " ${ NEW_HASH } "
export SITE_URL = "https://dev.seahaven.com"
export API_URL = "https://api.dev.seahaven.com/api"
2026-09-11 13:40:14 -04:00
export BUDGET = 2 INTERVAL = 0
set +e
bash " ${ VERIFY } " > " ${ dir } /log.txt " 2>& 1
code = $?
set -e
assert_exit "never-deployed" 1 " ${ code } " " ${ dir } /log.txt "
grep -q "last observed" " ${ dir } /log.txt " || { echo "FAIL: never-deployed missing last observed state" >& 2; failures = $(( failures + 1 )) ; }
rm -rf " ${ dir } "
}
2026-09-18 14:30:20 -04:00
# 5. Hash-matched Deployed release whose JS assets omit the baked API URL.
2026-09-11 15:38:07 -04:00
{
dir = " $( mktemp -d) "
make_stubs " ${ dir } /bin "
2026-09-18 14:30:20 -04:00
dist_json "Deployed" "" > " ${ dir } /distribution.json "
2026-09-11 15:38:07 -04:00
printf '%s' " ${ INDEX_HTML } " > " ${ dir } /index.html "
printf 'const x=1;' > " ${ dir } /asset.js "
export STUB_STATE = " ${ dir } " PATH = " ${ dir } /bin: ${ PATH } "
2026-09-18 14:30:20 -04:00
export DISTRIBUTION_ID = "E2CWLM1AFB964P"
export EXPECTED_INDEX_SHA256 = " ${ INDEX_HASH } "
export SITE_URL = "https://dev.seahaven.com"
export API_URL = "https://api.dev.seahaven.com/api"
2026-09-11 15:38:07 -04:00
export BUDGET = 2 INTERVAL = 0
set +e
bash " ${ VERIFY } " > " ${ dir } /log.txt " 2>& 1
code = $?
set -e
assert_exit "missing-baked-api-url" 1 " ${ code } " " ${ dir } /log.txt "
2026-09-18 14:30:20 -04:00
grep -q "baked API URL" " ${ dir } /log.txt " || { echo "FAIL: missing API URL did not name baked API URL" >& 2; failures = $(( failures + 1 )) ; }
2026-09-11 15:38:07 -04:00
rm -rf " ${ dir } "
}
2026-09-18 14:30:20 -04:00
# 6. Hash-matched Deployed release whose JS assets contain the staging API URL.
2026-09-11 15:38:07 -04:00
{
dir = " $( mktemp -d) "
make_stubs " ${ dir } /bin "
2026-09-18 14:30:20 -04:00
dist_json "Deployed" "" > " ${ dir } /distribution.json "
2026-09-11 15:38:07 -04:00
printf '%s' " ${ INDEX_HTML } " > " ${ dir } /index.html "
printf 'const api="https://api.staging.seahaven.com/api";' > " ${ dir } /asset.js "
export STUB_STATE = " ${ dir } " PATH = " ${ dir } /bin: ${ PATH } "
2026-09-18 14:30:20 -04:00
export DISTRIBUTION_ID = "E2CWLM1AFB964P"
export EXPECTED_INDEX_SHA256 = " ${ INDEX_HASH } "
export SITE_URL = "https://dev.seahaven.com"
export API_URL = "https://api.dev.seahaven.com/api"
2026-09-11 15:38:07 -04:00
export BUDGET = 2 INTERVAL = 0
set +e
bash " ${ VERIFY } " > " ${ dir } /log.txt " 2>& 1
code = $?
set -e
assert_exit "forbidden-staging-api-url" 1 " ${ code } " " ${ dir } /log.txt "
grep -q "forbidden URL api.staging.seahaven.com" " ${ dir } /log.txt " || { echo "FAIL: staging API URL did not name forbidden URL" >& 2; failures = $(( failures + 1 )) ; }
rm -rf " ${ dir } "
}
2026-09-11 13:40:14 -04:00
if [ [ " ${ failures } " -ne 0 ] ] ; then
echo " FAIL: ${ failures } verify-cloudfront-release cases failed " >& 2
exit 1
fi
echo "PASS: CloudFront release verify checks"