use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ToolRiskLevel {
Routine,
Bounded,
High,
Critical,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ToolRiskAction {
Allow,
RequireConfirmation,
ReviewByLlm,
RuleDeny,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ToolRiskType {
ReadOnly,
WorkspaceMutation,
CommandExecution,
VersionControl,
NetworkRead,
Delegation,
DynamicExecution,
ExternalIntegration,
Composite,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum OperationTarget {
Workspace,
OutsideWorkspace,
PublicNetwork,
ExternalService,
HostEnvironment,
PrivilegedSystem,
Multiple,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ImpactScope {
Observation,
SingleResource,
Workspace,
ExternalService,
Host,
SystemWide,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Reversibility {
NotApplicable,
Easy,
Conditional,
Difficult,
Irreversible,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EnvironmentSensitivity {
None,
Workspace,
Network,
Host,
Credentials,
Privileged,
Mixed,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ToolRiskReason {
KnownReadOnly,
BoundedWorkspaceMutation,
BoundedVersionControlMutation,
UnboundedCommandExecution,
DynamicOrDelegatedExecution,
ExternalOrUnknownIntegration,
EnvironmentSensitiveOperation,
ForceOrDestructiveOperation,
MalformedOrUnknownOperation,
WorkspaceBoundaryEscape,
SymlinkBoundaryEscape,
CatastrophicOperation,
CompositeInvocation,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct ToolRiskDimensions {
pub tool_type: ToolRiskType,
pub operation_target: OperationTarget,
pub impact_scope: ImpactScope,
pub reversibility: Reversibility,
pub environment_sensitivity: EnvironmentSensitivity,
}
impl ToolRiskDimensions {
pub const fn new(
tool_type: ToolRiskType,
operation_target: OperationTarget,
impact_scope: ImpactScope,
reversibility: Reversibility,
environment_sensitivity: EnvironmentSensitivity,
) -> Self {
Self {
tool_type,
operation_target,
impact_scope,
reversibility,
environment_sensitivity,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ToolRiskAssessment {
pub level: ToolRiskLevel,
pub dimensions: ToolRiskDimensions,
pub reasons: Vec<ToolRiskReason>,
}
impl ToolRiskAssessment {
pub fn new(
level: ToolRiskLevel,
dimensions: ToolRiskDimensions,
reasons: impl IntoIterator<Item = ToolRiskReason>,
) -> Self {
let mut deduplicated = Vec::new();
for reason in reasons {
if !deduplicated.contains(&reason) {
deduplicated.push(reason);
}
}
Self {
level,
dimensions,
reasons: deduplicated,
}
}
pub const fn baseline_action(&self) -> ToolRiskAction {
match self.level {
ToolRiskLevel::Routine => ToolRiskAction::Allow,
ToolRiskLevel::Bounded => ToolRiskAction::RequireConfirmation,
ToolRiskLevel::High => ToolRiskAction::ReviewByLlm,
ToolRiskLevel::Critical => ToolRiskAction::RuleDeny,
}
}
}