Files
mopac-discourse-go/smoke/smoke.sh
T
mrcharles f9cf30bc72 v0: stdlib-only Discourse client — categories/topics/posts + raw passthrough
Covers the MOPAC briefing/report surface (Redmine 495 Part A): category
list/create (create needs the admin-scoped key; current key 403s, typed
as ErrForbidden), topic create/list/latest/get, post create/update/get,
current-user identity probe, and a Do() JSON passthrough so unmodeled
endpoints need no client release. Key is env/constructor-only, never a
flag, never logged; errors classify via errors.Is. Fake-server unit
tests + containerized end-to-end smoke (redaction sweep included); live
reads verified against community.turnsys.com.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-08-29 06:12:22 -05:00

114 lines
4.3 KiB
Bash
Executable File

# End-to-end smoke for discourse-go: builds the CLI in the Docker
# builder, boots the FAKE Discourse in a container on 127.0.0.1:8610,
# drives the real binary from the host through env vars (0600 temp env
# file), asserts the happy paths + failure classes + redaction, and tears
# everything down. No live forum is ever contacted. Only exact container
# IDs spawned here are killed.
set -e
cd "$(dirname "$0")/.."
IMAGE="golang@sha256:e8c859f5632dcfde7b32d2012b4351728f6437930887c2f6a91ea242459e5514"
PORT=8610
SMOKE_KEY="smoke-key-do-not-use"
CID=""
cleanup() {
if [ -n "$CID" ]; then
docker rm -f "$CID" >/dev/null 2>&1 || true
fi
rm -rf .smoke
}
trap cleanup EXIT INT TERM
mkdir -p .smoke
umask 077
echo "--- build CLI (docker builder)"
docker run --rm -v "$PWD:/h" -w /h \
-u "$(id -u):$(id -g)" -e HOME=/tmp -e GOFLAGS=-buildvcs=false \
"$IMAGE" go build -o bin/discourse-go ./cmd/discourse-go
echo "--- boot fake Discourse (container, port $PORT)"
CID=$(docker run -d --rm \
-v "$PWD:/h" -w /h \
-u "$(id -u):$(id -g)" -e HOME=/tmp -e GOFLAGS=-buildvcs=false \
-p 127.0.0.1:$PORT:8610 \
"$IMAGE" go run ./smoke/fakediscourse -addr :8610)
# wait for the fake to answer (any HTTP response proves it is up)
wait_up() {
python3 - "$PORT" <<'PYEOF'
import sys, urllib.request, urllib.error
port = sys.argv[1]
req = urllib.request.Request('http://127.0.0.1:%s/session/current.json' % port,
headers={'Api-Key': 'probe', 'Api-Username': 'probe'})
try:
urllib.request.urlopen(req, timeout=2)
except urllib.error.HTTPError:
sys.exit(0) # got an HTTP answer: server is up
except Exception:
sys.exit(1) # not yet
sys.exit(0)
PYEOF
}
i=0
until [ -n "$CID" ] && [ "$(docker inspect -f '{{.State.Running}}' "$CID" 2>/dev/null)" = "true" ] && wait_up; do
i=$((i+1))
if [ "$i" -ge 60 ]; then
echo "smoke: fake server did not come up; logs:" >&2
docker logs "$CID" >&2 || true
exit 1
fi
sleep 1
done
# 0600 env file = the credential path the docs prescribe
ENVF=".smoke/env"
printf 'DISCOURSE_URL=http://127.0.0.1:%s\nDISCOURSE_API_KEY=%s\nDISCOURSE_API_USERNAME=smoker\n' \
"$PORT" "$SMOKE_KEY" > "$ENVF"
CLI() {
( set -a; . "$ENVF"; set +a; exec ./bin/discourse-go "$@" )
}
capture="$PWD/.smoke/out"
touch "$capture"
echo "--- whoami"
CLI whoami | tee -a "$capture" | grep -q '"username": "smoker"' || { echo "smoke: whoami failed" >&2; exit 1; }
echo "--- categories list"
CLI categories list | tee -a "$capture" | grep -q '"mopac-briefings"' || { echo "smoke: categories list failed" >&2; exit 1; }
echo "--- categories create + typed 404 check"
CLI categories create "Smoke Cat" -color 25AAE2 | tee -a "$capture" | grep -q '"slug": "smoke-cat"' || { echo "smoke: category create failed" >&2; exit 1; }
CLI raw POST /definitely/not/there -data '{}' 2>>"$capture" >>"$capture" || true
grep -q "not found" "$capture" || { echo "smoke: 404 class missing" >&2; exit 1; }
echo "--- topics create / list / post reply / update"
CLI topics create -title "Smoke Topic" -category 2 -raw "first body" | tee -a "$capture" | grep -q '"topic_id"' || { echo "smoke: topic create failed" >&2; exit 1; }
CLI topics list -category 2 | tee -a "$capture" | grep -q '"Smoke Topic"' || { echo "smoke: topics list failed" >&2; exit 1; }
CLI topics list -slug mopac-briefings | tee -a "$capture" | grep -q '"Smoke Topic"' || { echo "smoke: topics list by slug failed" >&2; exit 1; }
POST_ID=$(CLI posts create -topic 10 -raw "reply body" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')
CLI posts update "$POST_ID" -raw "edited body" -reason smoke | tee -a "$capture" | grep -q '"raw": "edited body"' || { echo "smoke: post update failed" >&2; exit 1; }
echo "--- raw passthrough"
CLI raw GET /latest.json | tee -a "$capture" | grep -q '"topic_list"' || { echo "smoke: raw GET failed" >&2; exit 1; }
echo "--- redaction: no key material in any captured output"
if grep -q "$SMOKE_KEY" "$capture"; then
echo "smoke: KEY LEAKED in output" >&2
exit 1
fi
echo "--- bad key: exit code 2 + typed error"
set +e
( set -a; . "$ENVF"; set +a; DISCOURSE_API_KEY=wrong-key exec ./bin/discourse-go whoami ) >"$PWD/.smoke/bad" 2>&1
code=$?
set -e
if [ "$code" -ne 2 ]; then echo "smoke: bad key exit=$code want 2" >&2; exit 1; fi
grep -q "HTTP 403" "$PWD/.smoke/bad" || { echo "smoke: typed error missing" >&2; exit 1; }
echo "smoke: OK"