Skip to content

fix(desktop): probe legacy app-data dir at most once per install#2784

Open
mattalldianhr wants to merge 1 commit into
block:mainfrom
mattalldianhr:fix/legacy-app-data-probe-once
Open

fix(desktop): probe legacy app-data dir at most once per install#2784
mattalldianhr wants to merge 1 commit into
block:mainfrom
mattalldianhr:fix/legacy-app-data-probe-once

Conversation

@mattalldianhr

Copy link
Copy Markdown

Problem

migrate_legacy_app_data_dir runs on every launch and calls legacy_dir.exists() on ~/Library/Application Support/xyz.block.sprout.app — a different app's container. On macOS that stat is itself gated by TCC, so it triggers the "Buzz would like to access data from other apps" consent prompt before the function bails.

For anyone who never ran Sprout there is no legacy dir at all, so the probe can never lead to a copy. It only produces a consent prompt, on every single launch, forever.

Implementation

Gate the probe behind a .legacy-app-data-probed marker written inside the current app-data dir.

Two deliberate decisions:

Marker placement. Unlike the reset sentinel in reset.rs — which lives in the app-data dir's parent so it survives the wipe — this marker goes inside app_data_dir. run_boot_reset wipes app_data_dir and the legacy dir together, which clears the marker, so a genuine post-reset migration can still run. Putting it in the parent would have permanently suppressed that path.

Write-before-probe. The marker is written before the exists() call. If it can't be written we skip the probe entirely rather than falling through. A missed migration is recoverable; an unkillable system prompt is not.

The body is extracted into migrate_legacy_app_data_dir_at(legacy_dir, current_dir) so the behavior is testable without a Tauri AppHandle.

Tests

Four regression tests in migration_tests.rs:

  • legacy_app_data_migration_copies_then_marks_probed — first run still migrates
  • legacy_app_data_migration_does_not_reprobe_after_marker — the actual fix
  • legacy_app_data_migration_marks_even_when_legacy_absent — the reported case
  • legacy_app_data_migration_reruns_after_marker_wiped — reset interaction preserved

I verified these catch the bug rather than merely passing: temporarily disabling the guard makes does_not_reprobe_after_marker fail, and restoring it makes it pass. The pre-existing reset::tests::test_legacy_app_data_removed_on_reset still passes.

How to test manually

On a machine with no ~/Library/Application Support/xyz.block.sprout.app:

  1. Launch Buzz → the "access data from other apps" prompt appears (pre-fix).
  2. With this change, the first launch writes the marker; subsequent launches never stat the foreign container, so the prompt does not recur.

Notes

`migrate_legacy_app_data_dir` ran on every launch and called
`legacy_dir.exists()` on `xyz.block.sprout.app` — another app's
container. On macOS that stat is itself gated by TCC, so it triggers the
"would like to access data from other apps" consent prompt before the
function bails.

Users who never ran Sprout have no legacy dir at all, so the probe could
never lead to a copy — it only produced a consent prompt on every single
launch.

Gate the probe behind a `.legacy-app-data-probed` marker written inside
the current app-data dir. Placement is deliberate: unlike the reset
sentinel in `reset.rs` (which lives in the parent so it survives a wipe),
this marker must be wiped alongside `app_data_dir` so a genuine
post-reset migration can still run. The marker is written *before* the
probe so an unwritable marker skips probing rather than prompting
forever.

Extracts the body into `migrate_legacy_app_data_dir_at` so the behavior
is testable without a Tauri AppHandle.

Tests: first-run copy, no-reprobe once marked, marking when the legacy
dir is absent, and re-running after a reset wipes the marker. Verified
the no-reprobe test fails without the guard.
@mattalldianhr
mattalldianhr requested a review from a team as a code owner July 24, 2026 23:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants