Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
f358e43
[PM-38440] feat: Add fill-assist-targeting-rules feature flag
andrebispo5 Jun 4, 2026
091c91f
[PM-38442] feat: Add fillAssistRules to EnvironmentServerConfigRespon…
andrebispo5 Jun 5, 2026
4218f94
[PM-38442] feat: Add fillAssistRulesURL to EnvironmentService
andrebispo5 Jun 5, 2026
0b40e36
[PM-38442] feat: Add FillAssistAPIService and FormsMap models
andrebispo5 Jun 5, 2026
3c1d6b4
[PM-38442] feat: Fix test doc comment for getFormsMap
andrebispo5 Jun 5, 2026
ee481b1
Merge branch 'main' into pm-38442/add-fill-assist-endpoint-and-models
andrebispo5 Jun 5, 2026
92c49fa
Merge branch 'main' into pm-38442/add-fill-assist-endpoint-and-models
andrebispo5 Jun 16, 2026
876216e
[PM-38442] fix: Fix FormsMapResponseModel conformance and update test…
andrebispo5 Jun 17, 2026
712fe31
Merge branch 'main' into pm-38442/add-fill-assist-endpoint-and-models
andrebispo5 Jun 17, 2026
181cccf
[PM-38442] fix: Implement custom Codable to exclude null hosts in For…
andrebispo5 Jun 17, 2026
540e046
[PM-38442] fix: Persist fillAssistRulesUrl from server config into En…
andrebispo5 Jun 17, 2026
0643e75
Merge branch 'pm-38442/add-fill-assist-endpoint-and-models' of https:…
andrebispo5 Jun 17, 2026
338367f
[PM-38442] fix: Restore missing manageSubscriptionURL after merge
andrebispo5 Jun 17, 2026
1fc8ee8
[PM-38442] fix: Add fillAssistRulesURL to Authenticator DefaultEnviro…
andrebispo5 Jun 17, 2026
ef95cce
[PM-38442] fix: Preserve fillAssistRulesUrl from original Environment…
andrebispo5 Jun 17, 2026
00ab004
[PM-38442] test: Add decode tests for FormsMapResponseModel null host…
andrebispo5 Jun 17, 2026
3564086
[PM-38442] test: Improve code coverage for fillAssistRules changes
andrebispo5 Jun 17, 2026
eff61fa
[PM-38442] refactor: Make fillAssistRulesUrl a var and simplify FillA…
andrebispo5 Jun 18, 2026
f90dc54
[PM-38442] refactor: Rename mapTheWebService to fillAssistService
andrebispo5 Jun 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ extension DefaultEnvironmentService {
environmentURLs.eventsURL
}

var fillAssistRulesURL: URL {
environmentURLs.fillAssistRulesURL
}

