commit 0491fc9858a319728b731bfe68afe32dc528801b
parent 8f9ee257ea8c2f14be0af88f137ce06882a97bab
Author: triesap <tyson@radroots.org>
Date: Fri, 3 Jul 2026 06:40:02 +0000
runtime: remove legacy path and fallback surfaces
- delete the public runtime path migration module and reexports
- make secret backend selection primary-only and fail-closed
- update nostr account manager tests for the contracted resolver
- keep runtime path and secret vault docs aligned with the API
Diffstat:
7 files changed, 32 insertions(+), 421 deletions(-)
diff --git a/crates/nostr_accounts/src/manager.rs b/crates/nostr_accounts/src/manager.rs
@@ -883,13 +883,12 @@ mod tests {
}
#[test]
- fn resolve_local_backend_applies_shared_fallback_policy() {
- let resolved = RadrootsNostrAccountsManager::resolve_local_backend(
+ fn resolve_local_backend_fails_when_primary_is_unavailable() {
+ let err = RadrootsNostrAccountsManager::resolve_local_backend(
RadrootsSecretBackendSelection {
primary: RadrootsSecretBackend::HostVault(
radroots_secret_vault::RadrootsHostVaultPolicy::desktop(),
),
- fallback: Some(RadrootsSecretBackend::EncryptedFile),
},
RadrootsSecretBackendAvailability {
host_vault: RadrootsHostVaultCapabilities::unavailable(),
@@ -898,10 +897,9 @@ mod tests {
memory: false,
},
)
- .expect("fallback resolves");
+ .expect_err("unavailable primary fails");
- assert_eq!(resolved.backend, RadrootsSecretBackend::EncryptedFile);
- assert!(resolved.used_fallback);
+ assert_eq!(err.to_string(), "secret backend host_vault is unavailable");
}
#[test]
@@ -912,7 +910,6 @@ mod tests {
temp.path().join("secrets"),
RadrootsSecretBackendSelection {
primary: RadrootsSecretBackend::ExternalCommand,
- fallback: None,
},
RadrootsSecretBackendAvailability {
host_vault: RadrootsHostVaultCapabilities::unavailable(),
@@ -941,7 +938,6 @@ mod tests {
primary: RadrootsSecretBackend::HostVault(
radroots_secret_vault::RadrootsHostVaultPolicy::desktop(),
),
- fallback: None,
},
RadrootsSecretBackendAvailability {
host_vault: RadrootsHostVaultCapabilities::unavailable(),
@@ -968,7 +964,6 @@ mod tests {
temp.path().join("secrets"),
RadrootsSecretBackendSelection {
primary: RadrootsSecretBackend::EncryptedFile,
- fallback: None,
},
RadrootsSecretBackendAvailability {
host_vault: RadrootsHostVaultCapabilities::unavailable(),
@@ -992,7 +987,6 @@ mod tests {
temp.path().join("secrets"),
RadrootsSecretBackendSelection {
primary: RadrootsSecretBackend::EncryptedFile,
- fallback: None,
},
RadrootsSecretBackendAvailability {
host_vault: RadrootsHostVaultCapabilities::unavailable(),
@@ -1005,7 +999,6 @@ mod tests {
.expect("encrypted file manager");
assert_eq!(resolved.backend, RadrootsSecretBackend::EncryptedFile);
- assert!(!resolved.used_fallback);
assert!(manager.list_accounts().expect("accounts").is_empty());
}
diff --git a/crates/runtime_paths/README b/crates/runtime_paths/README
@@ -11,8 +11,7 @@ runtime path selection and contract helpers for the `radroots` core libraries.
* resolver, override, and runtime-selection helpers that produce structured
`RadrootsPaths` outputs;
* service and app contract helpers for active profile, override, and root
- selection reporting;
- * migration and legacy-path inspection helpers for runtime relocation audits.
+ selection reporting.
## Copyright
diff --git a/crates/runtime_paths/src/lib.rs b/crates/runtime_paths/src/lib.rs
@@ -2,7 +2,6 @@
pub mod conventions;
pub mod error;
-pub mod migration;
pub mod namespace;
pub mod platform;
pub mod roots;
@@ -25,20 +24,13 @@ pub use conventions::{
default_shared_runtime_logs_dir,
};
pub use error::RadrootsRuntimePathsError;
-pub use migration::{
- RADROOTS_MIGRATION_COMPATIBILITY_WINDOW, RADROOTS_MIGRATION_POSTURE,
- RadrootsLegacyPathCandidate, RadrootsLegacyPathDetection, RadrootsMigrationReport,
- inspect_legacy_paths,
-};
pub use namespace::{RadrootsRuntimeNamespace, RadrootsRuntimeNamespaceKind};
pub use platform::{RadrootsHostEnvironment, RadrootsPathProfile, RadrootsPlatform};
pub use roots::{RadrootsPathOverrides, RadrootsPathResolver, RadrootsPaths};
pub use service::{
- RadrootsRuntimeLegacyPathContract, RadrootsRuntimeMigrationContract,
RadrootsRuntimePathConfigEntry, RadrootsRuntimePathPolicyContract,
RadrootsRuntimePathSelection, RadrootsRuntimePathSelectionError,
RadrootsRuntimeSelectionContract, RadrootsRuntimeSelectionOverrideContract,
- runtime_migration_contract,
};
#[cfg(test)]
diff --git a/crates/runtime_paths/src/migration.rs b/crates/runtime_paths/src/migration.rs
@@ -1,184 +0,0 @@
-use std::path::PathBuf;
-
-pub const RADROOTS_MIGRATION_POSTURE: &str = "explicit_operator_import_required";
-pub const RADROOTS_MIGRATION_COMPATIBILITY_WINDOW: &str = "detect_and_report_only";
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct RadrootsLegacyPathCandidate {
- pub id: String,
- pub description: String,
- pub path: PathBuf,
- pub destination: Option<PathBuf>,
- pub import_hint: String,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct RadrootsLegacyPathDetection {
- pub id: String,
- pub description: String,
- pub path: PathBuf,
- pub destination: Option<PathBuf>,
- pub import_hint: String,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct RadrootsMigrationReport {
- pub posture: &'static str,
- pub state: &'static str,
- pub silent_startup_relocation: bool,
- pub compatibility_window: &'static str,
- pub detected_legacy_paths: Vec<RadrootsLegacyPathDetection>,
-}
-
-impl RadrootsLegacyPathCandidate {
- #[must_use]
- pub fn new(
- id: impl Into<String>,
- description: impl Into<String>,
- path: impl Into<PathBuf>,
- destination: Option<PathBuf>,
- import_hint: impl Into<String>,
- ) -> Self {
- Self {
- id: id.into(),
- description: description.into(),
- path: path.into(),
- destination,
- import_hint: import_hint.into(),
- }
- }
-
- fn into_detection(self) -> RadrootsLegacyPathDetection {
- RadrootsLegacyPathDetection {
- id: self.id,
- description: self.description,
- path: self.path,
- destination: self.destination,
- import_hint: self.import_hint,
- }
- }
-}
-
-impl RadrootsMigrationReport {
- #[must_use]
- pub fn empty() -> Self {
- Self::from_detected_legacy_paths(Vec::new())
- }
-
- #[must_use]
- pub fn from_detected_legacy_paths(
- detected_legacy_paths: Vec<RadrootsLegacyPathDetection>,
- ) -> Self {
- let state = if detected_legacy_paths.is_empty() {
- "ready"
- } else {
- "legacy_state_detected"
- };
- Self {
- posture: RADROOTS_MIGRATION_POSTURE,
- state,
- silent_startup_relocation: false,
- compatibility_window: RADROOTS_MIGRATION_COMPATIBILITY_WINDOW,
- detected_legacy_paths,
- }
- }
-}
-
-#[must_use]
-pub fn inspect_legacy_paths(
- candidates: impl IntoIterator<Item = RadrootsLegacyPathCandidate>,
-) -> RadrootsMigrationReport {
- let detected = candidates
- .into_iter()
- .filter(|candidate| candidate.path.exists())
- .map(RadrootsLegacyPathCandidate::into_detection)
- .collect();
- RadrootsMigrationReport::from_detected_legacy_paths(detected)
-}
-
-#[cfg(test)]
-mod tests {
- use std::path::PathBuf;
-
- use super::{
- RADROOTS_MIGRATION_COMPATIBILITY_WINDOW, RADROOTS_MIGRATION_POSTURE,
- RadrootsLegacyPathCandidate, RadrootsMigrationReport, inspect_legacy_paths,
- };
-
- fn unique_test_dir() -> PathBuf {
- let nanos = std::time::SystemTime::now()
- .duration_since(std::time::UNIX_EPOCH)
- .expect("clock")
- .as_nanos();
- let path = std::env::temp_dir().join(format!("radroots_runtime_paths-test-{nanos}"));
- std::fs::create_dir_all(&path).expect("create temp test dir");
- path
- }
-
- #[test]
- fn inspect_legacy_paths_reports_only_paths_that_exist() {
- let temp = unique_test_dir();
- let existing = temp.join("old-state");
- let missing = temp.join("missing-state");
- std::fs::write(&existing, "legacy").expect("write legacy marker");
-
- let report = inspect_legacy_paths([
- RadrootsLegacyPathCandidate::new(
- "old-state",
- "old state",
- &existing,
- Some(temp.join("new-state")),
- "run the explicit importer",
- ),
- RadrootsLegacyPathCandidate::new(
- "missing-state",
- "missing state",
- &missing,
- None,
- "nothing to do",
- ),
- ]);
-
- assert_eq!(report.posture, RADROOTS_MIGRATION_POSTURE);
- assert_eq!(report.state, "legacy_state_detected");
- assert!(!report.silent_startup_relocation);
- assert_eq!(
- report.compatibility_window,
- RADROOTS_MIGRATION_COMPATIBILITY_WINDOW
- );
- assert_eq!(report.detected_legacy_paths.len(), 1);
- assert_eq!(report.detected_legacy_paths[0].id, "old-state");
- assert_eq!(report.detected_legacy_paths[0].path, existing);
- std::fs::remove_dir_all(temp).expect("remove temp test dir");
- }
-
- #[test]
- fn inspect_legacy_paths_is_ready_when_no_candidate_exists() {
- let temp = unique_test_dir();
-
- let report = inspect_legacy_paths([RadrootsLegacyPathCandidate::new(
- "missing-state",
- "missing state",
- temp.join("missing-state"),
- None,
- "nothing to do",
- )]);
-
- assert_eq!(report.state, "ready");
- assert!(report.detected_legacy_paths.is_empty());
- std::fs::remove_dir_all(temp).expect("remove temp test dir");
- }
-
- #[test]
- fn empty_report_matches_ready_state() {
- let report = RadrootsMigrationReport::empty();
- assert_eq!(report.posture, RADROOTS_MIGRATION_POSTURE);
- assert_eq!(report.state, "ready");
- assert!(!report.silent_startup_relocation);
- assert_eq!(
- report.compatibility_window,
- RADROOTS_MIGRATION_COMPATIBILITY_WINDOW
- );
- assert!(report.detected_legacy_paths.is_empty());
- }
-}
diff --git a/crates/runtime_paths/src/service.rs b/crates/runtime_paths/src/service.rs
@@ -4,8 +4,8 @@ use serde::Serialize;
use thiserror::Error;
use crate::{
- RadrootsMigrationReport, RadrootsPathOverrides, RadrootsPathProfile, RadrootsPathResolver,
- RadrootsPaths, RadrootsRuntimeNamespace, RadrootsRuntimePathsError,
+ RadrootsPathOverrides, RadrootsPathProfile, RadrootsPathResolver, RadrootsPaths,
+ RadrootsRuntimeNamespace, RadrootsRuntimePathsError,
};
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -62,7 +62,6 @@ pub struct RadrootsRuntimePathPolicyContract {
pub canonical_root_selection: String,
pub canonical_subordinate_path_override: String,
pub leaf_path_env_posture: String,
- pub compatibility_leaf_path_keys: Vec<String>,
}
impl RadrootsRuntimePathPolicyContract {
@@ -70,61 +69,15 @@ impl RadrootsRuntimePathPolicyContract {
canonical_root_selection: &str,
canonical_subordinate_path_override: &str,
leaf_path_env_posture: &str,
- compatibility_leaf_path_keys: &[&str],
) -> Self {
Self {
canonical_root_selection: canonical_root_selection.to_owned(),
canonical_subordinate_path_override: canonical_subordinate_path_override.to_owned(),
leaf_path_env_posture: leaf_path_env_posture.to_owned(),
- compatibility_leaf_path_keys: compatibility_leaf_path_keys
- .iter()
- .map(|entry| (*entry).to_owned())
- .collect(),
}
}
}
-#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
-pub struct RadrootsRuntimeMigrationContract {
- pub posture: String,
- pub state: String,
- pub silent_startup_relocation: bool,
- pub compatibility_window: String,
- pub detected_legacy_paths: Vec<RadrootsRuntimeLegacyPathContract>,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
-pub struct RadrootsRuntimeLegacyPathContract {
- pub id: String,
- pub description: String,
- pub path: PathBuf,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub destination: Option<PathBuf>,
- pub import_hint: String,
-}
-
-pub fn runtime_migration_contract(
- report: RadrootsMigrationReport,
-) -> RadrootsRuntimeMigrationContract {
- RadrootsRuntimeMigrationContract {
- posture: report.posture.to_owned(),
- state: report.state.to_owned(),
- silent_startup_relocation: report.silent_startup_relocation,
- compatibility_window: report.compatibility_window.to_owned(),
- detected_legacy_paths: report
- .detected_legacy_paths
- .into_iter()
- .map(|path| RadrootsRuntimeLegacyPathContract {
- id: path.id,
- description: path.description,
- path: path.path,
- destination: path.destination,
- import_hint: path.import_hint,
- })
- .collect(),
- }
-}
-
#[derive(Debug, Error, Clone, PartialEq, Eq)]
pub enum RadrootsRuntimePathSelectionError {
#[error("{env_var} must be valid utf-8 when set")]
@@ -352,9 +305,7 @@ mod tests {
use super::{
RadrootsRuntimePathConfigEntry, RadrootsRuntimePathPolicyContract,
RadrootsRuntimePathSelection, RadrootsRuntimePathSelectionError,
- runtime_migration_contract,
};
- use crate::{RadrootsLegacyPathDetection, RadrootsMigrationReport};
#[test]
fn caller_selection_preserves_profile_and_sources() {
@@ -611,8 +562,7 @@ mod tests {
let contract = RadrootsRuntimePathPolicyContract::new(
"profile_root_env_or_repo_wrapper",
"config_artifact",
- "compatibility_break_glass",
- &["MYC_PATHS_STATE_DIR"],
+ "runtime_owned_leaf_overrides",
);
assert_eq!(
@@ -620,31 +570,8 @@ mod tests {
"profile_root_env_or_repo_wrapper"
);
assert_eq!(
- contract.compatibility_leaf_path_keys,
- vec!["MYC_PATHS_STATE_DIR".to_owned()]
+ contract.leaf_path_env_posture,
+ "runtime_owned_leaf_overrides"
);
}
-
- #[test]
- fn runtime_migration_contract_maps_detected_paths() {
- let report = RadrootsMigrationReport {
- posture: "explicit_operator_import_required",
- state: "legacy_state_detected",
- silent_startup_relocation: false,
- compatibility_window: "detect_and_report_only",
- detected_legacy_paths: vec![RadrootsLegacyPathDetection {
- id: "legacy_path".to_owned(),
- description: "legacy path".to_owned(),
- path: PathBuf::from("/tmp/legacy"),
- destination: Some(PathBuf::from("/tmp/new")),
- import_hint: "copy it manually".to_owned(),
- }],
- };
-
- let contract = runtime_migration_contract(report);
-
- assert_eq!(contract.posture, "explicit_operator_import_required");
- assert_eq!(contract.detected_legacy_paths.len(), 1);
- assert_eq!(contract.detected_legacy_paths[0].id, "legacy_path");
- }
}
diff --git a/crates/secret_vault/src/error.rs b/crates/secret_vault/src/error.rs
@@ -14,14 +14,6 @@ pub enum RadrootsSecretVaultError {
BackendUnavailable {
backend: RadrootsSecretBackendKind,
},
- FallbackDisallowed {
- primary: RadrootsSecretBackendKind,
- fallback: RadrootsSecretBackendKind,
- },
- FallbackUnavailable {
- primary: RadrootsSecretBackendKind,
- fallback: RadrootsSecretBackendKind,
- },
HostVaultPolicyUnsupported {
requirement: RadrootsHostVaultRequirement,
},
@@ -57,14 +49,6 @@ impl fmt::Display for RadrootsSecretVaultError {
Self::BackendUnavailable { backend } => {
write!(f, "secret backend {backend} is unavailable")
}
- Self::FallbackDisallowed { primary, fallback } => write!(
- f,
- "secret backend {primary} may not silently downgrade to {fallback}"
- ),
- Self::FallbackUnavailable { primary, fallback } => write!(
- f,
- "secret backend {primary} fallback {fallback} is unavailable"
- ),
Self::HostVaultPolicyUnsupported { requirement } => write!(
f,
"host vault does not satisfy the required {requirement} policy"
@@ -138,22 +122,6 @@ mod tests {
"secret backend host_vault is unavailable"
);
assert_eq!(
- RadrootsSecretVaultError::FallbackDisallowed {
- primary: RadrootsSecretBackendKind::ExternalCommand,
- fallback: RadrootsSecretBackendKind::EncryptedFile,
- }
- .to_string(),
- "secret backend external_command may not silently downgrade to encrypted_file"
- );
- assert_eq!(
- RadrootsSecretVaultError::FallbackUnavailable {
- primary: RadrootsSecretBackendKind::HostVault,
- fallback: RadrootsSecretBackendKind::EncryptedFile,
- }
- .to_string(),
- "secret backend host_vault fallback encrypted_file is unavailable"
- );
- assert_eq!(
RadrootsSecretVaultError::HostVaultPolicyUnsupported {
requirement: RadrootsHostVaultRequirement::HardwareBacked,
}
diff --git a/crates/secret_vault/src/selection.rs b/crates/secret_vault/src/selection.rs
@@ -1,11 +1,10 @@
-use crate::backend::{RadrootsSecretBackend, RadrootsSecretBackendKind};
+use crate::backend::RadrootsSecretBackend;
use crate::error::RadrootsSecretVaultError;
use crate::policy::RadrootsHostVaultCapabilities;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct RadrootsSecretBackendSelection {
pub primary: RadrootsSecretBackend,
- pub fallback: Option<RadrootsSecretBackend>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -19,7 +18,6 @@ pub struct RadrootsSecretBackendAvailability {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct RadrootsResolvedSecretBackend {
pub backend: RadrootsSecretBackend,
- pub used_fallback: bool,
}
impl RadrootsSecretBackendSelection {
@@ -27,44 +25,10 @@ impl RadrootsSecretBackendSelection {
self,
availability: RadrootsSecretBackendAvailability,
) -> Result<RadrootsResolvedSecretBackend, RadrootsSecretVaultError> {
- if availability.supports(self.primary).is_ok() {
- return Ok(RadrootsResolvedSecretBackend {
- backend: self.primary,
- used_fallback: false,
- });
- }
-
- if let RadrootsSecretBackend::HostVault(policy) = self.primary
- && availability.host_vault.available
- {
- availability.host_vault.validate(policy)?;
- }
-
- match self.fallback {
- Some(fallback) => {
- if !self.primary.allows_fallback_to(fallback.kind()) {
- return Err(RadrootsSecretVaultError::FallbackDisallowed {
- primary: self.primary.kind(),
- fallback: fallback.kind(),
- });
- }
-
- availability.supports(fallback).map_err(|_| {
- RadrootsSecretVaultError::FallbackUnavailable {
- primary: self.primary.kind(),
- fallback: fallback.kind(),
- }
- })?;
-
- Ok(RadrootsResolvedSecretBackend {
- backend: fallback,
- used_fallback: true,
- })
- }
- None => Err(RadrootsSecretVaultError::BackendUnavailable {
- backend: self.primary.kind(),
- }),
- }
+ availability.supports(self.primary)?;
+ Ok(RadrootsResolvedSecretBackend {
+ backend: self.primary,
+ })
}
}
@@ -82,21 +46,10 @@ impl RadrootsSecretBackendAvailability {
}
}
-impl RadrootsSecretBackend {
- const fn allows_fallback_to(self, fallback: RadrootsSecretBackendKind) -> bool {
- matches!(
- (self.kind(), fallback),
- (
- RadrootsSecretBackendKind::HostVault,
- RadrootsSecretBackendKind::EncryptedFile
- )
- )
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
+ use crate::backend::RadrootsSecretBackendKind;
use crate::error::RadrootsHostVaultRequirement;
use crate::policy::{
RadrootsHostVaultHardwarePolicy, RadrootsHostVaultPolicy, RadrootsHostVaultResidency,
@@ -107,7 +60,6 @@ mod tests {
fn host_vault_is_selected_when_available() {
let selection = RadrootsSecretBackendSelection {
primary: RadrootsSecretBackend::HostVault(RadrootsHostVaultPolicy::desktop()),
- fallback: Some(RadrootsSecretBackend::EncryptedFile),
};
let resolved = selection
@@ -123,69 +75,64 @@ mod tests {
resolved,
RadrootsResolvedSecretBackend {
backend: RadrootsSecretBackend::HostVault(RadrootsHostVaultPolicy::desktop()),
- used_fallback: false,
}
);
}
#[test]
- fn host_vault_may_explicitly_fallback_to_encrypted_file() {
+ fn host_vault_unavailable_fails_closed() {
let selection = RadrootsSecretBackendSelection {
primary: RadrootsSecretBackend::HostVault(RadrootsHostVaultPolicy::desktop()),
- fallback: Some(RadrootsSecretBackend::EncryptedFile),
};
- let resolved = selection
+ let err = selection
.resolve(RadrootsSecretBackendAvailability {
host_vault: RadrootsHostVaultCapabilities::unavailable(),
encrypted_file: true,
external_command: false,
memory: false,
})
- .expect("encrypted file fallback resolves");
+ .expect_err("unavailable primary must fail");
assert_eq!(
- resolved,
- RadrootsResolvedSecretBackend {
- backend: RadrootsSecretBackend::EncryptedFile,
- used_fallback: true,
+ err,
+ RadrootsSecretVaultError::BackendUnavailable {
+ backend: RadrootsSecretBackendKind::HostVault,
}
);
}
#[test]
- fn host_vault_without_explicit_fallback_fails_closed() {
+ fn encrypted_file_unavailable_fails_closed() {
let selection = RadrootsSecretBackendSelection {
- primary: RadrootsSecretBackend::HostVault(RadrootsHostVaultPolicy::desktop()),
- fallback: None,
+ primary: RadrootsSecretBackend::EncryptedFile,
};
let err = selection
.resolve(RadrootsSecretBackendAvailability {
host_vault: RadrootsHostVaultCapabilities::unavailable(),
- encrypted_file: true,
+ encrypted_file: false,
external_command: false,
memory: false,
})
- .expect_err("missing fallback must fail");
+ .expect_err("unavailable primary must fail");
assert_eq!(
err,
RadrootsSecretVaultError::BackendUnavailable {
- backend: RadrootsSecretBackendKind::HostVault,
+ backend: RadrootsSecretBackendKind::EncryptedFile,
}
);
}
#[test]
- fn unsupported_host_vault_policy_fails_before_any_downgrade() {
+ fn unsupported_host_vault_policy_fails_closed() {
let selection = RadrootsSecretBackendSelection {
primary: RadrootsSecretBackend::HostVault(RadrootsHostVaultPolicy {
residency: RadrootsHostVaultResidency::DeviceLocalOnly,
user_presence: RadrootsHostVaultUserPresencePolicy::Required,
hardware: RadrootsHostVaultHardwarePolicy::RequireHardwareBacked,
}),
- fallback: Some(RadrootsSecretBackend::EncryptedFile),
};
let err = selection
@@ -206,10 +153,9 @@ mod tests {
}
#[test]
- fn external_command_may_not_downgrade_to_encrypted_file() {
+ fn external_command_unavailable_fails_closed() {
let selection = RadrootsSecretBackendSelection {
primary: RadrootsSecretBackend::ExternalCommand,
- fallback: Some(RadrootsSecretBackend::EncryptedFile),
};
let err = selection
@@ -219,13 +165,12 @@ mod tests {
external_command: false,
memory: false,
})
- .expect_err("external command downgrade must fail");
+ .expect_err("unavailable primary must fail");
assert_eq!(
err,
- RadrootsSecretVaultError::FallbackDisallowed {
- primary: RadrootsSecretBackendKind::ExternalCommand,
- fallback: RadrootsSecretBackendKind::EncryptedFile,
+ RadrootsSecretVaultError::BackendUnavailable {
+ backend: RadrootsSecretBackendKind::ExternalCommand,
}
);
}
@@ -234,7 +179,6 @@ mod tests {
fn external_command_resolves_when_available() {
let selection = RadrootsSecretBackendSelection {
primary: RadrootsSecretBackend::ExternalCommand,
- fallback: None,
};
let resolved = selection
@@ -250,7 +194,6 @@ mod tests {
resolved,
RadrootsResolvedSecretBackend {
backend: RadrootsSecretBackend::ExternalCommand,
- used_fallback: false,
}
);
}
@@ -259,7 +202,6 @@ mod tests {
fn memory_backend_must_be_selected_explicitly() {
let selection = RadrootsSecretBackendSelection {
primary: RadrootsSecretBackend::Memory,
- fallback: None,
};
let resolved = selection
@@ -275,7 +217,6 @@ mod tests {
resolved,
RadrootsResolvedSecretBackend {
backend: RadrootsSecretBackend::Memory,
- used_fallback: false,
}
);
@@ -295,29 +236,4 @@ mod tests {
}
);
}
-
- #[test]
- fn unavailable_explicit_fallback_reports_fallback_unavailable() {
- let selection = RadrootsSecretBackendSelection {
- primary: RadrootsSecretBackend::HostVault(RadrootsHostVaultPolicy::desktop()),
- fallback: Some(RadrootsSecretBackend::EncryptedFile),
- };
-
- let err = selection
- .resolve(RadrootsSecretBackendAvailability {
- host_vault: RadrootsHostVaultCapabilities::unavailable(),
- encrypted_file: false,
- external_command: false,
- memory: false,
- })
- .expect_err("unavailable fallback must fail");
-
- assert_eq!(
- err,
- RadrootsSecretVaultError::FallbackUnavailable {
- primary: RadrootsSecretBackendKind::HostVault,
- fallback: RadrootsSecretBackendKind::EncryptedFile,
- }
- );
- }
}