use super::*;
#[test]
fn test_compute_digest_canonical() {
let content = "name: test\nversion: \"1.0.0\"";
let digest = compute_digest(content);
assert!(digest.starts_with("sha256:"));
assert_eq!(digest.len(), 7 + 64);
let strict = compute_digest_strict(content).unwrap();
assert_eq!(digest, strict);
}
#[test]
fn test_compute_digest_golden_vector() {
let content = "name: eu-ai-act-baseline\nversion: \"1.0.0\"\nkind: compliance";
let digest = compute_digest(content);
assert_eq!(
digest,
"sha256:f47d932cdad4bde369ed0a7cf26fdcf4077777296346c4102d9017edbc62a070"
);
}
#[test]
fn test_compute_digest_key_ordering() {
let yaml1 = "z: 1\na: 2";
let yaml2 = "a: 2\nz: 1";
let digest1 = compute_digest(yaml1);
let digest2 = compute_digest(yaml2);
assert_eq!(digest1, digest2);
}
#[test]
#[allow(deprecated)]
fn test_compute_digest_raw_differs() {
let content = "name: eu-ai-act-baseline\nversion: \"1.0.0\"\nkind: compliance";
let canonical = compute_digest(content);
let raw = crate::verify::compute_digest_raw(content);
assert_ne!(canonical, raw);
assert_eq!(
raw,
"sha256:5a9a6b1e95e8c1d36779b87212835c9bfa9cae5d98cb9c75fb8c478750e5e200"
);
}
#[test]
#[allow(deprecated)]
fn test_compute_digest_raw_matches_bytes_helper() {
let content = "this is not: valid: yaml: [[";
let wrapped = crate::verify::compute_digest_raw(content);
let helper = crate::digest::sha256_hex_bytes(content.as_bytes());
assert_eq!(wrapped, helper);
}
#[test]
fn test_verify_digest_success() {
let content = "name: test\nversion: \"1.0.0\"";
let expected = compute_digest(content);
assert!(verify_digest(content, &expected).is_ok());
}
#[test]
fn test_verify_digest_mismatch() {
let content = "name: test\nversion: \"1.0.0\"";
let wrong = "sha256:0000000000000000000000000000000000000000000000000000000000000000";
let result = verify_digest(content, wrong);
assert!(matches!(result, Err(RegistryError::DigestMismatch { .. })));
}
#[test]
fn test_build_pae() {
let pae = build_pae("application/json", b"test");
let expected = b"DSSEv1 16 application/json 4 test";
assert_eq!(pae, expected);
}
#[test]
fn test_payload_type_length() {
assert_eq!(
PAYLOAD_TYPE_PACK_V1.len(),
35,
"PAYLOAD_TYPE_PACK_V1 must be 35 bytes"
);
assert!(PAYLOAD_TYPE_PACK_V1.is_ascii());
let pae = build_pae(PAYLOAD_TYPE_PACK_V1, b"{}");
let pae_str = String::from_utf8_lossy(&pae);
assert!(
pae_str.starts_with("DSSEv1 35 application/vnd.assay.pack+yaml;v=1 2 {}"),
"PAE must start with 'DSSEv1 35 ...' for pack signing"
);
}
#[test]
fn test_key_id_computation() {
let key = generate_keypair();
let key_id = compute_key_id_from_key(&key.verifying_key()).unwrap();
assert!(key_id.starts_with("sha256:"));
assert_eq!(key_id.len(), 7 + 64);
let hex_part = &key_id[7..];
assert!(
hex_part
.chars()
.all(|c| c.is_ascii_hexdigit() && !c.is_ascii_uppercase()),
"key_id hex must be lowercase"
);
}
#[test]
fn test_parse_dsse_envelope_invalid_base64() {
let result = parse_dsse_envelope("not valid base64!!!");
assert!(matches!(
result,
Err(RegistryError::SignatureInvalid { .. })
));
}
#[test]
fn test_parse_dsse_envelope_invalid_json() {
let b64 = BASE64.encode(b"not json");
let result = parse_dsse_envelope(&b64);
assert!(matches!(
result,
Err(RegistryError::SignatureInvalid { .. })
));
}
#[test]
fn test_parse_dsse_envelope_valid() {
let envelope = DsseEnvelope {
payload_type: PAYLOAD_TYPE_PACK_V1.to_string(),
payload: BASE64.encode(b"test payload"),
signatures: vec![],
};
let json = serde_json::to_vec(&envelope).unwrap();
let b64 = BASE64.encode(&json);
let parsed = parse_dsse_envelope(&b64).unwrap();
assert_eq!(parsed.payload_type, PAYLOAD_TYPE_PACK_V1);
}
#[test]
fn test_dsse_envelope_size_small_pack() {
let content = "name: small-pack\nversion: \"1.0.0\"\nrules: []";
let canonical = crate::canonicalize::to_canonical_jcs_bytes(
&crate::canonicalize::parse_yaml_strict(content).unwrap(),
)
.unwrap();
let envelope = DsseEnvelope {
payload_type: PAYLOAD_TYPE_PACK_V1.to_string(),
payload: BASE64.encode(&canonical),
signatures: vec![crate::types::DsseSignature {
key_id: "sha256:abc123def456abc123def456abc123def456abc123def456abc123def456abcd"
.to_string(),
signature: BASE64.encode([0u8; 64]), }],
};
let json = serde_json::to_vec(&envelope).unwrap();
let header_value = BASE64.encode(&json);
assert!(
header_value.len() < 1024,
"Small pack DSSE envelope should be < 1KB, got {} bytes",
header_value.len()
);
}
#[test]
fn test_dsse_envelope_size_medium_pack() {
let mut content = String::from("name: medium-pack\nversion: \"1.0.0\"\nrules:\n");
for i in 0..100 {
content.push_str(&format!(
" - name: rule_{}\n pattern: \"test_pattern_{}\"\n",
i, i
));
}
let canonical = crate::canonicalize::to_canonical_jcs_bytes(
&crate::canonicalize::parse_yaml_strict(&content).unwrap(),
)
.unwrap();
let envelope = DsseEnvelope {
payload_type: PAYLOAD_TYPE_PACK_V1.to_string(),
payload: BASE64.encode(&canonical),
signatures: vec![crate::types::DsseSignature {
key_id: "sha256:abc123def456abc123def456abc123def456abc123def456abc123def456abcd"
.to_string(),
signature: BASE64.encode([0u8; 64]),
}],
};
let json = serde_json::to_vec(&envelope).unwrap();
let header_value = BASE64.encode(&json);
println!(
"Medium pack: canonical={} bytes, envelope={} bytes, header={} bytes",
canonical.len(),
json.len(),
header_value.len()
);
if header_value.len() > 8192 {
println!("WARNING: Pack exceeds 8KB header limit - use sidecar endpoint");
}
}
#[test]
fn test_header_size_limit_constant() {
const RECOMMENDED_HEADER_LIMIT: usize = 8192;
assert_eq!(RECOMMENDED_HEADER_LIMIT, 8192);
}