shoc-frontend-new/scripts/test-verify-cloudfront-release.sh

237 lines
7.8 KiB
Bash
Raw Normal View History

#!/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"
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
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
cat "${STUB_STATE}/distribution.json"
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}"
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}"
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
cat "${state_dir}/index.html" > "${output}"
else
cat "${state_dir}/index.html"
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": [
{"Id": "current", "OriginPath": path}
]}
}
}
}))' "${status}" "${current_path}"
}
# 1. Empty origin, then propagates (InProgress -> Deployed, hash already matches).
{
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")"
python3 -c 'import json,sys; print(json.dumps({"Distribution":{"Status":sys.argv[1],"DistributionConfig":{"Origins":{"Items":[{"Id":"current","OriginPath":""}]}}}}))' "\${status}"
echo Deployed > "${dir}/status"
AWS
chmod +x "${dir}/bin/aws"
export STUB_STATE="${dir}" PATH="${dir}/bin:${PATH}"
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"
export BUDGET=5 INTERVAL=0
set +e
bash "${VERIFY}" > "${dir}/log.txt" 2>&1
code=$?
set -e
assert_exit "empty-origin-then-propagates" 0 "${code}" "${dir}/log.txt"
rm -rf "${dir}"
}
# 2. Empty origin never propagates (Deployed, stale hash).
{
dir="$(mktemp -d)"
make_stubs "${dir}/bin"
dist_json "Deployed" "" > "${dir}/distribution.json"
printf 'stale' > "${dir}/index.html"
export STUB_STATE="${dir}" PATH="${dir}/bin:${PATH}"
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"
export BUDGET=2 INTERVAL=0
set +e
bash "${VERIFY}" > "${dir}/log.txt" 2>&1
code=$?
set -e
assert_exit "empty-origin-never-propagates" 1 "${code}" "${dir}/log.txt"
grep -q "last observed" "${dir}/log.txt" || { echo "FAIL: timeout missing last observed state" >&2; failures=$((failures + 1)); }
rm -rf "${dir}"
}
# 3. Non-empty origin path fails fast.
{
dir="$(mktemp -d)"
make_stubs "${dir}/bin"
dist_json "Deployed" "/releases/deadbeef" > "${dir}/distribution.json"
printf '%s' "${INDEX_HTML}" > "${dir}/index.html"
export STUB_STATE="${dir}" PATH="${dir}/bin:${PATH}"
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"
export BUDGET=2 INTERVAL=0
set +e
bash "${VERIFY}" > "${dir}/log.txt" 2>&1
code=$?
set -e
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)); }
rm -rf "${dir}"
}
# 4. Never Deployed.
{
dir="$(mktemp -d)"
make_stubs "${dir}/bin"
dist_json "InProgress" "" > "${dir}/distribution.json"
printf '%s' "${INDEX_HTML}" > "${dir}/index.html"
export STUB_STATE="${dir}" PATH="${dir}/bin:${PATH}"
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"
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}"
}
# 5. Hash-matched Deployed release whose JS assets omit the baked API URL.
{
dir="$(mktemp -d)"
make_stubs "${dir}/bin"
dist_json "Deployed" "" > "${dir}/distribution.json"
printf '%s' "${INDEX_HTML}" > "${dir}/index.html"
printf 'const x=1;' > "${dir}/asset.js"
export STUB_STATE="${dir}" PATH="${dir}/bin:${PATH}"
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"
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"
grep -q "baked API URL" "${dir}/log.txt" || { echo "FAIL: missing API URL did not name baked API URL" >&2; failures=$((failures + 1)); }
rm -rf "${dir}"
}
# 6. Hash-matched Deployed release whose JS assets contain the staging API URL.
{
dir="$(mktemp -d)"
make_stubs "${dir}/bin"
dist_json "Deployed" "" > "${dir}/distribution.json"
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}"
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"
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}"
}
if [[ "${failures}" -ne 0 ]]; then
echo "FAIL: ${failures} verify-cloudfront-release cases failed" >&2
exit 1
fi
echo "PASS: CloudFront release verify checks"