docs: explain per-installation DWH access

This commit is contained in:
User
2026-08-21 03:58:50 +02:00
parent d0f7e0497d
commit 7b9b8b308d
14 changed files with 551 additions and 0 deletions
+77
View File
@@ -0,0 +1,77 @@
#!/usr/bin/env bash
set -euo pipefail
root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)
verify="$root/scripts/verify-dwh-auth-docs.sh"
temp_root=
report_pass() {
printf 'case=%s status=PASS\n' "$1"
}
report_fail() {
printf 'case=%s status=FAIL\n' "$1" >&2
exit 1
}
cleanup() {
if [[ "$temp_root" == /tmp/thothii-dwh-auth-docs.* && -d "$temp_root" ]]; then
rm -rf -- "$temp_root"
fi
}
trap cleanup EXIT
[[ -x "$verify" ]] || report_fail verifier_missing
temp_root=$(mktemp -d /tmp/thothii-dwh-auth-docs.XXXXXXXX) || report_fail fixture_root
fixture_root="$temp_root/fixture"
mkdir -p "$fixture_root/docs/install" "$fixture_root/docs/operations" \
"$fixture_root/docs/testing/evidence" "$fixture_root/scripts"
for relative in \
docs/install/dwh-auth-server.md \
docs/install/dwh-auth-client-enrollment.md \
docs/install/dwh-auth-tls.md \
docs/operations/psd-dwh-auth-rollout.md \
docs/testing/dwh-auth-manual-acceptance.md \
docs/testing/evidence/psd-dwh-auth-rollout-report-template.md \
docs/install/local-workspace-registry.md \
docs/install/server-workspace-registry.md \
docs/install/psd-workspace-setup.md \
docs/guida-utente.md \
docs/index.md \
mkdocs.yml; do
mkdir -p "$fixture_root/$(dirname "$relative")"
cp "$root/$relative" "$fixture_root/$relative"
done
cp -a "$root/docs/." "$fixture_root/docs/"
"$verify" --root "$fixture_root" || report_fail positive_source
report_pass positive_source
expect_rejected() {
local name=$1 target=$2 addition=$3
local case_root="$temp_root/$name"
cp -a "$fixture_root" "$case_root"
printf '\n%s\n' "$addition" >>"$case_root/$target"
if "$verify" --root "$case_root" >/dev/null 2>&1; then
report_fail "$name"
fi
report_pass "$name"
}
# Build synthetic only-in-fixture text at runtime: it is never a provisioned credential.
fake_key="thtdwh_v1.$(printf 'A%.0s' {1..16}).$(printf 'A%.0s' {1..43})"
fake_digest="$(printf 'A%.0s' {1..43})"
expect_rejected credential_literal docs/install/dwh-auth-client-enrollment.md "$fake_key"
expect_rejected credential_digest_literal docs/testing/evidence/psd-dwh-auth-rollout-report-template.md "secret_sha256: $fake_digest"
expect_rejected curl_insecure docs/install/dwh-auth-tls.md 'curl -k https://example.invalid/dwh/rpc/ping'
expect_rejected tls_disabled docs/install/dwh-auth-tls.md 'verify_tls=false'
expect_rejected secret_in_environment docs/install/dwh-auth-client-enrollment.md "DWH_API_KEY=$fake_key"
expect_rejected secret_in_argv docs/install/dwh-auth-client-enrollment.md "curl -H 'X-API-Key: $fake_key' https://example.invalid/dwh/rpc/ping"
expect_rejected world_readable_secret docs/install/dwh-auth-server.md 'chmod 0644 /root/dwh-auth-provision/client.key'
expect_rejected raw_nginx_capture docs/operations/psd-dwh-auth-rollout.md 'nginx -T > /tmp/nginx-full.conf'
expect_rejected compose_coupling docs/install/dwh-auth-server.md 'docker compose up dwh-auth'
report_pass summary
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
set -euo pipefail
root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)
if [[ $# -gt 0 ]]; then
[[ $# -eq 2 && $1 == --root && -d $2 ]] || { echo 'usage: verify-dwh-auth-docs.sh [--root DIRECTORY]' >&2; exit 2; }
root=$(cd "$2" && pwd -P)
fi
python3 - "$root" <<'PY'
import pathlib, re, sys
root = pathlib.Path(sys.argv[1])
docs = {
"server": "docs/install/dwh-auth-server.md",
"client": "docs/install/dwh-auth-client-enrollment.md",
"tls": "docs/install/dwh-auth-tls.md",
"rollout": "docs/operations/psd-dwh-auth-rollout.md",
"manual": "docs/testing/dwh-auth-manual-acceptance.md",
"evidence": "docs/testing/evidence/psd-dwh-auth-rollout-report-template.md",
"local": "docs/install/local-workspace-registry.md",
"server_registry": "docs/install/server-workspace-registry.md",
"psd": "docs/install/psd-workspace-setup.md",
"guide": "docs/guida-utente.md",
"index": "docs/index.md",
"nav": "mkdocs.yml",
}
text = {}
for label, relative in docs.items():
path = root / relative
if not path.is_file():
raise SystemExit(f"dwh-auth docs: missing {relative}")
text[label] = path.read_text(encoding="utf-8")
requirements = {
"server": ["/var/lib/dwh-auth", "root:dwh-auth", "2750", ".writer.lock", "0640", "/run/dwh-auth/verify.sock", "0660", "systemd", "key create", "key list", "key status", "key revoke", "check", "backup", "rollback", "disinstallazione", "rest_api", "postgres_direct", "ssh_tunnel"],
"client": ["Workspace management", "Save runtime secrets", "API_KEY_FILE", "THT_WS_PSD_CLINICAL_DWH_API_KEY_FILE", "TLS_CA_FILE", "/rpc/ping", "rest_api", "postgres_direct", "ssh_tunnel", "401", "503", "rotazione", "revoca"],
"tls": ["self-issued", ".it", ".com", "SAN", "TLS_CA_FILE", "openssl x509 -noout -fingerprint -sha256", "fuori banda", "rinnovo", "curl -k"],
"rollout": ["Task 9", "Task 10", "IN_DISCUSSION", "postgres_direct", "rest_api", "legacy-shared", "nginx -t", "204", "401", "503", "Qdrant", "Ollama", "rollback"],
"manual": ["204", "401", "503", "TLS", "registry", "postgres_direct", "ssh_tunnel"],
"evidence": ["ID pubblici", "owner", "mode", "timestamp", "checksum", "approvazione"],
}
for label, tokens in requirements.items():
lowered = text[label].lower()
for token in tokens:
if token.lower() not in lowered:
raise SystemExit(f"dwh-auth docs: {docs[label]} lacks required topic: {token}")
for path in [root / docs[k] for k in ("server", "client", "tls", "rollout", "manual", "evidence", "local", "server_registry", "psd", "guide", "index")]:
source = path.read_text(encoding="utf-8")
for target in re.findall(r"(?<!!)\[[^]]*\]\(([^)#]+)(?:#[^)]+)?\)", source):
if "://" in target or target.startswith("mailto:"):
continue
candidate = (path.parent / target).resolve()
if not candidate.is_file() or root.resolve() not in candidate.parents:
raise SystemExit(f"dwh-auth docs: broken local link {path.relative_to(root)} -> {target}")
nav = text["nav"]
for relative in (docs["server"], docs["client"], docs["tls"], docs["rollout"], docs["manual"], docs["evidence"]):
nav_relative = relative.removeprefix("docs/")
if nav.count(nav_relative) != 1:
raise SystemExit(f"dwh-auth docs: navigation must include once: {nav_relative}")
corpus = "\n".join(text.values())
for pattern, label in [
(r"thtdwh_v1\.[A-Za-z0-9_-]{16}\.[A-Za-z0-9_-]{43}", "credential literal"),
(r"(?mi)^\s*secret_sha256\s*[:=]\s*[A-Za-z0-9_-]{16,}", "credential digest literal"),
(r"(?mi)^\s*[A-Z][A-Z0-9_]*(?:API_KEY|SECRET|TOKEN|PASSWORD)\s*=\s*(?!/|<)[^\s#]+", "secret in environment"),
(r"(?i)(?:curl|dwh-auth)[^\n]{0,240}(?:-H\s+['\"][^'\"]*X-API-Key\s*:|--(?:api-key|token|password)\b)", "secret in argv"),
(r"(?im)^(?!.*(?:non usare|mai usare)).*curl\s+(?:[^\n]*\s)?(?:-k|--insecure)\b|verify_tls\s*=\s*false|insecure_skip_verify", "TLS bypass"),
(r"(?i)chmod\s+0?[0-7][0-7][4-7]\s+[^\n]*(?:\.key|secret|provision)", "world-readable secret"),
(r"(?m)^\s*nginx\s+-T\b", "raw Nginx capture"),
(r"(?i)docker\s+compose[^\n]*\bdwh-auth\b", "Compose coupling"),
]:
if re.search(pattern, corpus):
raise SystemExit(f"dwh-auth docs: forbidden {label}")
print("dwh-auth documentation contract passed")
PY