lmjtfy.git / tools / check-hosts
check-hosts115 lines · 5.6 KB · raw
1#!/usr/bin/env bash
2# Checks a running Worker's host handling with curl (src/host.rs): what
3# `lmjtfy.fun` does with a repository's path, and the routes of
4# `code.lmjtfy.fun`, in each mode of the GIT_REDIRECT switch. Costs nothing:
5# no request here reaches Jev or Workers AI.
6#
7#   check-hosts home on  http://127.0.0.1:8795   a dev server as lmjtfy.fun, redirect on
8#   check-hosts home off http://127.0.0.1:8796   ... redirect off: the apex serves the code
9#   check-hosts code on  http://127.0.0.1:8797   a dev server as code.lmjtfy.fun, redirect on
10#   check-hosts code off http://127.0.0.1:8798
11#
12# The mode named here must be the one the server was started with: a server
13# in the other mode fails the checks.
14#
15# `wrangler dev` sends the Worker its first route's host whatever the client
16# says, so each host and mode is its own dev server, given the host it should
17# be and the var (the toml's default is "off"):
18#   wrangler dev --local --host lmjtfy.fun      --port 8795 --var GIT_REDIRECT:on
19#   wrangler dev --local --host lmjtfy.fun      --port 8796 --var GIT_REDIRECT:off
20#   wrangler dev --local --host code.lmjtfy.fun --port 8797 --var GIT_REDIRECT:on
21#   wrangler dev --local --host code.lmjtfy.fun --port 8798 --var GIT_REDIRECT:off
22# (a Host header on the request is overwritten, measured 2026-10-05). A
23# fifth (8799), with the var set to something else (`--var GIT_REDIRECT:ON`), is
24# checked as `bad`: it must behave as off.
25#
26# What it cannot check: a clone, a pull, or any page that reads GitHub need
27# the secret LMJTFY_GITHUB_TOKEN, which a local server lacks; it answers 503
28# (git) or 502 (a page), and that is what is asserted.
29set -uo pipefail
30
31which=${1:?home or code}
32mode=${2:?on, off or bad}
33base=${3:?the dev server, e.g. http://127.0.0.1:8795}
34# `bad` is a switch the Worker refuses: it must act as off.
35[[ $mode == bad ]] && mode=off
36[[ $mode == on || $mode == off ]] || { echo "on, off or bad"; exit 2; }
37failed=0
38
39# For a redirect, curl was not told to follow, so its target is the Location.
40location() {
41  curl -s -o /dev/null --max-time 60 -D - "$base$1" | tr -d '\r' | sed -n 's/^[Ll]ocation: //p'
42}
43expect() { # description, wanted status, method, path [, wanted location]
44  local status
45  status=$(curl -s -o /dev/null --max-time 60 -X "$3" -w '%{http_code}' "$base$4")
46  if [[ $status != "$2" ]]; then echo "FAIL $1: $3 $4 -> $status, wanted $2"; failed=1; return; fi
47  if [[ -n ${5:-} ]]; then
48    local at
49    at=$(location "$4")
50    if [[ $at != "$5" ]]; then echo "FAIL $1: $3 $4 -> Location $at, wanted $5"; failed=1; return; fi
51  fi
52  echo "ok   $1: $3 $4 -> $status${5:+ $5}"
53}
54
55repos=(lmjtfy jevcrates postjevsql jevsnes jevhooks jevstrudel)
56refs='/info/refs?service=git-upload-pack'
57
58case $which in
59  home)
60    if [[ $mode == on ]]; then
61      for repo in "${repos[@]}"; do
62        expect "$repo, git's first request" 308 GET "/$repo.git$refs" "https://code.lmjtfy.fun/$repo.git$refs"
63        expect "$repo, a page and its query" 308 GET "/$repo.git/apps/x/y.rs?raw&a=b" "https://code.lmjtfy.fun/$repo.git/apps/x/y.rs?raw&a=b"
64        expect "$repo, its front page" 308 GET "/$repo.git" "https://code.lmjtfy.fun/$repo.git"
65        expect "$repo, a POST is told, not sent on" 405 POST "/$repo.git/git-upload-pack"
66      done
67      expect "an unserved repository is not sent on" 404 GET "/whiskers.git$refs"
68    else
69      # Off: the apex serves the code itself, exactly as before the code host.
70      for repo in "${repos[@]}"; do
71        expect "$repo, a clone is served here (no token: 503)" 503 GET "/$repo.git$refs"
72        expect "$repo, its front page is served here" 200 GET "/$repo.git"
73        expect "$repo, a push is not served" 403 GET "/$repo.git/info/refs?service=git-receive-pack"
74      done
75      expect "an unserved repository" 404 GET "/whiskers.git$refs"
76    fi
77    expect "the site" 200 GET "/rules"
78    expect "the home page" 200 GET "/"
79    # The home page's clone command and link follow the switch, so it never
80    # names an address that is not live.
81    page=$(curl -s --max-time 60 "$base/")
82    if [[ $mode == on ]]; then
83      want='https://code.lmjtfy.fun/lmjtfy.git'
84      grep -qF "git clone --recurse-submodules $want" <<<"$page" && grep -qF "href=\"$want\"" <<<"$page" \
85        && echo "ok   the home page offers the code host" || { echo "FAIL the home page does not offer $want"; failed=1; }
86    else
87      want='https://lmjtfy.fun/lmjtfy.git'
88      if grep -qF "git clone --recurse-submodules $want" <<<"$page" && grep -qF "href=\"$want\"" <<<"$page" && ! grep -qF 'code.lmjtfy.fun' <<<"$page"; then
89        echo "ok   the home page offers the apex and does not name the code host"
90      else
91        echo "FAIL the home page should offer $want and not name code.lmjtfy.fun"; failed=1
92      fi
93    fi
94    ;;
95  code)
96    expect "the front page" 200 GET "/"
97    for repo in "${repos[@]}"; do
98      expect "$repo, its front page" 200 GET "/$repo.git"
99      expect "$repo, a clone without the token" 503 GET "/$repo.git$refs"
100      expect "$repo, a push is not served" 403 GET "/$repo.git/info/refs?service=git-receive-pack"
101    done
102    expect "an unserved repository" 404 GET "/whiskers.git$refs"
103    expect "the code's picture" 200 GET "/card.png?code=main&repo=lmjtfy.git"
104    expect "a question's picture is the archive's" 404 GET "/card.png?q=x"
105    expect "an icon" 200 GET "/icons/file-rust.png"
106    for path in /ask /gate /rate /seen /feed /live /rules /rules.svg /datastar.js /live.js; do
107      expect "no $path here" 404 GET "$path"
108    done
109    expect "no asking here" 405 POST "/ask"
110    ;;
111  *) echo "home or code"; exit 2 ;;
112esac
113
114if ((failed)); then echo "FAILED"; exit 1; fi
115echo "all ok"