Files
felhom.eu/documentation/audits/i18n-slice2-2026-09-18/C/live/probeC.sh
T
admin 95c10954ae
gates / gates (push) Successful in 23s
docs: localisation slice 2 CLOSED (controller v0.254.0) — R-577, R-578, and a probe rule
10-localisation.md §10.3: the saved notes follow the box language at write time, with the
one-night consequence stated rather than hidden; the globe, and the table of WHO reads which
page and where its globe posts — getting that wrong makes the button do nothing, which it did
on /recovery until the live probe found it. Decision 6 superseded a second time; decision 8
(a claim carries the visitor's language) recorded. Decision 5 of §11's anonymous-surface line:
changing what a VISITOR reads is within what an anonymous request may do; changing anything the
household owns is not, and POST /lang can do only the first.

R-578 — the deadlock, and why it is a row rather than a fixed bug: UpdateOffboxStatus holds the
settings write lock while running its callback, boxLang() wants the read lock, sync.RWMutex is
not reentrant. On a real box an off-site run would have hung FOREVER holding that lock. The
symptom was a test suite going from 8 minutes to a 25-minute timeout. Fixed and guarded, but the
guard covers one package and three helper names; the class needs a gate.

R-577 — a guest share visitor still has no way to pick a language, and the household's setting
is the wrong default for a stranger. Deliberately left, pinned by a test, and the operator's to
decide because it is a promise the share feature makes.

.claude/rules/live-probes.md, unconditional: never send a deploy request for an app that is not
installed, not even expecting a refusal — the endpoint accepts first and validates later. Two
sessions made that mistake in two days, the second WITH a prompt line forbidding it. A prompt is
read once; a rule file is loaded every session.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-18 14:31:49 +02:00

32 lines
3.6 KiB
Bash

#!/bin/bash
# Release C probe. Every request below either reads a page or sets a display cookie. Nothing is
# installed, created, formatted or deleted; no deploy endpoint is touched at all (.claude/rules/live-probes.md).
IP=172.17.0.2:8080
H="Host: felhom.enkisfelhom.hu"
PW=$(cat /tmp/.felhompw); J=/tmp/pj.txt; rm -f $J /tmp/vj.txt
echo "##### A — NO SESSION: the visitor's own language"
echo -n " settings.json language before: "; grep -o '"language": *"[a-z]*"' /var/lib/felhom/docker/volumes/felhom-controller-data/_data/data/settings.json 2>/dev/null || echo "(no language key yet = hu)"
echo -n " /login with no cookie -> html lang="; curl -s -H "$H" "http://$IP/login" | grep -o '<html lang="[a-z]*"' | head -1
echo -n " globe present on /login -> "; curl -s -H "$H" "http://$IP/login" | grep -c 'class="shell-lang"'
echo -n " POST /lang lang=en back=/login -> "; curl -s -c /tmp/vj.txt -H "$H" -o /dev/null -w "%{http_code} " -X POST "http://$IP/lang" --data-urlencode "lang=en" --data-urlencode "back=/login"; grep -o 'felhom_lang[[:space:]]*[a-z]*' /tmp/vj.txt | head -1
echo -n " /login WITH the cookie -> html lang="; curl -s -b /tmp/vj.txt -H "$H" "http://$IP/login" | grep -o '<html lang="[a-z]*"' | head -1
echo -n " and an English phrase -> "; curl -s -b /tmp/vj.txt -H "$H" "http://$IP/login" | grep -c 'Forgot password'
echo -n " settings.json language after: "; grep -o '"language": *"[a-z]*"' /var/lib/felhom/docker/volumes/felhom-controller-data/_data/data/settings.json 2>/dev/null || echo "(no language key yet = hu)"
echo -n " POST /lang lang=xx -> "; curl -s -H "$H" -o /dev/null -w "%{http_code}\n" -X POST "http://$IP/lang" --data-urlencode "lang=xx" --data-urlencode "back=/login"
echo -n " POST /lang back=//evil -> "; curl -s -H "$H" -o /dev/null -w "%{redirect_url}\n" -X POST "http://$IP/lang" --data-urlencode "lang=en" --data-urlencode "back=//evil.example/x" 2>/dev/null | sed 's|http://[^/]*||'
echo -n " /claim and /recovery globes: "; for P in /claim /recovery; do echo -n "$P=$(curl -s -H "$H" "http://$IP$P" | grep -c 'class=\"shell-lang\"') "; done; echo
echo "##### B — WITH A SESSION: the household's own setting, cookie NOT read"
curl -s -c $J -H "$H" "http://$IP/login" -o /tmp/lg.html
CSRF=$(grep -o 'name="_csrf" value="[^"]*"' /tmp/lg.html | head -1 | sed 's/.*value="//;s/"//')
SESS=$(curl -s -b $J -H "$H" -D - -o /dev/null -X POST "http://$IP/login" --data-urlencode "password=$PW" --data-urlencode "_csrf=$CSRF" | grep -i '^set-cookie: felhom_session' | head -1 | sed 's/[Ss]et-[Cc]ookie: //;s/;.*//')
[ -z "$SESS" ] && { echo "LOGIN FAILED"; exit 1; }
LANGC=$(grep -o 'felhom_lang[[:space:]]*[a-z]*' /tmp/vj.txt | head -1 | awk '{print $2}')
echo -n " /launcher with session + the en cookie -> html lang="
curl -s -H "$H" -H "Cookie: $SESS; felhom_lang=$LANGC" "http://$IP/launcher" | grep -o '<html lang="[a-z]*"' | head -1
echo -n " the footer: version, globe, sign-out in order -> "
curl -s -H "$H" -H "Cookie: $SESS" "http://$IP/launcher" | grep -o 'class="sidebar-footer".*logout-link' | grep -o 'class="version"\|class="lang-globe"\|class="logout-link"' | tr '\n' ' '; echo
echo -n " the OLD text links are gone -> lang-switch-btn count = "
curl -s -H "$H" -H "Cookie: $SESS" "http://$IP/launcher" | grep -c 'lang-switch-btn'
echo "##### C — the saved notes, as they stand on this box"
grep -o '"last_warning": *"[^"]\{0,80\}' /var/lib/felhom/docker/volumes/felhom-controller-data/_data/data/settings.json 2>/dev/null | head -2; grep -o '"last_error": *"[^"]\{0,80\}' /var/lib/felhom/docker/volumes/felhom-controller-data/_data/data/settings.json 2>/dev/null | head -2