#![cfg(kani)]
use crate::claims::AttestationClaimsBuilder;
use crate::verification::{capability_covers, validate_issuer, validate_subject};
mod issuer_proofs {
use super::*;
#[kani::proof]
#[kani::unwind(20)]
fn validate_issuer_never_panics() {
let uri_root: [u8; 16] = kani::any();
let token_issuer: [u8; 16] = kani::any();
if let (Ok(uri_str), Ok(token_str)) =
(std::str::from_utf8(&uri_root), std::str::from_utf8(&token_issuer))
{
let _ = validate_issuer(uri_str, token_str);
}
}
#[kani::proof]
#[kani::unwind(12)]
fn matching_issuers_succeed() {
let data: [u8; 8] = kani::any();
if let Ok(s) = std::str::from_utf8(&data) {
let result = validate_issuer(s, s);
assert!(result.is_ok());
}
}
#[kani::proof]
#[kani::unwind(12)]
fn issuer_validation_symmetry() {
let a: [u8; 8] = kani::any();
let b: [u8; 8] = kani::any();
if let (Ok(str_a), Ok(str_b)) = (std::str::from_utf8(&a), std::str::from_utf8(&b)) {
let result_ab = validate_issuer(str_a, str_b);
let result_ba = validate_issuer(str_b, str_a);
assert!(result_ab.is_ok() == result_ba.is_ok());
}
}
}
mod subject_proofs {
use super::*;
#[kani::proof]
#[kani::unwind(20)]
fn validate_subject_never_panics() {
let presented: [u8; 16] = kani::any();
let token_sub: [u8; 16] = kani::any();
if let (Ok(pres_str), Ok(tok_str)) =
(std::str::from_utf8(&presented), std::str::from_utf8(&token_sub))
{
let _ = validate_subject(pres_str, tok_str);
}
}
#[kani::proof]
#[kani::unwind(20)]
fn matching_subjects_succeed() {
let data: [u8; 16] = kani::any();
if let Ok(s) = std::str::from_utf8(&data) {
let result = validate_subject(s, s);
assert!(result.is_ok());
}
}
#[kani::proof]
#[kani::unwind(12)]
fn subject_validation_deterministic() {
let a: [u8; 8] = kani::any();
let b: [u8; 8] = kani::any();
if let (Ok(str_a), Ok(str_b)) = (std::str::from_utf8(&a), std::str::from_utf8(&b)) {
let r1 = validate_subject(str_a, str_b);
let r2 = validate_subject(str_a, str_b);
assert!(r1.is_ok() == r2.is_ok());
}
}
}
mod capability_proofs {
use super::*;
use agent_uri::CapabilityPath;
#[kani::proof]
#[kani::unwind(12)]
fn empty_capabilities_never_panic() {
let attested: Vec<String> = vec![];
if let Ok(path) = CapabilityPath::parse("workflow") {
let result = capability_covers(&attested, &path);
assert!(!result);
}
}
#[kani::proof]
#[kani::unwind(12)]
fn exact_match_is_covered() {
let cap = "workflow";
let attested = vec![cap.to_string()];
if let Ok(path) = CapabilityPath::parse(cap) {
let result = capability_covers(&attested, &path);
assert!(result);
}
}
#[kani::proof]
#[kani::unwind(20)]
fn capability_covers_deterministic() {
let cap = "workflow";
let req = "workflow/approval";
if let Ok(path) = CapabilityPath::parse(req) {
let attested = vec![cap.to_string()];
let r1 = capability_covers(&attested, &path);
let r2 = capability_covers(&attested, &path);
assert!(r1 == r2);
}
}
#[kani::proof]
#[kani::unwind(20)]
fn prefix_covers_child() {
let parent = "workflow";
let child = "workflow/approval";
let attested = vec![parent.to_string()];
if let Ok(path) = CapabilityPath::parse(child) {
let result = capability_covers(&attested, &path);
assert!(result);
}
}
}
mod claims_proofs {
use super::*;
#[kani::proof]
#[kani::unwind(12)]
fn builder_missing_uri_errors() {
let result = AttestationClaimsBuilder::new().issuer("test.com").build();
assert!(result.is_err());
}
#[kani::proof]
#[kani::unwind(12)]
fn builder_missing_issuer_errors() {
let result = AttestationClaimsBuilder::new()
.agent_uri("agent://test.com/test/agent_01h455vb4pex5vsknk084sn02q")
.build();
assert!(result.is_err());
}
#[kani::proof]
#[kani::unwind(12)]
fn builder_construction_never_panics() {
let _builder = AttestationClaimsBuilder::new()
.agent_uri("agent://test.com/test/agent_01h455vb4pex5vsknk084sn02q")
.issuer("test.com")
.add_capability("workflow")
.audience("api.test.com");
}
}