diff --git a/WireAuthentication/Sources/WireAuthenticationUI/Components/OnPremHeaderView.swift b/WireAuthentication/Sources/WireAuthenticationUI/Components/OnPremHeaderView.swift index d68b02ec3cb..49738c7156e 100644 --- a/WireAuthentication/Sources/WireAuthenticationUI/Components/OnPremHeaderView.swift +++ b/WireAuthentication/Sources/WireAuthenticationUI/Components/OnPremHeaderView.swift @@ -51,6 +51,7 @@ package struct OnPremHeaderView: View { + Text(Image(systemName: "info.circle")) .foregroundColor(.gray) }) + .accessibilityIdentifier("onPremInfoButton") .multilineTextAlignment(.center) .font(.textStyle(.h2)) .lineLimit(nil) diff --git a/WireNetwork/Sources/WireNetwork/APIs/Rest/AuthenticationAPI/AuthenticationAPI.swift b/WireNetwork/Sources/WireNetwork/APIs/Rest/AuthenticationAPI/AuthenticationAPI.swift index d58be921703..1d2d4c86511 100644 --- a/WireNetwork/Sources/WireNetwork/APIs/Rest/AuthenticationAPI/AuthenticationAPI.swift +++ b/WireNetwork/Sources/WireNetwork/APIs/Rest/AuthenticationAPI/AuthenticationAPI.swift @@ -68,10 +68,12 @@ public protocol AuthenticationAPI: Sendable { func requestVerificationCode(for email: String) async throws /// Get Activation key & code for email - /// - Parameter email: email of user + /// - Parameters: + /// - email: email of user + /// - basicAuth: basicAuth value /// - Returns: Code & Key #if DEBUG - func getActivationCode(forEmail email: String) async throws -> (code: String, key: String) + func getActivationCode(forEmail email: String, basicAuth: String) async throws -> (code: String, key: String) #endif /// Register Personal Account diff --git a/WireNetwork/Sources/WireNetwork/APIs/Rest/AuthenticationAPI/AuthenticationAPIV0.swift b/WireNetwork/Sources/WireNetwork/APIs/Rest/AuthenticationAPI/AuthenticationAPIV0.swift index 8c3c437d883..2048640e17d 100644 --- a/WireNetwork/Sources/WireNetwork/APIs/Rest/AuthenticationAPI/AuthenticationAPIV0.swift +++ b/WireNetwork/Sources/WireNetwork/APIs/Rest/AuthenticationAPI/AuthenticationAPIV0.swift @@ -192,12 +192,12 @@ class AuthenticationAPIV0: AuthenticationAPI, VersionedAPI { .parse(code: response.statusCode, data: data) } - func getActivationCode(forEmail email: String) async throws -> (code: String, key: String) { + func getActivationCode(forEmail email: String, basicAuth: String) async throws -> (code: String, key: String) { let path = "/i/users/activation-code?email=\(email)" - let auth = ProcessInfo.processInfo.environment["BASIC_AUTH"]! + let request = try URLRequestBuilder(path: path) .withMethod(.get) - .addingHeader(field: "Authorization", value: "Basic \(auth)") + .addingHeader(field: "Authorization", value: "Basic \(basicAuth)") .build() let (data, response) = try await networkService.executeRequest(request) diff --git a/wire-ios/Tests/TestPlans/UITests.xctestplan b/wire-ios/Tests/TestPlans/UITests.xctestplan index 68c5a3f276f..e7f60c5d239 100644 --- a/wire-ios/Tests/TestPlans/UITests.xctestplan +++ b/wire-ios/Tests/TestPlans/UITests.xctestplan @@ -24,6 +24,22 @@ { "key" : "INBUCKET_PASSWORD", "value" : "$(INBUCKET_PASSWORD)" + }, + { + "key" : "ANTA_DEEPLINK_URL", + "value" : "$(ANTA_DEEPLINK_URL)" + }, + { + "key" : "ANTA_INBUCKET_URL", + "value" : "$(ANTA_INBUCKET_URL)" + }, + { + "key" : "BACKEND_URL_ANTA", + "value" : "$(BACKEND_URL_ANTA)" + }, + { + "key" : "BASIC_AUTH_ANTA", + "value" : "$(BASIC_AUTH_ANTA)" } ], "targetForVariableExpansion" : { diff --git a/wire-ios/Wire-iOS/Sources/AppDelegate.swift b/wire-ios/Wire-iOS/Sources/AppDelegate.swift index 2bf346c832e..7b7123316b2 100644 --- a/wire-ios/Wire-iOS/Sources/AppDelegate.swift +++ b/wire-ios/Wire-iOS/Sources/AppDelegate.swift @@ -516,11 +516,12 @@ private extension AppDelegate { } private func fetchDefaultEnvironment() -> BackendEnvironment2 { + let env = ProcessInfo.processInfo.arguments.contains("--useEnvStaging") ? "staging" : "default" guard let path = Bundle.backendBundle.path( - forResource: "default", + forResource: env, ofType: "json" ) else { - fatalError("default.json missing in Backend.bundle") + fatalError("\(env).json missing in Backend.bundle") } do { diff --git a/wire-ios/WireUITests/ApiClients/InbucketClient.swift b/wire-ios/WireUITests/ApiClients/InbucketClient.swift index 454ce5ea021..eaf4eaeda41 100644 --- a/wire-ios/WireUITests/ApiClients/InbucketClient.swift +++ b/wire-ios/WireUITests/ApiClients/InbucketClient.swift @@ -17,6 +17,7 @@ // import Foundation +import WireNetwork enum InbucketClient { @@ -24,7 +25,8 @@ enum InbucketClient { let envVariables = try EnvironmentVariables() var verificationCode = "" - let requestUrl = envVariables.inbucketURL.appending(path: "api/v1/mailbox/\(email)/latest") + let baseURL: URL = envVariables.inbucketURL + let requestUrl = baseURL.appending(path: "api/v1/mailbox/\(email)/latest") var request = URLRequest(url: requestUrl) request.httpMethod = "GET" diff --git a/wire-ios/WireUITests/Helper/BackendContext.swift b/wire-ios/WireUITests/Helper/BackendContext.swift new file mode 100644 index 00000000000..dec340714d5 --- /dev/null +++ b/wire-ios/WireUITests/Helper/BackendContext.swift @@ -0,0 +1,47 @@ +// +// Wire +// Copyright (C) 2025 Wire Swiss GmbH +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/. +// + +import Foundation +import WireNetwork + +public enum BackendContext { + static var current: BackendTarget = .staging + + static var backendEnvironment: BackendEnvironment { + switch current { + case .staging: + .staging + case .anta: + .anta + } + } +} + +public enum BackendTarget { + case staging + case anta + + var domainInfo: String { + switch self { + case .staging: + "staging.zinfra.io" + case .anta: + "anta.wire.link" + } + } +} diff --git a/wire-ios/WireUITests/Helper/EnvironmentVariables.swift b/wire-ios/WireUITests/Helper/EnvironmentVariables.swift index a5fd86b05d5..c3d554d8684 100644 --- a/wire-ios/WireUITests/Helper/EnvironmentVariables.swift +++ b/wire-ios/WireUITests/Helper/EnvironmentVariables.swift @@ -23,12 +23,19 @@ struct EnvironmentVariables { case missingInbucketURL case missingInbucketUsername case missingInbucketPassword + case missingDeepLinkURL } - var backendURL: URL - var inbucketURL: URL - var inbucketUsername: String - var inbucketPassword: String + private let stagingBackendURL: URL + private let antaBackendURL: URL + + private let stagingInbucketURL: URL + private let antaInbucketURL: URL + + let antaDeepLinkURL: URL + + let inbucketUsername: String + let inbucketPassword: String init() throws { guard let backendURLString = ProcessInfo.processInfo.environment["BACKEND_URL"], @@ -50,9 +57,55 @@ struct EnvironmentVariables { throw Failure.missingInbucketUsername } - self.backendURL = URL(string: "https://\(backendURLString)")! - self.inbucketURL = URL(string: "https://\(inbucketHostname)")! + guard let antaDeeplinkURL = ProcessInfo.processInfo.environment["ANTA_DEEPLINK_URL"], + !antaDeeplinkURL.isEmpty else { + throw Failure.missingDeepLinkURL + } + + guard let antaInbucketURL = ProcessInfo.processInfo.environment["ANTA_INBUCKET_URL"], + !antaInbucketURL.isEmpty else { + throw Failure.missingInbucketURL + } + + guard let backendURLAntaString = ProcessInfo.processInfo.environment["BACKEND_URL_ANTA"], + !backendURLAntaString.isEmpty else { + throw Failure.missingBackendURL + } + + self.stagingBackendURL = URL(string: "https://\(backendURLString)")! + self.stagingInbucketURL = URL(string: "https://\(inbucketHostname)")! self.inbucketUsername = inbucketUsername self.inbucketPassword = inbucketPassword + self.antaDeepLinkURL = URL(string: "https://\(antaDeeplinkURL)")! + self.antaInbucketURL = URL(string: "https://\(antaInbucketURL)")! + self.antaBackendURL = URL(string: "https://\(backendURLAntaString)")! } + + var inbucketURL: URL { + switch BackendContext.current { + case .anta: + antaInbucketURL + case .staging: + stagingInbucketURL + } + } + + var backendURL: URL { + switch BackendContext.current { + case .anta: + antaBackendURL + case .staging: + stagingBackendURL + } + } + + func deepLinkURL(for target: BackendTarget) -> URL { + switch target { + case .anta: + antaDeepLinkURL + case .staging: + fatalError("Not implemented yet") + } + } + } diff --git a/wire-ios/WireUITests/Helper/UserHelper.swift b/wire-ios/WireUITests/Helper/UserHelper.swift index ce1c11038d5..a74cab591e3 100644 --- a/wire-ios/WireUITests/Helper/UserHelper.swift +++ b/wire-ios/WireUITests/Helper/UserHelper.swift @@ -39,9 +39,10 @@ class UserHelper { private let authenticationManager = MockAuthManager() init(apiVersion: APIVersion = .v8) { + self.createdUsers = [] self.networkStack = NetworkStack( - backendEnvironment: .staging, + backendEnvironment: BackendContext.backendEnvironment, minTLSVersion: .v1_2, cookieEncryptionKey: Data(), authenticationManager: authenticationManager @@ -55,6 +56,22 @@ class UserHelper { self.conversationsAPI = ConversationsAPIBuilder(apiService: networkStack.apiService).makeAPI(for: apiVersion) } + func basicAuth(_ backend: BackendTarget = BackendContext.current) -> String { + switch backend { + case .staging: + guard let auth = ProcessInfo.processInfo.environment["BASIC_AUTH"] else { + fatalError("Missing BASIC_AUTH environment variable") + } + return auth + + case .anta: + guard let auth = ProcessInfo.processInfo.environment["BASIC_AUTH_ANTA"] else { + fatalError("Missing BASIC_AUTH_ANTA environment variable") + } + return auth + } + } + func createPersonalUser() async throws -> UserInfo { let user = UserGenerator.generateUniqueUserInfo() @@ -67,7 +84,10 @@ class UserHelper { cookieStorage.cookies = cookies // Get activation code - let (activationCode, activationKey) = try await BackendClient.getActivationCode(email: user.email) + let (activationCode, activationKey) = try await authenticationAPI.getActivationCode( + forEmail: user.email, + basicAuth: basicAuth() + ) // Activate user try await authenticationAPI.activateUser(email: user.email, key: activationKey, code: activationCode) @@ -153,7 +173,10 @@ class UserHelper { } func fetchAccessToken(email: String, password: String) async throws -> String { - let (activationCode, activationKey) = try await authenticationAPI.getActivationCode(forEmail: email) + let (activationCode, activationKey) = try await authenticationAPI.getActivationCode( + forEmail: email, + basicAuth: basicAuth() + ) try await authenticationAPI.activateUser(email: email, key: activationKey, code: activationCode) @@ -258,8 +281,9 @@ class UserHelper { } } -private extension BackendEnvironment { +extension BackendEnvironment { static let backendURL = "https://\(ProcessInfo.processInfo.environment["BACKEND_URL"]!)" + static let backendURLAnta = "https://\(ProcessInfo.processInfo.environment["BACKEND_URL_ANTA"]!)" static let staging = BackendEnvironment( url: URL(string: backendURL)!, webSocketURL: URL(string: backendURL)!, @@ -267,6 +291,14 @@ private extension BackendEnvironment { pinnedKeys: [], proxySettings: nil ) + + static let anta = BackendEnvironment( + url: URL(string: backendURLAnta)!, + webSocketURL: URL(string: backendURLAnta)!, + blacklistURL: URL(string: backendURLAnta)!, + pinnedKeys: [], + proxySettings: nil + ) } enum FilterConversationsByCriteria { diff --git a/wire-ios/WireUITests/Helper/WireUITestCase.swift b/wire-ios/WireUITests/Helper/WireUITestCase.swift index 231024ad302..772207d1b92 100644 --- a/wire-ios/WireUITests/Helper/WireUITestCase.swift +++ b/wire-ios/WireUITests/Helper/WireUITestCase.swift @@ -32,8 +32,7 @@ class WireUITestCase: XCTestCase { let launchArguments = [ "-resetData", - "--BackendEnvironmentTypeOverrideKey=staging", - "--persist-backend-type", + "--useEnvStaging", "--preferred-api-version=8" ] @@ -42,7 +41,7 @@ class WireUITestCase: XCTestCase { app.launchArguments = launchArguments app.setDeveloperFlags([ .useWireAuthentication: true, - .multibackend: false + .multibackend: true ]) app.launch() @@ -55,4 +54,47 @@ class WireUITestCase: XCTestCase { await userHelper.deleteCreatedUsers() } + func setCustomBackend(byDeeplink deeplink: URL, timeout: TimeInterval = 5, domainInfo: String) { + XCTContext.runActivity(named: "Set custom backend via deeplink") { _ in + let deeplinkFullURL = "wire://access/?config=\(deeplink)" + guard let url = URL(string: deeplinkFullURL) else { + XCTFail("Invalid deeplink: \(deeplinkFullURL)") + return + } + + XCUIDevice.shared.system.open(url) + + let alert = springboard.alerts.firstMatch + if alert.waitForExistence(timeout: 2) { + let openButton = springboard.alerts.buttons + .matching(NSPredicate(format: "label BEGINSWITH[c] 'Open'")) + .firstMatch + if openButton.waitForExistence(timeout: 1) { + openButton.tap() + } + } + + XCTAssertTrue( + app.wait(for: .runningForeground, timeout: timeout), + "App did not return to foreground after opening deeplink" + ) + guard let welcomePage = try? SetCustomBackendPage().tapOnProceedButton() else { + XCTFail("Failed to proceed to set custom backend") + return + } + let labeltext = welcomePage.setBackendLabel.label + XCTAssertTrue( + labeltext.contains(domainInfo), + "Expected domain missing from \(labeltext)" + ) + } + } + + func switchBackend(target: BackendTarget) throws { + + let deeplink = try EnvironmentVariables().deepLinkURL(for: target) + setCustomBackend(byDeeplink: deeplink, domainInfo: target.domainInfo) + // need to change for Inbucket + BackendContext.current = target + } } diff --git a/wire-ios/WireUITests/MultiBackendSupportTests.swift b/wire-ios/WireUITests/MultiBackendSupportTests.swift new file mode 100644 index 00000000000..ba1ea5b13f4 --- /dev/null +++ b/wire-ios/WireUITests/MultiBackendSupportTests.swift @@ -0,0 +1,100 @@ +// +// Wire +// Copyright (C) 2025 Wire Swiss GmbH +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/. +// + +import XCTest + +final class MultiBackendSupportTests: WireUITestCase { + + @MainActor + private func testLoginToBackend( + _ backend: BackendTarget + ) async throws -> (AccountSettingsPage, UserInfo) { + + let userHelper = UserHelper() + let user = try await userHelper.createPersonalUser() + + let firstTimePage = try app.loginUser(email: user.email, password: user.password) + + let accountPage = try firstTimePage + .acceptPopup(with: self) + .openSettings() + .openAccountSettings() + + try verifySwitchingAccount( + accountPage: accountPage, + expectedUser: user, + expectedDomain: backend.domainInfo + ) + + return (accountPage, user) + } + + @MainActor + func test_Add_MultiBackend_Accounts() async throws { + + defer { BackendContext.current = .staging } + + var (accountPageBackend1, userBackend1) = try await testLoginToBackend(.staging) + + _ = try accountPageBackend1 + .backToSettings() + .switchToConversationsTab() + .openUserAccountPageForUser(with: userBackend1.name) + .tapAddAccountOrTeamButton() + + try switchBackend(target: .anta) + + let (accountPageBackend2, userBackend2) = try await testLoginToBackend(.anta) + + accountPageBackend1 = try accountPageBackend2 + .backToSettings() + .switchToConversationsTab() + .openUserAccountPageForUser(with: userBackend2.name) + .switchUserAccountForUser(withName: userBackend1.name) + .openSettings() + .openAccountSettings() + + // Verify switching account + try verifySwitchingAccount( + accountPage: accountPageBackend1, + expectedUser: userBackend1, + expectedDomain: BackendTarget.staging.domainInfo + ) + } + + private func verifySwitchingAccount( + accountPage: AccountSettingsPage, + expectedUser: UserInfo, + expectedDomain: String + ) throws { + + let accountName = try XCTUnwrap(accountPage.getAccountName()) + let domainInfo = try XCTUnwrap(accountPage.getDomainInfo()) + let username = accountPage.getUsername() + let email = accountPage.getEmail() + + XCTAssertEqual(accountName, expectedUser.name, "Account name didn't match \(expectedUser.name)") + XCTAssertTrue( + username.contains(expectedUser.username), + "Username didn't contain \(expectedUser.username)" + ) + XCTAssertEqual(email, expectedUser.email, "Email didn't match \(expectedUser.email)") + XCTAssertEqual(domainInfo, expectedDomain, "Domain info \(domainInfo) mismatched on account page") + } + +} diff --git a/wire-ios/WireUITests/Pages/AccountSettingsPage.swift b/wire-ios/WireUITests/Pages/AccountSettingsPage.swift index 43fd583b8b2..7563a3fd060 100644 --- a/wire-ios/WireUITests/Pages/AccountSettingsPage.swift +++ b/wire-ios/WireUITests/Pages/AccountSettingsPage.swift @@ -36,6 +36,10 @@ class AccountSettingsPage: PageModel { app.descendants(matching: .any)["EmailField"].firstMatch } + var domainField: XCUIElement { + app.descendants(matching: .any)["DomainFieldDisabled"].firstMatch + } + var logoutButton: XCUIElement { app.staticTexts["Log Out"] } @@ -48,6 +52,10 @@ class AccountSettingsPage: PageModel { app.buttons["OK"] } + var backToSettingsButton: XCUIElement { + app.buttons["Settings"] + } + var backupOrRestoreButton: XCUIElement { app.descendants(matching: .any)["Back up or RestoreField"].firstMatch } @@ -64,8 +72,13 @@ class AccountSettingsPage: PageModel { emailField.label } - var backToSettingsButton: XCUIElement { - app.buttons["Settings"] + func getDomainInfo() -> String { + domainField.value as! String + } + + func backToSettings() throws -> SettingsPage { + backToSettingsButton.tap() + return try SettingsPage() } @discardableResult diff --git a/wire-ios/WireUITests/Pages/SetCustomBackendPage.swift b/wire-ios/WireUITests/Pages/SetCustomBackendPage.swift new file mode 100644 index 00000000000..6d131f6229e --- /dev/null +++ b/wire-ios/WireUITests/Pages/SetCustomBackendPage.swift @@ -0,0 +1,35 @@ +// +// Wire +// Copyright (C) 2025 Wire Swiss GmbH +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/. +// + +import XCTest + +class SetCustomBackendPage: PageModel { + override var pageMainElement: XCUIElement { + proceedButton + } + + var proceedButton: XCUIElement { + app.buttons["Proceed"] + } + + @discardableResult + func tapOnProceedButton() throws -> WelcomePage { + proceedButton.tap() + return try WelcomePage() + } +} diff --git a/wire-ios/WireUITests/Pages/UserAccountPage.swift b/wire-ios/WireUITests/Pages/UserAccountPage.swift index 66e117d9289..19e3e5b7cf1 100644 --- a/wire-ios/WireUITests/Pages/UserAccountPage.swift +++ b/wire-ios/WireUITests/Pages/UserAccountPage.swift @@ -42,7 +42,7 @@ class UserAccountPage: PageModel { } var manageTeamButton: XCUIElement { - app.staticTexts["Manage Team"].firstMatch + app.staticTexts["Manage Team & Billing"].firstMatch } var closeButton: XCUIElement { @@ -50,7 +50,7 @@ class UserAccountPage: PageModel { } var addAccountOrTeamButton: XCUIElement { - app.descendants(matching: .any)["Add Account or TeamField"] + app.descendants(matching: .any)["Add Account or Team"].firstMatch } func tapCreateTeamButtonAndContinue() throws -> TeamSetupStepsPage { @@ -73,7 +73,7 @@ class UserAccountPage: PageModel { } func switchUserAccountForUser(withName name: String) throws -> ConversationsPage { - let predicate = NSPredicate(format: "value BEGINSWITH %@", name) + let predicate = NSPredicate(format: "label BEGINSWITH %@", name) let button = app.buttons.containing(predicate).firstMatch button.tap() return try ConversationsPage() diff --git a/wire-ios/WireUITests/Pages/WelcomePage.swift b/wire-ios/WireUITests/Pages/WelcomePage.swift index 9fbe5168fd1..90e31dfb75e 100644 --- a/wire-ios/WireUITests/Pages/WelcomePage.swift +++ b/wire-ios/WireUITests/Pages/WelcomePage.swift @@ -34,6 +34,10 @@ class WelcomePage: PageModel { return elementsQuery["Email or SSO code"] } + var setBackendLabel: XCUIElement { + app.descendants(matching: .any)["onPremInfoButton"] + } + func enterEmailOrSSO(_ input: String) throws -> LoginPage { try typeEmailOrSSO(input) nextButton.tap() diff --git a/wire-ios/WireUITests/PersonalUserTests.swift b/wire-ios/WireUITests/PersonalUserTests.swift index bf6ffdad6f3..6885cb84b4a 100644 --- a/wire-ios/WireUITests/PersonalUserTests.swift +++ b/wire-ios/WireUITests/PersonalUserTests.swift @@ -135,8 +135,5 @@ final class PersonalUsersTests: WireUITestCase { let accountNameUserB = try XCTUnwrap(accountSettingsPage.getAccountName()) XCTAssertNotEqual(accountNameUserA, accountNameUserB, "Account name didn't change after deleting") - - try accountSettingsPage.logout() - .enterPassword(userB.password) } } diff --git a/wire-ios/WireUITests/env.xcconfig.tpl b/wire-ios/WireUITests/env.xcconfig.tpl index c199957fd08..c0e3e89d53e 100644 --- a/wire-ios/WireUITests/env.xcconfig.tpl +++ b/wire-ios/WireUITests/env.xcconfig.tpl @@ -21,3 +21,7 @@ INBUCKET_PASSWORD=op://Test Automation/BackendConnection staging/inbucketPasswor INBUCKET_URL=op://Test Automation/BackendConnection staging/trimmedInbucketUrl BACKEND_URL=op://Test Automation/BackendConnection staging/trimmedBackendURL BASIC_AUTH=op://Test Automation/BackendConnection staging/basicAuth +ANTA_DEEPLINK_URL=op://Test Automation/BackendConnection anta/trimmedDeeplinkUrl +ANTA_INBUCKET_URL=op://Test Automation/BackendConnection anta/trimmedInbucketUrl +BASIC_AUTH_ANTA=op://Test Automation/BackendConnection anta/basicAuth +BACKEND_URL_ANTA=op://Test Automation/BackendConnection anta/trimmedBackendURL