lldap and OpenLDAP's memberof overlay omit memberOf from "*", so every
lldap login fell through to the default group. Request memberOf by name
when the schema defines it, and on non-AD directories also search the
directory root for groupOfNames/groupOfUniqueNames entries listing the
user, since groups often sit outside the user search base and the
overlay tracks only one group class.
Also: skip ldap3's anonymous schema read after StartTLS, which AD and
Samba AD reject, so StartTLS works there; reword a server's StartTLS
refusal with an LDAPS hint; stop the bundle sanitizer masking part of
an OID as an IP; skip the sync right after auto-provisioning so the
default-group warning logs once.
Subprocess output and user-supplied URLs are scrubbed of credentials
before they reach the application log. Adds a shared redaction helper in
core/logging_filters and routes the existing support-bundle sanitizer
through the same pattern.
With LDAP auth in use, the debug log carried the full user DN on successful
auth -- e.g. "(DN: CN=Joe Schmoe,CN=Users,DC=ad,DC=example,DC=com, ...)". A DN's
leaf CN is the user's real name, PII on par with the email address already
redacted, and it passed straight into an uploaded support bundle. The log
sanitizer (shared by the support bundle and the in-app bug report) had no DN
pattern; DNs also leak via ldap3 exception strings and group-mapping logs.
- sanitize_log_content: redact LDAP DNs to [DN] -- a run of >=2 attr=value RDN
components (CN/OU/DC/UID/...). The value class excludes <>;+ (RFC 4514 requires
them escaped in a value) so the final comma-unbounded component doesn't swallow
trailing log text such as "-> GroupName". Ordinary key=value lines are untouched.
- ldap_service: stop logging the raw DN on successful auth (username + group
count suffices), keeping the PII off disk even before bundle sanitization.
Adds a passive log-health check that complements the active Connection
Diagnostic. Scans Bambuddy's recent app log against a curated allowlist
catalog of known failure signatures (rejected access code, FTPS :990
timeout, FTPS TLS failure, flapping MQTT, unreachable camera, SQLite
"database is locked" contention), dedupes and classifies each finding
as layer8/environment/bug, and deep-links to the troubleshooting wiki.
Sample log lines are sanitized before they leave the process. Exposed
via GET /system/health and surfaced on two surfaces sharing one
SystemHealthPanel component: a System Health section on the System
page, and inline in the bug reporter when the form opens.
The Add-Printer and Edit-Printer dialogs gained a setup-time pre-flight:
saving runs the connection diagnostic and, on a failed check, warns with
a "save anyway" escape hatch instead of silently saving a printer that
will immediately show offline.
Log read/parse/sanitize primitives extracted from routes/support.py into
a shared services/log_reader.py (behaviour-preserving); affected support
tests repointed accordingly.
Tests: test_log_health.py (11), test_system_api.py (2 new),
SystemHealthPanel + BugReportBubble + AddPrinterPreflight +
EditPrinterPreflight (8 frontend). All strings translated across the 9
locales. Backend ruff clean, full unit suite green, frontend build +
eslint clean, i18n parity green.