use moloch_core::crypto::{hash, SecretKey};
use moloch_core::event::{EventId, ResourceId, ResourceKind};
use moloch_core::{
ActionOutcome, AgentAttestationBuilder, ApprovalContext, ApprovalDecision, ApprovalPolicy,
ApprovalRequest, ApprovalResponse, Attestor, CapabilityBuilder, CapabilityId, CapabilityKind,
CausalContextBuilder, Confidence, CoordinatedAction, CoordinatedActionSpec,
CoordinationProtocol, CoordinationType, Decision, EmergencyAction, EmergencyEvent,
EmergencyPriority, EmergencyResolution, Evidence, FailureHandling, Goal, ImpactAssessment,
OutcomeAttestation, Participant, ParticipantRole, PostMortem, PrincipalId, ProposedAction,
ReasoningStep, ReasoningTrace, Resolution, Responsibility, RuntimeAttestation, Session,
SessionId, Severity, SuspensionScope, ToolAttestation,
};
use std::time::Duration;
fn test_key() -> SecretKey {
SecretKey::generate()
}
fn test_principal() -> PrincipalId {
PrincipalId::user("test@example.com").unwrap()
}
fn test_event_id() -> EventId {
EventId(hash(b"test-event"))
}
fn test_resource_id() -> ResourceId {
ResourceId::new(ResourceKind::File, "/tmp/test.txt")
}
#[test]
fn integration_complete_agent_action_flow() {
let agent_key = test_key();
let authority_key = test_key();
let grantor_key = test_key();
let principal = test_principal();
let session = Session::builder()
.principal(principal.clone())
.max_depth(10)
.max_duration(Duration::from_secs(3600))
.build()
.unwrap();
assert!(session.is_active());
let attestation = AgentAttestationBuilder::new()
.agent_id(agent_key.public_key())
.code_hash(hash(b"agent-code"))
.config_hash(hash(b"agent-config"))
.prompt_hash(hash(b"agent-prompt"))
.runtime(RuntimeAttestation::new(
"test-runtime-v1",
hash(b"runtime-binary"),
))
.tool(ToolAttestation::new(
"file_reader",
"1.0.0",
hash(b"tool-impl"),
))
.validity_period(Duration::from_secs(86400))
.sign(&authority_key)
.unwrap();
let now = chrono::Utc::now().timestamp_millis();
assert!(attestation.is_valid_at(now));
assert!(attestation.verify_signature().is_ok());
let capability = CapabilityBuilder::new()
.kind(CapabilityKind::Read)
.grantor(principal.clone())
.expires_in(Duration::from_secs(3600))
.sign(&grantor_key)
.unwrap();
let now = chrono::Utc::now().timestamp_millis();
assert!(capability.is_valid_at(now));
let causal_context = CausalContextBuilder::new()
.parent_event_id(EventId(hash(b"session-start"))) .root_event_id(EventId(hash(b"session-start")))
.session_id(session.id())
.principal(principal.clone())
.depth(1)
.sequence(1)
.build()
.unwrap();
assert!(!causal_context.is_root());
let reasoning = ReasoningTrace::builder()
.goal(Goal::from_user(
"Read configuration file",
EventId(hash(b"user-request")),
))
.step(ReasoningStep::new(1, "User requested to read config"))
.step(ReasoningStep::new(2, "Checking capability permissions"))
.step(ReasoningStep::new(3, "Proceeding with read operation"))
.decision(Decision::new(
"Read file /tmp/test.txt",
"User authorized this action",
"File contents returned",
))
.confidence(Confidence::high())
.build()
.unwrap();
assert!(reasoning.is_complete());
assert!(reasoning.verify_integrity());
let outcome = OutcomeAttestation::builder()
.action_event_id(test_event_id())
.outcome(ActionOutcome::success(
serde_json::json!({"file_content": "test data"}),
))
.attestor(Attestor::self_attestation(agent_key.public_key()))
.evidence(Evidence::data_hash(
test_resource_id(),
hash(b"test data"),
9,
))
.observed_now()
.sign(&agent_key)
.unwrap();
assert!(outcome.verify_against_attestor().is_ok());
assert!(outcome.is_evidence_sufficient(Severity::Low));
}
#[test]
fn integration_hitl_approval_flow() {
let agent_key = test_key();
let principal = test_principal();
let proposed = ProposedAction::builder()
.action_type("delete_file")
.resource(test_resource_id())
.reasoning("Will permanently delete important file")
.impact(ImpactAssessment::new(Severity::High))
.reversible(false)
.build()
.unwrap();
assert!(!proposed.is_reversible());
assert_eq!(proposed.impact().severity(), Severity::High);
let causal_context = CausalContextBuilder::new()
.root_event_id(test_event_id())
.session_id(SessionId::random())
.principal(principal.clone())
.depth(0)
.sequence(0)
.build()
.unwrap();
let context = ApprovalContext::new(
causal_context,
hash(b"attestation"),
CapabilityId::generate(),
);
let request = ApprovalRequest::new(
proposed,
agent_key.public_key(),
vec![principal.clone()],
ApprovalPolicy::single_approver(),
Duration::from_secs(600),
context,
);
assert!(!request.is_expired());
assert!(request.status().is_pending());
let response = ApprovalResponse::new(request.id(), principal, ApprovalDecision::Approve);
assert!(response.decision().is_approval());
}
#[test]
fn integration_multi_agent_coordination() {
let coordinator_key = test_key();
let peer_key = test_key();
let principal = test_principal();
let spec = CoordinatedActionSpec::new("Process data pipeline")
.with_criterion("All steps complete without error")
.with_criterion("Output matches expected format")
.with_failure_handling(FailureHandling::Retry { max_attempts: 3 });
let coordinator = Participant::with_commitment(
coordinator_key.public_key(),
ParticipantRole::Coordinator,
Responsibility::shared(0.6),
coordinator_key.sign(&spec.canonical_bytes()),
);
let peer = Participant::with_commitment(
peer_key.public_key(),
ParticipantRole::Peer,
Responsibility::shared(0.4), peer_key.sign(&spec.canonical_bytes()),
);
let causal_context = CausalContextBuilder::new()
.root_event_id(EventId(hash(b"coordination-start")))
.session_id(SessionId::random())
.principal(principal)
.depth(0)
.sequence(0)
.build()
.unwrap();
let coordination = CoordinatedAction::builder()
.coordination_type(CoordinationType::Pipeline)
.participant(coordinator)
.participant(peer)
.action(spec)
.protocol(CoordinationProtocol::LeaderFollower)
.causal_context(causal_context)
.started_now()
.build_verified()
.unwrap();
assert!(coordination.coordinator().is_some());
assert_eq!(coordination.participants().len(), 2);
}
#[test]
fn integration_emergency_response() {
let agent_key = test_key();
let principal = test_principal();
let emergency = EmergencyEvent::builder()
.action(EmergencyAction::suspend_agent(
agent_key.public_key(),
"Excessive rate limit violations",
Some(3600000), SuspensionScope::Full,
))
.initiator(principal.clone())
.priority(EmergencyPriority::High)
.trigger_evidence(test_event_id())
.declared_now()
.build()
.unwrap();
assert!(emergency.priority() == EmergencyPriority::High);
assert!(!emergency.is_critical());
assert!(emergency.action().affects_agent(&agent_key.public_key()));
let post_mortem = PostMortem::new(
"Agent exceeded rate limits due to retry loop",
"Bug in retry logic caused infinite loop",
"Temporary service slowdown for 15 minutes",
)
.with_action_taken("Suspended agent")
.with_action_taken("Fixed retry logic")
.with_prevention("Add circuit breaker pattern")
.with_lesson("Monitor retry patterns in production");
let resolution = EmergencyResolution::new(
test_event_id(), Resolution::fixed("Patched retry logic in agent code"),
principal,
)
.with_post_mortem(post_mortem);
assert!(!resolution.is_false_alarm());
assert!(resolution.post_mortem().is_some());
let pm = resolution.post_mortem().unwrap();
assert_eq!(pm.actions_taken().len(), 2);
assert_eq!(pm.prevention().len(), 1);
}
#[test]
fn integration_capability_constraints() {
let grantor_key = test_key();
let principal = test_principal();
let capability = CapabilityBuilder::new()
.kind(CapabilityKind::Write)
.grantor(principal.clone())
.expires_in(Duration::from_secs(3600))
.delegatable(2) .scope(moloch_core::ResourceScope::pattern("*.txt"))
.sign(&grantor_key)
.unwrap();
let now = chrono::Utc::now().timestamp_millis();
assert!(capability.is_valid_at(now));
assert!(capability.is_delegatable());
assert_eq!(capability.max_delegation_depth(), 2);
}
#[test]
fn integration_reasoning_triggers_approval() {
let reasoning = ReasoningTrace::builder()
.goal(Goal::from_user(
"Perform complex refactoring",
test_event_id(),
))
.step(ReasoningStep::new(1, "Analyzing code structure"))
.step(ReasoningStep::new(2, "Identified potential changes"))
.decision(Decision::new(
"Refactor module X",
"Might improve performance",
"Cleaner code structure",
))
.confidence(
Confidence::new(0.4) .with_uncertainty("Complex dependencies unclear")
.with_would_help("More context about usage patterns"),
)
.build()
.unwrap();
assert!(!reasoning.confidence().should_reject()); assert!(reasoning.confidence().requires_approval()); assert!(reasoning.confidence().should_warn()); }
#[test]
fn integration_outcome_evidence_by_severity() {
let agent_key = test_key();
let third_party_key = test_key();
let low_outcome = OutcomeAttestation::builder()
.action_event_id(test_event_id())
.outcome(ActionOutcome::success(serde_json::json!({})))
.attestor(Attestor::self_attestation(agent_key.public_key()))
.observed_now()
.sign(&agent_key)
.unwrap();
assert!(low_outcome.is_evidence_sufficient(Severity::Low));
assert!(!low_outcome.is_evidence_sufficient(Severity::Medium));
let medium_outcome = OutcomeAttestation::builder()
.action_event_id(test_event_id())
.outcome(ActionOutcome::success(serde_json::json!({})))
.attestor(Attestor::self_attestation(agent_key.public_key()))
.evidence(Evidence::external_confirmation(
"ci-system",
"build-123",
chrono::Utc::now().timestamp_millis(),
))
.observed_now()
.sign(&agent_key)
.unwrap();
assert!(medium_outcome.is_evidence_sufficient(Severity::Medium));
assert!(!medium_outcome.is_evidence_sufficient(Severity::High));
let high_outcome = OutcomeAttestation::builder()
.action_event_id(test_event_id())
.outcome(ActionOutcome::success(serde_json::json!({})))
.attestor(Attestor::self_attestation(agent_key.public_key()))
.evidence(Evidence::external_confirmation(
"ci-system",
"build-123",
chrono::Utc::now().timestamp_millis(),
))
.evidence(Evidence::external_confirmation(
"monitoring-system",
"check-456",
chrono::Utc::now().timestamp_millis(),
))
.observed_now()
.sign(&agent_key)
.unwrap();
assert!(high_outcome.is_evidence_sufficient(Severity::High));
assert!(!high_outcome.is_evidence_sufficient(Severity::Critical));
let critical_outcome = OutcomeAttestation::builder()
.action_event_id(test_event_id())
.outcome(ActionOutcome::success(serde_json::json!({})))
.attestor(Attestor::self_attestation(agent_key.public_key()))
.evidence(Evidence::third_party_attestation(
third_party_key.public_key(),
vec![1, 2, 3, 4],
))
.observed_now()
.sign(&agent_key)
.unwrap();
assert!(critical_outcome.is_evidence_sufficient(Severity::Critical));
}
#[test]
fn integration_attestation_expiry() {
let agent_key = test_key();
let authority_key = test_key();
let attestation = AgentAttestationBuilder::new()
.agent_id(agent_key.public_key())
.code_hash(hash(b"code"))
.config_hash(hash(b"config"))
.prompt_hash(hash(b"prompt"))
.runtime(RuntimeAttestation::new("rt", hash(b"rt")))
.validity_period(Duration::from_millis(1)) .sign(&authority_key)
.unwrap();
std::thread::sleep(Duration::from_millis(10));
let now = chrono::Utc::now().timestamp_millis();
assert!(!attestation.is_valid_at(now));
}
#[test]
fn integration_session_boundaries() {
let principal = test_principal();
let session_id = SessionId::random();
let root_context = CausalContextBuilder::new()
.root_event_id(EventId(hash(b"root")))
.session_id(session_id)
.principal(principal.clone())
.depth(0)
.sequence(0)
.build()
.unwrap();
assert!(root_context.is_root());
let child_context = CausalContextBuilder::new()
.parent_event_id(EventId(hash(b"parent")))
.root_event_id(EventId(hash(b"root")))
.session_id(session_id)
.principal(principal.clone())
.depth(1)
.sequence(1)
.build()
.unwrap();
assert!(!child_context.is_root());
assert_eq!(child_context.depth(), 1);
assert!(child_context.validate(10).is_ok()); assert!(child_context.validate(0).is_err()); }
#[test]
fn adversarial_forged_attestation_rejected() {
let agent_key = test_key();
let authority_key = test_key();
let attestation = AgentAttestationBuilder::new()
.agent_id(agent_key.public_key())
.code_hash(hash(b"code"))
.config_hash(hash(b"config"))
.prompt_hash(hash(b"prompt"))
.runtime(RuntimeAttestation::new("rt", hash(b"rt")))
.validity_period(Duration::from_secs(3600))
.sign(&authority_key)
.unwrap();
assert!(attestation.verify_signature().is_ok());
assert_eq!(attestation.authority(), &authority_key.public_key());
}
#[test]
fn adversarial_forged_outcome_rejected() {
let agent_key = test_key();
let wrong_key = test_key();
let outcome = OutcomeAttestation::builder()
.action_event_id(test_event_id())
.outcome(ActionOutcome::success(serde_json::json!({})))
.attestor(Attestor::self_attestation(agent_key.public_key()))
.observed_now()
.sign(&agent_key)
.unwrap();
let result = outcome.verify_signature(&wrong_key.public_key());
assert!(result.is_err());
}
#[test]
fn adversarial_coordination_no_coordinator() {
let peer1_key = test_key();
let peer2_key = test_key();
let principal = test_principal();
let peer1 = Participant::new(
peer1_key.public_key(),
ParticipantRole::Peer,
Responsibility::shared(0.5),
moloch_core::Sig::empty(),
);
let peer2 = Participant::new(
peer2_key.public_key(),
ParticipantRole::Peer,
Responsibility::shared(0.5),
moloch_core::Sig::empty(),
);
let causal_context = CausalContextBuilder::new()
.root_event_id(EventId(hash(b"root")))
.session_id(SessionId::random())
.principal(principal)
.depth(0)
.sequence(0)
.build()
.unwrap();
let result = CoordinatedAction::builder()
.coordination_type(CoordinationType::Parallel)
.participant(peer1)
.participant(peer2)
.action(CoordinatedActionSpec::new("Test"))
.protocol(CoordinationProtocol::TwoPhaseCommit)
.causal_context(causal_context)
.build();
assert!(result.is_err());
}
#[test]
fn adversarial_responsibility_sum() {
let key1 = test_key();
let key2 = test_key();
let principal = test_principal();
let p1 = Participant::new(
key1.public_key(),
ParticipantRole::Coordinator,
Responsibility::shared(0.3),
moloch_core::Sig::empty(),
);
let p2 = Participant::new(
key2.public_key(),
ParticipantRole::Peer,
Responsibility::shared(0.3), moloch_core::Sig::empty(),
);
let causal_context = CausalContextBuilder::new()
.root_event_id(EventId(hash(b"root")))
.session_id(SessionId::random())
.principal(principal)
.depth(0)
.sequence(0)
.build()
.unwrap();
let result = CoordinatedAction::builder()
.coordination_type(CoordinationType::Parallel)
.participant(p1)
.participant(p2)
.action(CoordinatedActionSpec::new("Test"))
.protocol(CoordinationProtocol::TwoPhaseCommit)
.causal_context(causal_context)
.build();
assert!(result.is_err());
}