Skip to content

[PM-39564] feat: Fill Assist support email field key for email-based login forms - #7107

Merged
aj-rosado merged 51 commits into
mainfrom
PM-39564/fill-assist-username-support-emaill
Jul 20, 2026
Merged

[PM-39564] feat: Fill Assist support email field key for email-based login forms#7107
aj-rosado merged 51 commits into
mainfrom
PM-39564/fill-assist-username-support-emaill

Conversation

@aj-rosado

@aj-rosado aj-rosado commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-39564

📔 Objective

Fill-assist rules in the forms JSON use "email" as the field key for sites where users log in with their email address (e.g. { "email": ["input[type='email']"] }). Previously this key was unrecognised — it fell through to else -> null in toAutofillViewForFieldKey, so autofill never triggered for those fields.

This PR adds a dedicated AutofillView.Login.Email sealed subtype and wires it through the fill pipeline with a validation guard: the email field is only filled when the cipher's stored username mathes the email pattern If the username is not an email address the field is skipped, avoiding placing a non-email value into an type="email" input.

  • AutofillView.Login.Email added alongside Username and Password
  • Fill-assist "email" key maps to Login.Email in toAutofillViewForFieldKey
  • FilledDataBuilderImpl guards Login.Email: skips fill when username does not pass isValidEmail(useStrictValidation = false)
  • AutofillPartitionExtensions.usernameSaveValue updated to capture Login.Email text values so saving credentials from email-only forms preserves the typed value
  • All exhaustive when expressions on AutofillView updated (AutofillViewExtensions, AutofillParserImpl.updateWebsiteIfNecessary)

aj-rosado added 24 commits May 29, 2026 12:03
…ow updates

Updating code to schema with required values
@github-actions github-actions Bot added the app:password-manager Bitwarden Password Manager app context label Jun 26, 2026
@aj-rosado aj-rosado changed the title [PM-39564] Fill Assist: Support email field key for email-based login forms [PM-39564] feat: Fill Assist support email field key for email-based login forms Jun 29, 2026
…l-assist-option-settings

# Conflicts:
#	app/src/main/kotlin/com/x8bit/bitwarden/data/autofill/parser/AutofillParserImpl.kt
aj-rosado added 3 commits July 7, 2026 15:44
…l-assist-option-settings

# Conflicts:
#	app/src/main/kotlin/com/x8bit/bitwarden/data/autofill/parser/AutofillParserImpl.kt
#	app/src/test/kotlin/com/x8bit/bitwarden/data/autofill/manager/FillAssistManagerTest.kt
…/fill-assist-username-support-emaill

# Conflicts:
#	app/src/main/kotlin/com/x8bit/bitwarden/data/autofill/util/FillAssistViewNodeExtensions.kt
@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 77.77778% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.81%. Comparing base (bd9c761) to head (be9e8d6).

Files with missing lines Patch % Lines
...twarden/data/autofill/parser/AutofillParserImpl.kt 0.00% 0 Missing and 1 partial ⚠️
...arden/data/autofill/util/AutofillViewExtensions.kt 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7107      +/-   ##
==========================================
- Coverage   86.09%   85.81%   -0.28%     
==========================================
  Files         885      928      +43     
  Lines       64733    66514    +1781     
  Branches     9638     9685      +47     
==========================================
+ Hits        55729    57082    +1353     
- Misses       5547     5964     +417     
- Partials     3457     3468      +11     
Flag Coverage Δ
app-data 17.44% <77.77%> (-0.30%) ⬇️
app-ui-auth-tools 18.60% <0.00%> (-0.14%) ⬇️
app-ui-platform 16.90% <0.00%> (+0.32%) ⬆️
app-ui-vault 27.94% <0.00%> (+0.55%) ⬆️
authenticator 6.11% <0.00%> (-0.01%) ⬇️
lib-core-network-bridge 4.03% <0.00%> (+0.01%) ⬆️
lib-data-ui 1.13% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Base automatically changed from PM-38966/add-fill-assist-option-settings to main July 20, 2026 15:02
# Conflicts:
#	app/src/main/kotlin/com/x8bit/bitwarden/data/autofill/util/FillAssistViewNodeExtensions.kt
#	app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/autofill/AutoFillViewModel.kt
#	app/src/test/kotlin/com/x8bit/bitwarden/data/autofill/util/FillAssistViewNodeExtensionsTest.kt
#	app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/autofill/AutoFillViewModelTest.kt
@aj-rosado
aj-rosado marked this pull request as ready for review July 20, 2026 16:03
@aj-rosado
aj-rosado requested review from a team and david-livefront as code owners July 20, 2026 16:03
@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Summary

