Lint / PHP (phpcs PSR-12) (push) Successful in 18s
Lint / JS (eslint) (push) Successful in 7s
Lint / PHP requirements (version + extensions) (push) Successful in 28s
Lint / Notify on failure (push) Skipped
Security / PHP Security (semgrep) (push) Successful in 1m56s
Lint / Deploy (push) Successful in 3s
api/user_avatar.php connected via ldap://$ldapHost:$ldapPort — never ldaps://, and there was no ldap_start_tls() call anywhere in the codebase. LDAP_BIND_PW was sent over the wire unencrypted on every avatar fetch. Switched to ldaps://, and changed LDAP_HOST/LDAP_PORT's defaults to ldap.lotusguild.org:6360 (lldap's LDAPS listener) instead of the bare IP on port 3890 (plaintext). PHP's ldap extension verifies the server cert's hostname by default, so a bare IP won't validate against the LDAPS cert (issued for *.lotusguild.org) — LDAP_HOST has to be a hostname the cert covers. This is deliberately not configurable back to plaintext ldap://. Infra change (pve-infra, separate repo/commit): added a Pi-hole split-horizon override so ldap.lotusguild.org resolves internally to the real LDAP server's LAN IP — its existing public DNS record points elsewhere (an unrelated host), and there was no internal-only DNS entry for it before this. Verified against the real lldap server (pct 147, LDAPS on 6360, a live Let's Encrypt *.lotusguild.org cert): confirmed the Pi-hole override resolves correctly from hosts using it as their resolver, then ran the exact ldap_connect/ldap_bind sequence via `php -r` directly on the production tinker_tickets host (10.10.10.45) with a deliberately wrong bind password — got "Invalid credentials" (a real LDAP protocol response), not a transport/TLS error, proving the full connect + TLS handshake + hostname verification + bind path works end-to-end in the actual deployment environment. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117oBw2jN4kALYeS8HPq4zV