feat(logging): detekt guard banning android.util.Log outside AppLog (#331) #348

Merged
JMR-dev merged 3 commits from feat-331-detekt-log-guard into main 2026-07-05 05:05:06 +00:00
JMR-dev commented 2026-07-05 04:04:53 +00:00 (Migrated from github.com)

Final step of the debug-logging strangler epic #324: a detekt style > ForbiddenImport rule that fails the build on any import android.util.Log outside the AppLog facade, so nothing can bypass the debug-report RingLogBuffer (raw android.util.Log writes to Logcat only and never reaches a user-reviewed DebugReport).

Rule

config/detekt/detekt.yml → style > ForbiddenImport, forbidding android.util.Log with a reason pointing devs to org.libremail.reporting.AppLog. Note: detekt 2.0.0-alpha.5 renamed the rule's old imports key to forbiddenImports (allowed props: active, allowedImports, forbiddenImports) — the config uses the new key. Import-based, so no type resolution needed.

Excludes (rule-level excludes: globs)

  • **/reporting/AppLog.kt — the one sanctioned wrapper; it is the facade.
  • Unit tests that mockkStatic(Log) only to mock/verify forwarding — they don't bypass the facade. AppLog forwards to android.util.Log, a throwing stub under plain JVM unit tests, so any test exercising AppLog-logging code must mock Log: the two facade tests (AppLogTest, AppLogUninstalledTest), RestartActivityLoggingTest, the sync-engine tests (SyncWorkerTest, MailSyncerTest, MailBackfillerTest, MailPrunerTest, MailMaintenanceGateTest, MailSyncConcurrencyTest, PruneWorkerTest, BackfillWorkerTest), and the auth/lock tests (AppLockViewModelTest, AccountSetupViewModelTest).

No production file is excluded — production code must migrate to AppLog.

Dependency — draft until #340 lands

Depends on #340/#326 — detekt flags the 2 auth/lock files (AppLockViewModel, AccountSetupViewModel) until #340 merges; those are #340's job to migrate, not this PR's. Validated the guard reaches 0 findings with all migrations present (temp-merged feat-326: :app:detekt → BUILD SUCCESSFUL, then discarded so this PR is config-only). Greens via auto-update once #340 lands.

Closes #331
Part of #324

🤖 Generated with Claude Code

Final step of the debug-logging strangler epic #324: a detekt `style > ForbiddenImport` rule that fails the build on any `import android.util.Log` outside the `AppLog` facade, so nothing can bypass the debug-report `RingLogBuffer` (raw `android.util.Log` writes to Logcat only and never reaches a user-reviewed `DebugReport`). ## Rule `config/detekt/detekt.yml` → `style > ForbiddenImport`, forbidding `android.util.Log` with a `reason` pointing devs to `org.libremail.reporting.AppLog`. Note: detekt 2.0.0-alpha.5 renamed the rule's old `imports` key to `forbiddenImports` (allowed props: `active, allowedImports, forbiddenImports`) — the config uses the new key. Import-based, so no type resolution needed. ## Excludes (rule-level `excludes:` globs) - `**/reporting/AppLog.kt` — the one sanctioned wrapper; it **is** the facade. - Unit tests that `mockkStatic(Log)` only to mock/verify forwarding — they don't bypass the facade. `AppLog` forwards to `android.util.Log`, a throwing stub under plain JVM unit tests, so any test exercising AppLog-logging code must mock `Log`: the two facade tests (`AppLogTest`, `AppLogUninstalledTest`), `RestartActivityLoggingTest`, the sync-engine tests (`SyncWorkerTest`, `MailSyncerTest`, `MailBackfillerTest`, `MailPrunerTest`, `MailMaintenanceGateTest`, `MailSyncConcurrencyTest`, `PruneWorkerTest`, `BackfillWorkerTest`), and the auth/lock tests (`AppLockViewModelTest`, `AccountSetupViewModelTest`). No production file is excluded — production code must migrate to `AppLog`. ## Dependency — draft until #340 lands Depends on #340/#326 — detekt flags the 2 auth/lock files (`AppLockViewModel`, `AccountSetupViewModel`) until #340 merges; those are #340's job to migrate, not this PR's. Validated the guard reaches **0 findings** with all migrations present (temp-merged `feat-326`: `:app:detekt` → BUILD SUCCESSFUL, then discarded so this PR is config-only). Greens via auto-update once #340 lands. Closes #331 Part of #324 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.