pub mod data_surface;
pub mod dependency_surface;
pub mod execution_surface;
pub mod provenance_surface;
pub mod taint_builder;
pub mod tool_surface;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
pub use data_surface::DataSurface;
pub use dependency_surface::DependencySurface;
pub use execution_surface::ExecutionSurface;
pub use provenance_surface::ProvenanceSurface;
pub use tool_surface::ToolSurface;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScanTarget {
pub name: String,
pub framework: Framework,
pub root_path: PathBuf,
pub tools: Vec<ToolSurface>,
pub execution: ExecutionSurface,
pub data: DataSurface,
pub dependencies: DependencySurface,
pub provenance: ProvenanceSurface,
pub source_files: Vec<SourceFile>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Framework {
Mcp,
OpenClaw,
LangChain,
CrewAi,
GptActions,
CursorRules,
Unknown,
}
impl std::fmt::Display for Framework {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Mcp => write!(f, "MCP"),
Self::OpenClaw => write!(f, "OpenClaw"),
Self::LangChain => write!(f, "LangChain"),
Self::CrewAi => write!(f, "CrewAI"),
Self::GptActions => write!(f, "GPT Actions"),
Self::CursorRules => write!(f, "Cursor Rules"),
Self::Unknown => write!(f, "Unknown"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SourceFile {
pub path: PathBuf,
pub language: Language,
pub content: String,
pub size_bytes: u64,
pub content_hash: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Language {
Python,
TypeScript,
JavaScript,
Shell,
Json,
Toml,
Yaml,
Markdown,
Unknown,
}
impl Language {
pub fn from_extension(ext: &str) -> Self {
match ext.to_lowercase().as_str() {
"py" => Self::Python,
"ts" | "tsx" => Self::TypeScript,
"js" | "jsx" | "mjs" | "cjs" => Self::JavaScript,
"sh" | "bash" | "zsh" => Self::Shell,
"json" => Self::Json,
"toml" => Self::Toml,
"yml" | "yaml" => Self::Yaml,
"md" | "markdown" => Self::Markdown,
_ => Self::Unknown,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SourceLocation {
pub file: PathBuf,
pub line: usize,
pub column: usize,
pub end_line: Option<usize>,
pub end_column: Option<usize>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ArgumentSource {
Literal(String),
Parameter { name: String },
EnvVar { name: String },
Interpolated,
Unknown,
Sanitized { sanitizer: String },
}
impl ArgumentSource {
pub fn is_tainted(&self) -> bool {
!matches!(self, Self::Literal(_) | Self::Sanitized { .. })
}
}