use super::super::decision::{reason_codes, DecisionEvent, PolicyDecisionEventContext};
use super::super::policy::PolicyMatchMetadata;
use super::super::tool_definition::ToolDefinitionBinding;
use super::types::HandleResult;
use crate::runtime::AuthzReceipt;
#[derive(Clone)]
pub(super) struct ToolMatchMetadata {
pub(super) tool_classes: Vec<String>,
pub(super) matched_tool_classes: Vec<String>,
pub(super) match_basis: Option<String>,
pub(super) matched_rule: Option<String>,
pub(super) typed_decision: Option<super::super::policy::TypedPolicyDecision>,
pub(super) policy_version: Option<String>,
pub(super) policy_digest: Option<String>,
pub(super) obligations: Vec<super::super::policy::PolicyObligation>,
pub(super) obligation_outcomes: Vec<super::super::decision::ObligationOutcome>,
pub(super) approval_state: Option<String>,
pub(super) approval_artifact: Option<super::super::policy::ApprovalArtifact>,
pub(super) approval_freshness: Option<super::super::policy::ApprovalFreshness>,
pub(super) approval_failure_reason: Option<String>,
pub(super) scope_contract: Option<super::super::policy::RestrictScopeContract>,
pub(super) scope_evaluation_state: Option<String>,
pub(super) scope_failure_reason: Option<String>,
pub(super) restrict_scope_present: Option<bool>,
pub(super) restrict_scope_target: Option<String>,
pub(super) restrict_scope_match: Option<bool>,
pub(super) restrict_scope_reason: Option<String>,
pub(super) redaction_contract: Option<super::super::policy::RedactArgsContract>,
pub(super) redaction_applied_state: Option<String>,
pub(super) redaction_reason: Option<String>,
pub(super) redaction_failure_reason: Option<String>,
pub(super) redact_args_present: Option<bool>,
pub(super) redact_args_target: Option<String>,
pub(super) redact_args_mode: Option<String>,
pub(super) redact_args_result: Option<String>,
pub(super) redact_args_reason: Option<String>,
pub(super) fail_closed: Option<super::super::policy::FailClosedContext>,
pub(super) lane: Option<String>,
pub(super) principal: Option<String>,
pub(super) auth_context_summary: Option<String>,
pub(super) auth_scheme: Option<String>,
pub(super) auth_issuer: Option<String>,
pub(super) delegated_from: Option<String>,
pub(super) delegation_depth: Option<u32>,
pub(super) tool_definition_binding: Option<ToolDefinitionBinding>,
}
impl ToolMatchMetadata {
pub(super) fn from_policy_metadata(metadata: &PolicyMatchMetadata) -> Self {
Self {
tool_classes: metadata.tool_classes.clone(),
matched_tool_classes: metadata.matched_tool_classes.clone(),
match_basis: metadata.match_basis.as_str().map(ToString::to_string),
matched_rule: metadata.matched_rule.clone(),
typed_decision: metadata.typed_decision,
policy_version: metadata.policy_version.clone(),
policy_digest: metadata.policy_digest.clone(),
obligations: metadata.obligations.clone(),
obligation_outcomes: Vec::new(),
approval_state: metadata.approval_state.clone(),
approval_artifact: metadata.approval_artifact.clone(),
approval_freshness: metadata.approval_freshness,
approval_failure_reason: metadata.approval_failure_reason.clone(),
scope_contract: match (
metadata.scope_type.clone(),
metadata.scope_value.clone(),
metadata.scope_match_mode.clone(),
) {
(Some(scope_type), Some(scope_value), Some(scope_match_mode)) => {
Some(super::super::policy::RestrictScopeContract {
scope_type,
scope_value,
scope_match_mode,
})
}
_ => None,
},
scope_evaluation_state: metadata.scope_evaluation_state.clone(),
scope_failure_reason: metadata.scope_failure_reason.clone(),
restrict_scope_present: metadata.restrict_scope_present,
restrict_scope_target: metadata.restrict_scope_target.clone(),
restrict_scope_match: metadata.restrict_scope_match,
restrict_scope_reason: metadata.restrict_scope_reason.clone(),
redaction_contract: match (
metadata.redaction_target.clone(),
metadata.redaction_mode.clone(),
metadata.redaction_scope.clone(),
) {
(Some(redaction_target), Some(redaction_mode), Some(redaction_scope)) => {
Some(super::super::policy::RedactArgsContract {
redaction_target,
redaction_mode,
redaction_scope,
})
}
_ => None,
},
redaction_applied_state: metadata.redaction_applied_state.clone(),
redaction_reason: metadata.redaction_reason.clone(),
redaction_failure_reason: metadata.redaction_failure_reason.clone(),
redact_args_present: metadata.redact_args_present,
redact_args_target: metadata.redact_args_target.clone(),
redact_args_mode: metadata.redact_args_mode.clone(),
redact_args_result: metadata.redact_args_result.clone(),
redact_args_reason: metadata.redact_args_reason.clone(),
fail_closed: metadata.fail_closed.clone(),
lane: metadata.lane.clone(),
principal: metadata.principal.clone(),
auth_context_summary: metadata.auth_context_summary.clone(),
auth_scheme: metadata.auth_scheme.clone(),
auth_issuer: metadata.auth_issuer.clone(),
delegated_from: metadata.delegated_from.clone(),
delegation_depth: metadata.delegation_depth,
tool_definition_binding: None,
}
}
pub(super) fn policy_context(&self) -> PolicyDecisionEventContext {
PolicyDecisionEventContext {
typed_decision: self.typed_decision,
policy_version: self.policy_version.clone(),
policy_digest: self.policy_digest.clone(),
obligations: self.obligations.clone(),
obligation_outcomes: self.obligation_outcomes.clone(),
approval_state: self.approval_state.clone(),
approval_artifact: self.approval_artifact.clone(),
approval_freshness: self.approval_freshness,
approval_failure_reason: self.approval_failure_reason.clone(),
scope_contract: self.scope_contract.clone(),
scope_evaluation_state: self.scope_evaluation_state.clone(),
scope_failure_reason: self.scope_failure_reason.clone(),
restrict_scope_present: self.restrict_scope_present,
restrict_scope_target: self.restrict_scope_target.clone(),
restrict_scope_match: self.restrict_scope_match,
restrict_scope_reason: self.restrict_scope_reason.clone(),
redaction_contract: self.redaction_contract.clone(),
redaction_applied_state: self.redaction_applied_state.clone(),
redaction_reason: self.redaction_reason.clone(),
redaction_failure_reason: self.redaction_failure_reason.clone(),
redact_args_present: self.redact_args_present,
redact_args_target: self.redact_args_target.clone(),
redact_args_mode: self.redact_args_mode.clone(),
redact_args_result: self.redact_args_result.clone(),
redact_args_reason: self.redact_args_reason.clone(),
fail_closed: self.fail_closed.clone(),
lane: self.lane.clone(),
principal: self.principal.clone(),
auth_context_summary: self.auth_context_summary.clone(),
auth_scheme: self.auth_scheme.clone(),
auth_issuer: self.auth_issuer.clone(),
delegated_from: self.delegated_from.clone(),
delegation_depth: self.delegation_depth,
tool_definition_binding: self.tool_definition_binding.clone(),
}
}
}
pub(super) fn error_not_tool_call(event_source: &str, tool_call_id: String) -> HandleResult {
HandleResult::Error {
reason_code: reason_codes::S_INTERNAL_ERROR.to_string(),
reason: "Not a tool call".to_string(),
decision_event: DecisionEvent::new(
event_source.to_string(),
tool_call_id,
"unknown".to_string(),
)
.error(
reason_codes::S_INTERNAL_ERROR,
Some("Not a tool call".to_string()),
),
}
}
pub(super) fn deny(
event_source: &str,
tool_call_id: String,
tool_name: String,
reason_code: &str,
reason: String,
tool_match: ToolMatchMetadata,
) -> HandleResult {
let decision_event = DecisionEvent::new(event_source.to_string(), tool_call_id, tool_name)
.deny(reason_code, Some(reason.clone()))
.with_tool_match(
tool_match.tool_classes.clone(),
tool_match.matched_tool_classes.clone(),
tool_match.match_basis.clone(),
tool_match.matched_rule.clone(),
)
.with_policy_context(tool_match.policy_context());
HandleResult::Deny {
reason_code: reason_code.to_string(),
reason,
decision_event,
}
}
pub(super) fn allow(
event_source: &str,
tool_call_id: String,
tool_name: String,
reason_code: &str,
receipt: Option<AuthzReceipt>,
effective_arguments: Option<serde_json::Value>,
tool_match: ToolMatchMetadata,
) -> HandleResult {
let decision_event = DecisionEvent::new(event_source.to_string(), tool_call_id, tool_name)
.allow(reason_code)
.with_tool_match(
tool_match.tool_classes.clone(),
tool_match.matched_tool_classes.clone(),
tool_match.match_basis.clone(),
tool_match.matched_rule.clone(),
)
.with_policy_context(tool_match.policy_context());
HandleResult::Allow {
receipt,
effective_arguments,
decision_event,
}
}