use auths_crypto::testing::gen_keypair;
use auths_sdk::workflows::ci::machine_identity::{
OidcMachineIdentity, SignCommitParams, sign_commit_with_identity,
};
use chrono::Utc;
use ring::signature::KeyPair;
use serde_json::json;
#[test]
fn test_sign_commit_with_oidc_binding() {
let keypair = gen_keypair();
let pubkey = keypair.public_key();
let pubkey_bytes: [u8; 32] = pubkey.as_ref().try_into().unwrap();
let mut normalized_claims = serde_json::Map::new();
normalized_claims.insert("repo".to_string(), "owner/repo".into());
normalized_claims.insert("actor".to_string(), "alice".into());
let oidc_identity = OidcMachineIdentity {
platform: "github".to_string(),
subject: "repo:owner/repo:ref:refs/heads/main".to_string(),
token_exp: 1704067200,
issuer: "https://token.actions.githubusercontent.com".to_string(),
audience: "sigstore".to_string(),
jti: Some("jti-test-12345".to_string()),
normalized_claims,
};
#[allow(clippy::disallowed_methods)] let timestamp = Utc::now();
let params = SignCommitParams {
commit_sha: "abc123def456789abcdef".to_string(),
issuer_did: "did:keri:Eissuer".to_string(),
device_did: "did:key:z6MkhaXgBZDvotDkL5257faWxcERV3PcxP7o8awhz7vMPFR".to_string(),
commit_message: Some("feat: add sign-commit feature".to_string()),
author: Some("Alice Developer".to_string()),
oidc_binding: Some(oidc_identity),
timestamp,
};
let attestation = sign_commit_with_identity(¶ms, &keypair, &pubkey_bytes)
.expect("sign_commit_with_identity should succeed");
assert_eq!(attestation.version, 1);
assert_eq!(
attestation.commit_sha,
Some("abc123def456789abcdef".to_string())
);
assert_eq!(
attestation.commit_message,
Some("feat: add sign-commit feature".to_string())
);
assert_eq!(attestation.author, Some("Alice Developer".to_string()));
assert!(attestation.oidc_binding.is_some());
let binding = attestation.oidc_binding.unwrap();
assert_eq!(
binding.issuer,
"https://token.actions.githubusercontent.com"
);
assert_eq!(binding.platform, Some("github".to_string()));
assert_eq!(binding.jti, Some("jti-test-12345".to_string()));
assert!(binding.normalized_claims.is_some());
assert!(!attestation.identity_signature.is_empty());
}
#[test]
fn test_sign_commit_without_oidc_binding() {
let keypair = gen_keypair();
let pubkey = keypair.public_key();
let pubkey_bytes: [u8; 32] = pubkey.as_ref().try_into().unwrap();
#[allow(clippy::disallowed_methods)] let timestamp = Utc::now();
let params = SignCommitParams {
commit_sha: "fedcba9876543210fedcba".to_string(),
issuer_did: "did:keri:Eissuer".to_string(),
device_did: "did:key:z6MkhaXgBZDvotDkL5257faWxcERV3PcxP7o8awhz7vMPFR".to_string(),
commit_message: Some("refactor: cleanup".to_string()),
author: Some("Bob".to_string()),
oidc_binding: None,
timestamp,
};
let attestation = sign_commit_with_identity(¶ms, &keypair, &pubkey_bytes)
.expect("sign_commit_with_identity should succeed without OIDC");
assert_eq!(
attestation.commit_sha,
Some("fedcba9876543210fedcba".to_string())
);
assert_eq!(
attestation.commit_message,
Some("refactor: cleanup".to_string())
);
assert!(attestation.oidc_binding.is_none());
assert!(!attestation.identity_signature.is_empty());
}
#[test]
fn test_attestation_serialization_roundtrip() {
let keypair = gen_keypair();
let pubkey = keypair.public_key();
let pubkey_bytes: [u8; 32] = pubkey.as_ref().try_into().unwrap();
let mut claims = serde_json::Map::new();
claims.insert("run_id".to_string(), json!("12345"));
let oidc = OidcMachineIdentity {
platform: "github".to_string(),
subject: "workload:12345".to_string(),
token_exp: 1704067200,
issuer: "https://token.actions.githubusercontent.com".to_string(),
audience: "sigstore".to_string(),
jti: Some("jti-12345".to_string()),
normalized_claims: claims,
};
#[allow(clippy::disallowed_methods)] let timestamp = Utc::now();
let params = SignCommitParams {
commit_sha: "1234567890abcdef1234567890abcdef12345678".to_string(),
issuer_did: "did:keri:Eissuer".to_string(),
device_did: "did:key:z6MkhaXgBZDvotDkL5257faWxcERV3PcxP7o8awhz7vMPFR".to_string(),
commit_message: Some("feat: test".to_string()),
author: Some("Tester".to_string()),
oidc_binding: Some(oidc),
timestamp,
};
let attestation = sign_commit_with_identity(¶ms, &keypair, &pubkey_bytes)
.expect("Creating attestation should succeed");
let json_str =
serde_json::to_string(&attestation).expect("Attestation should be serializable to JSON");
let deserialized: auths_verifier::core::Attestation =
serde_json::from_str(&json_str).expect("JSON should deserialize back to Attestation");
assert_eq!(deserialized.commit_sha, attestation.commit_sha);
assert_eq!(deserialized.commit_message, attestation.commit_message);
assert_eq!(deserialized.author, attestation.author);
assert_eq!(deserialized.oidc_binding, attestation.oidc_binding);
}
#[test]
fn test_attestation_rid_format() {
let keypair = gen_keypair();
let pubkey = keypair.public_key();
let pubkey_bytes: [u8; 32] = pubkey.as_ref().try_into().unwrap();
let commit_sha = "abc123def456";
#[allow(clippy::disallowed_methods)] let timestamp = Utc::now();
let params = SignCommitParams {
commit_sha: commit_sha.to_string(),
issuer_did: "did:keri:Eissuer".to_string(),
device_did: "did:key:z6MkhaXgBZDvotDkL5257faWxcERV3PcxP7o8awhz7vMPFR".to_string(),
commit_message: None,
author: None,
oidc_binding: None,
timestamp,
};
let attestation = sign_commit_with_identity(¶ms, &keypair, &pubkey_bytes)
.expect("Should create attestation");
let expected_rid = format!("auths/commits/{}", commit_sha);
assert_eq!(attestation.rid.as_str(), expected_rid);
}
#[test]
fn test_multiple_commits_independent_attestations() {
let keypair = gen_keypair();
let pubkey = keypair.public_key();
let pubkey_bytes: [u8; 32] = pubkey.as_ref().try_into().unwrap();
let shas = ["aaa111", "bbb222", "ccc333"];
let mut attestations = vec![];
for sha in shas.iter() {
#[allow(clippy::disallowed_methods)] let timestamp = Utc::now();
let params = SignCommitParams {
commit_sha: sha.to_string(),
issuer_did: "did:keri:Eissuer".to_string(),
device_did: "did:key:z6MkhaXgBZDvotDkL5257faWxcERV3PcxP7o8awhz7vMPFR".to_string(),
commit_message: Some(format!("Commit {}", sha)),
author: None,
oidc_binding: None,
timestamp,
};
let att = sign_commit_with_identity(¶ms, &keypair, &pubkey_bytes)
.expect("Should create attestation");
attestations.push(att);
}
for (i, att) in attestations.iter().enumerate() {
assert_eq!(att.commit_sha.as_deref(), Some(shas[i]));
let expected_msg = format!("Commit {}", shas[i]);
assert_eq!(att.commit_message.as_deref(), Some(expected_msg.as_str()));
}
}