use anyhow::Result;
use minijinja::Environment;
use lazy_static::lazy_static;
use regex::Regex;
const MAX_TEMPLATE_SIZE: usize = 1_000_000;
pub fn validate_template_syntax(content: &str) -> Result<()> {
let mut env = Environment::new();
env.add_template("_validation", content)
.map_err(|e| anyhow::anyhow!("Template syntax error: {e}"))?;
Ok(())
}
pub fn validate_prompt_file(content: &str) -> Result<()> {
if content.len() > MAX_TEMPLATE_SIZE {
anyhow::bail!(
"Template too large ({} bytes). Maximum size is {} bytes (1MB).",
content.len(),
MAX_TEMPLATE_SIZE
);
}
let template = super::template::parse_template("_validation", content)?;
validate_template_syntax(&template.content)?;
validate_no_dangerous_operations(&template.content)?;
Ok(())
}
lazy_static! {
static ref INCLUDE_PATTERN: Regex =
Regex::new(r"\{%[-+]?\s*include\s+")
.expect("Failed to compile include pattern");
static ref EXTENDS_PATTERN: Regex =
Regex::new(r"\{%[-+]?\s*extends\s+")
.expect("Failed to compile extends pattern");
static ref IMPORT_PATTERN: Regex =
Regex::new(r"\{%[-+]?\s*import\s+")
.expect("Failed to compile import pattern");
static ref FROM_IMPORT_PATTERN: Regex =
Regex::new(r"\{%[-+]?\s*from\s+")
.expect("Failed to compile from import pattern");
}
fn validate_no_dangerous_operations(content: &str) -> Result<()> {
if INCLUDE_PATTERN.is_match(content) {
anyhow::bail!(
"Template contains forbidden 'include' directive. \
File inclusion is not allowed for security reasons."
);
}
if EXTENDS_PATTERN.is_match(content) {
anyhow::bail!(
"Template contains forbidden 'extends' directive. \
Template inheritance is not supported."
);
}
if IMPORT_PATTERN.is_match(content) || FROM_IMPORT_PATTERN.is_match(content) {
anyhow::bail!(
"Template contains forbidden 'import' directive. \
Module imports are not allowed."
);
}
Ok(())
}