docs(auth): address authentication guide review

This commit is contained in:
2026-08-18 03:33:00 +02:00
parent f4f38717e1
commit 91925d64bf
12 changed files with 406 additions and 142 deletions
+107 -6
View File
@@ -1,7 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail
root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)
script_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)
root=$script_root
if [[ $# -gt 0 ]]; then
[[ $# -eq 2 && $1 == "--root" && -d $2 ]] || {
echo "usage: auth-docs-smoke.sh [--root DIRECTORY]" >&2
exit 2
}
root=$(cd "$2" && pwd -P)
fi
docs=(
"$root/docs/architecture/authentication.md"
"$root/docs/install/authentication-local.md"
@@ -18,6 +26,7 @@ docs=(
"$root/docs/index.md"
"$root/README.md"
"$root/PROJECT_STATE.md"
"$root/mkdocs.yml"
)
for path in "${docs[@]}"; do
@@ -36,21 +45,113 @@ required=(
"THT_AUTHENTIK_API_TOKEN"
"Remember me"
"oidc_mapped_group_missing"
"oidc_callback_failed"
"session.read_all"
"workspace.secrets.manage"
"auth.diagnostics.read"
)
for term in "${required[@]}"; do
rg -Fq "$term" "$corpus" || { echo "auth docs smoke: missing required term: $term" >&2; exit 1; }
done
if rg -n -i 'thothii-admin|thothctl[[:space:]]+auth' "$corpus"; then
canonical_compose='docker compose --env-file deploy/env/local.env -f compose.yaml -f deploy/compose.local.yaml up --build -d'
rg -Fxq "$canonical_compose" "$root/docs/install/local.md" || {
echo "auth docs smoke: missing canonical local Compose command" >&2
exit 1
}
if rg -n -F 'docker compose --env-file deploy/env/local.env +' "$corpus"; then
echo "auth docs smoke: noncanonical local Compose command" >&2
exit 1
fi
nav_count=$(awk 'index($0, "architecture/authentication.md") { count++ } END { print count + 0 }' "$root/mkdocs.yml")
[[ $nav_count == 1 ]] || {
echo "auth docs smoke: authentication navigation must appear exactly once" >&2
exit 1
}
python3 - "$root" <<'PY'
import pathlib
import re
import sys
root = pathlib.Path(sys.argv[1])
architecture = (root / "docs/architecture/authentication.md").read_text()
user_row = "| `user` | `session.use` |"
admin_row = (
"| `admin` | `session.use`, `session.read_all`, `session.manage_all`, `settings.manage`, "
"`workspace.manage`, `workspace.secrets.manage`, `pi.manage`, `auth.diagnostics.read` |"
)
if user_row not in architecture or admin_row not in architecture:
raise SystemExit("auth docs smoke: role-to-permission map is not exact")
diagnostic_heading = "## Diagnostics and ordering"
diagnostic_start = architecture.find(diagnostic_heading)
diagnostic_end = architecture.find("\n## ", diagnostic_start + len(diagnostic_heading))
diagnostic_section = architecture[diagnostic_start:diagnostic_end if diagnostic_end >= 0 else None]
match = re.search(r"```text\n([\s\S]*?)```", diagnostic_section)
expected_codes = [
"auth_ready",
"auth_config_incomplete",
"auth_config_invalid",
"auth_session_store_invalid",
"local_user_registry_invalid",
"local_admin_missing",
"oidc_secret_missing",
"oidc_discovery_unreachable",
"oidc_issuer_mismatch",
"oidc_jwks_unreachable",
"oidc_group_catalog_unreachable",
"oidc_group_catalog_unauthorized",
"oidc_mapped_group_missing",
"oidc_mapped_group_ambiguous",
"oidc_groups_claim_invalid",
"oidc_device_flow_unavailable",
]
actual_codes = [] if match is None else [line for line in match.group(1).splitlines() if line]
if actual_codes != expected_codes:
raise SystemExit("auth docs smoke: diagnostic code union is not exact")
for relative, language, forbidden, required in [
("docs/install/reverse-proxy-caddy.md", "caddyfile", "forward_auth", "forward_auth"),
("docs/install/reverse-proxy-nginx.md", "nginx", "auth_request", "auth_request"),
]:
source = (root / relative).read_text()
direct_start = source.find("## Direct ThothII-managed OIDC")
deprecated_start = source.find("## Deprecated upstream migration mode")
if direct_start < 0 or deprecated_start <= direct_start:
raise SystemExit(f"auth docs smoke: {relative} does not split direct and deprecated modes")
direct = source[direct_start:deprecated_start]
deprecated_end = source.find("\n## ", deprecated_start + 4)
deprecated = source[deprecated_start:deprecated_end if deprecated_end >= 0 else None]
blocks = re.findall(rf"```{language}\n([\s\S]*?)```", direct)
direct_code = "\n".join(blocks)
if "/api/auth/oidc/login" not in direct or "/api/auth/oidc/callback" not in direct:
raise SystemExit(f"auth docs smoke: {relative} omits unchanged public OIDC paths")
if re.search(rf"(?m)^\s*{forbidden}\b", direct_code):
raise SystemExit(f"auth docs smoke: {relative} applies external auth in direct OIDC mode")
deprecated_code = "\n".join(
re.findall(rf"```{language}\n([\s\S]*?)```", deprecated)
)
if not re.search(rf"(?m)^\s*{required}\b", deprecated_code):
raise SystemExit(f"auth docs smoke: {relative} omits scoped deprecated upstream auth")
PY
if rg -n -i --pcre2 '\bthothii-admin\b|\bthothctl\b[^\r\n]{0,256}\bauth\b' "$corpus"; then
echo "auth docs smoke: forbidden authentication CLI wording" >&2
exit 1
fi
if rg -n -i 'password[[:space:]]*[:=][[:space:]]*(?!<|YOUR|REPLACE|CHANGE|FILE|PROMPT)' --pcre2 "$corpus"; then
echo "auth docs smoke: plaintext password example" >&2
if rg -n -i --pcre2 -- '--password(?!-file)\b(?:[[:space:]]+|=)\S+' "$corpus"; then
echo "auth docs smoke: plaintext password option" >&2
exit 1
fi
if rg -n -i 'unmapped[^.]{0,100}(generate|produce|emit|cause)[^.]{0,100}(warning|warn)|unmapped[^.]{0,100}warning(s)?[[:space:]]+(are|is)[[:space:]]+emitted' "$corpus"; then
echo "auth docs smoke: misleading warning claim for unmapped groups" >&2
if rg -n -i --pcre2 '(?:^|[,{[:space:]])password[[:space:]]*:[[:space:]]*\S+|"password"[[:space:]]*:[[:space:]]*(?:"[^"]+"|[^,}[:space:]]+)' "$corpus"; then
echo "auth docs smoke: plaintext password field" >&2
exit 1
fi
if rg -n -i --pcre2 '(?:unmapped|additional|extra)[^.\r\n]{0,160}groups?[^.\r\n]{0,160}(?:generate|produce|emit|cause|trigger|raise|create|result)[^.\r\n]{0,160}(?:warnings?|alerts?|advisory|advisories|notices?|notifications?|noise)|(?:warnings?|alerts?|advisory|advisories|notices?|notifications?|noise)[^.\r\n]{0,160}(?:generate|produce|emit|cause|trigger|raise|create|result)[^.\r\n]{0,160}(?:unmapped|additional|extra)[^.\r\n]{0,160}groups?' "$corpus"; then
echo "auth docs smoke: misleading noise claim for unmapped groups" >&2
exit 1
fi