Skip to content

Read from harmony and implement fixes#7867

Closed
CrisBarreiro wants to merge 4 commits intofeature/cris/autofill-harmony-add-diagnostic-pixelsfrom
feature/cris/autofill-harmony-add-fixes
Closed

Read from harmony and implement fixes#7867
CrisBarreiro wants to merge 4 commits intofeature/cris/autofill-harmony-add-diagnostic-pixelsfrom
feature/cris/autofill-harmony-add-fixes

Conversation

@CrisBarreiro
Copy link
Collaborator

@CrisBarreiro CrisBarreiro commented Mar 4, 2026

Task/Issue URL: https://app.asana.com/1/137249556945/project/488551667048375/task/1213239127540038?focus=true

Description

Steps to test this PR

Feature 1

  • [ ]
  • [ ]

UI changes

Before After
!(Upload before screenshot) (Upload after screenshot)

Note

Medium Risk
Changes the secure-storage key read path to optionally read from Harmony and to fail fast under a new read-guard flag, which could impact credential decryption/access if toggles are misconfigured or Harmony data diverges.

Overview
Adds new autofill feature toggles addReadGuard and readFromHarmony, and threads them through secure storage key handling.

RealSecureStorageKeyStore now (1) can optionally return keys from Harmony when useHarmony is enabled and readFromHarmony is on, and (2) introduces a read guard that throws when encrypted preferences are null, Harmony reads fail, or Harmony/legacy keys are missing/mismatched (while still emitting diagnostic pixels).

Pixel schemas are updated to include an addReadGuard parameter across existing autofill key/prefs failure and mismatch pixels.

Written by Cursor Bugbot for commit 4f09c86. This will update automatically on new commits. Configure here.

Copy link
Collaborator Author

CrisBarreiro commented Mar 4, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Cached feature flags prevent remote emergency disable
    • Removed lazy Deferred caching for useHarmony and readFromHarmony feature flags so they are evaluated fresh on each call, allowing remote emergency disable mid-session.

Create PR

Or push these changes by commenting:

@cursor push d0d6002de8
Preview (d0d6002de8)
diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/store/keys/SecureStorageKeyStore.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/store/keys/SecureStorageKeyStore.kt
--- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/store/keys/SecureStorageKeyStore.kt
+++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/store/keys/SecureStorageKeyStore.kt
@@ -83,21 +83,13 @@
 
     private var initialUseHarmonyValue: Boolean? = null
 
-    private val useHarmonyDeferred: Deferred<Boolean> by lazy {
-        coroutineScope.async(dispatcherProvider.io()) {
-            autofillFeature.useHarmony().isEnabled()
-        }
+    private suspend fun useHarmony(): Boolean = withContext(dispatcherProvider.io()) {
+        autofillFeature.useHarmony().isEnabled()
     }
 
-    private val readFromHarmonyDeferred: Deferred<Boolean> by lazy {
-        coroutineScope.async(dispatcherProvider.io()) {
-            autofillFeature.readFromHarmony().isEnabled()
-        }
+    private suspend fun readFromHarmony(): Boolean = withContext(dispatcherProvider.io()) {
+        autofillFeature.readFromHarmony().isEnabled()
     }
-
-    private suspend fun useHarmony(): Boolean = useHarmonyDeferred.await()
-
-    private suspend fun readFromHarmony(): Boolean = readFromHarmonyDeferred.await()
     private val encryptedPreferencesDeferred: Deferred<SharedPreferences?> by lazy {
         coroutineScope.async(dispatcherProvider.io()) {
             try {


private suspend fun useHarmony(): Boolean = useHarmonyDeferred.await()

private suspend fun readFromHarmony(): Boolean = readFromHarmonyDeferred.await()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cached feature flags prevent remote emergency disable

Medium Severity

The useHarmony and readFromHarmony feature flags are now cached forever via lazy Deferred, meaning their values are evaluated once and never re-checked. Previously, autofillFeature.useHarmony().isEnabled() was called fresh on every invocation of updateKey, getKey, keyAlreadyExists, and canUseEncryption. This creates an inconsistency where addWriteGuard and addReadGuard can be toggled remotely mid-session (checked fresh each time), but useHarmony and readFromHarmony cannot. If harmony data corruption is detected and the server disables useHarmony or readFromHarmony, the cached value will keep the old behavior until the app is fully restarted, potentially serving corrupted data from harmony.


Please tell me if this was useful or not with a 👍 or 👎.

Fix in Cursor Fix in Web

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.

1 participant