var iconsURL: URL {
environmentURLs.iconsURL
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class EnvironmentServiceTests: XCTestCase {
XCTAssertEqual(subject.settingsURL, URL(string: "https://vault.bitwarden.com/#/settings"))
// swiftlint:disable:next line_length
XCTAssertEqual(subject.setUpTwoFactorURL, URL(string: "https://vault.bitwarden.com/#/settings/security/two-factor"))
// swiftlint:disable:next line_length
XCTAssertEqual(subject.fillAssistRulesURL, URL(string: "https://github.com/bitwarden/map-the-web/releases/latest/download"))
XCTAssertEqual(subject.webVaultURL, URL(string: "https://vault.bitwarden.com"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public struct EnvironmentURLData: Codable, Equatable, Hashable, Sendable {
/// The URL for the events API.
public let events: URL?

/// The base URL for fetching Fill-Assist targeting rules. Set from the server config.
public let fillAssistRulesUrl: URL?

/// The URL for the icons API.
public let icons: URL?

Expand All @@ -42,6 +45,7 @@ public struct EnvironmentURLData: Codable, Equatable, Hashable, Sendable {
/// - clientCertificateAlias: The human-readable alias for the client certificate.
/// - clientCertificateFingerprint: The SHA-256 fingerprint of the client certificate.
/// - events: The URL for the events API.
/// - fillAssistRulesUrl: The base URL for fetching Fill-Assist targeting rules.
/// - icons: The URL for the icons API.
/// - identity: The URL for the identity API.
/// - notifications: The URL for the notifications API.
Expand All @@ -53,6 +57,7 @@ public struct EnvironmentURLData: Codable, Equatable, Hashable, Sendable {
clientCertificateAlias: String? = nil,
clientCertificateFingerprint: String? = nil,
events: URL? = nil,
fillAssistRulesUrl: URL? = nil,
icons: URL? = nil,
identity: URL? = nil,
notifications: URL? = nil,
Expand All @@ -63,6 +68,7 @@ public struct EnvironmentURLData: Codable, Equatable, Hashable, Sendable {
self.clientCertificateAlias = clientCertificateAlias
self.clientCertificateFingerprint = clientCertificateFingerprint
self.events = events
self.fillAssistRulesUrl = fillAssistRulesUrl
self.icons = icons
self.identity = identity
self.notifications = notifications
Expand All @@ -83,11 +89,6 @@ public extension EnvironmentURLData {
subpageURL(additionalPath: "tools/import")
}

Comment thread
andrebispo5 marked this conversation as resolved.
/// The URL for managing the subscription plan.
var manageSubscriptionURL: URL? {
subpageURL(additionalPath: "settings/subscription")
}

/// Whether all of the environment URLs are not set.
var isEmpty: Bool {
api == nil
Expand All @@ -99,6 +100,11 @@ public extension EnvironmentURLData {
&& webVault == nil
}

/// The URL for managing the subscription plan.
var manageSubscriptionURL: URL? {
subpageURL(additionalPath: "settings/subscription")
}

/// The URL for a proxy on cookie redirect (used on SSO sync error).
var proxyCookieRedirectConnectorURL: URL? {
subpageURL(additionalPath: "proxy-cookie-redirect-connector.html", shouldAddPoundSign: false)
Expand Down Expand Up @@ -150,6 +156,26 @@ public extension EnvironmentURLData {
return url?.host
}

/// Returns a copy of this `EnvironmentURLData` with the given Fill-Assist rules URL applied.
///
/// - Parameter fillAssistRulesUrl: The Fill-Assist rules URL to set.
/// - Returns: A new `EnvironmentURLData` with `fillAssistRulesUrl` updated.
///
func with(fillAssistRulesUrl: URL?) -> EnvironmentURLData {
Comment thread
matt-livefront marked this conversation as resolved.
Outdated
EnvironmentURLData(
api: api,
base: base,
clientCertificateAlias: clientCertificateAlias,
clientCertificateFingerprint: clientCertificateFingerprint,
events: events,
fillAssistRulesUrl: fillAssistRulesUrl,
icons: icons,
identity: identity,
notifications: notifications,
webVault: webVault,
)
}

// MARK: Methods

/// The URL for a given subpage of the vault webpage.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,4 +275,19 @@ class EnvironmentURLDataTests: XCTestCase {
"https://web.vault.example.com/proxy-cookie-redirect-connector.html",
)
}

/// `with(fillAssistRulesUrl:)` returns a copy with `fillAssistRulesUrl` updated.
func test_with_fillAssistRulesUrl() {
let original = EnvironmentURLData(
api: URL(string: "https://api.example.com"),
base: URL(string: "https://vault.example.com"),
)
let fillAssistURL = URL(string: "https://custom.example.com/fill-assist")!

let updated = original.with(fillAssistRulesUrl: fillAssistURL)

XCTAssertEqual(updated.fillAssistRulesUrl, fillAssistURL)
XCTAssertEqual(updated.api, original.api)
XCTAssertEqual(updated.base, original.base)
}
}
12 changes: 12 additions & 0 deletions BitwardenKit/Core/Platform/Models/Domain/EnvironmentURLs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public struct EnvironmentURLs: Equatable {
/// The URL for the events API.
public let eventsURL: URL

/// The URL for fetching Fill-Assist targeting rules.
public let fillAssistRulesURL: URL

/// The URL for the icons API.
public let iconsURL: URL

Expand Down Expand Up @@ -57,6 +60,7 @@ public struct EnvironmentURLs: Equatable {
/// - baseURL: The base URL.
/// - changeEmailURL: The URL for changing email address.
/// - eventsURL: The URL for the events API.
/// - fillAssistRulesURL: The URL for fetching Fill-Assist targeting rules.
/// - iconsURL: The URL for the icons API.
/// - identityURL: The URL for the identity API.
/// - importItemsURL: The URL for importing items.
Expand All @@ -73,6 +77,7 @@ public struct EnvironmentURLs: Equatable {
baseURL: URL,
changeEmailURL: URL,
eventsURL: URL,
fillAssistRulesURL: URL,
iconsURL: URL,
identityURL: URL,
importItemsURL: URL,
Expand All @@ -89,6 +94,7 @@ public struct EnvironmentURLs: Equatable {
self.baseURL = baseURL
self.changeEmailURL = changeEmailURL
self.eventsURL = eventsURL
self.fillAssistRulesURL = fillAssistRulesURL
self.iconsURL = iconsURL
self.identityURL = identityURL
self.importItemsURL = importItemsURL
Expand All @@ -109,6 +115,10 @@ public extension EnvironmentURLs {
/// - Parameter environmentURLData: The environment URLs used to initialize `EnvironmentURLs`.
///
init(environmentURLData: EnvironmentURLData) {
// Capture fillAssistRulesUrl before the region switch may replace environmentURLData with a
// default that has fillAssistRulesUrl = nil, which would discard the server-config override.
let fillAssistRulesUrl = environmentURLData.fillAssistRulesUrl

// Use the default URLs if the region matches US or EU.
let environmentURLData: EnvironmentURLData = switch environmentURLData.region {
case .europe: .defaultEU
Expand All @@ -131,6 +141,8 @@ public extension EnvironmentURLs {
identityURL = environmentURLData.identity ?? URL(string: "https://identity.bitwarden.com")!
webVaultURL = environmentURLData.webVault ?? URL(string: "https://vault.bitwarden.com")!
}
fillAssistRulesURL = fillAssistRulesUrl
?? URL(string: "https://github.com/bitwarden/map-the-web/releases/latest/download")!
importItemsURL = environmentURLData.importItemsURL ?? URL(string: "https://vault.bitwarden.com/#/tools/import")!
recoveryCodeURL = environmentURLData.recoveryCodeURL ?? URL(
string: "https://vault.bitwarden.com/#/recover-2fa",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class EnvironmentURLsTests: BitwardenTestCase {
baseURL: URL(string: "https://vault.bitwarden.com")!,
changeEmailURL: URL(string: "https://vault.bitwarden.com/#/settings/account")!,
eventsURL: URL(string: "https://events.bitwarden.com")!,
fillAssistRulesURL: URL(string: "https://github.com/bitwarden/map-the-web/releases/latest/download")!,
iconsURL: URL(string: "https://icons.bitwarden.net")!,
identityURL: URL(string: "https://identity.bitwarden.com")!,
importItemsURL: URL(string: "https://vault.bitwarden.com/#/tools/import")!,
Expand Down Expand Up @@ -48,6 +49,7 @@ class EnvironmentURLsTests: BitwardenTestCase {
baseURL: URL(string: "https://vault.bitwarden.eu")!,
changeEmailURL: URL(string: "https://vault.bitwarden.eu/#/settings/account")!,
eventsURL: URL(string: "https://events.bitwarden.eu")!,
fillAssistRulesURL: URL(string: "https://github.com/bitwarden/map-the-web/releases/latest/download")!,
iconsURL: URL(string: "https://icons.bitwarden.eu")!,
identityURL: URL(string: "https://identity.bitwarden.eu")!,
importItemsURL: URL(string: "https://vault.bitwarden.eu/#/tools/import")!,
Expand Down Expand Up @@ -80,6 +82,7 @@ class EnvironmentURLsTests: BitwardenTestCase {
baseURL: URL(string: "https://example.com")!,
changeEmailURL: URL(string: "https://example.com/#/settings/account")!,
eventsURL: URL(string: "https://example.com/events")!,
fillAssistRulesURL: URL(string: "https://github.com/bitwarden/map-the-web/releases/latest/download")!,
iconsURL: URL(string: "https://example.com/icons")!,
identityURL: URL(string: "https://example.com/identity")!,
importItemsURL: URL(string: "https://example.com/#/tools/import")!,
Expand Down Expand Up @@ -111,6 +114,7 @@ class EnvironmentURLsTests: BitwardenTestCase {
baseURL: URL(string: "https://vault.bitwarden.eu")!,
changeEmailURL: URL(string: "https://vault.bitwarden.eu/#/settings/account")!,
eventsURL: URL(string: "https://events.bitwarden.eu")!,
fillAssistRulesURL: URL(string: "https://github.com/bitwarden/map-the-web/releases/latest/download")!,
iconsURL: URL(string: "https://icons.bitwarden.eu")!,
identityURL: URL(string: "https://identity.bitwarden.eu")!,
importItemsURL: URL(string: "https://vault.bitwarden.eu/#/tools/import")!,
Expand Down Expand Up @@ -142,6 +146,7 @@ class EnvironmentURLsTests: BitwardenTestCase {
baseURL: URL(string: "https://vault.bitwarden.com")!,
changeEmailURL: URL(string: "https://vault.bitwarden.com/#/settings/account")!,
eventsURL: URL(string: "https://events.bitwarden.com")!,
fillAssistRulesURL: URL(string: "https://github.com/bitwarden/map-the-web/releases/latest/download")!,
iconsURL: URL(string: "https://icons.bitwarden.net")!,
identityURL: URL(string: "https://identity.bitwarden.com")!,
importItemsURL: URL(string: "https://vault.bitwarden.com/#/tools/import")!,
Expand Down Expand Up @@ -173,6 +178,7 @@ class EnvironmentURLsTests: BitwardenTestCase {
baseURL: URL(string: "https://example.com/")!,
changeEmailURL: URL(string: "https://example.com/#/settings/account")!,
eventsURL: URL(string: "https://example.com/events")!,
fillAssistRulesURL: URL(string: "https://github.com/bitwarden/map-the-web/releases/latest/download")!,
iconsURL: URL(string: "https://example.com/icons")!,
identityURL: URL(string: "https://example.com/identity")!,
importItemsURL: URL(string: "https://example.com/#/tools/import")!,
Expand Down Expand Up @@ -210,6 +216,7 @@ class EnvironmentURLsTests: BitwardenTestCase {
baseURL: URL(string: "https://vault.bitwarden.com")!,
changeEmailURL: URL(string: "https://example.com/#/settings/account")!,
eventsURL: URL(string: "https://events.example.com")!,
fillAssistRulesURL: URL(string: "https://github.com/bitwarden/map-the-web/releases/latest/download")!,
iconsURL: URL(string: "https://icons.example.com")!,
identityURL: URL(string: "https://identity.example.com")!,
importItemsURL: URL(string: "https://example.com/#/tools/import")!,
Expand Down Expand Up @@ -239,6 +246,7 @@ class EnvironmentURLsTests: BitwardenTestCase {
baseURL: URL(string: "https://vault.bitwarden.com")!,
changeEmailURL: URL(string: "https://vault.bitwarden.com")!,
eventsURL: URL(string: "https://events.bitwarden.com")!,
fillAssistRulesURL: URL(string: "https://github.com/bitwarden/map-the-web/releases/latest/download")!,
iconsURL: URL(string: "https://icons.bitwarden.net")!,
identityURL: URL(string: "https://identity.bitwarden.com")!,
importItemsURL: URL(string: "https://vault.bitwarden.com/#/tools/import")!,
Expand All @@ -253,4 +261,18 @@ class EnvironmentURLsTests: BitwardenTestCase {
),
)
}

/// `init(environmentURLData:)` preserves a server-provided `fillAssistRulesUrl` even when the
/// region maps to a US/EU default (which has `fillAssistRulesUrl = nil`).
func test_init_environmentURLData_fillAssistRulesURL_preservedForCloudRegion() {
let customFillAssistURL = URL(string: "https://custom.example.com/fill-assist")!
let usData = EnvironmentURLData(
base: URL(string: "https://vault.bitwarden.com")!,
fillAssistRulesUrl: customFillAssistURL,
)

let subject = EnvironmentURLs(environmentURLData: usData)

XCTAssertEqual(subject.fillAssistRulesURL, customFillAssistURL)
}
}
4 changes: 4 additions & 0 deletions BitwardenKit/Core/Platform/Models/Domain/ServerConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ public struct EnvironmentServerConfig: Equatable, Codable, Sendable {
/// The Cloud Region (e.g. "US")
public let cloudRegion: String?

/// The Fill-Assist rules URL.
public let fillAssistRules: String?

/// The Identity URL.
public let identity: String?

Expand All @@ -92,6 +95,7 @@ public struct EnvironmentServerConfig: Equatable, Codable, Sendable {
public init(responseModel: EnvironmentServerConfigResponseModel) {
api = responseModel.api
cloudRegion = responseModel.cloudRegion
fillAssistRules = responseModel.fillAssistRules
identity = responseModel.identity
notifications = responseModel.notifications
sso = responseModel.sso
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ public struct EnvironmentServerConfigResponseModel: Equatable, JSONResponse {
/// The Cloud Region (e.g. "US")
public let cloudRegion: String?

/// The Fill-Assist rules URL.
public let fillAssistRules: String?

/// The Identity URL.
public let identity: String?

Expand All @@ -173,20 +176,23 @@ public struct EnvironmentServerConfigResponseModel: Equatable, JSONResponse {
/// - Parameters:
/// - api: The API URL.
/// - cloudRegion: The Cloud Region (e.g. "US").
/// - fillAssistRules: The Fill-Assist rules URL.
/// - identity: The Identity URL.
/// - notifications: The Notifications URL.
/// - sso: The SSO URL.
/// - vault: The Vault URL.
public init(
api: String?,
cloudRegion: String?,
fillAssistRules: String?,
identity: String?,
notifications: String?,
sso: String?,
vault: String?,
) {
self.api = api
self.cloudRegion = cloudRegion
self.fillAssistRules = fillAssistRules
self.identity = identity
self.notifications = notifications
self.sso = sso
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ class AppInfoServiceTests: BitwardenTestCase { // swiftlint:disable:this type_bo
environment: EnvironmentServerConfigResponseModel(
api: nil,
cloudRegion: "EU",
fillAssistRules: nil,
identity: nil,
notifications: nil,
sso: nil,
Expand Down Expand Up @@ -254,6 +255,7 @@ class AppInfoServiceTests: BitwardenTestCase { // swiftlint:disable:this type_bo
environment: EnvironmentServerConfigResponseModel(
api: nil,
cloudRegion: "US",
fillAssistRules: nil,
identity: nil,
notifications: nil,
sso: nil,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public protocol EnvironmentService {
/// The URL for the events API.
var eventsURL: URL { get }

/// The URL for fetching Fill-Assist targeting rules.
var fillAssistRulesURL: URL { get }

Comment thread
andrebispo5 marked this conversation as resolved.
/// The URL for the icons API.
var iconsURL: URL { get }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class MockEnvironmentService: EnvironmentService {
public var changeEmailURL = URL(string: "https://example.com/#/settings/account")!
public var clientCertificateFingerprint: String?
public var eventsURL = URL(string: "https://example.com/events")!
public var fillAssistRulesURL = URL(string: "https://example.com/fill-assist-rules")!
public var iconsURL = URL(string: "https://example.com/icons")!
public var identityURL = URL(string: "https://example.com/identity")!
public var importItemsURL = URL(string: "https://example.com/#/tools/import")!
Expand Down
Loading
Loading