Something went wrong. Try again.
Identities for entities did.bot
agent llm did
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227#!/usr/bin/env bash# Tests scripts/publish-site.sh without ever touching real AWS: fake `aws` and# `tofu` binaries go first on PATH, so every check here runs against what# publish-site.sh would have done rather than against a real bucket and a real# distribution.## What is worth a real test rather than a read-through:## 1. Without working credentials it refuses, before uploading anything.# 2. A first publish, before the stack exists, says how to create it rather# than failing inside the aws CLI.# 3. A build tree with no 404.html is refused before anything is uploaded:# the distribution answers every miss with that page (see# infra/site/main.tf), so a tree without one is not publishable.# 4. A dry run plans and writes nothing — no `s3 cp`, no `tofu apply`, no# invalidation.# 5. --publish uploads the tree under `releases/<sha>/`, hands that same sha# to `tofu apply`, waits for the distribution, and only then invalidates.# The order is the point: an invalidation issued before the config lands# re-caches the tree it was meant to clear.# 6. The upload is two passes, and the content-addressed one is the pass# carrying the immutable Cache-Control.## Usage: scripts/test-publish-site.shset -euo pipefail
cd "$(dirname "$0")/.."
workdir="$(mktemp -d)"# A previous real build's site/dist/ is not this test's to destroy: it is# moved aside for the duration and always restored, pass or fail, so running# this alongside `scripts/build-site.sh` (as the site-build and# publish-site-tests prek hooks both do, in the same `prek run --all-files`)# never leaves a real build silently replaced by this test's stub tree.dist_backup="$workdir/dist-backup"if [ -d site/dist ]; then mv site/dist "$dist_backup"firestore_dist() { rm -rf site/dist if [ -d "$dist_backup" ]; then mv "$dist_backup" site/dist fi rm -rf "$workdir"}trap restore_dist EXIT
log="$workdir/calls.log": >"$log"
# Minimal stand-ins for the two CLIs. Every invocation is appended to $log# verbatim, so the assertions below read as "was this command issued, and in# what order" checks. `creds` toggles whether the credential probe succeeds.cat >"$workdir/aws" <<EOF#!/usr/bin/env bashecho "aws \$@" >>"$log"case "\$1 \$2" in "sts get-caller-identity") if [ -n "\${FAKE_AWS_NO_CREDS:-}" ]; then echo "Unable to locate credentials" >&2 exit 255 fi echo "arn:aws:sts::000000000000:assumed-role/test/test" ;; "s3api head-bucket") if [ -n "\${FAKE_AWS_NO_BUCKET:-}" ]; then exit 254 fi ;; "cloudfront create-invalidation") echo "ITESTINVALIDATION" ;;esacexit 0EOFcat >"$workdir/tofu" <<EOF#!/usr/bin/env bashecho "tofu \$@" >>"$log"for arg in "\$@"; do if [ "\$arg" = "output" ]; then echo "ETESTDISTRIBUTION" fidoneexit 0EOFchmod +x "$workdir/aws" "$workdir/tofu"
export PATH="$workdir:$PATH"
# Fake a build output rather than running the real (slow) build.seed_dist() { rm -rf site/dist mkdir -p site/dist/_astro site/dist/features echo "<html></html>" >site/dist/index.html echo "<html>404</html>" >site/dist/404.html echo "<html></html>" >site/dist/features/index.html echo "body{}" >site/dist/_astro/fake.hash.css}seed_dist
status=0
fail() { echo "FAIL: $1" >&2 status=1}
echo "=== a failing credential check is refused, before any upload ===" >&2: >"$log"if FAKE_AWS_NO_CREDS=1 scripts/publish-site.sh --skip-build >"$workdir/out" 2>&1; then fail "publish should have failed with no credentials"elif ! grep -q "credential check failed" "$workdir/out"; then fail "the refusal did not say the credential check failed" cat "$workdir/out" >&2fiif grep -q '^aws s3 sync' "$log"; then fail "the tree was uploaded despite the credential check failing"fi
echo "=== a first publish, with no bucket yet, says how to create it ===" >&2: >"$log"if FAKE_AWS_NO_BUCKET=1 scripts/publish-site.sh --skip-build >"$workdir/out" 2>&1; then fail "publish should have failed with no bucket to upload to"elif ! grep -q "tofu -chdir=infra/site apply" "$workdir/out"; then fail "the refusal did not say how to create the stack" cat "$workdir/out" >&2fiif grep -q '^aws s3 sync' "$log"; then fail "the tree was uploaded despite the bucket not existing"fi
echo "=== a tree with no 404.html is refused, before any upload ===" >&2: >"$log"rm site/dist/404.htmlif scripts/publish-site.sh --skip-build >"$workdir/out" 2>&1; then fail "publish should have failed with no 404.html in the tree"elif ! grep -q "404.html" "$workdir/out"; then fail "the refusal did not name 404.html" cat "$workdir/out" >&2fiif grep -q '^aws s3 sync' "$log"; then fail "the tree was uploaded despite it carrying no 404.html"fiseed_dist
echo "=== --dry-run plans and writes nothing ===" >&2: >"$log"if ! scripts/publish-site.sh --skip-build --dry-run >"$workdir/out" 2>&1; then fail "the dry run should succeed against the stubs" cat "$workdir/out" >&2fiif ! grep -q "dry run" "$workdir/out"; then fail "the dry run did not say it was a dry run"fiif ! grep -q '^tofu -chdir=infra/site plan' "$log"; then fail "the dry run did not plan the stack" cat "$log" >&2fiif [ "$(grep -c -- '^aws s3 sync .*--dryrun' "$log" || true)" -ne 2 ]; then fail "the dry run did not rehearse both upload passes" cat "$log" >&2fiif grep -qE '^tofu -chdir=infra/site apply|create-invalidation' "$log"; then fail "the dry run applied or invalidated" cat "$log" >&2fi
echo "=== a plain run uploads the tree, flips the origin, then invalidates ===" >&2: >"$log"if ! scripts/publish-site.sh --skip-build >"$workdir/out" 2>&1; then fail "a plain run should succeed against the stubs" cat "$workdir/out" >&2fi
uploads="$(grep -c '^aws s3 sync' "$log" || true)"if [ "$uploads" -ne 2 ]; then fail "expected two upload passes (default caching, then immutable), saw $uploads" cat "$log" >&2fiif grep -q -- '--dryrun' "$log"; then fail "a plain run rehearsed the upload instead of making it"fi
# The release is the commit, and the whole tree lands under that one prefix:# this is what makes the apply below a pointer move onto a finished tree# rather than onto a bucket half-rewritten.release="$(git rev-parse --short=12 HEAD)"if [ -n "$(git status --porcelain --untracked-files=no)" ]; then release="${release}-dirty"fiif [ "$(grep -c "s3://did-bot-site/releases/${release}" "$log" || true)" -ne "$uploads" ]; then fail "not every upload pass went to releases/${release}" cat "$log" >&2fiif ! grep -q "tofu -chdir=infra/site apply -var release_sha=${release}" "$log"; then fail "the apply did not carry the sha the tree was uploaded under" cat "$log" >&2fi
if ! grep -q '^aws cloudfront wait distribution-deployed' "$log"; then fail "the publish did not wait for the distribution to deploy"fiapply_line="$(grep -n 'tofu -chdir=infra/site apply' "$log" | head -1 | cut -d: -f1)"wait_line="$(grep -n 'cloudfront wait distribution-deployed' "$log" | head -1 | cut -d: -f1)"invalidate_line="$(grep -n 'cloudfront create-invalidation' "$log" | head -1 | cut -d: -f1)"if [ -z "$invalidate_line" ]; then fail "the publish did not invalidate the distribution"elif [ "$apply_line" -gt "$wait_line" ] || [ "$wait_line" -gt "$invalidate_line" ]; then fail "expected apply, then wait, then invalidate; saw $apply_line, $wait_line, $invalidate_line" cat "$log" >&2fi
# The content-addressed pass may be kept forever; the pass beside it may not,# or a reader holds a stale page long after the invalidation that cleared it.immutable="$(grep '^aws s3 sync' "$log" | grep -c -- '--cache-control public, max-age=31536000, immutable' || true)"if [ "$immutable" -ne 1 ]; then fail "expected exactly one immutable upload pass, saw $immutable" cat "$log" >&2fiif ! grep '^aws s3 sync' "$log" | grep -- '--cache-control' | grep -q -- '--include _astro/\*'; then fail "the immutable pass does not name the content-addressed paths" cat "$log" >&2fi
if [ "$status" -eq 0 ]; then echo "test-publish-site: ok" >&2fiexit "$status"