1use super::weights::{
2 EVIDENCE_WEIGHT_BEHAVIOR, EVIDENCE_WEIGHT_CONTEXT, EVIDENCE_WEIGHT_INTENT, EVIDENCE_WEIGHT_IOC,
3 SEVERITY_WEIGHT_CRITICAL, SEVERITY_WEIGHT_HIGH, SEVERITY_WEIGHT_LOW, SEVERITY_WEIGHT_MEDIUM,
4};
5use serde::{Deserialize, Serialize};
6use std::fmt;
7use strum_macros::Display;
8
9#[derive(
11 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Display,
12)]
13#[serde(rename_all = "snake_case")]
14#[strum(serialize_all = "snake_case")]
15pub enum ThreatCategory {
16 RemoteExec,
18 SupplyChain,
20 PersistentPromptTampering,
22 CredentialExposure,
24 ToolAbuse,
26 AutonomyEscalation,
28 PrivilegeEscalation,
30 DataExfiltration,
32 PersuasiveLanguage,
34 SocialManipulation,
36 ScopeCreep,
38 Obfuscation,
40 UnsafeBinary,
42 Generic,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display)]
48#[serde(rename_all = "snake_case")]
49#[strum(serialize_all = "snake_case")]
50pub enum OperationalContext {
51 Install,
52 Network,
53 Secrets,
54 CodeModification,
55 ExternalComms,
56}
57
58#[derive(
60 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Display,
61)]
62#[serde(rename_all = "lowercase")]
63#[strum(serialize_all = "lowercase")]
64pub enum Severity {
65 Low,
67 Medium,
69 High,
71 Critical,
73}
74
75impl Severity {
76 pub fn weight(&self) -> u32 {
78 match self {
79 Severity::Low => SEVERITY_WEIGHT_LOW,
80 Severity::Medium => SEVERITY_WEIGHT_MEDIUM,
81 Severity::High => SEVERITY_WEIGHT_HIGH,
82 Severity::Critical => SEVERITY_WEIGHT_CRITICAL,
83 }
84 }
85
86 pub fn default_action(&self) -> RecommendedAction {
88 match self {
89 Severity::Critical | Severity::High => RecommendedAction::Block,
90 Severity::Medium => RecommendedAction::RequireApproval,
91 Severity::Low => RecommendedAction::Log,
92 }
93 }
94
95 pub fn action_str(&self) -> &'static str {
97 match self {
98 Severity::Critical | Severity::High => "BLOCK",
99 Severity::Medium => "REQUIRE_APPROVAL",
100 Severity::Low => "LOG",
101 }
102 }
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107#[serde(rename_all = "snake_case")]
108pub enum MatchTarget {
109 Document,
111 Section { name: String },
113 CodeBlock { language: Option<String> },
115 ReferencedFile { path: String },
117}
118
119impl fmt::Display for MatchTarget {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 match self {
122 MatchTarget::Document => write!(f, "document"),
123 MatchTarget::Section { name } => write!(f, "section:{}", name),
124 MatchTarget::CodeBlock { language } => {
125 write!(f, "code_block:{}", language.as_deref().unwrap_or("unknown"))
126 }
127 MatchTarget::ReferencedFile { path } => write!(f, "file:{}", path),
128 }
129 }
130}
131
132#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Display)]
134#[serde(rename_all = "snake_case")]
135#[strum(serialize_all = "snake_case")]
136pub enum EvidenceKind {
137 Ioc,
139 Behavior,
141 Intent,
143 Context,
145}
146
147impl EvidenceKind {
148 pub fn weight(&self) -> u32 {
150 match self {
151 Self::Ioc => EVIDENCE_WEIGHT_IOC,
152 Self::Behavior => EVIDENCE_WEIGHT_BEHAVIOR,
153 Self::Intent => EVIDENCE_WEIGHT_INTENT,
154 Self::Context => EVIDENCE_WEIGHT_CONTEXT,
155 }
156 }
157
158 pub fn description(&self) -> &'static str {
160 match self {
161 Self::Ioc => "Known malicious indicator",
162 Self::Behavior => "Concrete risky behavior",
163 Self::Intent => "Manipulative or coercive intent",
164 Self::Context => "Contextual risk signal",
165 }
166 }
167}
168
169#[derive(
171 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Display,
172)]
173#[serde(rename_all = "snake_case")]
174#[strum(serialize_all = "snake_case")]
175pub enum ArtifactKind {
176 SkillDocument,
178 AgentInstruction,
180 PromptPackDocument,
182 McpServerManifest,
184 CodeSnippet,
186 ReferencedArtifact,
188 PackageManifest,
190 Lockfile,
192 GenericArtifact,
194}
195
196impl ArtifactKind {
197 #[must_use]
210 pub fn specificity(self) -> u8 {
211 match self {
212 Self::GenericArtifact => 0,
213 Self::CodeSnippet => 1,
214 Self::ReferencedArtifact | Self::PromptPackDocument => 2,
215 Self::SkillDocument | Self::AgentInstruction => 3,
221 Self::PackageManifest | Self::McpServerManifest | Self::Lockfile => 4,
222 }
223 }
224}
225
226#[derive(
228 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Display,
229)]
230#[serde(rename_all = "snake_case")]
231#[strum(serialize_all = "snake_case")]
232pub enum ArtifactScope {
233 AgentEntrypoint,
234 PackageRootArtifact,
235 SupportingArtifact,
236}
237
238#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Display)]
240#[serde(rename_all = "snake_case")]
241#[strum(serialize_all = "snake_case")]
242pub enum SignalClass {
243 Hygiene,
244 SuspiciousPackageBehavior,
245 MaliciousBehavior,
246 ReviewSignal,
247}
248
249#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Display)]
251#[serde(rename_all = "snake_case")]
252#[strum(serialize_all = "snake_case")]
253pub enum Verdict {
254 Benign,
255 Suspicious,
256 Malicious,
257}
258
259#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Display)]
261#[serde(rename_all = "snake_case")]
262#[strum(serialize_all = "snake_case")]
263pub enum RecommendedAction {
264 Log,
266 RequireApproval,
268 Block,
270}
271
272#[derive(
273 Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Display,
274)]
275#[serde(rename_all = "snake_case")]
276#[strum(serialize_all = "snake_case")]
277pub enum BlastRadiusLevel {
278 #[default]
279 Low,
280 Medium,
281 High,
282}
283
284#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Display)]
285#[serde(rename_all = "snake_case")]
286#[strum(serialize_all = "snake_case")]
287pub enum PackageHealth {
288 Healthy,
289 NeedsReview,
290 Elevated,
291}