PM-35112: feat: Add underlying FedRAMP environment (#7138)

This commit is contained in:
David Perez
2026-07-06 17:44:20 +00:00
committed by GitHub
parent 7d31d00283
commit 6ea0afb865
18 changed files with 267 additions and 38 deletions
@@ -33,6 +33,9 @@ class RestrictionManagerImpl(
// If the baseEnvironmentUrl matches the predefined EU environment, assume it is the
// default EU environment.
Environment.Eu.environmentUrlData.base -> Environment.Eu
// If the baseEnvironmentUrl matches the predefined FedRAMP environment, assume it is
// the default FedRAMP environment.
Environment.FedRamp.environmentUrlData.base -> Environment.FedRamp
// Otherwise make a custom self-host environment.
else -> Environment.SelfHosted(EnvironmentUrlDataJson(baseEnvironmentUrl))
}
@@ -43,6 +43,13 @@ private fun EnvironmentUrlDataJson.authTabData(
)
}
EnvironmentRegion.FED_RAMP -> {
AuthTabData.HttpsScheme(
host = "bitwarden-gov.com",
path = "$kind-callback",
)
}
EnvironmentRegion.SELF_HOSTED -> {
AuthTabData.CustomScheme(
callbackUrl = "bitwarden://$kind-callback",
@@ -50,6 +50,7 @@ class EnvironmentViewModel @Inject constructor(
val environmentUrlData = when (val environment = environmentRepository.environment) {
Environment.Us,
Environment.Eu,
Environment.FedRamp,
-> EnvironmentUrlDataJson(base = "")
is Environment.SelfHosted -> environment.environmentUrlData
@@ -1,5 +1,6 @@
package com.x8bit.bitwarden.ui.auth.feature.landing
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -274,28 +275,35 @@ private fun LandingScreenContent(
Spacer(modifier = Modifier.height(height = 24.dp))
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.standardHorizontalMargin()
.fillMaxWidth()
.wrapContentHeight(),
AnimatedVisibility(
visible = state.allowCreateAccount,
label = "CreateAccountAnimatedVisibility",
) {
Text(
text = stringResource(id = BitwardenString.new_to_bitwarden),
style = BitwardenTheme.typography.bodyMedium,
color = BitwardenTheme.colorScheme.text.secondary,
)
Column {
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.standardHorizontalMargin()
.fillMaxWidth()
.wrapContentHeight(),
) {
Text(
text = stringResource(id = BitwardenString.new_to_bitwarden),
style = BitwardenTheme.typography.bodyMedium,
color = BitwardenTheme.colorScheme.text.secondary,
)
BitwardenTextButton(
label = stringResource(id = BitwardenString.create_an_account),
onClick = onCreateAccountClick,
modifier = Modifier
.testTag("CreateAccountLabel"),
)
BitwardenTextButton(
label = stringResource(id = BitwardenString.create_an_account),
onClick = onCreateAccountClick,
modifier = Modifier
.testTag("CreateAccountLabel"),
)
}
Spacer(modifier = Modifier.height(height = 8.dp))
}
}
Spacer(modifier = Modifier.height(height = 8.dp))
BitwardenTextButton(
label = stringResource(id = BitwardenString.app_settings),
onClick = onAppSettingsClick,
@@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.auth.feature.landing
import android.os.Parcelable
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import com.bitwarden.core.data.manager.model.FlagKey
import com.bitwarden.data.repository.model.Environment
import com.bitwarden.ui.platform.base.BackgroundEvent
import com.bitwarden.ui.platform.base.BaseViewModel
@@ -16,6 +17,7 @@ import com.bitwarden.ui.util.asText
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.auth.repository.model.LogoutReason
import com.x8bit.bitwarden.data.auth.repository.model.UserState
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
import com.x8bit.bitwarden.ui.platform.model.SnackbarRelay
@@ -43,6 +45,7 @@ class LandingViewModel @Inject constructor(
private val environmentRepository: EnvironmentRepository,
snackbarRelayManager: SnackbarRelayManager<SnackbarRelay>,
savedStateHandle: SavedStateHandle,
featureFlagManager: FeatureFlagManager,
) : BaseViewModel<LandingState, LandingEvent, LandingAction>(
initialState = savedStateHandle[KEY_STATE]
?: LandingState(
@@ -53,12 +56,13 @@ class LandingViewModel @Inject constructor(
selectedEnvironmentLabel = environmentRepository.environment.label,
dialog = null,
accountSummaries = authRepository.userStateFlow.value?.toAccountSummaries().orEmpty(),
isFedRampEnabled = featureFlagManager.getFeatureFlag(FlagKey.FedRamp),
),
) {
/**
* Returns the [AccountSummary] from the current state that matches the current email input and
* the the current environment, or `null` if there is no match.
* the current environment, or `null` if there is no match.
*/
private val matchingAccountSummary: AccountSummary?
get() {
@@ -106,6 +110,12 @@ class LandingViewModel @Inject constructor(
.map { LandingAction.Internal.SnackbarDataReceived(it) }
.onEach(::sendAction)
.launchIn(viewModelScope)
featureFlagManager
.getFeatureFlagFlow(FlagKey.FedRamp)
.map { LandingAction.Internal.FedRampFeatureUpdated(it) }
.onEach(::sendAction)
.launchIn(viewModelScope)
}
override fun handleAction(action: LandingAction) {
@@ -136,6 +146,7 @@ class LandingViewModel @Inject constructor(
}
is LandingAction.Internal.SnackbarDataReceived -> handleSnackbarDataReceived(action)
is LandingAction.Internal.FedRampFeatureUpdated -> handleFedRampFeatureUpdated(action)
}
}
@@ -231,6 +242,7 @@ class LandingViewModel @Inject constructor(
val environment = when (action.environmentType) {
Environment.Type.US -> Environment.Us
Environment.Type.EU -> Environment.Eu
Environment.Type.FED_RAMP -> Environment.FedRamp
Environment.Type.SELF_HOSTED -> {
// Launch the self-hosted screen and select the full environment details there.
sendEvent(LandingEvent.NavigateToEnvironment)
@@ -258,6 +270,10 @@ class LandingViewModel @Inject constructor(
sendEvent(LandingEvent.ShowSnackbar(action.data))
}
private fun handleFedRampFeatureUpdated(action: LandingAction.Internal.FedRampFeatureUpdated) {
mutableStateFlow.update { it.copy(isFedRampEnabled = action.isEnabled) }
}
/**
* If the user state account is changed to an active but not "logged in" account we can
* pre-populate the email field with this account.
@@ -284,12 +300,22 @@ data class LandingState(
val selectedEnvironmentLabel: String,
val dialog: DialogState?,
val accountSummaries: List<AccountSummary>,
val isFedRampEnabled: Boolean,
) : Parcelable {
/**
* The selectable environments.
*/
val environmentTypeOptions: ImmutableList<Environment.Type>
get() = Environment.Type.entries.toImmutableList()
get() = Environment.Type
.entries
.filterNot { it == Environment.Type.FED_RAMP && !isFedRampEnabled }
.toImmutableList()
/**
* Determines if the user should be allowed to create a new account.
*/
val allowCreateAccount: Boolean
get() = selectedEnvironmentType != Environment.Type.FED_RAMP
/**
* Determines whether the app bar should be visible based on the presence of account summaries.
@@ -453,5 +479,12 @@ sealed class LandingAction {
* Internal action to update the email input state from a non-user action
*/
data class UpdateEmailState(val emailInput: String) : Internal()
/**
* Indicates that FedRamp feature has been enabled or disabled.
*/
data class FedRampFeatureUpdated(
val isEnabled: Boolean,
) : Internal()
}
}
@@ -125,6 +125,11 @@ class StartRegistrationViewModel @Inject constructor(
sendEvent(StartRegistrationEvent.NavigateToEnvironment)
return
}
Environment.Type.FED_RAMP -> {
// New account creation is not supported with FedRAMP.
return
}
}
// Update the environment in the repo; the VM state will update accordingly because it is
@@ -296,7 +301,10 @@ data class StartRegistrationState(
* The selectable environments.
*/
val environmentTypeOptions: ImmutableList<Environment.Type>
get() = Environment.Type.entries.toImmutableList()
get() = Environment.Type
.entries
.filterNot { it == Environment.Type.FED_RAMP }
.toImmutableList()
}
/**
@@ -13,4 +13,5 @@ val Environment.Type.displayLabel: Text
Environment.Type.US -> Environment.Us.label.asText()
Environment.Type.EU -> Environment.Eu.label.asText()
Environment.Type.SELF_HOSTED -> BitwardenString.self_hosted.asText()
Environment.Type.FED_RAMP -> Environment.FedRamp.label.asText()
}
@@ -133,6 +133,21 @@ class RestrictionManagerTest {
)
}
@Suppress("MaxLineLength")
@Test
fun `initialize with baseEnvironmentUrl bundle data matching the current FedRAMP environment should set the environment to FedRAMP`() {
every {
restrictionsManager.applicationRestrictions
} returns mockBundle("baseEnvironmentUrl" to "https://vault.bitwarden-gov.com")
restrictionManager.initialize()
verify(exactly = 1) {
restrictionsManager.applicationRestrictions
}
assertEquals(Environment.FedRamp, fakeEnvironmentRepository.environment)
}
@Suppress("MaxLineLength")
@Test
fun `initialize with baseEnvironmentUrl bundle data matching the current self-hosted environment should set the environment to self-hosted`() {
@@ -23,6 +23,13 @@ class EnvironmentUrlDataJsonExtensionsTest {
),
EnvironmentUrlDataJson.DEFAULT_EU.duoAuthTabData,
)
assertEquals(
AuthTabData.HttpsScheme(
host = "bitwarden-gov.com",
path = "duo-callback",
),
EnvironmentUrlDataJson.DEFAULT_FED_RAMP.duoAuthTabData,
)
assertEquals(
AuthTabData.HttpsScheme(
host = "bitwarden.pw",
@@ -55,6 +62,13 @@ class EnvironmentUrlDataJsonExtensionsTest {
),
EnvironmentUrlDataJson.DEFAULT_EU.webAuthnAuthTabData,
)
assertEquals(
AuthTabData.HttpsScheme(
host = "bitwarden-gov.com",
path = "webauthn-callback",
),
EnvironmentUrlDataJson.DEFAULT_FED_RAMP.webAuthnAuthTabData,
)
assertEquals(
AuthTabData.HttpsScheme(
host = "bitwarden.pw",
@@ -87,6 +101,13 @@ class EnvironmentUrlDataJsonExtensionsTest {
),
EnvironmentUrlDataJson.DEFAULT_EU.ssoAuthTabData,
)
assertEquals(
AuthTabData.HttpsScheme(
host = "bitwarden-gov.com",
path = "sso-callback",
),
EnvironmentUrlDataJson.DEFAULT_FED_RAMP.ssoAuthTabData,
)
assertEquals(
AuthTabData.HttpsScheme(
host = "bitwarden.pw",
@@ -342,6 +342,23 @@ class LandingScreenTest : BitwardenComposeTest() {
assertTrue(onNavigateToPreAuthSettingsCalled)
}
@Test
fun `allowCreateAccount state should show and hide CreateAccount UI`() {
composeTestRule
.onNodeWithText(text = "Create an account")
.performScrollTo()
.assertIsDisplayed()
mutableStateFlow.update { it.copy(selectedEnvironmentType = Environment.Type.FED_RAMP) }
composeTestRule.onNodeWithText(text = "Create an account").assertDoesNotExist()
mutableStateFlow.update { it.copy(selectedEnvironmentType = Environment.Type.EU) }
composeTestRule
.onNodeWithText(text = "Create an account")
.performScrollTo()
.assertIsDisplayed()
}
@Test
fun `selecting environment should send EnvironmentOptionSelect action`() {
val selectedEnvironment = Environment.Eu
@@ -506,4 +523,5 @@ private val DEFAULT_STATE = LandingState(
selectedEnvironmentLabel = Environment.Us.label,
dialog = null,
accountSummaries = emptyList(),
isFedRampEnabled = true,
)
@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.auth.feature.landing
import androidx.lifecycle.SavedStateHandle
import app.cash.turbine.test
import com.bitwarden.core.data.manager.model.FlagKey
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
import com.bitwarden.data.repository.model.Environment
import com.bitwarden.ui.platform.base.BaseViewModelTest
@@ -15,6 +16,7 @@ import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.auth.repository.model.LogoutReason
import com.x8bit.bitwarden.data.auth.repository.model.UserState
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
@@ -47,6 +49,13 @@ class LandingViewModelTest : BaseViewModelTest() {
getSnackbarDataFlow(SnackbarRelay.ENVIRONMENT_SAVED)
} returns mutableSnackbarSharedFlow
}
private val mutableFedRampFlagStateFlow = MutableStateFlow(true)
private val featureFlagManager: FeatureFlagManager = mockk {
every { getFeatureFlagFlow(key = FlagKey.FedRamp) } returns mutableFedRampFlagStateFlow
every {
getFeatureFlag(key = FlagKey.FedRamp)
} answers { mutableFedRampFlagStateFlow.value }
}
@Test
fun `initial state should be correct when there is no remembered email`() = runTest {
@@ -124,6 +133,19 @@ class LandingViewModelTest : BaseViewModelTest() {
}
}
@Test
fun `FedRAMP flag changes should update state`() = runTest {
val viewModel = createViewModel()
viewModel.stateFlow.test {
assertEquals(DEFAULT_STATE, awaitItem())
mutableFedRampFlagStateFlow.value = false
assertEquals(DEFAULT_STATE.copy(isFedRampEnabled = false), awaitItem())
mutableFedRampFlagStateFlow.value = true
assertEquals(DEFAULT_STATE.copy(isFedRampEnabled = true), awaitItem())
}
}
@Test
fun `LockAccountClick should call lockVault for the given account`() {
val accountUserId = "userId"
@@ -623,6 +645,7 @@ class LandingViewModelTest : BaseViewModelTest() {
vaultRepository = vaultRepository,
environmentRepository = fakeEnvironmentRepository,
snackbarRelayManager = snackbarRelayManager,
featureFlagManager = featureFlagManager,
savedStateHandle = savedStateHandle,
)
@@ -637,4 +660,5 @@ private val DEFAULT_STATE = LandingState(
selectedEnvironmentLabel = Environment.Us.label,
dialog = null,
accountSummaries = emptyList(),
isFedRampEnabled = true,
)
@@ -251,22 +251,34 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
}
@Test
fun `EnvironmentTypeSelect should update value of selected region for US or EU`() = runTest {
val inputEnvironmentType = Environment.Type.EU
val viewModel = createViewModel()
viewModel.stateFlow.test {
awaitItem()
viewModel.trySendAction(
EnvironmentTypeSelect(
inputEnvironmentType,
),
)
assertEquals(
DEFAULT_STATE.copy(selectedEnvironmentType = Environment.Type.EU),
awaitItem(),
)
fun `EnvironmentTypeSelect should update value of selected region for UE, US, and FedRAMP`() =
runTest {
val viewModel = createViewModel()
viewModel.stateFlow.test {
skipItems(count = 1)
viewModel.trySendAction(
EnvironmentTypeSelect(environmentType = Environment.Type.EU),
)
assertEquals(
DEFAULT_STATE.copy(selectedEnvironmentType = Environment.Type.EU),
awaitItem(),
)
viewModel.trySendAction(
EnvironmentTypeSelect(environmentType = Environment.Type.US),
)
assertEquals(
DEFAULT_STATE.copy(selectedEnvironmentType = Environment.Type.US),
awaitItem(),
)
viewModel.trySendAction(
EnvironmentTypeSelect(environmentType = Environment.Type.FED_RAMP),
)
expectNoEvents()
}
}
}
@Test
fun `EnvironmentTypeSelect should emit NavigateToEnvironment for self-hosted`() = runTest {
@@ -23,6 +23,14 @@ class EnvironmentExtensionsTest {
)
}
@Test
fun `displayLabel for FED_RAMP type should return the correct value`() {
assertEquals(
"bitwarden-gov.com".asText(),
Environment.Type.FED_RAMP.displayLabel,
)
}
@Test
fun `displayLabel for SELF_HOSTED type should return the correct value`() {
assertEquals(
@@ -49,6 +49,7 @@ data class EnvironmentUrlDataJson(
get() = when (base) {
DEFAULT_US.base -> EnvironmentRegion.UNITED_STATES
DEFAULT_EU.base -> EnvironmentRegion.EUROPEAN_UNION
DEFAULT_FED_RAMP.base -> EnvironmentRegion.FED_RAMP
else -> {
if (base.contains(BITWARDEN_INTERNAL_DOMAIN)) {
EnvironmentRegion.INTERNAL
@@ -106,5 +107,11 @@ data class EnvironmentUrlDataJson(
webVault = "https://vault.bitwarden.eu",
events = "https://events.bitwarden.eu",
)
/**
* Default [EnvironmentUrlDataJson] for the FedRAMP environment.
*/
val DEFAULT_FED_RAMP: EnvironmentUrlDataJson =
EnvironmentUrlDataJson(base = "https://vault.bitwarden-gov.com")
}
}
@@ -45,6 +45,17 @@ sealed class Environment {
get() = "bitwarden.eu"
}
/**
* The default FedRAMP environment.
*/
data object FedRamp : Environment() {
override val type: Type get() = Type.FED_RAMP
override val environmentUrlData: EnvironmentUrlDataJson
get() = EnvironmentUrlDataJson.DEFAULT_FED_RAMP
override val label: String
get() = "bitwarden-gov.com"
}
/**
* A custom self-hosted environment with a fully configurable [environmentUrlData].
*/
@@ -63,6 +74,7 @@ sealed class Environment {
enum class Type {
US,
EU,
FED_RAMP,
SELF_HOSTED,
}
}
@@ -6,6 +6,7 @@ package com.bitwarden.data.repository.model
enum class EnvironmentRegion {
UNITED_STATES,
EUROPEAN_UNION,
FED_RAMP,
INTERNAL,
SELF_HOSTED,
}
@@ -7,15 +7,21 @@ import java.net.URI
private const val DEFAULT_US_API_URL: String = "https://api.bitwarden.com"
private const val DEFAULT_EU_API_URL: String = "https://api.bitwarden.eu"
private const val DEFAULT_FED_RAMP_API_URL: String = "https://api.bitwarden-gov.com"
private const val DEFAULT_US_EVENTS_URL: String = "https://events.bitwarden.com"
private const val DEFAULT_EU_EVENTS_URL: String = "https://events.bitwarden.eu"
private const val DEFAULT_FED_RAMP_EVENTS_URL: String = "https://events.bitwarden-gov.com"
private const val DEFAULT_US_IDENTITY_URL: String = "https://identity.bitwarden.com"
private const val DEFAULT_EU_IDENTITY_URL: String = "https://identity.bitwarden.eu"
private const val DEFAULT_FED_RAMP_IDENTITY_URL: String = "https://identity.bitwarden-gov.com"
private const val DEFAULT_US_WEB_VAULT_URL: String = "https://vault.bitwarden.com"
private const val DEFAULT_EU_WEB_VAULT_URL: String = "https://vault.bitwarden.eu"
private const val DEFAULT_FED_RAMP_WEB_VAULT_URL: String = "https://vault.bitwarden-gov.com"
private const val DEFAULT_US_WEB_SEND_URL: String = "https://send.bitwarden.com/#"
private const val DEFAULT_FED_RAMP_WEB_SEND_URL: String = "https://send.bitwarden-gov.com/#"
private const val DEFAULT_US_ICON_URL: String = "https://icons.bitwarden.net"
private const val DEFAULT_EU_ICON_URL: String = "https://icons.bitwarden.eu"
private const val DEFAULT_FED_RAMP_ICON_URL: String = "https://icons.bitwarden-gov.com"
/**
* Returns the base api URL or the default value if one is not present.
@@ -24,6 +30,7 @@ val EnvironmentUrlDataJson.baseApiUrl: String
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_API_URL
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_API_URL
EnvironmentRegion.FED_RAMP -> DEFAULT_FED_RAMP_API_URL
EnvironmentRegion.INTERNAL,
EnvironmentRegion.SELF_HOSTED,
-> {
@@ -40,6 +47,7 @@ val EnvironmentUrlDataJson.appLinksScheme: String
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES,
EnvironmentRegion.EUROPEAN_UNION,
EnvironmentRegion.FED_RAMP,
EnvironmentRegion.INTERNAL,
-> "https"
@@ -53,6 +61,7 @@ val EnvironmentUrlDataJson.baseEventsUrl: String
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_EVENTS_URL
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_EVENTS_URL
EnvironmentRegion.FED_RAMP -> DEFAULT_FED_RAMP_EVENTS_URL
EnvironmentRegion.INTERNAL,
EnvironmentRegion.SELF_HOSTED,
-> {
@@ -69,6 +78,7 @@ val EnvironmentUrlDataJson.baseIdentityUrl: String
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_IDENTITY_URL
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_IDENTITY_URL
EnvironmentRegion.FED_RAMP -> DEFAULT_FED_RAMP_IDENTITY_URL
EnvironmentRegion.INTERNAL,
EnvironmentRegion.SELF_HOSTED,
-> {
@@ -87,6 +97,7 @@ val EnvironmentUrlDataJson.baseWebVaultUrlOrNull: String?
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_WEB_VAULT_URL
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_WEB_VAULT_URL
EnvironmentRegion.FED_RAMP -> DEFAULT_FED_RAMP_WEB_VAULT_URL
EnvironmentRegion.INTERNAL,
EnvironmentRegion.SELF_HOSTED,
-> this.webVault.sanitizeUrl ?: this.base.sanitizeUrl
@@ -106,6 +117,7 @@ val EnvironmentUrlDataJson.baseWebVaultUrlOrDefault: String
val EnvironmentUrlDataJson.baseWebSendUrl: String
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_WEB_SEND_URL
EnvironmentRegion.FED_RAMP -> DEFAULT_FED_RAMP_WEB_SEND_URL
EnvironmentRegion.EUROPEAN_UNION,
EnvironmentRegion.INTERNAL,
EnvironmentRegion.SELF_HOSTED,
@@ -128,6 +140,7 @@ val EnvironmentUrlDataJson.baseIconUrl: String
get() = when (this.environmentRegion) {
EnvironmentRegion.UNITED_STATES -> DEFAULT_US_ICON_URL
EnvironmentRegion.EUROPEAN_UNION -> DEFAULT_EU_ICON_URL
EnvironmentRegion.FED_RAMP -> DEFAULT_FED_RAMP_ICON_URL
EnvironmentRegion.INTERNAL,
EnvironmentRegion.SELF_HOSTED,
-> {
@@ -139,7 +152,7 @@ val EnvironmentUrlDataJson.baseIconUrl: String
/**
* Returns the appropriate pre-defined labels for environments matching the known US/EU values.
* Otherwise returns the host of the custom base URL.
* Otherwise, returns the host of the custom base URL.
*
* @see getSelfHostedUrlOrNull
*/
@@ -147,6 +160,7 @@ val EnvironmentUrlDataJson.labelOrBaseUrlHost: String
get() = when (this) {
EnvironmentUrlDataJson.DEFAULT_US -> Environment.Us.label
EnvironmentUrlDataJson.DEFAULT_EU -> Environment.Eu.label
EnvironmentUrlDataJson.DEFAULT_FED_RAMP -> Environment.FedRamp.label
else -> {
// Grab the domain
// Ex:
@@ -189,6 +203,7 @@ fun EnvironmentUrlDataJson.toEnvironmentUrls(): Environment =
EnvironmentUrlDataJson.DEFAULT_LEGACY_EU,
-> Environment.Eu
EnvironmentUrlDataJson.DEFAULT_FED_RAMP -> Environment.FedRamp
else -> Environment.SelfHosted(environmentUrlData = this)
}
@@ -193,6 +193,15 @@ class EnvironmentUrlsDataJsonExtensionsTest {
)
}
@Test
fun `labelOrBaseUrlHost should correctly convert FedRAMP environment to the correct label`() {
val environment = EnvironmentUrlDataJson.DEFAULT_FED_RAMP
assertEquals(
Environment.FedRamp.label,
environment.labelOrBaseUrlHost,
)
}
@Suppress("MaxLineLength")
@Test
fun `labelOrBaseUrlHost should correctly convert self hosted environment to the correct label`() {
@@ -219,6 +228,14 @@ class EnvironmentUrlsDataJsonExtensionsTest {
)
}
@Test
fun `toEnvironmentUrls should correctly convert FedRAMP urls to the expected type`() {
assertEquals(
Environment.FedRamp,
EnvironmentUrlDataJson.DEFAULT_FED_RAMP.toEnvironmentUrls(),
)
}
@Test
fun `toEnvironmentUrls should correctly convert custom urls to the expected type`() {
assertEquals(
@@ -254,6 +271,14 @@ class EnvironmentUrlsDataJsonExtensionsTest {
)
}
@Test
fun `toEnvironmentUrlsOrDefault should correctly convert FedRAMP urls to the expected type`() {
assertEquals(
Environment.FedRamp,
EnvironmentUrlDataJson.DEFAULT_FED_RAMP.toEnvironmentUrlsOrDefault(),
)
}
@Suppress("MaxLineLength")
@Test
fun `toEnvironmentUrlsOrDefault should correctly convert legacy EU urls to the expected type`() {
@@ -357,6 +382,16 @@ class EnvironmentUrlsDataJsonExtensionsTest {
)
}
@Test
fun `appLinksScheme should return the correct scheme for FedRAMP environment`() {
val expectedScheme = "https"
assertEquals(
expectedScheme,
EnvironmentUrlDataJson.DEFAULT_FED_RAMP.appLinksScheme,
)
}
@Test
fun `appLinksScheme should return the correct scheme for internal environment`() {
val expectedScheme = "https"