Skip to main content

agentmesh/
trust_support.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Trust-plane interoperability primitives layered on top of the core trust manager.
5
6use crate::identity::{AgentIdentity, PublicIdentity};
7use crate::identity_support::UserContext;
8use crate::trust::TrustManager;
9use crate::types::TrustTier;
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12use std::collections::HashMap;
13use std::sync::{Arc, Mutex};
14use std::time::{SystemTime, UNIX_EPOCH};
15
16fn unix_secs_now() -> u64 {
17    SystemTime::now()
18        .duration_since(UNIX_EPOCH)
19        .unwrap_or_default()
20        .as_secs()
21}
22
23fn hex(bytes: &[u8]) -> String {
24    bytes.iter().map(|byte| format!("{byte:02x}")).collect()
25}
26
27fn capability_matches(granted: &str, requested: &str) -> bool {
28    granted == "*"
29        || granted == requested
30        || granted
31            .strip_suffix(":*")
32            .map(|prefix| requested.starts_with(&format!("{prefix}:")))
33            .unwrap_or(false)
34        || requested.starts_with(&format!("{granted}:"))
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct CapabilityGrant {
39    pub grant_id: String,
40    pub capability: String,
41    pub action: String,
42    pub resource: String,
43    pub qualifier: Option<String>,
44    pub granted_to: String,
45    pub granted_by: String,
46    pub resource_ids: Vec<String>,
47    pub conditions: HashMap<String, String>,
48    pub granted_at_secs: u64,
49    pub expires_at_secs: Option<u64>,
50    pub active: bool,
51    pub revoked_at_secs: Option<u64>,
52}
53
54impl CapabilityGrant {
55    pub fn parse_capability(capability: &str) -> Result<(String, String, Option<String>), String> {
56        let parts = capability.split(':').collect::<Vec<_>>();
57        if parts.len() < 2 {
58            return Err(format!("invalid capability '{capability}'"));
59        }
60        Ok((
61            parts[0].to_string(),
62            parts[1].to_string(),
63            parts.get(2).map(|value| (*value).to_string()),
64        ))
65    }
66
67    pub fn create(
68        capability: &str,
69        granted_to: &str,
70        granted_by: &str,
71        resource_ids: Vec<String>,
72    ) -> Result<Self, String> {
73        let (action, resource, qualifier) = Self::parse_capability(capability)?;
74        Ok(Self {
75            grant_id: format!("grant_{:012x}", rand::random::<u64>()),
76            capability: capability.to_string(),
77            action,
78            resource,
79            qualifier,
80            granted_to: granted_to.to_string(),
81            granted_by: granted_by.to_string(),
82            resource_ids,
83            conditions: HashMap::new(),
84            granted_at_secs: unix_secs_now(),
85            expires_at_secs: None,
86            active: true,
87            revoked_at_secs: None,
88        })
89    }
90
91    pub fn is_valid(&self) -> bool {
92        self.active
93            && self
94                .expires_at_secs
95                .map(|expires_at| unix_secs_now() < expires_at)
96                .unwrap_or(true)
97    }
98
99    pub fn matches(&self, requested: &str, resource_id: Option<&str>) -> bool {
100        (self.is_valid()
101            && capability_matches(&self.capability, requested)
102            && self.resource_ids.is_empty())
103            || (self.is_valid()
104                && capability_matches(&self.capability, requested)
105                && resource_id
106                    .map(|resource| self.resource_ids.iter().any(|entry| entry == resource))
107                    .unwrap_or(false))
108    }
109
110    pub fn revoke(&mut self) {
111        self.active = false;
112        self.revoked_at_secs = Some(unix_secs_now());
113    }
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct CapabilityScope {
118    pub agent_did: String,
119    pub grants: Vec<CapabilityGrant>,
120    pub denied: Vec<String>,
121}
122
123impl CapabilityScope {
124    pub fn new(agent_did: &str) -> Self {
125        Self {
126            agent_did: agent_did.to_string(),
127            grants: Vec::new(),
128            denied: Vec::new(),
129        }
130    }
131
132    pub fn add_grant(&mut self, grant: CapabilityGrant) -> Result<(), String> {
133        if grant.granted_to != self.agent_did {
134            return Err("grant is for a different agent".to_string());
135        }
136        self.grants.push(grant);
137        Ok(())
138    }
139
140    pub fn has_capability(&self, capability: &str, resource_id: Option<&str>) -> bool {
141        !self
142            .denied
143            .iter()
144            .any(|denied| capability_matches(denied, capability))
145            && self
146                .grants
147                .iter()
148                .any(|grant| grant.matches(capability, resource_id))
149    }
150
151    pub fn get_capabilities(&self) -> Vec<String> {
152        let mut capabilities = self
153            .grants
154            .iter()
155            .filter(|grant| grant.is_valid())
156            .map(|grant| grant.capability.clone())
157            .collect::<Vec<_>>();
158        capabilities.sort();
159        capabilities.dedup();
160        capabilities
161    }
162
163    pub fn filter_capabilities(&self, requested: &[String]) -> Vec<String> {
164        requested
165            .iter()
166            .filter(|capability| self.has_capability(capability, None))
167            .cloned()
168            .collect()
169    }
170
171    pub fn deny(&mut self, capability: &str) {
172        if !self.denied.iter().any(|entry| entry == capability) {
173            self.denied.push(capability.to_string());
174        }
175    }
176
177    pub fn revoke_all(&mut self) -> usize {
178        let mut count = 0;
179        for grant in &mut self.grants {
180            if grant.active {
181                grant.revoke();
182                count += 1;
183            }
184        }
185        count
186    }
187}
188
189pub struct CapabilityRegistry {
190    scopes: Mutex<HashMap<String, CapabilityScope>>,
191}
192
193impl CapabilityRegistry {
194    pub fn new() -> Self {
195        Self {
196            scopes: Mutex::new(HashMap::new()),
197        }
198    }
199
200    pub fn scope_for(&self, agent_did: &str) -> CapabilityScope {
201        self.scopes
202            .lock()
203            .unwrap_or_else(|e| e.into_inner())
204            .entry(agent_did.to_string())
205            .or_insert_with(|| CapabilityScope::new(agent_did))
206            .clone()
207    }
208
209    pub fn grant(
210        &self,
211        granted_to: &str,
212        granted_by: &str,
213        capability: &str,
214        resource_ids: Vec<String>,
215    ) -> Result<CapabilityGrant, String> {
216        let grant = CapabilityGrant::create(capability, granted_to, granted_by, resource_ids)?;
217        let mut scopes = self.scopes.lock().unwrap_or_else(|e| e.into_inner());
218        scopes
219            .entry(granted_to.to_string())
220            .or_insert_with(|| CapabilityScope::new(granted_to))
221            .add_grant(grant.clone())?;
222        Ok(grant)
223    }
224
225    pub fn has_capability(
226        &self,
227        agent_did: &str,
228        capability: &str,
229        resource_id: Option<&str>,
230    ) -> bool {
231        self.scopes
232            .lock()
233            .unwrap_or_else(|e| e.into_inner())
234            .get(agent_did)
235            .map(|scope| scope.has_capability(capability, resource_id))
236            .unwrap_or(false)
237    }
238}
239
240impl Default for CapabilityRegistry {
241    fn default() -> Self {
242        Self::new()
243    }
244}
245
246#[derive(Debug, Clone, Serialize, Deserialize)]
247pub struct HandshakeChallenge {
248    pub challenge_id: String,
249    pub nonce: String,
250    pub issued_at_secs: u64,
251    pub expires_in_seconds: u64,
252}
253
254impl HandshakeChallenge {
255    pub fn generate() -> Self {
256        Self {
257            challenge_id: format!("challenge_{:016x}", rand::random::<u64>()),
258            nonce: hex(&rand::random::<[u8; 32]>()),
259            issued_at_secs: unix_secs_now(),
260            expires_in_seconds: 30,
261        }
262    }
263
264    pub fn is_expired(&self) -> bool {
265        unix_secs_now().saturating_sub(self.issued_at_secs) > self.expires_in_seconds
266    }
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct HandshakeResponse {
271    pub challenge_id: String,
272    pub response_nonce: String,
273    pub agent_did: String,
274    pub capabilities: Vec<String>,
275    pub trust_score: u32,
276    pub signature_hex: String,
277    pub public_key_hex: String,
278    pub user_context: Option<UserContext>,
279    pub timestamp_secs: u64,
280}
281
282#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
283#[serde(rename_all = "snake_case")]
284pub enum HandshakeTrustLevel {
285    VerifiedPartner,
286    Trusted,
287    Standard,
288    Untrusted,
289}
290
291#[derive(Debug, Clone, Serialize, Deserialize)]
292pub struct HandshakeResult {
293    pub verified: bool,
294    pub peer_did: String,
295    pub peer_name: Option<String>,
296    pub trust_score: u32,
297    pub trust_level: HandshakeTrustLevel,
298    pub capabilities: Vec<String>,
299    pub user_context: Option<UserContext>,
300    pub handshake_started_secs: u64,
301    pub handshake_completed_secs: u64,
302    pub latency_ms: u64,
303    pub rejection_reason: Option<String>,
304}
305
306impl HandshakeResult {
307    pub fn success(
308        peer_did: &str,
309        trust_score: u32,
310        capabilities: Vec<String>,
311        started_at_secs: u64,
312        user_context: Option<UserContext>,
313    ) -> Self {
314        let completed = unix_secs_now();
315        let trust_level = match TrustTier::from_score(trust_score) {
316            TrustTier::VerifiedPartner => HandshakeTrustLevel::VerifiedPartner,
317            TrustTier::Trusted => HandshakeTrustLevel::Trusted,
318            TrustTier::Standard => HandshakeTrustLevel::Standard,
319            TrustTier::Probationary | TrustTier::Untrusted => HandshakeTrustLevel::Untrusted,
320        };
321        Self {
322            verified: true,
323            peer_did: peer_did.to_string(),
324            peer_name: None,
325            trust_score,
326            trust_level,
327            capabilities,
328            user_context,
329            handshake_started_secs: started_at_secs,
330            handshake_completed_secs: completed,
331            latency_ms: completed.saturating_sub(started_at_secs) * 1000,
332            rejection_reason: None,
333        }
334    }
335
336    pub fn failure(peer_did: &str, started_at_secs: u64, reason: &str) -> Self {
337        let completed = unix_secs_now();
338        Self {
339            verified: false,
340            peer_did: peer_did.to_string(),
341            peer_name: None,
342            trust_score: 0,
343            trust_level: HandshakeTrustLevel::Untrusted,
344            capabilities: Vec::new(),
345            user_context: None,
346            handshake_started_secs: started_at_secs,
347            handshake_completed_secs: completed,
348            latency_ms: completed.saturating_sub(started_at_secs) * 1000,
349            rejection_reason: Some(reason.to_string()),
350        }
351    }
352}
353
354pub struct TrustHandshake {
355    agent_did: String,
356    identity: Option<AgentIdentity>,
357    trust_manager: Option<Arc<TrustManager>>,
358    peers: Mutex<HashMap<String, PublicIdentity>>,
359    pending: Mutex<HashMap<String, HandshakeChallenge>>,
360}
361
362impl TrustHandshake {
363    pub fn new(
364        agent_did: &str,
365        identity: Option<AgentIdentity>,
366        trust_manager: Option<Arc<TrustManager>>,
367    ) -> Self {
368        Self {
369            agent_did: agent_did.to_string(),
370            identity,
371            trust_manager,
372            peers: Mutex::new(HashMap::new()),
373            pending: Mutex::new(HashMap::new()),
374        }
375    }
376
377    pub fn register_peer(&self, identity: &AgentIdentity) {
378        self.peers.lock().unwrap_or_else(|e| e.into_inner()).insert(
379            identity.did.clone(),
380            PublicIdentity {
381                did: identity.did.clone(),
382                public_key: identity.public_key.to_bytes().to_vec(),
383                capabilities: identity.capabilities.clone(),
384            },
385        );
386    }
387
388    pub fn issue_challenge(&self, peer_did: &str) -> HandshakeChallenge {
389        let challenge = HandshakeChallenge::generate();
390        self.pending
391            .lock()
392            .unwrap_or_else(|e| e.into_inner())
393            .insert(peer_did.to_string(), challenge.clone());
394        challenge
395    }
396
397    pub fn create_response(
398        &self,
399        peer_identity: &AgentIdentity,
400        challenge: &HandshakeChallenge,
401        trust_score: u32,
402        user_context: Option<UserContext>,
403    ) -> HandshakeResponse {
404        let payload = format!("{}:{}", challenge.challenge_id, challenge.nonce);
405        let signature = peer_identity.sign(payload.as_bytes());
406        HandshakeResponse {
407            challenge_id: challenge.challenge_id.clone(),
408            response_nonce: challenge.nonce.clone(),
409            agent_did: peer_identity.did.clone(),
410            capabilities: peer_identity.capabilities.clone(),
411            trust_score,
412            signature_hex: hex(&signature),
413            public_key_hex: hex(&peer_identity.public_key.to_bytes()),
414            user_context,
415            timestamp_secs: unix_secs_now(),
416        }
417    }
418
419    pub fn verify_response(
420        &self,
421        response: &HandshakeResponse,
422        required_trust_score: u32,
423        required_capabilities: &[String],
424    ) -> HandshakeResult {
425        let started = unix_secs_now();
426        let challenge = self
427            .pending
428            .lock()
429            .unwrap_or_else(|e| e.into_inner())
430            .remove(&response.agent_did);
431        let Some(challenge) = challenge else {
432            return HandshakeResult::failure(&response.agent_did, started, "no pending challenge");
433        };
434        if challenge.is_expired()
435            || challenge.challenge_id != response.challenge_id
436            || challenge.nonce != response.response_nonce
437        {
438            return HandshakeResult::failure(
439                &response.agent_did,
440                started,
441                "challenge mismatch or expiration",
442            );
443        }
444        let Some(identity) = self
445            .peers
446            .lock()
447            .unwrap_or_else(|e| e.into_inner())
448            .get(&response.agent_did)
449            .cloned()
450        else {
451            return HandshakeResult::failure(&response.agent_did, started, "peer not registered");
452        };
453        let payload = format!("{}:{}", challenge.challenge_id, challenge.nonce);
454        let signature = response
455            .signature_hex
456            .as_bytes()
457            .chunks(2)
458            .filter_map(|chunk| std::str::from_utf8(chunk).ok())
459            .filter_map(|chunk| u8::from_str_radix(chunk, 16).ok())
460            .collect::<Vec<_>>();
461        if !identity.verify(payload.as_bytes(), &signature) {
462            return HandshakeResult::failure(
463                &response.agent_did,
464                started,
465                "signature verification failed",
466            );
467        }
468        if response.trust_score < required_trust_score {
469            return HandshakeResult::failure(
470                &response.agent_did,
471                started,
472                "trust score below threshold",
473            );
474        }
475        if !required_capabilities.iter().all(|required| {
476            response
477                .capabilities
478                .iter()
479                .any(|cap| capability_matches(cap, required))
480        }) {
481            return HandshakeResult::failure(
482                &response.agent_did,
483                started,
484                "required capabilities missing",
485            );
486        }
487        HandshakeResult::success(
488            &response.agent_did,
489            response.trust_score,
490            response.capabilities.clone(),
491            started,
492            response.user_context.clone(),
493        )
494    }
495
496    pub fn verify_registered_peer(
497        &self,
498        peer_did: &str,
499        required_trust_score: u32,
500        required_capabilities: &[String],
501    ) -> HandshakeResult {
502        let started = unix_secs_now();
503        let Some(identity) = self
504            .peers
505            .lock()
506            .unwrap_or_else(|e| e.into_inner())
507            .get(peer_did)
508            .cloned()
509        else {
510            return HandshakeResult::failure(peer_did, started, "peer not registered");
511        };
512        let trust_score = self
513            .trust_manager
514            .as_ref()
515            .map(|manager| manager.get_trust_score(peer_did).score)
516            .unwrap_or(500);
517        if trust_score < required_trust_score {
518            return HandshakeResult::failure(peer_did, started, "trust score below threshold");
519        }
520        if !required_capabilities.iter().all(|required| {
521            identity
522                .capabilities
523                .iter()
524                .any(|cap| capability_matches(cap, required))
525        }) {
526            return HandshakeResult::failure(peer_did, started, "required capabilities missing");
527        }
528        HandshakeResult::success(
529            peer_did,
530            trust_score,
531            identity.capabilities.clone(),
532            started,
533            None,
534        )
535    }
536
537    pub fn agent_did(&self) -> &str {
538        &self.agent_did
539    }
540
541    pub fn has_local_identity(&self) -> bool {
542        self.identity.is_some()
543    }
544}
545
546#[derive(Debug, Clone, Serialize, Deserialize)]
547pub struct PeerInfo {
548    pub peer_did: String,
549    pub peer_name: Option<String>,
550    pub protocol: String,
551    pub trust_score: u32,
552    pub trust_verified: bool,
553    pub last_verified_secs: Option<u64>,
554    pub capabilities: Vec<String>,
555    pub endpoint: Option<String>,
556}
557
558pub struct TrustBridge {
559    pub agent_did: String,
560    pub default_trust_threshold: u32,
561    peers: Mutex<HashMap<String, PeerInfo>>,
562    handshake: TrustHandshake,
563}
564
565impl TrustBridge {
566    pub fn new(
567        agent_did: &str,
568        identity: Option<AgentIdentity>,
569        trust_manager: Option<Arc<TrustManager>>,
570    ) -> Self {
571        Self {
572            agent_did: agent_did.to_string(),
573            default_trust_threshold: 700,
574            peers: Mutex::new(HashMap::new()),
575            handshake: TrustHandshake::new(agent_did, identity, trust_manager),
576        }
577    }
578
579    pub fn register_peer(&self, identity: &AgentIdentity, protocol: &str) {
580        self.handshake.register_peer(identity);
581        self.peers.lock().unwrap_or_else(|e| e.into_inner()).insert(
582            identity.did.clone(),
583            PeerInfo {
584                peer_did: identity.did.clone(),
585                peer_name: None,
586                protocol: protocol.to_string(),
587                trust_score: 0,
588                trust_verified: false,
589                last_verified_secs: None,
590                capabilities: identity.capabilities.clone(),
591                endpoint: None,
592            },
593        );
594    }
595
596    pub fn verify_peer(
597        &self,
598        peer_did: &str,
599        protocol: &str,
600        required_trust_score: Option<u32>,
601        required_capabilities: &[String],
602    ) -> HandshakeResult {
603        let result = self.handshake.verify_registered_peer(
604            peer_did,
605            required_trust_score.unwrap_or(self.default_trust_threshold),
606            required_capabilities,
607        );
608        if result.verified {
609            self.peers.lock().unwrap_or_else(|e| e.into_inner()).insert(
610                peer_did.to_string(),
611                PeerInfo {
612                    peer_did: peer_did.to_string(),
613                    peer_name: result.peer_name.clone(),
614                    protocol: protocol.to_string(),
615                    trust_score: result.trust_score,
616                    trust_verified: true,
617                    last_verified_secs: Some(unix_secs_now()),
618                    capabilities: result.capabilities.clone(),
619                    endpoint: None,
620                },
621            );
622        }
623        result
624    }
625
626    pub fn is_peer_trusted(&self, peer_did: &str, required_score: Option<u32>) -> bool {
627        self.peers
628            .lock()
629            .unwrap_or_else(|e| e.into_inner())
630            .get(peer_did)
631            .map(|peer| {
632                peer.trust_verified
633                    && peer.trust_score >= required_score.unwrap_or(self.default_trust_threshold)
634            })
635            .unwrap_or(false)
636    }
637
638    pub fn get_peer(&self, peer_did: &str) -> Option<PeerInfo> {
639        self.peers
640            .lock()
641            .unwrap_or_else(|e| e.into_inner())
642            .get(peer_did)
643            .cloned()
644    }
645
646    pub fn get_trusted_peers(&self, min_score: Option<u32>) -> Vec<PeerInfo> {
647        self.peers
648            .lock()
649            .unwrap_or_else(|e| e.into_inner())
650            .values()
651            .filter(|peer| {
652                peer.trust_verified
653                    && peer.trust_score >= min_score.unwrap_or(self.default_trust_threshold)
654            })
655            .cloned()
656            .collect()
657    }
658
659    pub fn revoke_peer_trust(&self, peer_did: &str) -> bool {
660        if let Some(peer) = self
661            .peers
662            .lock()
663            .unwrap_or_else(|e| e.into_inner())
664            .get_mut(peer_did)
665        {
666            peer.trust_verified = false;
667            peer.trust_score = 0;
668            return true;
669        }
670        false
671    }
672}
673
674pub struct ProtocolBridge {
675    pub agent_did: String,
676    pub trust_bridge: TrustBridge,
677    pub supported_protocols: Vec<String>,
678}
679
680impl ProtocolBridge {
681    pub fn new(
682        agent_did: &str,
683        identity: Option<AgentIdentity>,
684        trust_manager: Option<Arc<TrustManager>>,
685    ) -> Self {
686        Self {
687            agent_did: agent_did.to_string(),
688            trust_bridge: TrustBridge::new(agent_did, identity, trust_manager),
689            supported_protocols: vec!["a2a".into(), "mcp".into(), "iatp".into(), "acp".into()],
690        }
691    }
692
693    pub fn translate(&self, message: &Value, from_protocol: &str, to_protocol: &str) -> Value {
694        if from_protocol == "a2a" && to_protocol == "mcp" {
695            let task_type = message
696                .get("task_type")
697                .and_then(Value::as_str)
698                .unwrap_or("execute");
699            let parameters = message
700                .get("parameters")
701                .cloned()
702                .unwrap_or(Value::Object(Default::default()));
703            serde_json::json!({
704                "method": "tools/call",
705                "params": { "name": task_type, "arguments": parameters }
706            })
707        } else if from_protocol == "mcp" && to_protocol == "a2a" {
708            let params = message
709                .get("params")
710                .cloned()
711                .unwrap_or(Value::Object(Default::default()));
712            serde_json::json!({
713                "task_type": params.get("name").and_then(Value::as_str).unwrap_or("execute"),
714                "parameters": params.get("arguments").cloned().unwrap_or(Value::Object(Default::default()))
715            })
716        } else {
717            message.clone()
718        }
719    }
720
721    pub fn add_verification_footer(
722        &self,
723        content: &str,
724        trust_score: u32,
725        agent_did: &str,
726    ) -> String {
727        format!(
728            "{content}\n\n> Verified by AgentMesh (Trust Score: {trust_score}/1000)\n> Agent: {agent_did}\n"
729        )
730    }
731}
732
733#[derive(Debug, Clone, Serialize, Deserialize)]
734pub struct TrustedAgentCard {
735    pub peer_did: String,
736    pub peer_name: Option<String>,
737    pub trust_score: u32,
738    pub capabilities: Vec<String>,
739    pub protocol: String,
740    pub issuer_did: String,
741    pub issued_at_secs: u64,
742    pub metadata: HashMap<String, String>,
743}
744
745impl TrustedAgentCard {
746    pub fn from_handshake_result(
747        issuer_did: &str,
748        protocol: &str,
749        result: &HandshakeResult,
750    ) -> Self {
751        Self {
752            peer_did: result.peer_did.clone(),
753            peer_name: result.peer_name.clone(),
754            trust_score: result.trust_score,
755            capabilities: result.capabilities.clone(),
756            protocol: protocol.to_string(),
757            issuer_did: issuer_did.to_string(),
758            issued_at_secs: unix_secs_now(),
759            metadata: HashMap::new(),
760        }
761    }
762}
763
764pub struct CardRegistry {
765    cards: Mutex<HashMap<String, TrustedAgentCard>>,
766}
767
768impl CardRegistry {
769    pub fn new() -> Self {
770        Self {
771            cards: Mutex::new(HashMap::new()),
772        }
773    }
774
775    pub fn put(&self, card: TrustedAgentCard) {
776        self.cards
777            .lock()
778            .unwrap_or_else(|e| e.into_inner())
779            .insert(card.peer_did.clone(), card);
780    }
781
782    pub fn get(&self, peer_did: &str) -> Option<TrustedAgentCard> {
783        self.cards
784            .lock()
785            .unwrap_or_else(|e| e.into_inner())
786            .get(peer_did)
787            .cloned()
788    }
789}
790
791impl Default for CardRegistry {
792    fn default() -> Self {
793        Self::new()
794    }
795}
796
797#[cfg(test)]
798mod tests {
799    use super::*;
800
801    #[test]
802    fn capability_registry_tracks_grants_and_denies() {
803        let registry = CapabilityRegistry::new();
804        registry
805            .grant(
806                "did:agentmesh:peer",
807                "did:agentmesh:root",
808                "read:data",
809                Vec::new(),
810            )
811            .unwrap();
812        assert!(registry.has_capability("did:agentmesh:peer", "read:data", None));
813        assert!(!registry.has_capability("did:agentmesh:peer", "write:data", None));
814    }
815
816    #[test]
817    fn trust_handshake_verifies_registered_peer() {
818        let peer = AgentIdentity::generate("peer", vec!["data.read".into()]).unwrap();
819        let trust = Arc::new(TrustManager::with_defaults());
820        trust.set_trust(&peer.did, 750);
821        let handshake = TrustHandshake::new("did:agentmesh:self", None, Some(trust));
822        handshake.register_peer(&peer);
823        let result = handshake.verify_registered_peer(&peer.did, 700, &["data.read".into()]);
824        assert!(result.verified);
825        assert_eq!(result.trust_level, HandshakeTrustLevel::Trusted);
826    }
827
828    #[test]
829    fn trust_bridge_records_verified_peer() {
830        let peer = AgentIdentity::generate("peer", vec!["data.read".into()]).unwrap();
831        let trust = Arc::new(TrustManager::with_defaults());
832        trust.set_trust(&peer.did, 900);
833        let bridge = TrustBridge::new("did:agentmesh:self", None, Some(trust));
834        bridge.register_peer(&peer, "mcp");
835        let result = bridge.verify_peer(&peer.did, "mcp", Some(700), &["data.read".into()]);
836        assert!(result.verified);
837        assert!(bridge.is_peer_trusted(&peer.did, Some(700)));
838        assert_eq!(bridge.get_trusted_peers(None).len(), 1);
839    }
840
841    #[test]
842    fn protocol_bridge_translates_between_a2a_and_mcp() {
843        let bridge = ProtocolBridge::new("did:agentmesh:self", None, None);
844        let a2a = serde_json::json!({
845            "task_type": "search.web",
846            "parameters": { "query": "agentmesh" }
847        });
848        let mcp = bridge.translate(&a2a, "a2a", "mcp");
849        assert_eq!(mcp["method"], "tools/call");
850        let a2a_roundtrip = bridge.translate(&mcp, "mcp", "a2a");
851        assert_eq!(a2a_roundtrip["task_type"], "search.web");
852    }
853
854    #[test]
855    fn card_registry_stores_handshake_cards() {
856        let result = HandshakeResult::success(
857            "did:agentmesh:peer",
858            800,
859            vec!["search.web".into()],
860            unix_secs_now(),
861            None,
862        );
863        let card = TrustedAgentCard::from_handshake_result("did:agentmesh:self", "mcp", &result);
864        let registry = CardRegistry::new();
865        registry.put(card);
866        assert_eq!(registry.get("did:agentmesh:peer").unwrap().protocol, "mcp");
867    }
868}