use std::time::Duration;
use tenuo::*;
#[test]
fn test_reserved_tool_namespace_rejection() {
let keypair = SigningKey::generate();
let result = Warrant::builder()
.capability("tenuo:revoke", ConstraintSet::new())
.ttl(Duration::from_secs(3600))
.holder(keypair.public_key())
.build(&keypair);
assert!(result.is_err(), "Expected error for reserved namespace");
let err = result.unwrap_err();
assert!(
err.to_string().contains("Reserved tool namespace"),
"Error message should mention reserved namespace: {}",
err
);
}
#[test]
fn test_extension_preservation() {
let keypair = SigningKey::generate();
let original = Warrant::builder()
.capability("test_tool", ConstraintSet::new())
.ttl(Duration::from_secs(3600))
.extension("com.example.trace_id", b"abc123".to_vec())
.extension("com.example.billing_tag", b"team-ml".to_vec())
.holder(keypair.public_key())
.build(&keypair)
.unwrap();
let encoded = wire::encode(&original).unwrap();
let decoded = wire::decode(&encoded).unwrap();
let extensions = &decoded.payload.extensions;
assert_eq!(
extensions.get("com.example.trace_id"),
Some(&b"abc123".to_vec())
);
assert_eq!(
extensions.get("com.example.billing_tag"),
Some(&b"team-ml".to_vec())
);
assert!(decoded.verify(&keypair.public_key()).is_ok());
}
#[test]
fn test_clock_tolerance() {
use chrono::Duration as ChronoDuration;
let keypair = SigningKey::generate();
let warrant = Warrant::builder()
.capability("test_tool", ConstraintSet::new())
.ttl(Duration::from_secs(60))
.holder(keypair.public_key())
.build(&keypair)
.unwrap();
assert!(!warrant.is_expired_with_tolerance(ChronoDuration::seconds(120)));
assert!(warrant.is_expired_with_tolerance(ChronoDuration::seconds(-120)));
}
#[test]
fn test_warrant_size_limit() {
assert_eq!(wire::MAX_WARRANT_SIZE, 64 * 1024);
let keypair = SigningKey::generate();
let mut builder = Warrant::builder()
.ttl(Duration::from_secs(3600))
.holder(keypair.public_key());
for i in 0..100 {
let tool_name = format!("tool_{}", i);
let mut constraints = ConstraintSet::new();
constraints.insert("arg".to_string(), Exact::new("value"));
builder = builder.capability(tool_name, constraints);
}
let warrant = builder.build(&keypair).unwrap();
let encoded = wire::encode(&warrant).unwrap();
assert!(
encoded.len() < wire::MAX_WARRANT_SIZE,
"Encoded size {} should be under MAX_WARRANT_SIZE {}",
encoded.len(),
wire::MAX_WARRANT_SIZE
);
}
#[test]
fn test_contains_constraint_basic() {
let required = vec!["apple".to_string(), "banana".to_string()];
let contains_struct = Contains::new(required.clone());
let constraint = Constraint::Contains(contains_struct);
match constraint {
Constraint::Contains(ref items) => {
assert_eq!(items.required.len(), 2);
}
_ => panic!("Expected Contains constraint"),
}
}
#[test]
fn test_subset_constraint_basic() {
let allowed = vec!["red".to_string(), "green".to_string(), "blue".to_string()];
let subset_struct = Subset::new(allowed.clone());
let constraint = Constraint::Subset(subset_struct);
match constraint {
Constraint::Subset(ref items) => {
assert_eq!(items.allowed.len(), 3);
}
_ => panic!("Expected Subset constraint"),
}
}