use aa_proto::assembly::common::v1::AgentId as ProtoAgentId;
use sha2::{Digest, Sha256};
pub fn proto_agent_id_to_key(id: &ProtoAgentId) -> [u8; 16] {
let composite = format!("{}/{}/{}", id.org_id, id.team_id, id.agent_id);
let digest = Sha256::digest(composite.as_bytes());
let mut out = [0u8; 16];
out.copy_from_slice(&digest[..16]);
out
}
pub fn validate_proto_agent_id(id: &ProtoAgentId) -> Result<(), &'static str> {
if id.agent_id.is_empty() {
return Err("agent_id is empty");
}
validate_did_key(&id.agent_id)
}
fn validate_did_key(value: &str) -> Result<(), &'static str> {
let multibase = value
.strip_prefix("did:key:")
.ok_or("agent_id is not a did:key DID (missing \"did:key:\" prefix)")?;
let encoded = multibase
.strip_prefix('z')
.ok_or("agent_id is not a valid did:key DID (expected base58btc \"z\" multibase prefix)")?;
if encoded.is_empty() {
return Err("agent_id is not a valid did:key DID (empty multibase value)");
}
let decoded = bs58::decode(encoded)
.into_vec()
.map_err(|_| "agent_id is not a valid did:key DID (multibase value is not valid base58btc)")?;
if decoded.is_empty() {
return Err("agent_id is not a valid did:key DID (multibase value decodes to empty bytes)");
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
fn proto_id(agent_id: &str) -> ProtoAgentId {
ProtoAgentId {
org_id: "acme-corp".into(),
team_id: "platform".into(),
agent_id: agent_id.into(),
}
}
#[test]
fn accepts_valid_did_key() {
let id = proto_id("did:key:z6Mkm5rByiqq5UNbvPFPfXtGJwdg2kD1T");
assert!(validate_proto_agent_id(&id).is_ok());
}
#[test]
fn rejects_empty_agent_id() {
let id = proto_id("");
assert_eq!(validate_proto_agent_id(&id), Err("agent_id is empty"));
}
#[test]
fn rejects_non_did_string() {
let id = proto_id("agent-lifecycle-1");
assert!(validate_proto_agent_id(&id).is_err());
}
#[test]
fn rejects_wrong_did_method() {
let id = proto_id("did:web:example.com");
assert!(validate_proto_agent_id(&id).is_err());
}
#[test]
fn rejects_did_key_without_multibase_prefix() {
let id = proto_id("did:key:6Mkm5rByiqq5UNbvPFPfXtGJwdg2kD1T");
assert!(validate_proto_agent_id(&id).is_err());
}
#[test]
fn rejects_did_key_with_empty_multibase() {
let id = proto_id("did:key:z");
assert!(validate_proto_agent_id(&id).is_err());
}
#[test]
fn rejects_did_key_with_invalid_base58() {
let id = proto_id("did:key:z0OIl");
assert!(validate_proto_agent_id(&id).is_err());
}
}