Skip to content

fix(datastore): apply privacy filters on save and startup - #662

Merged
ErikBjare merged 5 commits into
ActivityWatch:masterfrom
TimeToBuildBob:fix/privacy-filters-never-apply
Sep 11, 2026
Merged

fix(datastore): apply privacy filters on save and startup#662
ErikBjare merged 5 commits into
ActivityWatch:masterfrom
TimeToBuildBob:fix/privacy-filters-never-apply

Conversation

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

Summary

Privacy filter rules saved from the webui never actually applied. DatastoreWorker starts with an empty PrivacyFilterEngine, insert/heartbeat paths do filter against that engine, and RefreshPrivacyFilter reloads settings.privacy_filters — but nothing called refresh after save, and startup never loaded the persisted key. The UI could save drop/redact rules all day; matching events were stored unchanged.

Fixes #659.

What changed

  • Reload the in-memory engine when settings.privacy_filters is written or deleted (SetKeyValue / DeleteKeyValue).
  • Load the same key at worker startup so rules survive a server restart.
  • Keep RefreshPrivacyFilter as an explicit path (HTTP settings endpoints still call it as belt-and-suspenders).
  • Datastore tests: a drop rule saved via set_key_value actually drops a matching insert (no explicit refresh), and the same rule still applies after reopen.

Test plan

  • cargo test -p aw-datastore --test datastore
  • Save a drop rule in the webui Privacy Filters settings, generate a matching window event, confirm it is not stored.
  • Restart the server with that setting present, confirm matching events still drop.

@greptile-apps

greptile-apps Bot commented Aug 28, 2026

Copy link
Copy Markdown

Greptile Summary

The PR keeps the in-memory privacy filter synchronized with its persisted setting during startup and settings changes, while restoring the prior filter state if a transaction fails.

  • Loads persisted privacy rules before processing events.
  • Reloads rules when the privacy setting is written or deleted.
  • Restores the transaction-start engine after a failed commit.
  • Adds tests covering immediate activation, deletion, and restart persistence.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the current rollback path restores the transaction-start filter engine, and non-absence loading errors preserve the active rules.

Important Files Changed

Filename Overview
aw-datastore/src/worker.rs Synchronizes privacy-filter state with settings and restores the pre-transaction engine on commit failure; the previously reported rollback and recovery issues are addressed.
aw-datastore/tests/datastore.rs Adds coverage for activation after saving, deactivation after deletion, and loading persisted rules after reopening.
aw-server/src/endpoints/settings.rs Retains explicit privacy-filter refreshes after successful HTTP setting writes and deletions.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Start worker] --> B[Load persisted privacy filters]
    B --> C[Begin transaction]
    C --> D[Snapshot active engine]
    D --> E[Process settings and event commands]
    E --> F{Commit succeeds?}
    F -- Yes --> G[Keep updated engine]
    F -- No --> H[Restore transaction-start engine]
    G --> C
    H --> C
Loading

Reviews (4): Last reviewed commit: "fix(datastore): restore privacy engine f..." | Re-trigger Greptile

Comment thread aw-datastore/src/worker.rs
@codecov

codecov Bot commented Aug 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.02564% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.75%. Comparing base (656f3c9) to head (1b3aaa2).
⚠️ Report is 97 commits behind head on master.

Files with missing lines Patch % Lines
aw-datastore/src/worker.rs 77.77% 4 Missing ⚠️
aw-server/src/endpoints/settings.rs 66.66% 2 Missing ⚠️
aw-datastore/tests/datastore.rs 98.14% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #662      +/-   ##
==========================================
+ Coverage   70.81%   79.75%   +8.93%     
==========================================
  Files          51       66      +15     
  Lines        2916     5680    +2764     
==========================================
+ Hits         2065     4530    +2465     
- Misses        851     1150     +299     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

macOS CI failure was the known sync_roundtrip flake, not this PR

Run 33137074103 failed only on macOS, in aw-sync:

thread panicked at aw-datastore/src/datastore.rs:129:6:
Failed to upgrade database when adding data field to buckets:
  SqliteFailure(..., Some("duplicate column name: data"))

