chore(detekt): forbid android.util.Log outside AppLog — strangler guard (#324) #331

Closed
opened 2026-07-05 00:49:33 +00:00 by JMR-dev · 0 comments
JMR-dev commented 2026-07-05 00:49:33 +00:00 (Migrated from github.com)

Part of #324 (strangler-migrate debug logging to AppLog).

Sequencing: LAST — BLOCKED on ALL migration areas. This enables the strangler seam: a
detekt rule that fails the build on any android.util.Log import outside the AppLog facade.
It can only be turned on after the Seam + auth/lock + DB/keystore + connectivity/send +
sync-engine + stragglers tickets have all merged — enabling it earlier fails CI's Static
analysis gate. Do not start until those are green on main.

Scope (files)

  • config/detekt/detekt.yml — add the ForbiddenImport rule.
  • Any residual import android.util.Log in app/src/test cleared by the area tickets
    (verify none remain except the two facade tests, below).

Change

Add to config/detekt/detekt.yml (merged onto defaults; buildUponDefaultConfig = true):

style:
  ForbiddenImport:
    active: true
    imports:
      - value: 'android.util.Log'
        reason: >-
          Log via org.libremail.reporting.AppLog so lines reach the debug-report RingLogBuffer;
          raw android.util.Log bypasses it (epic #324).
    excludes:
      - '**/reporting/AppLog.kt'
      - '**/reporting/AppLogTest.kt'
      - '**/reporting/AppLogUninstalledTest.kt'

Notes / gotchas

  • detekt 2.0.0-alpha.5 (dev.detekt plugin). ForbiddenImport is in the style ruleset;
    confirm the ruleset id against this alpha's catalog and adjust the YAML section if it moved.
    It is import-based, so it needs no type resolution (our code never fully-qualifies
    android.util.Log).
  • excludes must cover the facade AND its two tests. AppLog.kt legitimately imports
    Log (it is the one allowed wrapper). AppLogTest and AppLogUninstalledTest
    mockkStatic(Log::class) to verify the facade forwards to Logcat, so they import Log too.
  • Precondition to verify before enabling: every OTHER test that imports Log today
    (AppLockViewModelTest, ImapClientTest, AccountSetupViewModelTest, SendWorkerTest) must
    have dropped that import during its area migration (they switch from mocking Log to
    asserting the RingLogBuffer). Run Grep 'import android.util.Log' app/src and confirm only
    AppLog.kt + the two facade tests remain; otherwise :app:detekt (which covers test +
    androidTest source sets) fails.
  • Optional hardening: add a ForbiddenMethodCall on android.util.Log.* to also catch
    fully-qualified calls — but that requires the detekt type-resolution task, and no current code
    fully-qualifies, so ForbiddenImport alone is sufficient.

Test / verification

  • The gate itself is the test: ./gradlew :app:detekt passes with the rule active (all areas
    migrated). Optionally add a raw Log.d to a throwaway file to confirm detekt fails, then
    revert. No product-runtime surface, so no E2E is applicable to this ticket specifically —
    the migration areas carry the behavioral tests.

Parallelism: NONE — strictly last, after every migration area merges.

Part of #324 (strangler-migrate debug logging to AppLog). **Sequencing: LAST — BLOCKED on ALL migration areas.** This enables the strangler seam: a detekt rule that fails the build on any `android.util.Log` import outside the `AppLog` facade. It can only be turned on **after** the Seam + auth/lock + DB/keystore + connectivity/send + sync-engine + stragglers tickets have all merged — enabling it earlier fails CI's Static analysis gate. Do not start until those are green on `main`. ## Scope (files) - `config/detekt/detekt.yml` — add the `ForbiddenImport` rule. - Any residual `import android.util.Log` in `app/src/test` cleared by the area tickets (verify none remain except the two facade tests, below). ## Change Add to `config/detekt/detekt.yml` (merged onto defaults; `buildUponDefaultConfig = true`): ```yaml style: ForbiddenImport: active: true imports: - value: 'android.util.Log' reason: >- Log via org.libremail.reporting.AppLog so lines reach the debug-report RingLogBuffer; raw android.util.Log bypasses it (epic #324). excludes: - '**/reporting/AppLog.kt' - '**/reporting/AppLogTest.kt' - '**/reporting/AppLogUninstalledTest.kt' ``` ## Notes / gotchas - **detekt 2.0.0-alpha.5** (`dev.detekt` plugin). `ForbiddenImport` is in the `style` ruleset; confirm the ruleset id against this alpha's catalog and adjust the YAML section if it moved. It is import-based, so it needs **no type resolution** (our code never fully-qualifies `android.util.Log`). - **`excludes` must cover the facade AND its two tests.** `AppLog.kt` legitimately imports `Log` (it is the one allowed wrapper). `AppLogTest` and `AppLogUninstalledTest` `mockkStatic(Log::class)` to verify the facade forwards to Logcat, so they import `Log` too. - **Precondition to verify before enabling:** every OTHER test that imports `Log` today (`AppLockViewModelTest`, `ImapClientTest`, `AccountSetupViewModelTest`, `SendWorkerTest`) must have dropped that import during its area migration (they switch from mocking `Log` to asserting the `RingLogBuffer`). Run `Grep 'import android.util.Log' app/src` and confirm only `AppLog.kt` + the two facade tests remain; otherwise `:app:detekt` (which covers test + androidTest source sets) fails. - Optional hardening: add a `ForbiddenMethodCall` on `android.util.Log.*` to also catch fully-qualified calls — but that requires the detekt type-resolution task, and no current code fully-qualifies, so `ForbiddenImport` alone is sufficient. ## Test / verification - The gate itself is the test: `./gradlew :app:detekt` passes with the rule active (all areas migrated). Optionally add a raw `Log.d` to a throwaway file to confirm detekt fails, then revert. No product-runtime surface, so no E2E is applicable to this ticket specifically — the migration areas carry the behavioral tests. **Parallelism:** NONE — strictly last, after every migration area merges.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: JMR-dev/LibreMail#331