#!/usr/bin/env python3 """Validate current authentication documentation, not retired rollout transcripts.""" import argparse import re from pathlib import Path AUTH = { "docs/architecture/authentication.md": ["## Diagnostics and ordering", "HttpOnly", "SameSite=Lax", "authRevision", "401", "403", "direct, non-empty", "ignored silently"], "docs/install/authentication-local.md": ["tht auth", "--password-file"], "docs/install/authentication-oidc.md": ["groups", "THT_OIDC_CLIENT_SECRET", "THT_AUTHENTIK_API_TOKEN", "/api/auth/oidc/callback"], "docs/install/authentik.md": ["groups"], "docs/install/authentication-upstream.md": ["AUTH_MODE=upstream"], "docs/testing/authentication-manual-acceptance.md": ["Remember me", "403", "Header identità inventati", "non sostituiscono"], } DWH = { "docs/install/dwh-auth-server.md": ["/var/lib/dwh-auth/", "/run/dwh-auth/verify.sock", "key create", "key revoke", "encrypted", "401", "503"], "docs/install/dwh-auth-client-enrollment.md": ["rest_api", "postgres_direct", "ssh_tunnel", "API_KEY_FILE", "TLS_CA_FILE", "/rpc/ping", "401", "503"], "docs/install/dwh-auth-tls.md": ["SAN", "TLS_CA_FILE", "openssl x509 -noout -fingerprint -sha256"], } 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""".split() ADMIN = """session.use session.read_all session.manage_all settings.manage workspace.manage workspace.secrets.manage database.manage memory.manage evidence.manage pi.manage auth.diagnostics.read""".split() def verify(root, mode): requirements = AUTH if mode == "auth" else DWH sources = {} for relative, tokens in requirements.items(): path = root / relative if not path.is_file(): raise ValueError(f"missing {relative}") source = path.read_text() sources[relative] = source for token in tokens: if token.lower() not in source.lower(): raise ValueError(f"{relative}: missing topic {token}") for target in re.findall(r"(?