test_own_data_does_not_return_via_peer and test_push_does_not_reexport_synced_buckets both call round_trip(), which builds temp db paths from pid + name + nanos. Run in parallel on macOS they can land in the same clock tick, open the same SQLite file, and race the v1→v2 migration. Nothing to do with privacy filters — it hits any PR in this repo.

That is exactly what #655 fixes (green, mergeable, open since 2026-08-24). To unblock this branch's CI the same fix was carried here, and cfbfad9 makes aw-sync/tests/sync_roundtrip.rs byte-identical to #655's version — so #655 and #662 land in either order with no conflict, and both keep the timestamp component (the counter alone resets on PID reuse, and these tests never delete their temp dbs).

Also in this push: 95898ce addresses the Greptile P1 — a failed batched commit rolled SQLite back but left the in-memory privacy engine holding the rolled-back rules.

Local: cargo test -p aw-sync --test sync_roundtrip 3/3, cargo test -p aw-datastore 13/13, fmt clean, no new clippy warnings.

Merging #655 is still worth doing on its own — it fixes the flake on master, where this PR's copy does not help.

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review

Comment thread aw-datastore/src/worker.rs Outdated
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review

The webui saved settings.privacy_filters, but DatastoreWorker started
with an empty engine and never reloaded on SetKeyValue. Insert and
heartbeat paths filtered correctly against rules that were never loaded,
so drop/redact rules appeared to do nothing (ActivityWatch#659).

Reload the in-memory engine when that key is written or deleted, load it
at worker startup, and keep RefreshPrivacyFilter as an explicit path.
The reopen assertion already passed on windows-latest; remove_file then
hit ERROR_SHARING_VIOLATION because the worker thread still held the
SQLite handle. Unique-ify the temp db and treat cleanup as best-effort.
A SetKeyValue/DeleteKeyValue on settings.privacy_filters reloads the
in-memory engine from the still-open transaction. If the batched commit
later fails, SQLite rolls back but the engine keeps the rules from the
rolled-back write, so subsequent inserts filter against state that no
longer exists on disk — including running unfiltered after a rolled-back
delete.

Reload from the durable connection on the commit-failure path so the
engine matches what actually persisted.
The reload treated every get_key_value error as "key deleted" and
emptied the engine. A transient InternalError from the query would
therefore disable filtering entirely and let the events these rules exist
to exclude get stored.

Clear only on NoSuchKey; warn and keep the current engine otherwise.
@TimeToBuildBob
TimeToBuildBob force-pushed the fix/privacy-filters-never-apply branch from 67195c5 to 6bf2934 Compare August 31, 2026 15:22
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Rebased onto current master (2ded7d7). Conflicts were only in aw-sync/tests/sync_roundtrip.rs — the two tmp_db uniqueness commits already landed via #666, so I dropped them. Privacy-filter commits applied cleanly. cargo test -p aw-datastore --test datastore: 19 passed.

A privacy-setting mutation reloads the engine from the still-open
transaction. On commit failure, re-querying the durable connection and
keeping the current engine on read error left a rolled-back delete's
empty engine in place, so later inserts ran unfiltered.

Restore the snapshot taken at transaction start instead. Recovery then
does not depend on a second read succeeding.
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Greptile 3/5 leftover: a rolled-back delete plus a failed durable reload could keep the uncommitted (empty) engine, so later inserts ran unfiltered.

1b3aaa2 snapshots the engine when the SQLite transaction opens — before any SetKeyValue/DeleteKeyValue reload — and restores that snapshot on commit failure. Recovery no longer depends on a second read succeeding.

cargo test -p aw-datastore --test datastore: 19 passed. Local in-band review 5/5.

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

CI-green and mergeable (Greptile 5/5) — waiting only on a maintainer click.

This PR is ready to merge, but the bot has pull-only access to this repo and can't self-merge — surfacing it here so it isn't lost. The monitoring loop will stop re-flagging it now that this note is posted.

@ErikBjare
ErikBjare merged commit 062a20e into ActivityWatch:master Sep 11, 2026
8 checks passed
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.

Privacy Filters feature isn't working

2 participants