Reviewed the fill-assist email field-key support (PR #7107) against main. The functional change is 10 files, +199/-8 — a new AutofillView.Login.Email sealed subtype wired through the fill pipeline with an email-validation guard, plus tests.

This is a clean, focused, and well-tested change. All exhaustive when expressions on the AutofillView hierarchy were correctly updated (FilledDataBuilderImpl, AutofillViewExtensions, AutofillParserImpl.updateWebsiteIfNecessary), the fill-assist "email" key is mapped in toAutofillViewForFieldKey, and usernameSaveValue now captures Login.Email values so credentials saved from email-only forms are preserved. Each behavioral path has direct unit coverage (fill when valid email, skip when not, save-value extraction, and the field-key mapping precedence).

Findings

Severity Count
🔴 Critical 0
🟠 Important 0
🟡 Debt 0
🔵 Suggested 0
❓ Question 1

❓ Question — FilledDataBuilderImpl.kt:157: The PR description documents the guard as isValidEmail(useStrictValidation = false), but the code calls isValidEmail() (strict, the default). Strict validation will skip filling for usernames a type="email" input would accept (e.g. admin@localhost). The KDoc and tests are consistent with the strict implementation, so this is likely a stale description — flagged inline to reconcile description vs. code.

Notes (no action required)

  • FillAssistManagerImpl change merges two guard returns into a single || condition — semantically identical (short-circuit), pure readability refactor.
  • The missing-username heuristic (updateForMissingUsernameFields) checks only for Login.Username, but it runs on the heuristic-parsed views before fill-assist views are substituted, and fill-assist is the only producer of Login.Email — so there is no interaction/regression there.

Verification

  • Confirmed no other exhaustive when/filterIsInstance sites on AutofillView.Login were missed.
  • CI unit-test jobs were still pending at review time; no failures observed, but green tests should be confirmed before merge.

Overall: LGTM pending the description/validation-strictness clarification.

) {
val value = when (autofillView) {
is AutofillView.Login.Email -> {
if (!autofillCipher.username.isValidEmail()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

❓ The PR description states the guard uses isValidEmail(useStrictValidation = false) (only checks for the presence of @), but this calls isValidEmail() which defaults to useStrictValidation = true — requiring a full local@domain.tld match.

The strict regex is ^[A-Za-z0-9._%+-/*]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$, so usernames a browser type="email" field would otherwise accept (e.g. admin@localhost, or user@intranet with no TLD) will be skipped and left unfilled.

Is strict validation the intended behavior here? If so, consider updating the PR description to match. If non-strict was intended, pass useStrictValidation = false. The KDoc on Login.Email and the tests are consistent with the current (strict) implementation, so this is likely just a stale description — flagging to reconcile.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@claude description updated to match the behaviour

@claude claude Bot Jul 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude finished @aj-rosado's task in 29s —— View job


Reconciliation confirmed ✅

Thanks @aj-rosado — the description now matches the implementation.

To confirm the resolution: the guard at FilledDataBuilderImpl.kt:157 calls isValidEmail(), which uses the default useStrictValidation = true:

is AutofillView.Login.Email -> {
    if (!autofillCipher.username.isValidEmail()) {
        return@mapNotNull null
    }
    autofillCipher.username
}

So the strict regex (^[A-Za-z0-9._%+-/*]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$) is what governs whether the type="email" field gets filled. The KDoc on Login.Email and the unit tests were already consistent with this strict behaviour, and the description is now aligned too.

No code change needed — my original comment was a doc/code consistency flag, and it's now resolved.

}
}

@Suppress("MaxLineLength")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This suppression is not needed, right?

verify(exactly = 1) { autofillViewEmail.buildFilledItemOrNull(emailUsername) }
}

@Suppress("MaxLineLength")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ditto

isVaultLocked = false,
)
coEvery { autofillCipherProvider.getLoginAutofillCiphers(uri = URI) } returns
listOf(autofillCipher)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we format this:

```kotlin
coEvery {
    autofillCipherProvider.getLoginAutofillCiphers(uri = URI)
} returns listOf(autofillCipher)

isVaultLocked = false,
)
coEvery { autofillCipherProvider.getLoginAutofillCiphers(uri = URI) } returns
listOf(autofillCipher)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ditto

@aj-rosado
aj-rosado added this pull request to the merge queue Jul 20, 2026
Merged via the queue into main with commit 0a57b9b Jul 20, 2026
23 checks passed
@aj-rosado
aj-rosado deleted the PM-39564/fill-assist-username-support-emaill branch July 20, 2026 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app:password-manager Bitwarden Password Manager app context t:feature Change Type - Feature Development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants