lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

id_contract.rs (3256B)


      1 use radroots_secrets::error::SecretIdError;
      2 use radroots_secrets::id::{BackendKind, KeyVersion, SECRET_ID_MAX_BYTES};
      3 use radroots_secrets::{Error, SecretId, SecretRef};
      4 
      5 #[test]
      6 fn identifiers_accept_the_portable_alphabet_and_reject_unsafe_values() {
      7     for valid in ["a", "account-01", "farm.primary_key:v2", "A_B"] {
      8         assert_eq!(SecretId::parse(valid).expect("valid id").as_str(), valid);
      9     }
     10 
     11     assert_eq!(
     12         SecretId::parse(""),
     13         Err(Error::InvalidSecretId(SecretIdError::Empty))
     14     );
     15     assert_eq!(
     16         SecretId::parse("-leading-separator"),
     17         Err(Error::InvalidSecretId(SecretIdError::InvalidCharacter {
     18             byte_offset: 0
     19         }))
     20     );
     21     assert_eq!(
     22         SecretId::parse("path/traversal"),
     23         Err(Error::InvalidSecretId(SecretIdError::InvalidCharacter {
     24             byte_offset: 4
     25         }))
     26     );
     27     assert_eq!(
     28         SecretId::parse("é"),
     29         Err(Error::InvalidSecretId(SecretIdError::InvalidCharacter {
     30             byte_offset: 0
     31         }))
     32     );
     33     assert_eq!(
     34         SecretId::parse("a".repeat(SECRET_ID_MAX_BYTES + 1)),
     35         Err(Error::InvalidSecretId(SecretIdError::TooLong {
     36             actual_bytes: SECRET_ID_MAX_BYTES + 1,
     37             max_bytes: SECRET_ID_MAX_BYTES,
     38         }))
     39     );
     40 }
     41 
     42 #[test]
     43 fn identifiers_and_references_are_redacted_in_diagnostics() {
     44     let id = SecretId::parse("account-signing-key").expect("valid id");
     45     assert_eq!(format!("{id:?}"), "SecretId(<redacted>)");
     46     assert_eq!(id.to_string(), "<redacted secret id>");
     47 
     48     let reference = SecretRef::new(
     49         id,
     50         BackendKind::Keyring,
     51         KeyVersion::new(7).expect("non-zero version"),
     52     );
     53     let diagnostic = format!("{reference:?}");
     54     assert!(diagnostic.contains("<redacted>"));
     55     assert!(diagnostic.contains("Keyring"));
     56     assert!(diagnostic.contains("KeyVersion(7)"));
     57     assert!(!diagnostic.contains("account-signing-key"));
     58 }
     59 
     60 #[test]
     61 fn references_expose_only_validated_metadata() {
     62     assert_eq!(KeyVersion::new(0), Err(Error::InvalidKeyVersion));
     63     let version = KeyVersion::new(3).expect("non-zero version");
     64     let reference = SecretRef::new(
     65         SecretId::parse("service-token").expect("valid id"),
     66         BackendKind::External,
     67         version,
     68     );
     69 
     70     assert_eq!(reference.id().as_str(), "service-token");
     71     assert_eq!(reference.backend(), BackendKind::External);
     72     assert_eq!(reference.key_version().get(), 3);
     73 }
     74 
     75 #[cfg(feature = "serde")]
     76 #[test]
     77 fn identifier_serde_round_trips_through_validation() {
     78     let id = SecretId::parse("farm.primary-key:v1").expect("valid id");
     79     let json = serde_json::to_string(&id).expect("serialize id");
     80     assert_eq!(json, "\"farm.primary-key:v1\"");
     81     assert_eq!(
     82         serde_json::from_str::<SecretId>(&json)
     83             .expect("deserialize id")
     84             .as_str(),
     85         id.as_str()
     86     );
     87     assert!(serde_json::from_str::<SecretId>("\"../escape\"").is_err());
     88 }
     89 
     90 #[test]
     91 fn normalized_errors_never_echo_identifier_input() {
     92     let raw = "secret/value";
     93     let error = SecretId::parse(raw).expect_err("invalid id");
     94     let display = error.to_string();
     95     let debug = format!("{error:?}");
     96     assert!(!display.contains(raw));
     97     assert!(!debug.contains(raw));
     98 }