diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index 3ac779b..a44ad19 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -79,7 +79,7 @@ jobs: archive: zip steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: ref: ${{ needs.resolve-version.outputs.tag }} @@ -125,7 +125,7 @@ jobs: echo "ARCHIVE=$ARCHIVE" >> "$GITHUB_ENV" - name: Upload binary artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: cli-${{ matrix.target }} path: ${{ env.ARCHIVE }} @@ -135,10 +135,10 @@ jobs: needs: [resolve-version, build-cli] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Download all artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: path: release-artifacts diff --git a/.github/workflows/release-framework.yml b/.github/workflows/release-framework.yml index 8e81897..7e8a6ce 100644 --- a/.github/workflows/release-framework.yml +++ b/.github/workflows/release-framework.yml @@ -13,7 +13,7 @@ jobs: name: Package Framework runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Extract version from tag id: version diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 513f7be..b0acdfb 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -495,7 +495,7 @@ dependencies = [ [[package]] name = "devtrail-cli" -version = "1.3.0" +version = "1.4.0" dependencies = [ "anyhow", "assert_cmd", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 299b7a9..9c69439 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "devtrail-cli" -version = "1.3.0" +version = "1.4.0" edition = "2021" description = "CLI tool for DevTrail - Documentation Governance for AI-Assisted Development" license = "MIT" diff --git a/cli/src/commands/mod.rs b/cli/src/commands/mod.rs index b7f44fa..a91ef9f 100644 --- a/cli/src/commands/mod.rs +++ b/cli/src/commands/mod.rs @@ -8,3 +8,4 @@ pub mod status; pub mod update; pub mod update_cli; pub mod update_framework; +pub mod validate; diff --git a/cli/src/commands/validate.rs b/cli/src/commands/validate.rs new file mode 100644 index 0000000..d840e01 --- /dev/null +++ b/cli/src/commands/validate.rs @@ -0,0 +1,171 @@ +use anyhow::Result; +use colored::Colorize; +use std::collections::BTreeMap; +use std::path::PathBuf; + +use crate::utils; +use crate::validation::{self, Severity, ValidationIssue}; + +pub fn run(path: &str, fix: bool) -> Result<()> { + let resolved = match utils::resolve_project_root(path) { + Some(r) => r, + None => { + let target = PathBuf::from(path) + .canonicalize() + .unwrap_or_else(|_| PathBuf::from(path)); + utils::info(&format!( + "DevTrail is not installed in {}", + target.display() + )); + utils::info("Run 'devtrail init' to initialize DevTrail in this directory."); + return Ok(()); + } + }; + + if resolved.is_fallback { + utils::info(&format!( + "Using DevTrail installation at repo root: {}", + resolved.path.display() + )); + } + + let target = resolved.path; + let devtrail_dir = target.join(".devtrail"); + + // Header + println!(); + println!(" {}", "DevTrail Validate".bold().cyan()); + println!(" {}", target.display().to_string().dimmed()); + println!(); + + // Run validation + let (result, doc_count) = validation::validate_all(&devtrail_dir); + + if doc_count == 0 { + utils::info("No documents found to validate."); + println!( + " {} Create documents with {} or {}", + "→".blue().bold(), + "devtrail-new".cyan(), + "/devtrail-new".cyan() + ); + println!(); + return Ok(()); + } + + // Apply fixes if requested + if fix { + apply_fixes(&devtrail_dir); + // Re-validate after fixes + let (result, doc_count) = validation::validate_all(&devtrail_dir); + print_results(&result, doc_count); + return exit_with_code(&result); + } + + print_results(&result, doc_count); + exit_with_code(&result) +} + +fn apply_fixes(devtrail_dir: &std::path::Path) { + let paths = crate::document::discover_documents(devtrail_dir); + let mut fixed_count = 0; + + for path in &paths { + if let Ok(doc) = crate::document::parse_document(path) { + if let Some(new_content) = validation::apply_fixes(&doc) { + if std::fs::write(path, new_content).is_ok() { + println!( + " {} Fixed: {}", + "✓".green().bold(), + path.file_name() + .and_then(|n| n.to_str()) + .unwrap_or("?") + ); + fixed_count += 1; + } + } + } + } + + if fixed_count > 0 { + println!(); + println!( + " {} {} file(s) fixed automatically", + "→".blue().bold(), + fixed_count + ); + println!(); + } +} + +fn print_results(result: &validation::ValidationResult, doc_count: usize) { + let all_issues: Vec<&ValidationIssue> = result + .errors + .iter() + .chain(result.warnings.iter()) + .collect(); + + if all_issues.is_empty() { + println!( + " {} All {} document(s) passed validation", + "✓".green().bold(), + doc_count + ); + println!(); + return; + } + + // Group by file + let mut by_file: BTreeMap<&PathBuf, Vec<&ValidationIssue>> = BTreeMap::new(); + for issue in &all_issues { + by_file.entry(&issue.file).or_default().push(issue); + } + + for (file, issues) in &by_file { + let filename = file + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or("?"); + + println!(" {}", filename.bold()); + + for issue in issues { + let severity_label = match issue.severity { + Severity::Error => "error".red().bold(), + Severity::Warning => "warn".yellow().bold(), + }; + println!( + " {} [{}] {}", + severity_label, issue.rule, issue.message + ); + if let Some(hint) = &issue.fix_hint { + println!(" {} {}", "hint:".dimmed(), hint.dimmed()); + } + } + println!(); + } + + // Summary + let error_count = result.errors.len(); + let warning_count = result.warnings.len(); + + let summary = format!( + " {} error(s), {} warning(s) in {} document(s)", + error_count, warning_count, doc_count + ); + + if error_count > 0 { + println!("{}", summary.red().bold()); + } else { + println!("{}", summary.yellow()); + } + println!(); +} + +fn exit_with_code(result: &validation::ValidationResult) -> Result<()> { + if result.errors.is_empty() { + Ok(()) + } else { + std::process::exit(1); + } +} diff --git a/cli/src/complexity.rs b/cli/src/complexity.rs new file mode 100644 index 0000000..1217689 --- /dev/null +++ b/cli/src/complexity.rs @@ -0,0 +1,134 @@ +use anyhow::{Context, Result}; +use std::path::PathBuf; +use std::process::Command; + +/// Report of cyclomatic complexity analysis +#[derive(Debug)] +#[allow(dead_code)] +pub struct ComplexityReport { + pub functions: Vec, + pub above_threshold: Vec, + pub threshold: u32, +} + +/// Complexity data for a single function +#[derive(Debug, Clone)] +#[allow(dead_code)] +pub struct FunctionComplexity { + pub nloc: u32, + pub ccn: u32, + pub token_count: u32, + pub param_count: u32, + pub length: u32, + pub filename: String, + pub function_name: String, +} + +/// Check if lizard is available in PATH +#[allow(dead_code)] +pub fn is_lizard_available() -> bool { + Command::new("lizard") + .arg("--version") + .output() + .map(|o| o.status.success()) + .unwrap_or(false) +} + +/// Analyze cyclomatic complexity using lizard +#[allow(dead_code)] +pub fn analyze_complexity(paths: &[PathBuf], threshold: u32) -> Result { + if !is_lizard_available() { + anyhow::bail!( + "lizard is not installed. Install with: pip install lizard\n\ + Without lizard, use qualitative criteria for complexity assessment." + ); + } + + let path_strs: Vec = paths.iter().map(|p| p.display().to_string()).collect(); + + let output = Command::new("lizard") + .arg("--csv") + .args(&path_strs) + .output() + .context("Failed to execute lizard")?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + anyhow::bail!("lizard failed: {}", stderr); + } + + let stdout = String::from_utf8_lossy(&output.stdout); + let functions = parse_lizard_csv(&stdout)?; + + let above_threshold: Vec = functions + .iter() + .filter(|f| f.ccn > threshold) + .cloned() + .collect(); + + Ok(ComplexityReport { + functions, + above_threshold, + threshold, + }) +} + +/// Parse lizard CSV output +#[allow(dead_code)] +fn parse_lizard_csv(csv: &str) -> Result> { + let mut functions = Vec::new(); + + for line in csv.lines() { + // Skip header and empty lines + if line.starts_with("NLOC") || line.trim().is_empty() || line.starts_with('-') { + continue; + } + + let fields: Vec<&str> = line.split(',').collect(); + if fields.len() < 7 { + continue; + } + + let nloc = fields[0].trim().parse::().unwrap_or(0); + let ccn = fields[1].trim().parse::().unwrap_or(0); + let token_count = fields[2].trim().parse::().unwrap_or(0); + let param_count = fields[3].trim().parse::().unwrap_or(0); + let length = fields[4].trim().parse::().unwrap_or(0); + let filename = fields[5].trim().trim_matches('"').to_string(); + let function_name = fields[6].trim().trim_matches('"').to_string(); + + functions.push(FunctionComplexity { + nloc, + ccn, + token_count, + param_count, + length, + filename, + function_name, + }); + } + + Ok(functions) +} + +/// Generate JSON output for agent consumption +#[allow(dead_code)] +pub fn report_to_json(report: &ComplexityReport) -> String { + let mut entries = Vec::new(); + for f in &report.above_threshold { + entries.push(format!( + r#" {{"function":"{}","file":"{}","ccn":{},"nloc":{},"params":{}}}"#, + f.function_name, f.filename, f.ccn, f.nloc, f.param_count + )); + } + + format!( + r#"{{"threshold":{},"total_functions":{},"above_threshold":{},"functions":[ +{} +]}}"#, + report.threshold, + report.functions.len(), + report.above_threshold.len(), + entries.join(",\n") + ) +} diff --git a/cli/src/document.rs b/cli/src/document.rs new file mode 100644 index 0000000..8c3c089 --- /dev/null +++ b/cli/src/document.rs @@ -0,0 +1,275 @@ +use anyhow::{Context, Result}; +use serde::Deserialize; +use std::fmt; +use std::path::{Path, PathBuf}; + +/// All supported DevTrail document types +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DocType { + Ailog, + Aidec, + Adr, + Eth, + Req, + Tes, + Inc, + Tde, + Sec, + Mcard, + Sbom, + Dpia, +} + +impl DocType { + /// Prefix used in filenames (e.g., "AILOG", "SEC") + pub fn prefix(&self) -> &'static str { + match self { + DocType::Ailog => "AILOG", + DocType::Aidec => "AIDEC", + DocType::Adr => "ADR", + DocType::Eth => "ETH", + DocType::Req => "REQ", + DocType::Tes => "TES", + DocType::Inc => "INC", + DocType::Tde => "TDE", + DocType::Sec => "SEC", + DocType::Mcard => "MCARD", + DocType::Sbom => "SBOM", + DocType::Dpia => "DPIA", + } + } + + /// Parse a DocType from a filename prefix + pub fn from_prefix(prefix: &str) -> Option { + match prefix { + "AILOG" => Some(DocType::Ailog), + "AIDEC" => Some(DocType::Aidec), + "ADR" => Some(DocType::Adr), + "ETH" => Some(DocType::Eth), + "REQ" => Some(DocType::Req), + "TES" => Some(DocType::Tes), + "INC" => Some(DocType::Inc), + "TDE" => Some(DocType::Tde), + "SEC" => Some(DocType::Sec), + "MCARD" => Some(DocType::Mcard), + "SBOM" => Some(DocType::Sbom), + "DPIA" => Some(DocType::Dpia), + _ => None, + } + } + + /// All valid prefixes + pub const ALL_PREFIXES: &'static [&'static str] = &[ + "AILOG", "AIDEC", "ADR", "ETH", "REQ", "TES", "INC", "TDE", + "SEC", "MCARD", "SBOM", "DPIA", + ]; +} + +impl fmt::Display for DocType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.prefix()) + } +} + +/// Frontmatter fields extracted from a DevTrail document. +/// All fields are optional so the validator can report which are missing. +#[derive(Debug, Clone, Deserialize, Default)] +#[allow(dead_code)] +pub struct Frontmatter { + pub id: Option, + pub title: Option, + pub status: Option, + pub created: Option, + pub agent: Option, + pub confidence: Option, + pub review_required: Option, + pub risk_level: Option, + pub eu_ai_act_risk: Option, + pub nist_genai_risks: Option>, + pub iso_42001_clause: Option>, + pub tags: Option>, + pub related: Option>, + // INC-specific + pub severity: Option, + // ETH-specific + pub gdpr_legal_basis: Option, + // SEC-specific + pub threat_model_methodology: Option, + pub owasp_asvs_level: Option, + // MCARD-specific + pub model_name: Option, + pub model_type: Option, + pub model_version: Option, + pub provider: Option, + pub license: Option, + // SBOM-specific + pub sbom_format_reference: Option, + pub system_name: Option, + // DPIA-specific + pub gdpr_article_35: Option, + pub dpo_consulted: Option, + pub supervisory_authority_consulted: Option, +} + +/// A parsed DevTrail document +#[derive(Debug)] +pub struct DevTrailDocument { + pub path: PathBuf, + pub filename: String, + pub doc_type: DocType, + pub frontmatter: Frontmatter, + pub body: String, +} + +/// Parse a DevTrail document from a file path +pub fn parse_document(path: &Path) -> Result { + let content = std::fs::read_to_string(path) + .with_context(|| format!("Failed to read {}", path.display()))?; + + let filename = path + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or("") + .to_string(); + + // Determine doc type from filename prefix + let doc_type = detect_doc_type(&filename) + .with_context(|| format!("Cannot determine document type for {}", filename))?; + + // Extract frontmatter + let (frontmatter, body) = extract_frontmatter(&content) + .with_context(|| format!("Failed to parse frontmatter in {}", path.display()))?; + + Ok(DevTrailDocument { + path: path.to_path_buf(), + filename, + doc_type, + frontmatter, + body, + }) +} + +/// Detect document type from filename prefix +fn detect_doc_type(filename: &str) -> Option { + for prefix in DocType::ALL_PREFIXES { + if filename.starts_with(&format!("{}-", prefix)) { + return DocType::from_prefix(prefix); + } + } + None +} + +/// Extract YAML frontmatter (between --- delimiters) and body +fn extract_frontmatter(content: &str) -> Result<(Frontmatter, String)> { + let trimmed = content.trim_start(); + if !trimmed.starts_with("---") { + anyhow::bail!("No frontmatter found (missing opening ---)"); + } + + let after_first = &trimmed[3..]; + let end_pos = after_first + .find("\n---") + .ok_or_else(|| anyhow::anyhow!("No closing --- found for frontmatter"))?; + + let yaml_str = &after_first[..end_pos]; + let body_start = end_pos + 4; // skip "\n---" + let body = if body_start < after_first.len() { + after_first[body_start..].to_string() + } else { + String::new() + }; + + let frontmatter: Frontmatter = serde_yaml::from_str(yaml_str) + .with_context(|| "Failed to deserialize frontmatter YAML")?; + + Ok((frontmatter, body)) +} + +/// Discover all user-generated DevTrail documents under a .devtrail/ directory +pub fn discover_documents(devtrail_dir: &Path) -> Vec { + let mut results = Vec::new(); + walk_for_documents(devtrail_dir, &mut results); + results.sort(); + results +} + +fn walk_for_documents(dir: &Path, results: &mut Vec) { + let entries = match std::fs::read_dir(dir) { + Ok(e) => e, + Err(_) => return, + }; + + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + // Skip templates directory + if path.ends_with("templates") { + continue; + } + walk_for_documents(&path, results); + } else if path.extension().and_then(|e| e.to_str()) == Some("md") { + let filename = path + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or(""); + // Match pattern: TYPE-YYYY-MM-DD-NNN-*.md + if detect_doc_type(filename).is_some() && is_dated_document(filename) { + results.push(path); + } + } + } +} + +/// Check if filename follows the dated pattern TYPE-YYYY-MM-DD-NNN-*.md +fn is_dated_document(filename: &str) -> bool { + // Find the first '-' (after the type prefix) + let after_prefix = match filename.find('-') { + Some(pos) => &filename[pos + 1..], + None => return false, + }; + // Should start with a date pattern YYYY-MM-DD + if after_prefix.len() < 10 { + return false; + } + let date_part = &after_prefix[..10]; + // Basic date pattern check: NNNN-NN-NN + date_part.len() == 10 + && date_part.chars().nth(4) == Some('-') + && date_part.chars().nth(7) == Some('-') + && date_part[..4].chars().all(|c| c.is_ascii_digit()) + && date_part[5..7].chars().all(|c| c.is_ascii_digit()) + && date_part[8..10].chars().all(|c| c.is_ascii_digit()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_detect_doc_type() { + assert_eq!(detect_doc_type("AILOG-2025-01-01-001-test.md"), Some(DocType::Ailog)); + assert_eq!(detect_doc_type("SEC-2025-01-01-001-auth.md"), Some(DocType::Sec)); + assert_eq!(detect_doc_type("MCARD-2025-01-01-001-gpt.md"), Some(DocType::Mcard)); + assert_eq!(detect_doc_type("SBOM-2025-01-01-001-deps.md"), Some(DocType::Sbom)); + assert_eq!(detect_doc_type("DPIA-2025-01-01-001-gdpr.md"), Some(DocType::Dpia)); + assert_eq!(detect_doc_type("README.md"), None); + assert_eq!(detect_doc_type("TEMPLATE-SEC.md"), None); + } + + #[test] + fn test_is_dated_document() { + assert!(is_dated_document("AILOG-2025-01-27-001-implement-auth.md")); + assert!(is_dated_document("SEC-2026-03-24-001-api-review.md")); + assert!(!is_dated_document("TEMPLATE-SEC.md")); + assert!(!is_dated_document("README.md")); + } + + #[test] + fn test_extract_frontmatter() { + let content = "---\nid: AILOG-2025-01-01-001\ntitle: Test\nstatus: draft\n---\n\n# Body"; + let (fm, body) = extract_frontmatter(content).unwrap(); + assert_eq!(fm.id.as_deref(), Some("AILOG-2025-01-01-001")); + assert_eq!(fm.title.as_deref(), Some("Test")); + assert!(body.contains("# Body")); + } +} diff --git a/cli/src/main.rs b/cli/src/main.rs index e82a9a1..e025564 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -2,7 +2,9 @@ use clap::{Parser, Subcommand}; use colored::Colorize; mod commands; +mod complexity; mod config; +mod document; mod download; mod inject; mod manifest; @@ -11,6 +13,7 @@ mod self_update; #[cfg(feature = "tui")] mod tui; mod utils; +mod validation; /// DevTrail CLI - Documentation Governance for AI-Assisted Development #[derive(Parser)] @@ -53,6 +56,15 @@ enum Commands { #[arg(default_value = ".")] path: String, }, + /// Validate DevTrail documents for compliance and correctness + Validate { + /// Target directory (default: current directory) + #[arg(default_value = ".")] + path: String, + /// Automatically fix simple issues + #[arg(long)] + fix: bool, + }, /// Show version, author, and license information About, /// Explore DevTrail documentation interactively @@ -76,6 +88,7 @@ fn main() { Commands::UpdateFramework => commands::update_framework::run(), Commands::UpdateCli => commands::update_cli::run(), Commands::Remove { full } => commands::remove::run(full), + Commands::Validate { path, fix } => commands::validate::run(&path, fix), Commands::Status { path } => commands::status::run(&path), Commands::Repair { path } => commands::repair::run(&path), Commands::About => commands::about::run(), diff --git a/cli/src/utils.rs b/cli/src/utils.rs index a3890db..132555e 100644 --- a/cli/src/utils.rs +++ b/cli/src/utils.rs @@ -35,6 +35,7 @@ pub fn is_user_document(path: &Path) -> bool { // Check for patterns like AILOG-2025-01-27-001-description.md let prefixes = [ "AILOG-", "AIDEC-", "ETH-", "ADR-", "REQ-", "TES-", "INC-", "TDE-", + "SEC-", "MCARD-", "SBOM-", "DPIA-", ]; prefixes.iter().any(|p| name.starts_with(p)) diff --git a/cli/src/validation.rs b/cli/src/validation.rs new file mode 100644 index 0000000..7ffb1ba --- /dev/null +++ b/cli/src/validation.rs @@ -0,0 +1,540 @@ +use std::path::{Path, PathBuf}; + +use crate::document::{self, DevTrailDocument, DocType}; + +/// Severity of a validation issue +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Severity { + Error, + Warning, +} + +/// A single validation issue found in a document +#[derive(Debug, Clone)] +pub struct ValidationIssue { + pub file: PathBuf, + pub rule: String, + pub message: String, + pub severity: Severity, + pub fix_hint: Option, +} + +/// Result of validating one or more documents +#[derive(Debug, Default)] +pub struct ValidationResult { + pub errors: Vec, + pub warnings: Vec, +} + +impl ValidationResult { + pub fn merge(&mut self, other: ValidationResult) { + self.errors.extend(other.errors); + self.warnings.extend(other.warnings); + } + + fn add(&mut self, issue: ValidationIssue) { + match issue.severity { + Severity::Error => self.errors.push(issue), + Severity::Warning => self.warnings.push(issue), + } + } +} + +/// Valid status values per DOCUMENTATION-POLICY.md +const VALID_STATUSES: &[&str] = &["draft", "review", "accepted", "superseded", "deprecated"]; + +/// Valid risk levels +const VALID_RISK_LEVELS: &[&str] = &["low", "medium", "high", "critical"]; + +/// Valid confidence levels +const VALID_CONFIDENCES: &[&str] = &["low", "medium", "high"]; + +/// Patterns that indicate sensitive information +const SENSITIVE_PATTERNS: &[&str] = &[ + "password:", "api_key:", "secret:", "token:", "private_key:", + "credentials:", "Bearer ", "AWS_SECRET", "PRIVATE KEY", +]; + +/// Validate all documents found under a .devtrail/ directory +pub fn validate_all(devtrail_dir: &Path) -> (ValidationResult, usize) { + let paths = document::discover_documents(devtrail_dir); + let doc_count = paths.len(); + let mut result = ValidationResult::default(); + + for path in &paths { + match document::parse_document(path) { + Ok(doc) => { + result.merge(validate_document(&doc, devtrail_dir)); + } + Err(e) => { + result.errors.push(ValidationIssue { + file: path.clone(), + rule: "PARSE-001".to_string(), + message: format!("Failed to parse document: {e}"), + severity: Severity::Error, + fix_hint: Some("Check that the file has valid YAML frontmatter between --- delimiters".to_string()), + }); + } + } + } + + (result, doc_count) +} + +/// Validate a single parsed document +fn validate_document(doc: &DevTrailDocument, devtrail_dir: &Path) -> ValidationResult { + let mut result = ValidationResult::default(); + + check_naming(&mut result, doc); + check_required_meta(&mut result, doc); + check_id_matches_filename(&mut result, doc); + check_valid_status(&mut result, doc); + check_cross_rules(&mut result, doc); + check_type_specific(&mut result, doc); + check_related_exist(&mut result, doc, devtrail_dir); + check_sensitive_info(&mut result, doc); + check_observability(&mut result, doc); + + result +} + +/// NAMING-001: Verify filename follows TYPE-YYYY-MM-DD-NNN-description.md +fn check_naming(result: &mut ValidationResult, doc: &DevTrailDocument) { + let name = &doc.filename; + let prefix = doc.doc_type.prefix(); + + // Check: PREFIX-YYYY-MM-DD-NNN-*.md + let after_prefix = match name.strip_prefix(&format!("{}-", prefix)) { + Some(rest) => rest, + None => { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "NAMING-001".to_string(), + message: format!("Filename should start with '{}-'", prefix), + severity: Severity::Error, + fix_hint: None, + }); + return; + } + }; + + // Check date part + if after_prefix.len() < 10 { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "NAMING-001".to_string(), + message: "Filename missing date component (expected YYYY-MM-DD after prefix)".to_string(), + severity: Severity::Error, + fix_hint: None, + }); + return; + } + + let date_part = &after_prefix[..10]; + let valid_date = date_part.chars().nth(4) == Some('-') + && date_part.chars().nth(7) == Some('-') + && date_part[..4].chars().all(|c| c.is_ascii_digit()) + && date_part[5..7].chars().all(|c| c.is_ascii_digit()) + && date_part[8..10].chars().all(|c| c.is_ascii_digit()); + + if !valid_date { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "NAMING-001".to_string(), + message: format!("Invalid date in filename: '{}'", date_part), + severity: Severity::Error, + fix_hint: None, + }); + return; + } + + // Check sequence number after date + let after_date = &after_prefix[10..]; + if !after_date.starts_with('-') { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "NAMING-001".to_string(), + message: "Missing sequence number after date (expected -NNN-)".to_string(), + severity: Severity::Error, + fix_hint: None, + }); + } +} + +/// META-001: Check presence of required fields +fn check_required_meta(result: &mut ValidationResult, doc: &DevTrailDocument) { + let fm = &doc.frontmatter; + let file = &doc.path; + + let required: &[(&str, bool)] = &[ + ("id", fm.id.is_some()), + ("title", fm.title.is_some()), + ("status", fm.status.is_some()), + ("created", fm.created.is_some()), + ("agent", fm.agent.is_some()), + ("confidence", fm.confidence.is_some()), + ("review_required", fm.review_required.is_some()), + ("risk_level", fm.risk_level.is_some()), + ]; + + for (field, present) in required { + if !present { + result.add(ValidationIssue { + file: file.clone(), + rule: "META-001".to_string(), + message: format!("Missing required field: {}", field), + severity: Severity::Error, + fix_hint: Some(format!("Add '{}' to the frontmatter", field)), + }); + } + } +} + +/// META-002: Check that frontmatter id matches filename prefix +fn check_id_matches_filename(result: &mut ValidationResult, doc: &DevTrailDocument) { + if let Some(id) = &doc.frontmatter.id { + let expected_prefix = doc.doc_type.prefix(); + if !id.starts_with(expected_prefix) { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "META-002".to_string(), + message: format!( + "Frontmatter id '{}' does not match filename prefix '{}'", + id, expected_prefix + ), + severity: Severity::Error, + fix_hint: Some(format!("Change id to start with '{}-'", expected_prefix)), + }); + } + } +} + +/// META-003: Check that status has a valid value +fn check_valid_status(result: &mut ValidationResult, doc: &DevTrailDocument) { + if let Some(status) = &doc.frontmatter.status { + if !VALID_STATUSES.contains(&status.as_str()) { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "META-003".to_string(), + message: format!( + "Invalid status '{}'. Valid values: {}", + status, + VALID_STATUSES.join(", ") + ), + severity: Severity::Error, + fix_hint: None, + }); + } + } +} + +/// CROSS-001, CROSS-002, CROSS-003: Cross-field validation rules +fn check_cross_rules(result: &mut ValidationResult, doc: &DevTrailDocument) { + let fm = &doc.frontmatter; + + // CROSS-001: high/critical risk_level requires review_required: true + if let Some(risk) = &fm.risk_level { + if (risk == "high" || risk == "critical") && fm.review_required != Some(true) { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "CROSS-001".to_string(), + message: format!( + "risk_level is '{}' but review_required is not true", + risk + ), + severity: Severity::Error, + fix_hint: Some("Set review_required: true".to_string()), + }); + } + } + + // Validate risk_level value + if let Some(risk) = &fm.risk_level { + if !VALID_RISK_LEVELS.contains(&risk.as_str()) { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "META-003".to_string(), + message: format!( + "Invalid risk_level '{}'. Valid values: {}", + risk, + VALID_RISK_LEVELS.join(", ") + ), + severity: Severity::Error, + fix_hint: None, + }); + } + } + + // Validate confidence value + if let Some(conf) = &fm.confidence { + if !VALID_CONFIDENCES.contains(&conf.as_str()) { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "META-003".to_string(), + message: format!( + "Invalid confidence '{}'. Valid values: {}", + conf, + VALID_CONFIDENCES.join(", ") + ), + severity: Severity::Error, + fix_hint: None, + }); + } + } + + // CROSS-002: eu_ai_act_risk: high requires review_required: true + if let Some(eu_risk) = &fm.eu_ai_act_risk { + if eu_risk == "high" && fm.review_required != Some(true) { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "CROSS-002".to_string(), + message: "eu_ai_act_risk is 'high' but review_required is not true".to_string(), + severity: Severity::Error, + fix_hint: Some("Set review_required: true".to_string()), + }); + } + } + + // CROSS-003: SEC, MCARD, DPIA always require review + let always_review_types = [DocType::Sec, DocType::Mcard, DocType::Dpia]; + if always_review_types.contains(&doc.doc_type) && fm.review_required != Some(true) { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "CROSS-003".to_string(), + message: format!( + "{} documents must have review_required: true", + doc.doc_type + ), + severity: Severity::Error, + fix_hint: Some("Set review_required: true".to_string()), + }); + } +} + +/// TYPE-001, TYPE-002: Type-specific field requirements +fn check_type_specific(result: &mut ValidationResult, doc: &DevTrailDocument) { + let fm = &doc.frontmatter; + + // TYPE-001: INC must have severity + if doc.doc_type == DocType::Inc && fm.severity.is_none() { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "TYPE-001".to_string(), + message: "INC documents must have a 'severity' field (SEV1/SEV2/SEV3/SEV4)".to_string(), + severity: Severity::Error, + fix_hint: Some("Add 'severity: SEV3' to the frontmatter".to_string()), + }); + } + + // TYPE-002: ETH should have gdpr_legal_basis if body contains "Data Privacy" + if doc.doc_type == DocType::Eth + && (doc.body.contains("Data Privacy") || doc.body.contains("Privacidad de Datos")) + && fm.gdpr_legal_basis.is_none() + { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "TYPE-002".to_string(), + message: "ETH document mentions Data Privacy but lacks 'gdpr_legal_basis' field".to_string(), + severity: Severity::Warning, + fix_hint: Some("Add 'gdpr_legal_basis: consent' (or appropriate basis) to the frontmatter".to_string()), + }); + } +} + +/// REF-001: Check that documents listed in related: exist +fn check_related_exist(result: &mut ValidationResult, doc: &DevTrailDocument, devtrail_dir: &Path) { + if let Some(related) = &doc.frontmatter.related { + for rel_id in related { + if rel_id.is_empty() { + continue; + } + // Search for a file matching this id + if !find_document_by_id(devtrail_dir, rel_id) { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "REF-001".to_string(), + message: format!("Related document '{}' not found in .devtrail/", rel_id), + severity: Severity::Warning, + fix_hint: None, + }); + } + } + } +} + +/// Search for a document whose filename starts with the given id +fn find_document_by_id(devtrail_dir: &Path, id: &str) -> bool { + let docs = document::discover_documents(devtrail_dir); + docs.iter().any(|p| { + p.file_name() + .and_then(|n| n.to_str()) + .map(|n| n.starts_with(id)) + .unwrap_or(false) + }) +} + +/// SEC-001: Check for sensitive information patterns +fn check_sensitive_info(result: &mut ValidationResult, doc: &DevTrailDocument) { + let full_content = doc.body.to_string(); + for pattern in SENSITIVE_PATTERNS { + if full_content.contains(pattern) { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "SEC-001".to_string(), + message: format!("Possible sensitive information detected: '{}'", pattern.trim()), + severity: Severity::Error, + fix_hint: Some("Remove or redact sensitive information before committing".to_string()), + }); + } + } +} + +/// OBS-001: If document has tag 'observabilidad' or 'observability', check for relevant sections +fn check_observability(result: &mut ValidationResult, doc: &DevTrailDocument) { + let has_obs_tag = doc.frontmatter.tags.as_ref().is_some_and(|tags| { + tags.iter().any(|t| t == "observabilidad" || t == "observability") + }); + + if has_obs_tag { + let has_obs_section = doc.body.contains("## Observability") + || doc.body.contains("## Observabilidad") + || doc.body.contains("instrumentation") + || doc.body.contains("instrumentación") + || doc.body.contains("OpenTelemetry") + || doc.body.contains("observability_scope"); + + if !has_obs_section { + result.add(ValidationIssue { + file: doc.path.clone(), + rule: "OBS-001".to_string(), + message: "Document tagged with 'observabilidad'/'observability' but lacks observability-related content".to_string(), + severity: Severity::Warning, + fix_hint: Some("Add a section describing the instrumentation scope or observability risks".to_string()), + }); + } + } +} + +/// Apply automatic fixes to a document +pub fn apply_fixes(doc: &DevTrailDocument) -> Option { + let content = match std::fs::read_to_string(&doc.path) { + Ok(c) => c, + Err(_) => return None, + }; + + let mut modified = false; + let mut new_content = content.clone(); + + // Fix: Add review_required: true for high-risk documents + let needs_review = doc.frontmatter.risk_level.as_deref() == Some("high") + || doc.frontmatter.risk_level.as_deref() == Some("critical") + || doc.frontmatter.eu_ai_act_risk.as_deref() == Some("high") + || matches!(doc.doc_type, DocType::Sec | DocType::Mcard | DocType::Dpia); + + if needs_review && doc.frontmatter.review_required != Some(true) { + if new_content.contains("review_required: false") { + new_content = new_content.replacen("review_required: false", "review_required: true", 1); + modified = true; + } else if doc.frontmatter.review_required.is_none() { + // Insert review_required after risk_level + if let Some(pos) = new_content.find("risk_level:") { + if let Some(line_end) = new_content[pos..].find('\n') { + let insert_pos = pos + line_end + 1; + new_content.insert_str(insert_pos, "review_required: true\n"); + modified = true; + } + } + } + } + + // Fix: Correct id if it doesn't match filename prefix + if let Some(id) = &doc.frontmatter.id { + let expected_prefix = doc.doc_type.prefix(); + if !id.starts_with(expected_prefix) { + // Extract date-seq from filename + let name_no_ext = doc.filename.strip_suffix(".md").unwrap_or(&doc.filename); + if let Some(dash_pos) = name_no_ext.find('-') { + let after_type = &name_no_ext[dash_pos + 1..]; + if after_type.len() >= 14 { + let new_id = format!("{}-{}", expected_prefix, &after_type[..14]); + let old_id_line = format!("id: {}", id); + let new_id_line = format!("id: {}", new_id); + if new_content.contains(&old_id_line) { + new_content = new_content.replacen(&old_id_line, &new_id_line, 1); + modified = true; + } + } + } + } + } + + if modified { + Some(new_content) + } else { + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::document::Frontmatter; + + fn make_doc(filename: &str, doc_type: DocType, fm: Frontmatter, body: &str) -> DevTrailDocument { + DevTrailDocument { + path: PathBuf::from(format!(".devtrail/test/{}", filename)), + filename: filename.to_string(), + doc_type, + frontmatter: fm, + body: body.to_string(), + } + } + + #[test] + fn test_cross_001_high_risk_needs_review() { + let fm = Frontmatter { + id: Some("AILOG-2025-01-01-001".into()), + risk_level: Some("high".into()), + review_required: Some(false), + ..Default::default() + }; + let doc = make_doc("AILOG-2025-01-01-001-test.md", DocType::Ailog, fm, ""); + let mut result = ValidationResult::default(); + check_cross_rules(&mut result, &doc); + assert!(result.errors.iter().any(|e| e.rule == "CROSS-001")); + } + + #[test] + fn test_cross_003_sec_needs_review() { + let fm = Frontmatter { + id: Some("SEC-2025-01-01-001".into()), + review_required: Some(false), + ..Default::default() + }; + let doc = make_doc("SEC-2025-01-01-001-test.md", DocType::Sec, fm, ""); + let mut result = ValidationResult::default(); + check_cross_rules(&mut result, &doc); + assert!(result.errors.iter().any(|e| e.rule == "CROSS-003")); + } + + #[test] + fn test_sec_001_sensitive_info() { + let fm = Frontmatter::default(); + let doc = make_doc("AILOG-2025-01-01-001-test.md", DocType::Ailog, fm, "The api_key: sk-12345 was used"); + let mut result = ValidationResult::default(); + check_sensitive_info(&mut result, &doc); + assert!(result.errors.iter().any(|e| e.rule == "SEC-001")); + } + + #[test] + fn test_type_001_inc_needs_severity() { + let fm = Frontmatter { + id: Some("INC-2025-01-01-001".into()), + ..Default::default() + }; + let doc = make_doc("INC-2025-01-01-001-test.md", DocType::Inc, fm, ""); + let mut result = ValidationResult::default(); + check_type_specific(&mut result, &doc); + assert!(result.errors.iter().any(|e| e.rule == "TYPE-001")); + } +} diff --git a/cli/tests/validate_test.rs b/cli/tests/validate_test.rs new file mode 100644 index 0000000..c591ece --- /dev/null +++ b/cli/tests/validate_test.rs @@ -0,0 +1,440 @@ +use assert_cmd::Command; +use predicates::prelude::*; +use tempfile::TempDir; + +/// Helper to create a minimal DevTrail installation +fn setup_devtrail(dir: &std::path::Path) { + let devtrail = dir.join(".devtrail"); + std::fs::create_dir_all(devtrail.join("07-ai-audit/agent-logs")).unwrap(); + std::fs::create_dir_all(devtrail.join("07-ai-audit/decisions")).unwrap(); + std::fs::create_dir_all(devtrail.join("07-ai-audit/ethical-reviews")).unwrap(); + std::fs::create_dir_all(devtrail.join("08-security")).unwrap(); + std::fs::create_dir_all(devtrail.join("09-ai-models")).unwrap(); + std::fs::create_dir_all(devtrail.join("05-operations/incidents")).unwrap(); + std::fs::create_dir_all(devtrail.join("templates")).unwrap(); + std::fs::write(devtrail.join("config.yml"), "language: en\n").unwrap(); + std::fs::write( + devtrail.join("dist-manifest.yml"), + "version: \"3.0.0\"\ndescription: test\n", + ) + .unwrap(); +} + +/// Helper to create a document file with frontmatter +fn create_doc(dir: &std::path::Path, subpath: &str, filename: &str, frontmatter: &str) { + let path = dir.join(".devtrail").join(subpath); + std::fs::create_dir_all(&path).unwrap(); + std::fs::write( + path.join(filename), + format!("---\n{}\n---\n\n# Document\n", frontmatter), + ) + .unwrap(); +} + +#[test] +fn test_validate_not_installed() { + let dir = TempDir::new().unwrap(); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .success() + .stdout(predicate::str::contains("not installed")); +} + +#[test] +fn test_validate_no_documents() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .success() + .stdout(predicate::str::contains("No documents found")); +} + +#[test] +fn test_validate_valid_document() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "07-ai-audit/agent-logs", + "AILOG-2025-01-27-001-implement-auth.md", + "id: AILOG-2025-01-27-001\ntitle: Implement auth\nstatus: draft\ncreated: 2025-01-27\nagent: claude-code-v1.0\nconfidence: high\nreview_required: false\nrisk_level: low\ntags: []\nrelated: []", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .success() + .stdout(predicate::str::contains("passed validation")); +} + +#[test] +fn test_validate_missing_frontmatter_fields() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "07-ai-audit/agent-logs", + "AILOG-2025-01-27-001-test.md", + "id: AILOG-2025-01-27-001\ntitle: Test", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .failure() + .stdout(predicate::str::contains("META-001")); +} + +#[test] +fn test_validate_invalid_status() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "07-ai-audit/agent-logs", + "AILOG-2025-01-27-001-test.md", + "id: AILOG-2025-01-27-001\ntitle: Test\nstatus: invalid_status\ncreated: 2025-01-27\nagent: test\nconfidence: high\nreview_required: false\nrisk_level: low", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .failure() + .stdout(predicate::str::contains("META-003")); +} + +#[test] +fn test_validate_cross_001_high_risk_no_review() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "07-ai-audit/agent-logs", + "AILOG-2025-01-27-001-test.md", + "id: AILOG-2025-01-27-001\ntitle: Test\nstatus: draft\ncreated: 2025-01-27\nagent: test\nconfidence: high\nreview_required: false\nrisk_level: high", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .failure() + .stdout(predicate::str::contains("CROSS-001")); +} + +#[test] +fn test_validate_sensitive_info_detected() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + let path = dir.path().join(".devtrail/07-ai-audit/agent-logs"); + std::fs::create_dir_all(&path).unwrap(); + std::fs::write( + path.join("AILOG-2025-01-27-001-secrets.md"), + "---\nid: AILOG-2025-01-27-001\ntitle: Test\nstatus: draft\ncreated: 2025-01-27\nagent: test\nconfidence: high\nreview_required: false\nrisk_level: low\n---\n\nThe api_key: sk-12345 was leaked\n", + ) + .unwrap(); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .failure() + .stdout(predicate::str::contains("SEC-001")); +} + +#[test] +fn test_validate_related_not_found() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "07-ai-audit/agent-logs", + "AILOG-2025-01-27-001-test.md", + "id: AILOG-2025-01-27-001\ntitle: Test\nstatus: draft\ncreated: 2025-01-27\nagent: test\nconfidence: high\nreview_required: false\nrisk_level: low\nrelated:\n - AIDEC-2025-01-27-001", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .success() // Warnings don't cause failure + .stdout(predicate::str::contains("REF-001")); +} + +#[test] +fn test_validate_sec_requires_review() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "08-security", + "SEC-2025-01-27-001-api-review.md", + "id: SEC-2025-01-27-001\ntitle: API Review\nstatus: draft\ncreated: 2025-01-27\nagent: test\nconfidence: medium\nreview_required: false\nrisk_level: high", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .failure() + .stdout(predicate::str::contains("CROSS-003")); +} + +#[test] +fn test_validate_fix_review_required() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + let doc_path = dir + .path() + .join(".devtrail/08-security/SEC-2025-01-27-001-fix-test.md"); + std::fs::write( + &doc_path, + "---\nid: SEC-2025-01-27-001\ntitle: Fix Test\nstatus: draft\ncreated: 2025-01-27\nagent: test\nconfidence: medium\nreview_required: false\nrisk_level: high\n---\n\n# Test\n", + ) + .unwrap(); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg("--fix") + .arg(dir.path().to_str().unwrap()) + .assert() + .stdout(predicate::str::contains("Fixed")); + + // Verify the file was modified + let content = std::fs::read_to_string(&doc_path).unwrap(); + assert!(content.contains("review_required: true")); +} + +#[test] +fn test_validate_obs_001_tag_without_content() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "07-ai-audit/agent-logs", + "AILOG-2025-01-27-001-obs.md", + "id: AILOG-2025-01-27-001\ntitle: Obs Test\nstatus: draft\ncreated: 2025-01-27\nagent: test\nconfidence: high\nreview_required: false\nrisk_level: low\ntags:\n - observability", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .success() // Warnings don't cause failure + .stdout(predicate::str::contains("OBS-001")); +} + +#[test] +fn test_validate_inc_needs_severity() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "05-operations/incidents", + "INC-2025-01-27-001-outage.md", + "id: INC-2025-01-27-001\ntitle: Outage\nstatus: draft\ncreated: 2025-01-27\nagent: test\nconfidence: high\nreview_required: true\nrisk_level: high", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .failure() + .stdout(predicate::str::contains("TYPE-001")); +} + +// ============================================================================= +// F2.QA.02 — Verification of new templates +// ============================================================================= + +/// F2.QA.02.01 — Create a test document for each new type (SEC, MCARD, SBOM, DPIA) +/// and validate with `devtrail validate` +#[test] +fn test_validate_sec_document_valid() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "08-security", + "SEC-2026-03-24-001-api-assessment.md", + "id: SEC-2026-03-24-001\ntitle: API Security Assessment\nstatus: draft\ncreated: 2026-03-24\nagent: claude-code-v1.0\nconfidence: medium\nreview_required: true\nrisk_level: high\nthreat_model_methodology: STRIDE\nowasp_asvs_level: 1\ntags:\n - security\nrelated: []", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .success() + .stdout(predicate::str::contains("passed validation")); +} + +#[test] +fn test_validate_mcard_document_valid() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "09-ai-models", + "MCARD-2026-03-24-001-gpt4-turbo.md", + "id: MCARD-2026-03-24-001\ntitle: GPT-4 Turbo Card\nstatus: draft\ncreated: 2026-03-24\nagent: claude-code-v1.0\nconfidence: medium\nreview_required: true\nrisk_level: medium\nmodel_name: gpt-4-turbo\nmodel_type: LLM\ntags:\n - ai-model\nrelated: []", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .success() + .stdout(predicate::str::contains("passed validation")); +} + +#[test] +fn test_validate_sbom_document_valid() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "07-ai-audit", + "SBOM-2026-03-24-001-platform-deps.md", + "id: SBOM-2026-03-24-001\ntitle: Platform AI SBOM\nstatus: accepted\ncreated: 2026-03-24\nagent: claude-code-v1.0\nconfidence: high\nreview_required: false\nrisk_level: low\ntags:\n - sbom\nrelated: []", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .success() + .stdout(predicate::str::contains("passed validation")); +} + +#[test] +fn test_validate_dpia_document_valid() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "07-ai-audit/ethical-reviews", + "DPIA-2026-03-24-001-user-profiling.md", + "id: DPIA-2026-03-24-001\ntitle: User Profiling DPIA\nstatus: draft\ncreated: 2026-03-24\nagent: claude-code-v1.0\nconfidence: low\nreview_required: true\nrisk_level: high\ntags:\n - privacy\n - gdpr\nrelated: []", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .success() + .stdout(predicate::str::contains("passed validation")); +} + +/// F2.QA.02.01 — Also verify that MCARD and DPIA fail without review_required: true +#[test] +fn test_validate_mcard_requires_review() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "09-ai-models", + "MCARD-2026-03-24-001-no-review.md", + "id: MCARD-2026-03-24-001\ntitle: Test\nstatus: draft\ncreated: 2026-03-24\nagent: test\nconfidence: medium\nreview_required: false\nrisk_level: medium\ntags: []\nrelated: []", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .failure() + .stdout(predicate::str::contains("CROSS-003")); +} + +#[test] +fn test_validate_dpia_requires_review() { + let dir = TempDir::new().unwrap(); + setup_devtrail(dir.path()); + + create_doc( + dir.path(), + "07-ai-audit/ethical-reviews", + "DPIA-2026-03-24-001-no-review.md", + "id: DPIA-2026-03-24-001\ntitle: Test\nstatus: draft\ncreated: 2026-03-24\nagent: test\nconfidence: low\nreview_required: false\nrisk_level: high\ntags: []\nrelated: []", + ); + + let mut cmd = Command::cargo_bin("devtrail").unwrap(); + cmd.arg("validate") + .arg(dir.path().to_str().unwrap()) + .assert() + .failure() + .stdout(predicate::str::contains("CROSS-003")); +} + +/// F2.QA.02.03 — Verify that new templates and directories exist in dist/ +#[test] +fn test_new_templates_exist_in_dist() { + let dist_templates = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .unwrap() + .join("dist/.devtrail/templates"); + + // EN templates + assert!(dist_templates.join("TEMPLATE-SEC.md").exists(), "TEMPLATE-SEC.md (EN) missing"); + assert!(dist_templates.join("TEMPLATE-MCARD.md").exists(), "TEMPLATE-MCARD.md (EN) missing"); + assert!(dist_templates.join("TEMPLATE-SBOM.md").exists(), "TEMPLATE-SBOM.md (EN) missing"); + assert!(dist_templates.join("TEMPLATE-DPIA.md").exists(), "TEMPLATE-DPIA.md (EN) missing"); + + // ES templates + let es = dist_templates.join("i18n/es"); + assert!(es.join("TEMPLATE-SEC.md").exists(), "TEMPLATE-SEC.md (ES) missing"); + assert!(es.join("TEMPLATE-MCARD.md").exists(), "TEMPLATE-MCARD.md (ES) missing"); + assert!(es.join("TEMPLATE-SBOM.md").exists(), "TEMPLATE-SBOM.md (ES) missing"); + assert!(es.join("TEMPLATE-DPIA.md").exists(), "TEMPLATE-DPIA.md (ES) missing"); + + // New directories + let devtrail = dist_templates.parent().unwrap(); + assert!(devtrail.join("08-security").exists(), "08-security/ directory missing"); + assert!(devtrail.join("09-ai-models").exists(), "09-ai-models/ directory missing"); +} + +/// F2.QA.02.02 — Verify devtrail-new.sh has all 12 types configured +#[test] +fn test_devtrail_new_script_has_all_types() { + let script_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .unwrap() + .join("dist/scripts/devtrail-new.sh"); + + let content = std::fs::read_to_string(&script_path).expect("Cannot read devtrail-new.sh"); + + // Verify all 12 types are in DOC_PATHS + for doc_type in &["ailog", "aidec", "adr", "eth", "req", "tes", "inc", "tde", "sec", "mcard", "sbom", "dpia"] { + assert!( + content.contains(&format!("[\"{}\"]", doc_type)), + "devtrail-new.sh missing DOC_PATHS entry for '{}'", doc_type + ); + } + + // Verify the menu has 12 options + assert!(content.contains("1-12 or name"), "devtrail-new.sh menu does not show 1-12 range"); +} diff --git a/dist/.agent/workflows/devtrail-mcard.md b/dist/.agent/workflows/devtrail-mcard.md new file mode 100644 index 0000000..534783b --- /dev/null +++ b/dist/.agent/workflows/devtrail-mcard.md @@ -0,0 +1,319 @@ +--- +description: Create a Model/System Card (MCARD) document through an interactive step-by-step flow. Guides the user through each section with specific questions and example responses. +--- + +# DevTrail MCARD Skill + +Create AI Model/System Card documentation through an interactive guided flow. + +## Instructions + +When invoked, follow these steps: + +### 1. Check for Parameters + +If the user specified a model name (e.g., `/devtrail-mcard GPT-4o`), use it as the model name and proceed to step 2 asking only for the model type. + +If no parameter is given, proceed to step 2 asking for both model name and type. + +### 2. Gather Model Identity + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ DevTrail MCARD — Model/System Card ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Step 1/7: Model Identity ║ +║ ║ +║ Please provide the following: ║ +║ ║ +║ 1. Model name: [e.g., "GPT-4o", "BERT-base-uncased"] ║ +║ 2. Model type: ║ +║ • LLM — Large Language Model ║ +║ • classifier — Classification model ║ +║ • regressor — Regression model ║ +║ • generator — Generative model (image, audio, etc.) ║ +║ • recommender — Recommendation system ║ +║ • other — Specify ║ +║ 3. Provider: [e.g., "OpenAI", "Google", "Hugging Face"] ║ +║ 4. Version: [e.g., "2024-05-13", "v1.0", "gpt-4o-2024-05-13"] ║ +║ 5. License: [e.g., "Proprietary", "Apache 2.0", "MIT"] ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 3. Gather Intended Use + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 2/7: Intended Use ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ 1. Primary intended uses: ║ +║ Example: "Code generation", "Customer support chatbot", ║ +║ "Sentiment analysis on product reviews" ║ +║ ║ +║ 2. Primary intended users: ║ +║ Example: "Internal engineering team", "End users via API", ║ +║ "Data science team" ║ +║ ║ +║ 3. Out-of-scope uses (what the model should NOT be used for): ║ +║ Example: "Medical diagnosis", "Legal advice", ║ +║ "Autonomous decision-making without human review" ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 4. Gather Training Data Details + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 3/7: Training Data ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ 1. Dataset name: [e.g., "Common Crawl", "Internal corpus v3"] ║ +║ 2. Source: [e.g., "Web scraping", "Licensed data provider"] ║ +║ 3. Size: [e.g., "1.5T tokens", "500K samples", "200GB"] ║ +║ 4. Collection methodology: ║ +║ Example: "Web crawling with quality filters" ║ +║ 5. Preprocessing steps: ║ +║ Example: "Deduplication, PII removal, language filtering" ║ +║ 6. Known limitations in the data: ║ +║ Example: "English-centric, underrepresents African languages" ║ +║ 7. PII assessment: ║ +║ Example: "PII filtered using regex + NER; residual risk low" ║ +║ 8. Data license: [e.g., "CC-BY-4.0", "Proprietary"] ║ +║ ║ +║ Type "unknown" or "N/A" for fields you cannot fill. ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 5. Gather Performance and Evaluation + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 4/7: Performance & Evaluation ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Performance Metrics (provide at least one): ║ +║ Format: Metric | Value | Test Dataset | Conditions ║ +║ Example: "Accuracy | 92.3% | MMLU | 5-shot" ║ +║ "F1 | 0.87 | SQuAD v2 | zero-shot" ║ +║ "BLEU | 34.2 | WMT-22 en-de | beam search k=5" ║ +║ ║ +║ Disaggregated evaluation (optional): ║ +║ Format: Subgroup | Metric | Value ║ +║ Example: "English | Accuracy | 95.1%" ║ +║ "Spanish | Accuracy | 88.4%" ║ +║ ║ +║ Type "unknown" if metrics are not available. ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 6. Gather Bias, Security, and Ethics + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 5/7: Bias, Security & Ethics ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Bias & Fairness (if evaluated): ║ +║ Format: Group | Metric | Performance | Mitigation ║ +║ Example: "Female | Toxicity | 0.02 | Content filter applied" ║ +║ Type "not evaluated" if no bias analysis was performed. ║ +║ ║ +║ Security Concerns: ║ +║ • Known vulnerabilities: [None / describe] ║ +║ • Adversarial robustness: [Low / Medium / High] ║ +║ • Prompt injection risk: [Low / Medium / High / N/A] ║ +║ • Data poisoning risk: [Low / Medium / High] ║ +║ • Model extraction risk: [Low / Medium / High] ║ +║ ║ +║ Ethical Considerations: ║ +║ • Was sensitive data used in training? [Yes / No / Unknown] ║ +║ • Human subjects involved? [Yes / No / Unknown] ║ +║ • Dual-use potential? [Yes / No] ║ +║ • Societal impact notes: [Brief description] ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 7. Gather Environmental Impact + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 6/7: Environmental Impact ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ 1. Training energy (kWh): [e.g., "1,287 kWh", "Unknown"] ║ +║ 2. CO2 equivalent (tons): [e.g., "0.58 tCO2", "Unknown"] ║ +║ 3. Hardware used: [e.g., "8x NVIDIA A100 80GB"] ║ +║ 4. Training duration: [e.g., "72 hours", "Unknown"] ║ +║ 5. Inference cost: [e.g., "$0.005 per 1K tokens", "Unknown"] ║ +║ 6. Region / Grid carbon intensity: [e.g., "US-East", "Unknown"] ║ +║ ║ +║ Type "unknown" for fields you cannot fill. ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 8. Gather Limitations and Recommendations + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 7/7: Limitations & Recommendations ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Known limitations: ║ +║ Example: "Poor performance on low-resource languages", ║ +║ "Context window limited to 128K tokens", ║ +║ "Hallucination rate ~5% on factual queries" ║ +║ ║ +║ Known failure modes: ║ +║ Example: "Produces incorrect math on multi-step problems", ║ +║ "May refuse safe queries due to over-filtering" ║ +║ ║ +║ Recommendations for deployers: ║ +║ Example: "Implement output filtering for PII", ║ +║ "Use human-in-the-loop for high-stakes decisions", ║ +║ "Monitor for performance drift monthly" ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 9. Determine Regulatory Classifications + +Based on the gathered information, determine: + +- **EU AI Act risk level**: Classify based on intended use: + - `unacceptable`: social scoring, real-time biometric identification + - `high`: employment decisions, credit scoring, law enforcement, education + - `limited`: chatbots, emotion recognition, deepfake generation + - `minimal`: spam filters, game AI, search optimization + - `not_applicable`: no EU deployment planned + +- **NIST GenAI risks**: Select applicable risks from: + `privacy`, `bias`, `confabulation`, `cbrn`, `dangerous_content`, `environmental`, `human_ai_config`, `information_integrity`, `information_security`, `intellectual_property`, `obscene_content`, `value_chain` + +- **Overall risk level**: `low`, `medium`, `high`, or `critical` + +### 10. Check Language Configuration + +Read `.devtrail/config.yml` to determine language: + +```yaml +language: en # or es +``` + +Use template path based on language: +- `en` (default): `.devtrail/templates/TEMPLATE-MCARD.md` +- `es`: `.devtrail/templates/i18n/es/TEMPLATE-MCARD.md` + +### 11. Generate Document ID + +Determine the next sequence number: + +```bash +# Get current date +date +%Y-%m-%d + +# Find existing MCARD documents for today +ls .devtrail/09-ai-models/MCARD-$(date +%Y-%m-%d)-*.md 2>/dev/null | wc -l +``` + +ID format: `MCARD-YYYY-MM-DD-NNN` + +### 12. Confirm Before Creating + +Display a summary and ask for confirmation: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ DevTrail MCARD — Summary ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Model: [model_name] ([model_type]) ║ +║ Provider: [provider] — Version: [version] ║ +║ EU AI Act Risk: [risk classification] ║ +║ NIST GenAI Risks: [applicable risks] ║ +║ Overall Risk: [risk level] ║ +║ ║ +║ Proposed filename: ║ +║ MCARD-YYYY-MM-DD-NNN-[model-name-slug].md ║ +║ ║ +║ Location: ║ +║ .devtrail/09-ai-models/ ║ +║ ║ +║ Review required: YES ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ + +Confirm creation? [Y/n]: +``` + +Wait for user confirmation before proceeding. + +### 13. Load Template and Create Document + +1. Read the appropriate template (EN or ES based on config) +2. Replace placeholders: + - `YYYY-MM-DD` -> Current date + - `NNN` -> Sequence number (001, 002, etc.) + - `[agent-name]` -> `gemini-cli-v1.0` + - `[Model Name]` -> User-provided model name +3. Fill in all sections with the gathered information +4. Set `review_required: true` in the frontmatter +5. Save to `.devtrail/09-ai-models/MCARD-YYYY-MM-DD-NNN-[model-name-slug].md` + +### 14. Report Result + +After creation, display: + +``` +DevTrail MCARD created: + .devtrail/09-ai-models/MCARD-YYYY-MM-DD-NNN-[description].md + + Model: [model_name] ([model_type]) + Provider: [provider] + Review required: yes + Risk level: [risk_level] + EU AI Act: [classification] +``` + +## Edge Cases + +1. **No `.devtrail/09-ai-models/` directory**: Create it before saving +2. **User provides partial information**: Fill known fields, mark unknown fields with `[To be determined]` +3. **User declines confirmation**: Acknowledge and exit gracefully +4. **Third-party model with limited info**: Mark unknown sections with `[Information not publicly available]` and note in limitations +5. **No `.devtrail/config.yml`**: Default to English (`en`) diff --git a/dist/.agent/workflows/devtrail-new.md b/dist/.agent/workflows/devtrail-new.md index ca7a435..7e302a4 100644 --- a/dist/.agent/workflows/devtrail-new.md +++ b/dist/.agent/workflows/devtrail-new.md @@ -14,7 +14,7 @@ When invoked, follow these steps: If the user specified a document type (e.g., `/devtrail-new ailog`), skip to step 4 using that type. -Valid types: `ailog`, `aidec`, `adr`, `eth`, `req`, `tes`, `inc`, `tde` +Valid types: `ailog`, `aidec`, `adr`, `eth`, `req`, `tes`, `inc`, `tde`, `sec`, `mcard`, `sbom`, `dpia` ### 2. Analyze Context @@ -40,7 +40,7 @@ Based on the analysis, suggest a document type: | Pattern | Suggested Type | |---------|---------------| -| New code in `src/`, `lib/`, `app/` (>10 lines) | AILOG | +| New code in `src/`, `lib/`, `app/` (>20 lines) | AILOG | | Multiple implementation alternatives discussed | AIDEC | | Structural/architectural changes, new modules | ADR | | Files with `auth`, `user`, `privacy`, `gdpr` | ETH (draft) | @@ -119,6 +119,10 @@ ID format: `[TYPE]-YYYY-MM-DD-NNN` | TES | `.devtrail/04-testing/` | | INC | `.devtrail/05-operations/incidents/` | | TDE | `.devtrail/06-evolution/technical-debt/` | +| SEC | `.devtrail/08-security/` | +| MCARD | `.devtrail/09-ai-models/` | +| SBOM | `.devtrail/07-ai-audit/` | +| DPIA | `.devtrail/07-ai-audit/ethical-reviews/` | ### 8. Report Result @@ -144,6 +148,10 @@ After creation, display: | `tes` | Test Plan | Test strategies and plans | | `inc` | Incident Post-mortem | Incident analysis | | `tde` | Technical Debt | Identified technical debt | +| `sec` | Security Assessment | Threat modeling and security controls | +| `mcard` | Model/System Card | AI model documentation | +| `sbom` | Software Bill of Materials | AI component inventory | +| `dpia` | Data Protection Impact Assessment | Privacy impact analysis | ## Edge Cases diff --git a/dist/.agent/workflows/devtrail-sec.md b/dist/.agent/workflows/devtrail-sec.md new file mode 100644 index 0000000..fb9a1d5 --- /dev/null +++ b/dist/.agent/workflows/devtrail-sec.md @@ -0,0 +1,295 @@ +--- +description: Create a DevTrail Security Assessment (SEC) document. Interactive step-by-step flow that gathers scope, threat model methodology, and OWASP ASVS level, then generates a pre-filled SEC document based on code context. Always marks as draft with review_required. +--- + +# DevTrail Security Assessment Skill + +Create a Security Assessment document with threat modeling and OWASP ASVS compliance checks. + +## Instructions + +When invoked via `/devtrail-sec [component-name]`, follow these steps: + +### 1. Gather Assessment Scope + +If the user provided a `[component-name]`, use it as the system/component under assessment. + +If no component was specified, **ask the user**: + +``` +What system or component would you like to assess? +Examples: "authentication API", "payment gateway", "user data pipeline" +``` + +Wait for the user to respond before proceeding. + +### 2. Ask Threat Model Methodology + +Present the available methodologies and ask the user to choose: + +``` +Which threat modeling methodology would you like to use? + + 1. STRIDE (recommended) - Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege + 2. PASTA - Process for Attack Simulation and Threat Analysis + 3. LINDDUN - Linkability, Identifiability, Non-repudiation, Detectability, Disclosure, Unawareness, Non-compliance + 4. Custom - Define your own methodology + +Select [1/2/3/4] (default: 1): +``` + +Wait for the user to respond before proceeding. + +### 3. Ask Target OWASP ASVS Level + +Ask the user to select the verification level: + +``` +Which OWASP ASVS verification level should be targeted? + + L1 - Opportunistic: Basic security controls (default for most apps) + L2 - Standard: For apps handling sensitive data + L3 - Advanced: For critical infrastructure, medical, financial systems + +Select [L1/L2/L3] (default: L1): +``` + +Wait for the user to respond before proceeding. + +### 4. Analyze Code Context + +Gather information about the component: + +```bash +# Get current date +date +%Y-%m-%d + +# Get modified files (staged and unstaged) +git status --porcelain + +# Get recent changes summary +git diff --stat HEAD~1 2>/dev/null || git diff --stat + +# Count lines changed +git diff --numstat HEAD~1 2>/dev/null || git diff --numstat +``` + +Also scan the codebase for security-relevant patterns in the component area: +- Authentication/authorization code +- Input validation +- Cryptographic operations +- Network/API endpoints +- Data storage and access patterns +- Dependency files (package.json, Cargo.toml, requirements.txt, etc.) + +### 5. Confirm with User + +**Always display this confirmation before creating:** + +``` ++------------------------------------------------------------------+ +| DevTrail Security Assessment | ++------------------------------------------------------------------+ +| | +| Component: [component-name] | +| Methodology: [STRIDE / PASTA / LINDDUN / custom] | +| ASVS Level: [L1 / L2 / L3] | +| | +| Code Context: | +| Files scanned: [N] | +| Security-relevant patterns: [list] | +| | +| Proposed filename: | +| SEC-YYYY-MM-DD-NNN-[description].md | +| | ++------------------------------------------------------------------+ + +Confirm creation? [Y/n]: +``` + +Wait for user confirmation before proceeding. + +### 6. Check Language Configuration + +Read `.devtrail/config.yml` to determine language: + +```yaml +language: en # or es +``` + +Use template path based on language: +- `en` (default): `.devtrail/templates/TEMPLATE-SEC.md` +- `es`: `.devtrail/templates/i18n/es/TEMPLATE-SEC.md` + +### 7. Generate Document ID + +Determine the next sequence number: + +```bash +# Find existing SEC documents for today +ls .devtrail/08-security/SEC-$(date +%Y-%m-%d)-*.md 2>/dev/null | wc -l +``` + +ID format: `SEC-YYYY-MM-DD-NNN` + +### 8. Load Template and Create Document + +1. Read the appropriate template +2. Replace placeholders: + - `YYYY-MM-DD` -> Current date + - `NNN` -> Sequence number (001, 002, etc.) + - `[agent-name]` -> The agent platform name and version + - `[System/Component]` -> The component name from step 1 + - `threat_model_methodology: STRIDE` -> The methodology chosen in step 2 + - `owasp_asvs_level: 1` -> The ASVS level chosen in step 3 +3. Pre-fill fields based on code context analysis: + - Populate "Scope and Objectives" with detected component boundaries + - Fill threat model rows with identified threats from code patterns + - Mark relevant OWASP ASVS controls based on detected patterns + - List discovered vulnerabilities or potential weaknesses +4. Ensure frontmatter contains: + - `status: draft` + - `review_required: true` + - `risk_level: high` + - `confidence: medium` +5. Save to: `.devtrail/08-security/SEC-YYYY-MM-DD-NNN-[description].md` + +### 9. Report Result + +After creation, display: + +``` +DevTrail Security Assessment created: + .devtrail/08-security/SEC-YYYY-MM-DD-NNN-description.md + + Status: draft + Review required: yes + Risk level: high + Methodology: [STRIDE / PASTA / LINDDUN / custom] + ASVS Level: [L1 / L2 / L3] + + IMPORTANT: This is a DRAFT. A qualified security reviewer must + validate all findings before any remediation decisions are made. +``` + +## Expected Output Example + +For invocation `/devtrail-sec authentication-api`, after the interactive flow selects STRIDE and L1, the generated document would look like: + +```markdown +--- +id: SEC-2026-03-24-001 +title: "Authentication API Security Assessment" +status: draft +created: 2026-03-24 +agent: agent-v1.0 +confidence: medium +review_required: true +risk_level: high +eu_ai_act_risk: not_applicable +iso_42001_clause: [6, 8] +threat_model_methodology: STRIDE +owasp_asvs_level: 1 +tags: [security] +related: [] +--- + +# SEC: Authentication API Security Assessment + +> **IMPORTANT**: This document is a DRAFT created by an AI agent. +> It requires human review and approval before proceeding. + +## Scope and Objectives + +| Field | Value | +|-------|-------| +| System Under Assessment | Authentication API v1.0 | +| Assessment Type | code review / threat model | +| Assessment Date | 2026-03-24 | +| Assessor | agent-v1.0 | + +**Objectives**: + +- Identify authentication and session management vulnerabilities +- Validate input handling on login and token endpoints + +**In Scope**: + +- /api/auth/* endpoints +- JWT token generation and validation +- Password hashing and storage + +**Out of Scope**: + +- Frontend client code +- Third-party OAuth providers + +## Threat Model + +> Methodology: **STRIDE** + +### Spoofing + +| Threat ID | Description | Likelihood (1-5) | Impact (1-5) | Risk Score | Mitigation | +|-----------|-------------|:-----------------:|:------------:|:----------:|------------| +| S-001 | Credential stuffing on login endpoint | 4 | 4 | 16 | Rate limiting, account lockout | +| S-002 | JWT token forgery via weak signing key | 2 | 5 | 10 | Use RS256 with rotated keys | + +### Tampering + +| Threat ID | Description | Likelihood (1-5) | Impact (1-5) | Risk Score | Mitigation | +|-----------|-------------|:-----------------:|:------------:|:----------:|------------| +| T-001 | Parameter manipulation on password reset | 3 | 4 | 12 | Server-side validation, signed tokens | + +(... remaining STRIDE categories ...) + +## OWASP ASVS Compliance + +| Control ID | Description | Level (L1/L2/L3) | Status | Evidence | Notes | +|------------|-------------|:-----------------:|:------:|----------|-------| +| V2.1.1 | Verify password length >= 12 chars | L1 | Fail | src/auth/validation.rs:45 | Min length set to 8 | +| V3.1.1 | Verify session token generation uses CSPRNG | L1 | Pass | src/auth/session.rs:12 | Uses ring::rand | + +(... remaining relevant controls ...) + +## Vulnerabilities Found + +| Vuln ID | CWE | Severity (CVSS) | Description | Affected Component | Remediation | Status | +|---------|-----|:----------------:|-------------|-------------------|-------------|:------:| +| VULN-001 | CWE-521 | 5.3 | Weak password policy (min 8 chars) | auth/validation.rs | Enforce min 12 chars | open | + +## Security Controls + +| Business Function | Practice | Maturity Level (1-3) | Current Status | Gaps | +|-------------------|----------|:--------------------:|----------------|------| +| Implementation | Secure Build | 1 | Basic dependency scanning | No SAST configured | + +## Recommendations + +| Priority | Description | Effort | Impact | +|:--------:|-------------|:------:|:------:| +| High | Increase minimum password length to 12 characters | Low | Medium | +| High | Implement rate limiting on authentication endpoints | Medium | High | +| Medium | Add SAST to CI pipeline | Medium | Medium | + +--- + +## Approval + +| Field | Value | +|-------|-------| +| Approved by | [Name] | +| Date | [YYYY-MM-DD] | +| Decision | [APPROVED / REJECTED / CONDITIONAL] | +| Conditions | [If applicable] | + + +``` + +## Edge Cases + +1. **No git repository**: Inform user that git is required for context analysis +2. **Component not found in codebase**: Proceed with a generic assessment, note limited code context +3. **User declines**: Acknowledge and exit gracefully +4. **No security-relevant code found**: Generate template with empty threat rows for manual completion +5. **Multiple components match**: Ask user to clarify which specific component to assess diff --git a/dist/.agent/workflows/devtrail-status.md b/dist/.agent/workflows/devtrail-status.md index ef0c012..e0cdefa 100644 --- a/dist/.agent/workflows/devtrail-status.md +++ b/dist/.agent/workflows/devtrail-status.md @@ -19,10 +19,23 @@ Search for DevTrail documents created or modified in the last hour: git log --since="1 hour ago" --name-only --pretty=format: -- ".devtrail/**/*.md" | sort -u | grep -v "^$" ``` -If git is not available or the directory is not a git repo, use file modification times: -- Check `.devtrail/07-ai-audit/agent-logs/` for recent AILOG files -- Check `.devtrail/07-ai-audit/decisions/` for recent AIDEC files -- Check `.devtrail/07-ai-audit/ethical-reviews/` for recent ETH files +If git is not available or the directory is not a git repo, use file modification times. +Check these directories for each document type: + +| Type | Prefix | Directory | +|------|--------|-----------| +| AILOG | `AILOG-` | `.devtrail/07-ai-audit/agent-logs/` | +| AIDEC | `AIDEC-` | `.devtrail/07-ai-audit/decisions/` | +| ADR | `ADR-` | `.devtrail/04-architecture/decisions/` | +| ETH | `ETH-` | `.devtrail/07-ai-audit/ethical-reviews/` | +| REQ | `REQ-` | `.devtrail/03-requirements/` | +| TES | `TES-` | `.devtrail/05-testing/` | +| INC | `INC-` | `.devtrail/06-operations/incidents/` | +| TDE | `TDE-` | `.devtrail/06-operations/tech-debt/` | +| SEC | `SEC-` | `.devtrail/08-security/` | +| MCARD | `MCARD-` | `.devtrail/09-ai-models/` | +| SBOM | `SBOM-` | `.devtrail/07-ai-audit/` | +| DPIA | `DPIA-` | `.devtrail/07-ai-audit/ethical-reviews/` | ### 2. Find Modified Source Files @@ -41,7 +54,13 @@ Filter to show only files that might need documentation: For each modified source file, check if there's a corresponding DevTrail document: - Files with >10 lines of changes in business logic folders should have an AILOG -- Security-related files should have documentation with `risk_level: high` +- Security-related files (auth, crypto, secrets) should have a SEC assessment +- Architecture/structural changes should have an ADR +- AI/ML model changes should have a MCARD +- Dependency changes (`package.json`, `Cargo.toml`, `go.mod`, etc.) should have an SBOM +- Changes involving personal data processing should have a DPIA +- Test files should have a TES record +- Bug fixes or incidents should have an INC record ### 4. Display Results diff --git a/dist/.claude/skills/devtrail-mcard/SKILL.md b/dist/.claude/skills/devtrail-mcard/SKILL.md new file mode 100644 index 0000000..63c7a83 --- /dev/null +++ b/dist/.claude/skills/devtrail-mcard/SKILL.md @@ -0,0 +1,321 @@ +--- +name: devtrail-mcard +description: Create a Model/System Card (MCARD) document through an interactive step-by-step flow. Guides the user through each section with specific questions and example responses. +allowed-tools: Read, Write, Glob, Bash(git status *, git log *, git diff *, date *, wc *) +--- + +# DevTrail MCARD Skill + +Create AI Model/System Card documentation through an interactive guided flow. + +## Instructions + +When invoked, follow these steps: + +### 1. Check for Parameters + +If the user specified a model name (e.g., `/devtrail-mcard GPT-4o`), use it as the model name and proceed to step 2 asking only for the model type. + +If no parameter is given, proceed to step 2 asking for both model name and type. + +### 2. Gather Model Identity + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ DevTrail MCARD — Model/System Card ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Step 1/7: Model Identity ║ +║ ║ +║ Please provide the following: ║ +║ ║ +║ 1. Model name: [e.g., "GPT-4o", "BERT-base-uncased"] ║ +║ 2. Model type: ║ +║ • LLM — Large Language Model ║ +║ • classifier — Classification model ║ +║ • regressor — Regression model ║ +║ • generator — Generative model (image, audio, etc.) ║ +║ • recommender — Recommendation system ║ +║ • other — Specify ║ +║ 3. Provider: [e.g., "OpenAI", "Google", "Hugging Face"] ║ +║ 4. Version: [e.g., "2024-05-13", "v1.0", "gpt-4o-2024-05-13"] ║ +║ 5. License: [e.g., "Proprietary", "Apache 2.0", "MIT"] ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 3. Gather Intended Use + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 2/7: Intended Use ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ 1. Primary intended uses: ║ +║ Example: "Code generation", "Customer support chatbot", ║ +║ "Sentiment analysis on product reviews" ║ +║ ║ +║ 2. Primary intended users: ║ +║ Example: "Internal engineering team", "End users via API", ║ +║ "Data science team" ║ +║ ║ +║ 3. Out-of-scope uses (what the model should NOT be used for): ║ +║ Example: "Medical diagnosis", "Legal advice", ║ +║ "Autonomous decision-making without human review" ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 4. Gather Training Data Details + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 3/7: Training Data ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ 1. Dataset name: [e.g., "Common Crawl", "Internal corpus v3"] ║ +║ 2. Source: [e.g., "Web scraping", "Licensed data provider"] ║ +║ 3. Size: [e.g., "1.5T tokens", "500K samples", "200GB"] ║ +║ 4. Collection methodology: ║ +║ Example: "Web crawling with quality filters" ║ +║ 5. Preprocessing steps: ║ +║ Example: "Deduplication, PII removal, language filtering" ║ +║ 6. Known limitations in the data: ║ +║ Example: "English-centric, underrepresents African languages" ║ +║ 7. PII assessment: ║ +║ Example: "PII filtered using regex + NER; residual risk low" ║ +║ 8. Data license: [e.g., "CC-BY-4.0", "Proprietary"] ║ +║ ║ +║ Type "unknown" or "N/A" for fields you cannot fill. ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 5. Gather Performance and Evaluation + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 4/7: Performance & Evaluation ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Performance Metrics (provide at least one): ║ +║ Format: Metric | Value | Test Dataset | Conditions ║ +║ Example: "Accuracy | 92.3% | MMLU | 5-shot" ║ +║ "F1 | 0.87 | SQuAD v2 | zero-shot" ║ +║ "BLEU | 34.2 | WMT-22 en-de | beam search k=5" ║ +║ ║ +║ Disaggregated evaluation (optional): ║ +║ Format: Subgroup | Metric | Value ║ +║ Example: "English | Accuracy | 95.1%" ║ +║ "Spanish | Accuracy | 88.4%" ║ +║ ║ +║ Type "unknown" if metrics are not available. ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 6. Gather Bias, Security, and Ethics + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 5/7: Bias, Security & Ethics ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Bias & Fairness (if evaluated): ║ +║ Format: Group | Metric | Performance | Mitigation ║ +║ Example: "Female | Toxicity | 0.02 | Content filter applied" ║ +║ Type "not evaluated" if no bias analysis was performed. ║ +║ ║ +║ Security Concerns: ║ +║ • Known vulnerabilities: [None / describe] ║ +║ • Adversarial robustness: [Low / Medium / High] ║ +║ • Prompt injection risk: [Low / Medium / High / N/A] ║ +║ • Data poisoning risk: [Low / Medium / High] ║ +║ • Model extraction risk: [Low / Medium / High] ║ +║ ║ +║ Ethical Considerations: ║ +║ • Was sensitive data used in training? [Yes / No / Unknown] ║ +║ • Human subjects involved? [Yes / No / Unknown] ║ +║ • Dual-use potential? [Yes / No] ║ +║ • Societal impact notes: [Brief description] ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 7. Gather Environmental Impact + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 6/7: Environmental Impact ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ 1. Training energy (kWh): [e.g., "1,287 kWh", "Unknown"] ║ +║ 2. CO2 equivalent (tons): [e.g., "0.58 tCO2", "Unknown"] ║ +║ 3. Hardware used: [e.g., "8x NVIDIA A100 80GB"] ║ +║ 4. Training duration: [e.g., "72 hours", "Unknown"] ║ +║ 5. Inference cost: [e.g., "$0.005 per 1K tokens", "Unknown"] ║ +║ 6. Region / Grid carbon intensity: [e.g., "US-East", "Unknown"] ║ +║ ║ +║ Type "unknown" for fields you cannot fill. ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 8. Gather Limitations and Recommendations + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 7/7: Limitations & Recommendations ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Known limitations: ║ +║ Example: "Poor performance on low-resource languages", ║ +║ "Context window limited to 128K tokens", ║ +║ "Hallucination rate ~5% on factual queries" ║ +║ ║ +║ Known failure modes: ║ +║ Example: "Produces incorrect math on multi-step problems", ║ +║ "May refuse safe queries due to over-filtering" ║ +║ ║ +║ Recommendations for deployers: ║ +║ Example: "Implement output filtering for PII", ║ +║ "Use human-in-the-loop for high-stakes decisions", ║ +║ "Monitor for performance drift monthly" ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 9. Determine Regulatory Classifications + +Based on the gathered information, determine: + +- **EU AI Act risk level**: Classify based on intended use: + - `unacceptable`: social scoring, real-time biometric identification + - `high`: employment decisions, credit scoring, law enforcement, education + - `limited`: chatbots, emotion recognition, deepfake generation + - `minimal`: spam filters, game AI, search optimization + - `not_applicable`: no EU deployment planned + +- **NIST GenAI risks**: Select applicable risks from: + `privacy`, `bias`, `confabulation`, `cbrn`, `dangerous_content`, `environmental`, `human_ai_config`, `information_integrity`, `information_security`, `intellectual_property`, `obscene_content`, `value_chain` + +- **Overall risk level**: `low`, `medium`, `high`, or `critical` + +### 10. Check Language Configuration + +Read `.devtrail/config.yml` to determine language: + +```yaml +language: en # or es +``` + +Use template path based on language: +- `en` (default): `.devtrail/templates/TEMPLATE-MCARD.md` +- `es`: `.devtrail/templates/i18n/es/TEMPLATE-MCARD.md` + +### 11. Generate Document ID + +Determine the next sequence number: + +```bash +# Get current date +date +%Y-%m-%d + +# Find existing MCARD documents for today +ls .devtrail/09-ai-models/MCARD-$(date +%Y-%m-%d)-*.md 2>/dev/null | wc -l +``` + +ID format: `MCARD-YYYY-MM-DD-NNN` + +### 12. Confirm Before Creating + +Display a summary and ask for confirmation: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ DevTrail MCARD — Summary ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Model: [model_name] ([model_type]) ║ +║ Provider: [provider] — Version: [version] ║ +║ EU AI Act Risk: [risk classification] ║ +║ NIST GenAI Risks: [applicable risks] ║ +║ Overall Risk: [risk level] ║ +║ ║ +║ Proposed filename: ║ +║ MCARD-YYYY-MM-DD-NNN-[model-name-slug].md ║ +║ ║ +║ Location: ║ +║ .devtrail/09-ai-models/ ║ +║ ║ +║ Review required: YES ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ + +Confirm creation? [Y/n]: +``` + +Wait for user confirmation before proceeding. + +### 13. Load Template and Create Document + +1. Read the appropriate template (EN or ES based on config) +2. Replace placeholders: + - `YYYY-MM-DD` -> Current date + - `NNN` -> Sequence number (001, 002, etc.) + - `[agent-name]` -> `claude-code-v1.0` + - `[Model Name]` -> User-provided model name +3. Fill in all sections with the gathered information +4. Set `review_required: true` in the frontmatter +5. Save to `.devtrail/09-ai-models/MCARD-YYYY-MM-DD-NNN-[model-name-slug].md` + +### 14. Report Result + +After creation, display: + +``` +DevTrail MCARD created: + .devtrail/09-ai-models/MCARD-YYYY-MM-DD-NNN-[description].md + + Model: [model_name] ([model_type]) + Provider: [provider] + Review required: yes + Risk level: [risk_level] + EU AI Act: [classification] +``` + +## Edge Cases + +1. **No `.devtrail/09-ai-models/` directory**: Create it before saving +2. **User provides partial information**: Fill known fields, mark unknown fields with `[To be determined]` +3. **User declines confirmation**: Acknowledge and exit gracefully +4. **Third-party model with limited info**: Mark unknown sections with `[Information not publicly available]` and note in limitations +5. **No `.devtrail/config.yml`**: Default to English (`en`) diff --git a/dist/.claude/skills/devtrail-new/SKILL.md b/dist/.claude/skills/devtrail-new/SKILL.md index 2778f59..66b10d0 100644 --- a/dist/.claude/skills/devtrail-new/SKILL.md +++ b/dist/.claude/skills/devtrail-new/SKILL.md @@ -16,7 +16,7 @@ When invoked, follow these steps: If the user specified a document type (e.g., `/devtrail-new ailog`), skip to step 4 using that type. -Valid types: `ailog`, `aidec`, `adr`, `eth`, `req`, `tes`, `inc`, `tde` +Valid types: `ailog`, `aidec`, `adr`, `eth`, `req`, `tes`, `inc`, `tde`, `sec`, `mcard`, `sbom`, `dpia` ### 2. Analyze Context @@ -42,7 +42,7 @@ Based on the analysis, suggest a document type: | Pattern | Suggested Type | |---------|---------------| -| New code in `src/`, `lib/`, `app/` (>10 lines) | AILOG | +| New code in `src/`, `lib/`, `app/` (>20 lines) | AILOG | | Multiple implementation alternatives discussed | AIDEC | | Structural/architectural changes, new modules | ADR | | Files with `auth`, `user`, `privacy`, `gdpr` | ETH (draft) | @@ -121,6 +121,10 @@ ID format: `[TYPE]-YYYY-MM-DD-NNN` | TES | `.devtrail/04-testing/` | | INC | `.devtrail/05-operations/incidents/` | | TDE | `.devtrail/06-evolution/technical-debt/` | +| SEC | `.devtrail/08-security/` | +| MCARD | `.devtrail/09-ai-models/` | +| SBOM | `.devtrail/07-ai-audit/` | +| DPIA | `.devtrail/07-ai-audit/ethical-reviews/` | ### 8. Report Result @@ -146,6 +150,10 @@ After creation, display: | `tes` | Test Plan | Test strategies and plans | | `inc` | Incident Post-mortem | Incident analysis | | `tde` | Technical Debt | Identified technical debt | +| `sec` | Security Assessment | Threat modeling and security controls | +| `mcard` | Model/System Card | AI model documentation | +| `sbom` | Software Bill of Materials | AI component inventory | +| `dpia` | Data Protection Impact Assessment | Privacy impact analysis | ## Edge Cases diff --git a/dist/.claude/skills/devtrail-sec/SKILL.md b/dist/.claude/skills/devtrail-sec/SKILL.md new file mode 100644 index 0000000..280efa0 --- /dev/null +++ b/dist/.claude/skills/devtrail-sec/SKILL.md @@ -0,0 +1,297 @@ +--- +name: devtrail-sec +description: Create a DevTrail Security Assessment (SEC) document. Interactive step-by-step flow that gathers scope, threat model methodology, and OWASP ASVS level, then generates a pre-filled SEC document based on code context. Always marks as draft with review_required. +allowed-tools: Read, Write, Glob, Bash(git diff *, git log *, git status *, date *, wc *) +--- + +# DevTrail Security Assessment Skill + +Create a Security Assessment document with threat modeling and OWASP ASVS compliance checks. + +## Instructions + +When invoked via `/devtrail-sec [component-name]`, follow these steps: + +### 1. Gather Assessment Scope + +If the user provided a `[component-name]`, use it as the system/component under assessment. + +If no component was specified, **ask the user**: + +``` +What system or component would you like to assess? +Examples: "authentication API", "payment gateway", "user data pipeline" +``` + +Wait for the user to respond before proceeding. + +### 2. Ask Threat Model Methodology + +Present the available methodologies and ask the user to choose: + +``` +Which threat modeling methodology would you like to use? + + 1. STRIDE (recommended) - Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege + 2. PASTA - Process for Attack Simulation and Threat Analysis + 3. LINDDUN - Linkability, Identifiability, Non-repudiation, Detectability, Disclosure, Unawareness, Non-compliance + 4. Custom - Define your own methodology + +Select [1/2/3/4] (default: 1): +``` + +Wait for the user to respond before proceeding. + +### 3. Ask Target OWASP ASVS Level + +Ask the user to select the verification level: + +``` +Which OWASP ASVS verification level should be targeted? + + L1 - Opportunistic: Basic security controls (default for most apps) + L2 - Standard: For apps handling sensitive data + L3 - Advanced: For critical infrastructure, medical, financial systems + +Select [L1/L2/L3] (default: L1): +``` + +Wait for the user to respond before proceeding. + +### 4. Analyze Code Context + +Gather information about the component: + +```bash +# Get current date +date +%Y-%m-%d + +# Get modified files (staged and unstaged) +git status --porcelain + +# Get recent changes summary +git diff --stat HEAD~1 2>/dev/null || git diff --stat + +# Count lines changed +git diff --numstat HEAD~1 2>/dev/null || git diff --numstat +``` + +Also scan the codebase for security-relevant patterns in the component area: +- Authentication/authorization code +- Input validation +- Cryptographic operations +- Network/API endpoints +- Data storage and access patterns +- Dependency files (package.json, Cargo.toml, requirements.txt, etc.) + +### 5. Confirm with User + +**Always display this confirmation before creating:** + +``` ++------------------------------------------------------------------+ +| DevTrail Security Assessment | ++------------------------------------------------------------------+ +| | +| Component: [component-name] | +| Methodology: [STRIDE / PASTA / LINDDUN / custom] | +| ASVS Level: [L1 / L2 / L3] | +| | +| Code Context: | +| Files scanned: [N] | +| Security-relevant patterns: [list] | +| | +| Proposed filename: | +| SEC-YYYY-MM-DD-NNN-[description].md | +| | ++------------------------------------------------------------------+ + +Confirm creation? [Y/n]: +``` + +Wait for user confirmation before proceeding. + +### 6. Check Language Configuration + +Read `.devtrail/config.yml` to determine language: + +```yaml +language: en # or es +``` + +Use template path based on language: +- `en` (default): `.devtrail/templates/TEMPLATE-SEC.md` +- `es`: `.devtrail/templates/i18n/es/TEMPLATE-SEC.md` + +### 7. Generate Document ID + +Determine the next sequence number: + +```bash +# Find existing SEC documents for today +ls .devtrail/08-security/SEC-$(date +%Y-%m-%d)-*.md 2>/dev/null | wc -l +``` + +ID format: `SEC-YYYY-MM-DD-NNN` + +### 8. Load Template and Create Document + +1. Read the appropriate template +2. Replace placeholders: + - `YYYY-MM-DD` -> Current date + - `NNN` -> Sequence number (001, 002, etc.) + - `[agent-name]` -> `claude-code-v1.0` + - `[System/Component]` -> The component name from step 1 + - `threat_model_methodology: STRIDE` -> The methodology chosen in step 2 + - `owasp_asvs_level: 1` -> The ASVS level chosen in step 3 +3. Pre-fill fields based on code context analysis: + - Populate "Scope and Objectives" with detected component boundaries + - Fill threat model rows with identified threats from code patterns + - Mark relevant OWASP ASVS controls based on detected patterns + - List discovered vulnerabilities or potential weaknesses +4. Ensure frontmatter contains: + - `status: draft` + - `review_required: true` + - `risk_level: high` + - `confidence: medium` +5. Save to: `.devtrail/08-security/SEC-YYYY-MM-DD-NNN-[description].md` + +### 9. Report Result + +After creation, display: + +``` +DevTrail Security Assessment created: + .devtrail/08-security/SEC-YYYY-MM-DD-NNN-description.md + + Status: draft + Review required: yes + Risk level: high + Methodology: [STRIDE / PASTA / LINDDUN / custom] + ASVS Level: [L1 / L2 / L3] + + IMPORTANT: This is a DRAFT. A qualified security reviewer must + validate all findings before any remediation decisions are made. +``` + +## Expected Output Example + +For invocation `/devtrail-sec authentication-api`, after the interactive flow selects STRIDE and L1, the generated document would look like: + +```markdown +--- +id: SEC-2026-03-24-001 +title: "Authentication API Security Assessment" +status: draft +created: 2026-03-24 +agent: claude-code-v1.0 +confidence: medium +review_required: true +risk_level: high +eu_ai_act_risk: not_applicable +iso_42001_clause: [6, 8] +threat_model_methodology: STRIDE +owasp_asvs_level: 1 +tags: [security] +related: [] +--- + +# SEC: Authentication API Security Assessment + +> **IMPORTANT**: This document is a DRAFT created by an AI agent. +> It requires human review and approval before proceeding. + +## Scope and Objectives + +| Field | Value | +|-------|-------| +| System Under Assessment | Authentication API v1.0 | +| Assessment Type | code review / threat model | +| Assessment Date | 2026-03-24 | +| Assessor | claude-code-v1.0 | + +**Objectives**: + +- Identify authentication and session management vulnerabilities +- Validate input handling on login and token endpoints + +**In Scope**: + +- /api/auth/* endpoints +- JWT token generation and validation +- Password hashing and storage + +**Out of Scope**: + +- Frontend client code +- Third-party OAuth providers + +## Threat Model + +> Methodology: **STRIDE** + +### Spoofing + +| Threat ID | Description | Likelihood (1-5) | Impact (1-5) | Risk Score | Mitigation | +|-----------|-------------|:-----------------:|:------------:|:----------:|------------| +| S-001 | Credential stuffing on login endpoint | 4 | 4 | 16 | Rate limiting, account lockout | +| S-002 | JWT token forgery via weak signing key | 2 | 5 | 10 | Use RS256 with rotated keys | + +### Tampering + +| Threat ID | Description | Likelihood (1-5) | Impact (1-5) | Risk Score | Mitigation | +|-----------|-------------|:-----------------:|:------------:|:----------:|------------| +| T-001 | Parameter manipulation on password reset | 3 | 4 | 12 | Server-side validation, signed tokens | + +(... remaining STRIDE categories ...) + +## OWASP ASVS Compliance + +| Control ID | Description | Level (L1/L2/L3) | Status | Evidence | Notes | +|------------|-------------|:-----------------:|:------:|----------|-------| +| V2.1.1 | Verify password length >= 12 chars | L1 | Fail | src/auth/validation.rs:45 | Min length set to 8 | +| V3.1.1 | Verify session token generation uses CSPRNG | L1 | Pass | src/auth/session.rs:12 | Uses ring::rand | + +(... remaining relevant controls ...) + +## Vulnerabilities Found + +| Vuln ID | CWE | Severity (CVSS) | Description | Affected Component | Remediation | Status | +|---------|-----|:----------------:|-------------|-------------------|-------------|:------:| +| VULN-001 | CWE-521 | 5.3 | Weak password policy (min 8 chars) | auth/validation.rs | Enforce min 12 chars | open | + +## Security Controls + +| Business Function | Practice | Maturity Level (1-3) | Current Status | Gaps | +|-------------------|----------|:--------------------:|----------------|------| +| Implementation | Secure Build | 1 | Basic dependency scanning | No SAST configured | + +## Recommendations + +| Priority | Description | Effort | Impact | +|:--------:|-------------|:------:|:------:| +| High | Increase minimum password length to 12 characters | Low | Medium | +| High | Implement rate limiting on authentication endpoints | Medium | High | +| Medium | Add SAST to CI pipeline | Medium | Medium | + +--- + +## Approval + +| Field | Value | +|-------|-------| +| Approved by | [Name] | +| Date | [YYYY-MM-DD] | +| Decision | [APPROVED / REJECTED / CONDITIONAL] | +| Conditions | [If applicable] | + + +``` + +## Edge Cases + +1. **No git repository**: Inform user that git is required for context analysis +2. **Component not found in codebase**: Proceed with a generic assessment, note limited code context +3. **User declines**: Acknowledge and exit gracefully +4. **No security-relevant code found**: Generate template with empty threat rows for manual completion +5. **Multiple components match**: Ask user to clarify which specific component to assess diff --git a/dist/.claude/skills/devtrail-status/SKILL.md b/dist/.claude/skills/devtrail-status/SKILL.md index 5b741f6..c651a70 100644 --- a/dist/.claude/skills/devtrail-status/SKILL.md +++ b/dist/.claude/skills/devtrail-status/SKILL.md @@ -21,10 +21,23 @@ Search for DevTrail documents created or modified in the last hour: git log --since="1 hour ago" --name-only --pretty=format: -- ".devtrail/**/*.md" | sort -u | grep -v "^$" ``` -If git is not available or the directory is not a git repo, use file modification times: -- Check `.devtrail/07-ai-audit/agent-logs/` for recent AILOG files -- Check `.devtrail/07-ai-audit/decisions/` for recent AIDEC files -- Check `.devtrail/07-ai-audit/ethical-reviews/` for recent ETH files +If git is not available or the directory is not a git repo, use file modification times. +Check these directories for each document type: + +| Type | Prefix | Directory | +|------|--------|-----------| +| AILOG | `AILOG-` | `.devtrail/07-ai-audit/agent-logs/` | +| AIDEC | `AIDEC-` | `.devtrail/07-ai-audit/decisions/` | +| ADR | `ADR-` | `.devtrail/04-architecture/decisions/` | +| ETH | `ETH-` | `.devtrail/07-ai-audit/ethical-reviews/` | +| REQ | `REQ-` | `.devtrail/03-requirements/` | +| TES | `TES-` | `.devtrail/05-testing/` | +| INC | `INC-` | `.devtrail/06-operations/incidents/` | +| TDE | `TDE-` | `.devtrail/06-operations/tech-debt/` | +| SEC | `SEC-` | `.devtrail/08-security/` | +| MCARD | `MCARD-` | `.devtrail/09-ai-models/` | +| SBOM | `SBOM-` | `.devtrail/07-ai-audit/` | +| DPIA | `DPIA-` | `.devtrail/07-ai-audit/ethical-reviews/` | ### 2. Find Modified Source Files @@ -43,7 +56,13 @@ Filter to show only files that might need documentation: For each modified source file, check if there's a corresponding DevTrail document: - Files with >10 lines of changes in business logic folders should have an AILOG -- Security-related files should have documentation with `risk_level: high` +- Security-related files (auth, crypto, secrets) should have a SEC assessment +- Architecture/structural changes should have an ADR +- AI/ML model changes should have a MCARD +- Dependency changes (`package.json`, `Cargo.toml`, `go.mod`, etc.) should have an SBOM +- Changes involving personal data processing should have a DPIA +- Test files should have a TES record +- Bug fixes or incidents should have an INC record ### 4. Display Results diff --git a/dist/.devtrail/08-security/.gitkeep b/dist/.devtrail/08-security/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/dist/.devtrail/09-ai-models/.gitkeep b/dist/.devtrail/09-ai-models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/dist/.devtrail/templates/TEMPLATE-DPIA.md b/dist/.devtrail/templates/TEMPLATE-DPIA.md new file mode 100644 index 0000000..1313e8e --- /dev/null +++ b/dist/.devtrail/templates/TEMPLATE-DPIA.md @@ -0,0 +1,97 @@ +--- +id: DPIA-YYYY-MM-DD-NNN +title: "[System/Process] Data Protection Impact Assessment" +status: draft +created: YYYY-MM-DD +agent: [agent-name] +confidence: low # DPIA requires extensive human judgment +review_required: true # Always mandatory +risk_level: high +eu_ai_act_risk: not_applicable # unacceptable | high | limited | minimal | not_applicable +gdpr_article_35: true # Art. 35 GDPR triggers DPIA +iso_42001_clause: [6, 8] +dpo_consulted: false +supervisory_authority_consulted: false +tags: [privacy, gdpr, dpia] +related: [] +--- + +# DPIA: [System/Process] Data Protection Impact Assessment + +> **IMPORTANT**: This document is a DRAFT created by an AI agent. +> It requires human review and approval before proceeding. + +## Processing Description + +- **Nature of Processing**: [Describe how data is collected, stored, used, and deleted] +- **Scope**: [Scale of processing — number of data subjects, volume, geographic scope] +- **Context**: [Relationship between controller and data subjects, expectations] +- **Purpose**: [Specific purpose of the processing activity] +- **Legal Basis (Art. 6 GDPR)**: [consent / contract / legal_obligation / vital_interests / public_task / legitimate_interests] +- **Categories of Data Subjects**: [Employees, customers, minors, patients, etc.] +- **Categories of Personal Data**: [Name, email, health data, biometric data, location, etc.] +- **Recipients**: [Who receives or has access to the data] +- **International Transfers**: [Countries/regions, transfer mechanisms (SCCs, adequacy decisions, BCRs)] +- **Retention Period**: [How long data is retained and criteria for determining retention] + +## Necessity and Proportionality + +- **Necessity Assessment**: [Why is this processing necessary to achieve the stated purpose] +- **Purpose Limitation**: [How processing is limited to the stated purpose only] +- **Data Minimization**: [How only the minimum necessary data is collected and processed] +- **Storage Limitation**: [How data retention is limited to what is necessary] +- **Data Quality**: [How accuracy and completeness of data is ensured] + +## Risk Assessment + +### Risks to Data Subjects + +| Risk | Likelihood | Severity | Risk Level | Source of Risk | Nature of Impact | +|------|-----------|----------|------------|----------------|-----------------| +| [Risk 1] | [Low/Med/High] | [Low/Med/High] | [Low/Med/High] | [Source] | [physical/material/non-material] | +| [Risk 2] | [Low/Med/High] | [Low/Med/High] | [Low/Med/High] | [Source] | [physical/material/non-material] | +| [Risk 3] | [Low/Med/High] | [Low/Med/High] | [Low/Med/High] | [Source] | [physical/material/non-material] | + +### Risks to Rights and Freedoms + +| Risk | Likelihood | Severity | Risk Level | Source of Risk | Nature of Impact | +|------|-----------|----------|------------|----------------|-----------------| +| [Risk 1] | [Low/Med/High] | [Low/Med/High] | [Low/Med/High] | [Source] | [physical/material/non-material] | +| [Risk 2] | [Low/Med/High] | [Low/Med/High] | [Low/Med/High] | [Source] | [physical/material/non-material] | + +## Measures to Mitigate Risks + +| Risk | Measure | Type | Residual Risk | Responsible | +|------|---------|------|---------------|-------------| +| [Risk 1] | [Mitigation measure] | [technical/organizational/legal] | [Low/Med/High] | [Role/Person] | +| [Risk 2] | [Mitigation measure] | [technical/organizational/legal] | [Low/Med/High] | [Role/Person] | +| [Risk 3] | [Mitigation measure] | [technical/organizational/legal] | [Low/Med/High] | [Role/Person] | + +## Consultation + +> If residual risk remains high after mitigation, consultation with the supervisory authority is mandatory per Art. 36 GDPR. + +- **Data Protection Officer Opinion**: [DPO opinion and recommendations] +- **Data Subjects Consulted**: [Yes/No] — [Methodology: surveys, focus groups, public consultation, etc.] +- **Supervisory Authority Consulted**: [Yes/No] — [Reference number or details if applicable] + +## AI-Specific Considerations + +> Complete this section when the processing involves AI systems, particularly under the EU AI Act. + +- **Automated Decision-Making (Art. 22 GDPR)**: [Does the processing involve solely automated decision-making with legal or significant effects? Describe safeguards] +- **Right to Explanation**: [How data subjects can obtain meaningful information about the logic involved] +- **Human Oversight Measures**: [Describe human-in-the-loop or human-on-the-loop mechanisms] +- **Transparency to Data Subjects**: [How data subjects are informed about AI involvement in processing their data] + +## Review Schedule + +- **Next Review Date**: [YYYY-MM-DD] +- **Review Trigger Events**: + - [Change in processing scope or purpose] + - [New categories of personal data] + - [Regulatory changes] + - [Security incidents] +- **Review Responsible**: [Role/Person responsible for conducting the review] + + diff --git a/dist/.devtrail/templates/TEMPLATE-MCARD.md b/dist/.devtrail/templates/TEMPLATE-MCARD.md new file mode 100644 index 0000000..8097649 --- /dev/null +++ b/dist/.devtrail/templates/TEMPLATE-MCARD.md @@ -0,0 +1,158 @@ +--- +id: MCARD-YYYY-MM-DD-NNN +title: "[Model Name] Card" +status: draft +created: YYYY-MM-DD +agent: [agent-name] +confidence: medium +review_required: true +risk_level: medium +eu_ai_act_risk: not_applicable # unacceptable | high | limited | minimal | not_applicable +nist_genai_risks: [] # privacy | bias | confabulation | cbrn | dangerous_content | environmental | human_ai_config | information_integrity | information_security | intellectual_property | obscene_content | value_chain +iso_42001_clause: [8] +model_name: "" +model_type: LLM # LLM | classifier | regressor | generator | recommender | other +model_version: "" +provider: "" +license: "" +tags: [ai-model] +related: [] +--- + +# MCARD: [Model Name] Card + +> **IMPORTANT**: This document is a DRAFT created by an AI agent. +> It requires human review and approval before proceeding. + +## Model Details + +> Based on Mitchell et al. (2019) — "Model Cards for Model Reporting". + +| Field | Value | +|-------|-------| +| Developer | [Organization or individual who developed the model] | +| Model Date | [YYYY-MM-DD — date the model was trained or released] | +| Model Version | [Version identifier] | +| Model Type | [LLM / classifier / regressor / generator / recommender / other] | +| Training Algorithms | [Algorithm(s) used for training] | +| Base Model | [Base model name and version, if fine-tuned; N/A otherwise] | +| Paper / Resource | [URL or citation to paper, blog post, or documentation] | +| Citation | [BibTeX or plain-text citation] | +| License | [Model license — e.g., Apache 2.0, MIT, proprietary] | + +## Intended Use + +### Primary Intended Uses + +- [Primary use case 1] +- [Primary use case 2] + +### Primary Intended Users + +- [User group 1] +- [User group 2] + +### Out-of-Scope Uses + +- [Use case the model is NOT designed for 1] +- [Use case the model is NOT designed for 2] + +## Training Data + +> For SBOM interoperability, consider aligning with CycloneDX `modelCard.modelParameters` fields. + +| Field | Value | +|-------|-------| +| Dataset Name | [Name of the training dataset] | +| Source | [Where the data was obtained] | +| Size | [Number of samples, tokens, or storage size] | +| Collection Methodology | [How the data was collected] | +| Preprocessing | [Cleaning, filtering, augmentation steps applied] | +| Known Limitations | [Biases, gaps, or quality issues in the data] | +| PII Assessment | [Whether PII is present and how it was handled] | +| License | [License governing the training data] | + +## Performance Metrics + +| Metric | Value | Test Dataset | Confidence Interval | Conditions | +|--------|:-----:|--------------|:--------------------:|------------| +| [Accuracy / F1 / BLEU / etc.] | [Value] | [Dataset name and split] | [95% CI range] | [Conditions or configuration] | +| [Metric 2] | [Value] | [Dataset name and split] | [95% CI range] | [Conditions or configuration] | +| [Metric 3] | [Value] | [Dataset name and split] | [95% CI range] | [Conditions or configuration] | + +### Disaggregated Evaluation + +> Report performance broken down by relevant subgroups when applicable. + +| Subgroup | Metric | Value | Baseline Comparison | +|----------|--------|:-----:|:-------------------:| +| [Subgroup 1] | [Metric] | [Value] | [+/- vs overall] | +| [Subgroup 2] | [Metric] | [Value] | [+/- vs overall] | + +## Bias and Fairness Evaluation + +| Demographic Group | Metric | Performance | Disparity vs Baseline | Mitigation Applied | +|-------------------|--------|:-----------:|:---------------------:|--------------------| +| [Group 1 — e.g., age range, gender, ethnicity] | [Metric] | [Value] | [+/- percentage or absolute] | [Mitigation description] | +| [Group 2] | [Metric] | [Value] | [+/- percentage or absolute] | [Mitigation description] | +| [Group 3] | [Metric] | [Value] | [+/- percentage or absolute] | [Mitigation description] | + +## Environmental Impact + +| Metric | Value | Notes | +|--------|-------|-------| +| Training Energy (kWh) | [Value] | [Methodology or estimation source] | +| CO2 Equivalent (tons) | [Value] | [Grid carbon intensity used] | +| Hardware Used | [GPUs/TPUs, count, model] | [Cloud provider / region] | +| Training Duration | [Hours / days] | [Total compute time] | +| Inference Cost | [Cost per request or per 1K tokens] | [Average / peak] | +| Region / Grid Carbon Intensity | [Region name] | [gCO2/kWh] | + +## Security Considerations + +| Concern | Assessment | Details | +|---------|:----------:|---------| +| Known Vulnerabilities | [None / Description] | [CVE references or description of known issues] | +| Adversarial Robustness | [Low / Medium / High] | [Assessment methodology and results] | +| Prompt Injection Risk | [Low / Medium / High] | [Evaluation of susceptibility to prompt injection] | +| Data Poisoning Risk | [Low / Medium / High] | [Assessment of training data integrity] | +| Model Extraction Risk | [Low / Medium / High] | [Risk of model weights or behavior being extracted] | + +## Ethical Considerations + +- **Sensitive Data Used**: [Whether sensitive or personal data was used in training and how it was handled] +- **Human Subjects in Training**: [Whether human subjects were involved in data collection; IRB or ethics board review status] +- **Dual-Use Potential**: [Whether the model could be repurposed for harmful applications; safeguards in place] +- **Societal Impact Assessment**: [Broader societal implications — positive and negative] + +## Limitations and Recommendations + +### Known Limitations + +- [Limitation 1 — e.g., poor performance on specific languages or domains] +- [Limitation 2 — e.g., context window constraints] +- [Limitation 3 — e.g., tendency to hallucinate in specific scenarios] + +### Failure Modes + +- [Failure mode 1 — conditions under which the model fails predictably] +- [Failure mode 2 — edge cases or adversarial inputs] + +### Recommendations for Deployers + +- [Recommendation 1 — e.g., implement output filtering] +- [Recommendation 2 — e.g., set up human-in-the-loop for high-risk decisions] +- [Recommendation 3 — e.g., monitor for drift over time] + +--- + +## Approval + +| Field | Value | +|-------|-------| +| Approved by | [Name] | +| Date | [YYYY-MM-DD] | +| Decision | [APPROVED / REJECTED / CONDITIONAL] | +| Conditions | [If applicable] | + + diff --git a/dist/.devtrail/templates/TEMPLATE-SBOM.md b/dist/.devtrail/templates/TEMPLATE-SBOM.md new file mode 100644 index 0000000..cd56a78 --- /dev/null +++ b/dist/.devtrail/templates/TEMPLATE-SBOM.md @@ -0,0 +1,77 @@ +--- +id: SBOM-YYYY-MM-DD-NNN +title: "[System/Component] AI SBOM" +status: accepted +created: YYYY-MM-DD +agent: [agent-name] +confidence: high +review_required: false # Factual inventory +risk_level: low +iso_42001_clause: [8] +sbom_format_reference: SPDX-3.0 | CycloneDX-1.6 | custom +system_name: "" +tags: [sbom, supply-chain] +related: [] +--- + +# SBOM: [System/Component] AI Software Bill of Materials + +## AI/ML Components + +> This section maps to CycloneDX `component` with `type: machine-learning-model`. + +| Component Name | Version | Provider | Type | License | Risk Level | Vulnerability Status | Last Audit Date | +|----------------|---------|----------|------|---------|------------|---------------------|-----------------| +| [Component 1] | [x.y.z] | [Provider] | model | [License] | [Low/Med/High] | [Clean/Vulnerable] | [YYYY-MM-DD] | +| [Component 2] | [x.y.z] | [Provider] | library | [License] | [Low/Med/High] | [Clean/Vulnerable] | [YYYY-MM-DD] | +| [Component 3] | [x.y.z] | [Provider] | service | [License] | [Low/Med/High] | [Clean/Vulnerable] | [YYYY-MM-DD] | +| [Component 4] | [x.y.z] | [Provider] | dataset | [License] | [Low/Med/High] | [Clean/Vulnerable] | [YYYY-MM-DD] | + +## Training Data Sources + +> Aligns with ISO 42001 Annex A.7 (Data for AI Systems). + +| Dataset | Source | License | PII Included | Bias Assessment Summary | Data Provenance | Retention Policy | +|---------|--------|---------|--------------|------------------------|-----------------|-----------------| +| [Dataset 1] | [Source] | [License] | [Yes/No] | [Summary] | [Provenance] | [Policy] | +| [Dataset 2] | [Source] | [License] | [Yes/No] | [Summary] | [Provenance] | [Policy] | + +## Third-Party AI Services + +| Service | Provider | Purpose | Data Shared | DPA in Place | SLA | Region | Compliance Certifications | +|---------|----------|---------|-------------|--------------|-----|--------|--------------------------| +| [Service 1] | [Provider] | [Purpose] | [Data types] | [Yes/No] | [SLA terms] | [Region] | [SOC2, ISO 27001, etc.] | +| [Service 2] | [Provider] | [Purpose] | [Data types] | [Yes/No] | [SLA terms] | [Region] | [SOC2, ISO 27001, etc.] | + +## Software Dependencies + +> Consider generating this section automatically with tools like `syft` or `trivy`. + +| Package | Version | License | Known Vulnerabilities | Last Updated | +|---------|---------|---------|----------------------|-------------| +| [Package 1] | [x.y.z] | [License] | [CVE-YYYY-NNNNN, ...] | [YYYY-MM-DD] | +| [Package 2] | [x.y.z] | [License] | [None] | [YYYY-MM-DD] | +| [Package 3] | [x.y.z] | [License] | [CVE-YYYY-NNNNN] | [YYYY-MM-DD] | + +## Supply Chain Risk Assessment + +> Aligns with NIST AI 600-1 Category 12: Value Chain and Component Integration. + +- **Overall Risk Level**: [Low/Medium/High/Critical] + +- **Key Risks Identified**: + - [Risk 1: Description] + - [Risk 2: Description] + - [Risk 3: Description] + +- **Mitigations**: + - [Mitigation 1: Description] + - [Mitigation 2: Description] + - [Mitigation 3: Description] + +- **Monitoring Plan**: + - [Monitoring activity 1: Frequency and responsible party] + - [Monitoring activity 2: Frequency and responsible party] + - [Monitoring activity 3: Frequency and responsible party] + + diff --git a/dist/.devtrail/templates/TEMPLATE-SEC.md b/dist/.devtrail/templates/TEMPLATE-SEC.md new file mode 100644 index 0000000..339d6ce --- /dev/null +++ b/dist/.devtrail/templates/TEMPLATE-SEC.md @@ -0,0 +1,171 @@ +--- +id: SEC-YYYY-MM-DD-NNN +title: "[System/Component] Security Assessment" +status: draft +created: YYYY-MM-DD +agent: [agent-name] +confidence: medium +review_required: true +risk_level: high +eu_ai_act_risk: not_applicable # unacceptable | high | limited | minimal | not_applicable +iso_42001_clause: [6, 8] +threat_model_methodology: STRIDE # STRIDE | PASTA | LINDDUN | custom +owasp_asvs_level: 1 # 1 | 2 | 3 +tags: [security] +related: [] +--- + +# SEC: [System/Component] Security Assessment + +> **IMPORTANT**: This document is a DRAFT created by an AI agent. +> It requires human review and approval before proceeding. + +## Scope and Objectives + +| Field | Value | +|-------|-------| +| System Under Assessment | [Name and version of the system or component] | +| Assessment Type | [design review / code review / penetration test / threat model] | +| Assessment Date | [YYYY-MM-DD] | +| Assessor | [Agent name or human assessor] | + +**Objectives**: + +- [Primary objective of this security assessment] +- [Secondary objective, if applicable] + +**In Scope**: + +- [Component, service, or boundary included] +- [Component, service, or boundary included] + +**Out of Scope**: + +- [Component, service, or boundary excluded] +- [Component, service, or boundary excluded] + +## Threat Model + +> Methodology: **STRIDE** (Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege). +> Replace with PASTA, LINDDUN, or custom as indicated in frontmatter. + +### Spoofing + +| Threat ID | Description | Likelihood (1-5) | Impact (1-5) | Risk Score | Mitigation | +|-----------|-------------|:-----------------:|:------------:|:----------:|------------| +| S-001 | [Threat description] | [1-5] | [1-5] | [L x I] | [Proposed mitigation] | +| S-002 | [Threat description] | [1-5] | [1-5] | [L x I] | [Proposed mitigation] | + +### Tampering + +| Threat ID | Description | Likelihood (1-5) | Impact (1-5) | Risk Score | Mitigation | +|-----------|-------------|:-----------------:|:------------:|:----------:|------------| +| T-001 | [Threat description] | [1-5] | [1-5] | [L x I] | [Proposed mitigation] | +| T-002 | [Threat description] | [1-5] | [1-5] | [L x I] | [Proposed mitigation] | + +### Repudiation + +| Threat ID | Description | Likelihood (1-5) | Impact (1-5) | Risk Score | Mitigation | +|-----------|-------------|:-----------------:|:------------:|:----------:|------------| +| R-001 | [Threat description] | [1-5] | [1-5] | [L x I] | [Proposed mitigation] | +| R-002 | [Threat description] | [1-5] | [1-5] | [L x I] | [Proposed mitigation] | + +### Information Disclosure + +| Threat ID | Description | Likelihood (1-5) | Impact (1-5) | Risk Score | Mitigation | +|-----------|-------------|:-----------------:|:------------:|:----------:|------------| +| I-001 | [Threat description] | [1-5] | [1-5] | [L x I] | [Proposed mitigation] | +| I-002 | [Threat description] | [1-5] | [1-5] | [L x I] | [Proposed mitigation] | + +### Denial of Service + +| Threat ID | Description | Likelihood (1-5) | Impact (1-5) | Risk Score | Mitigation | +|-----------|-------------|:-----------------:|:------------:|:----------:|------------| +| D-001 | [Threat description] | [1-5] | [1-5] | [L x I] | [Proposed mitigation] | +| D-002 | [Threat description] | [1-5] | [1-5] | [L x I] | [Proposed mitigation] | + +### Elevation of Privilege + +| Threat ID | Description | Likelihood (1-5) | Impact (1-5) | Risk Score | Mitigation | +|-----------|-------------|:-----------------:|:------------:|:----------:|------------| +| E-001 | [Threat description] | [1-5] | [1-5] | [L x I] | [Proposed mitigation] | +| E-002 | [Threat description] | [1-5] | [1-5] | [L x I] | [Proposed mitigation] | + +## OWASP ASVS Compliance + +> Reference: OWASP Application Security Verification Standard (ASVS) 5.0. +> Verify controls at the level indicated in frontmatter (`owasp_asvs_level`). + +| Control ID | Description | Level (L1/L2/L3) | Status | Evidence | Notes | +|------------|-------------|:-----------------:|:------:|----------|-------| +| V1.1.1 | [Architecture — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V2.1.1 | [Authentication — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V3.1.1 | [Session Management — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V4.1.1 | [Access Control — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V5.1.1 | [Validation — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V6.1.1 | [Stored Cryptography — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V7.1.1 | [Error Handling and Logging — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V8.1.1 | [Data Protection — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V9.1.1 | [Communication — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V10.1.1 | [Malicious Code — description of control] | L2 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V11.1.1 | [Business Logic — description of control] | L2 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V12.1.1 | [Files and Resources — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V13.1.1 | [API and Web Service — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V14.1.1 | [Configuration — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V50.1.1 | [OAuth and OIDC — description of control] | L1 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V51.1.1 | [Self-Contained Tokens — description of control] | L2 | [Pass / Fail / NA] | [Link or reference] | [Notes] | +| V52.1.1 | [SAML — description of control] | L2 | [Pass / Fail / NA] | [Link or reference] | [Notes] | + +> Add or remove rows as needed. Focus on controls relevant to the system under assessment. + +## Vulnerabilities Found + +| Vuln ID | CWE | Severity (CVSS) | Description | Affected Component | Remediation | Status | +|---------|-----|:----------------:|-------------|-------------------|-------------|:------:| +| VULN-001 | [CWE-XXX] | [0.0-10.0] | [Vulnerability description] | [Component or module] | [Remediation steps] | [open / mitigated / accepted] | +| VULN-002 | [CWE-XXX] | [0.0-10.0] | [Vulnerability description] | [Component or module] | [Remediation steps] | [open / mitigated / accepted] | +| VULN-003 | [CWE-XXX] | [0.0-10.0] | [Vulnerability description] | [Component or module] | [Remediation steps] | [open / mitigated / accepted] | + +## Security Controls + +> Reference: OWASP Software Assurance Maturity Model (SAMM). + +| Business Function | Practice | Maturity Level (1-3) | Current Status | Gaps | +|-------------------|----------|:--------------------:|----------------|------| +| Governance | Strategy and Metrics | [1-3] | [Description of current state] | [Identified gaps] | +| Governance | Policy and Compliance | [1-3] | [Description of current state] | [Identified gaps] | +| Governance | Education and Guidance | [1-3] | [Description of current state] | [Identified gaps] | +| Design | Threat Assessment | [1-3] | [Description of current state] | [Identified gaps] | +| Design | Security Requirements | [1-3] | [Description of current state] | [Identified gaps] | +| Design | Security Architecture | [1-3] | [Description of current state] | [Identified gaps] | +| Implementation | Secure Build | [1-3] | [Description of current state] | [Identified gaps] | +| Implementation | Secure Deployment | [1-3] | [Description of current state] | [Identified gaps] | +| Implementation | Defect Management | [1-3] | [Description of current state] | [Identified gaps] | +| Verification | Architecture Assessment | [1-3] | [Description of current state] | [Identified gaps] | +| Verification | Requirements-driven Testing | [1-3] | [Description of current state] | [Identified gaps] | +| Verification | Security Testing | [1-3] | [Description of current state] | [Identified gaps] | +| Operations | Incident Management | [1-3] | [Description of current state] | [Identified gaps] | +| Operations | Environment Management | [1-3] | [Description of current state] | [Identified gaps] | +| Operations | Operational Management | [1-3] | [Description of current state] | [Identified gaps] | + +## Recommendations + +| Priority | Description | Effort | Impact | +|:--------:|-------------|:------:|:------:| +| Critical | [Recommendation description] | [Low / Medium / High] | [Low / Medium / High] | +| High | [Recommendation description] | [Low / Medium / High] | [Low / Medium / High] | +| Medium | [Recommendation description] | [Low / Medium / High] | [Low / Medium / High] | +| Low | [Recommendation description] | [Low / Medium / High] | [Low / Medium / High] | + +--- + +## Approval + +| Field | Value | +|-------|-------| +| Approved by | [Name] | +| Date | [YYYY-MM-DD] | +| Decision | [APPROVED / REJECTED / CONDITIONAL] | +| Conditions | [If applicable] | + + diff --git a/dist/.devtrail/templates/i18n/es/TEMPLATE-DPIA.md b/dist/.devtrail/templates/i18n/es/TEMPLATE-DPIA.md new file mode 100644 index 0000000..a6e3aff --- /dev/null +++ b/dist/.devtrail/templates/i18n/es/TEMPLATE-DPIA.md @@ -0,0 +1,97 @@ +--- +id: DPIA-YYYY-MM-DD-NNN +title: "[Sistema/Proceso] Evaluación de Impacto en Protección de Datos" +status: draft +created: YYYY-MM-DD +agent: [agent-name] +confidence: low # La DPIA requiere juicio humano extenso +review_required: true # Siempre obligatorio +risk_level: high +eu_ai_act_risk: not_applicable # unacceptable | high | limited | minimal | not_applicable +gdpr_article_35: true # Art. 35 RGPD activa la DPIA +iso_42001_clause: [6, 8] +dpo_consulted: false +supervisory_authority_consulted: false +tags: [privacy, gdpr, dpia] +related: [] +--- + +# DPIA: [Sistema/Proceso] Evaluación de Impacto en Protección de Datos + +> **IMPORTANTE**: Este documento es un BORRADOR creado por un agente de IA. +> Requiere revisión y aprobación humana antes de proceder. + +## Descripción del Tratamiento + +- **Naturaleza del Tratamiento**: [Describir cómo se recogen, almacenan, usan y eliminan los datos] +- **Alcance**: [Escala del tratamiento — número de interesados, volumen, ámbito geográfico] +- **Contexto**: [Relación entre el responsable del tratamiento y los interesados, expectativas] +- **Finalidad**: [Finalidad específica de la actividad de tratamiento] +- **Base Legal (Art. 6 RGPD)**: [consentimiento / contrato / obligación_legal / intereses_vitales / interés_público / intereses_legítimos] +- **Categorías de Interesados**: [Empleados, clientes, menores, pacientes, etc.] +- **Categorías de Datos Personales**: [Nombre, email, datos de salud, datos biométricos, ubicación, etc.] +- **Destinatarios**: [Quién recibe o tiene acceso a los datos] +- **Transferencias Internacionales**: [Países/regiones, mecanismos de transferencia (CCT, decisiones de adecuación, NCV)] +- **Período de Retención**: [Cuánto tiempo se conservan los datos y criterios para determinar la retención] + +## Necesidad y Proporcionalidad + +- **Evaluación de Necesidad**: [Por qué este tratamiento es necesario para lograr la finalidad declarada] +- **Limitación de Finalidad**: [Cómo se limita el tratamiento solo a la finalidad declarada] +- **Minimización de Datos**: [Cómo solo se recogen y tratan los datos mínimos necesarios] +- **Limitación de Almacenamiento**: [Cómo se limita la retención de datos a lo necesario] +- **Calidad de Datos**: [Cómo se asegura la exactitud e integridad de los datos] + +## Evaluación de Riesgos + +### Riesgos para los Interesados + +| Riesgo | Probabilidad | Severidad | Nivel de Riesgo | Fuente del Riesgo | Naturaleza del Impacto | +|--------|-------------|----------|-----------------|-------------------|----------------------| +| [Riesgo 1] | [Bajo/Medio/Alto] | [Bajo/Medio/Alto] | [Bajo/Medio/Alto] | [Fuente] | [físico/material/no material] | +| [Riesgo 2] | [Bajo/Medio/Alto] | [Bajo/Medio/Alto] | [Bajo/Medio/Alto] | [Fuente] | [físico/material/no material] | +| [Riesgo 3] | [Bajo/Medio/Alto] | [Bajo/Medio/Alto] | [Bajo/Medio/Alto] | [Fuente] | [físico/material/no material] | + +### Riesgos para los Derechos y Libertades + +| Riesgo | Probabilidad | Severidad | Nivel de Riesgo | Fuente del Riesgo | Naturaleza del Impacto | +|--------|-------------|----------|-----------------|-------------------|----------------------| +| [Riesgo 1] | [Bajo/Medio/Alto] | [Bajo/Medio/Alto] | [Bajo/Medio/Alto] | [Fuente] | [físico/material/no material] | +| [Riesgo 2] | [Bajo/Medio/Alto] | [Bajo/Medio/Alto] | [Bajo/Medio/Alto] | [Fuente] | [físico/material/no material] | + +## Medidas para Mitigar Riesgos + +| Riesgo | Medida | Tipo | Riesgo Residual | Responsable | +|--------|--------|------|-----------------|-------------| +| [Riesgo 1] | [Medida de mitigación] | [técnica/organizativa/legal] | [Bajo/Medio/Alto] | [Rol/Persona] | +| [Riesgo 2] | [Medida de mitigación] | [técnica/organizativa/legal] | [Bajo/Medio/Alto] | [Rol/Persona] | +| [Riesgo 3] | [Medida de mitigación] | [técnica/organizativa/legal] | [Bajo/Medio/Alto] | [Rol/Persona] | + +## Consulta + +> Si el riesgo residual permanece alto después de la mitigación, la consulta con la autoridad de control es obligatoria según el Art. 36 RGPD. + +- **Opinión del Delegado de Protección de Datos**: [Opinión y recomendaciones del DPD] +- **Interesados Consultados**: [Sí/No] — [Metodología: encuestas, grupos focales, consulta pública, etc.] +- **Autoridad de Control Consultada**: [Sí/No] — [Número de referencia o detalles si aplica] + +## Consideraciones Específicas de IA + +> Completar esta sección cuando el tratamiento involucre sistemas de IA, particularmente bajo EU AI Act. + +- **Toma de Decisiones Automatizada (Art. 22 RGPD)**: [¿El tratamiento implica toma de decisiones exclusivamente automatizada con efectos legales o significativos? Describir salvaguardas] +- **Derecho a una Explicación**: [Cómo los interesados pueden obtener información significativa sobre la lógica involucrada] +- **Medidas de Supervisión Humana**: [Describir mecanismos de humano-en-el-bucle o humano-sobre-el-bucle] +- **Transparencia hacia los Interesados**: [Cómo se informa a los interesados sobre la participación de IA en el tratamiento de sus datos] + +## Calendario de Revisión + +- **Próxima Fecha de Revisión**: [YYYY-MM-DD] +- **Eventos que Activan Revisión**: + - [Cambio en el alcance o finalidad del tratamiento] + - [Nuevas categorías de datos personales] + - [Cambios regulatorios] + - [Incidentes de seguridad] +- **Responsable de la Revisión**: [Rol/Persona responsable de realizar la revisión] + + diff --git a/dist/.devtrail/templates/i18n/es/TEMPLATE-MCARD.md b/dist/.devtrail/templates/i18n/es/TEMPLATE-MCARD.md new file mode 100644 index 0000000..cbc4df6 --- /dev/null +++ b/dist/.devtrail/templates/i18n/es/TEMPLATE-MCARD.md @@ -0,0 +1,158 @@ +--- +id: MCARD-YYYY-MM-DD-NNN +title: "[Nombre del Modelo] Card" +status: draft +created: YYYY-MM-DD +agent: [agent-name] +confidence: medium +review_required: true +risk_level: medium +eu_ai_act_risk: not_applicable # unacceptable | high | limited | minimal | not_applicable +nist_genai_risks: [] # privacy | bias | confabulation | cbrn | dangerous_content | environmental | human_ai_config | information_integrity | information_security | intellectual_property | obscene_content | value_chain +iso_42001_clause: [8] +model_name: "" +model_type: LLM # LLM | classifier | regressor | generator | recommender | other +model_version: "" +provider: "" +license: "" +tags: [ai-model] +related: [] +--- + +# MCARD: [Nombre del Modelo] Card + +> **IMPORTANTE**: Este documento es un BORRADOR creado por un agente de IA. +> Requiere revisión y aprobación humana antes de proceder. + +## Detalles del Modelo + +> Basado en Mitchell et al. (2019) — "Model Cards for Model Reporting". + +| Campo | Valor | +|-------|-------| +| Desarrollador | [Organización o individuo que desarrolló el modelo] | +| Fecha del Modelo | [YYYY-MM-DD — fecha en que el modelo fue entrenado o publicado] | +| Versión del Modelo | [Identificador de versión] | +| Tipo de Modelo | [LLM / clasificador / regresor / generador / recomendador / otro] | +| Algoritmos de Entrenamiento | [Algoritmo(s) utilizados para el entrenamiento] | +| Modelo Base | [Nombre y versión del modelo base, si es fine-tuned; N/A en caso contrario] | +| Publicación / Recurso | [URL o cita al artículo, blog o documentación] | +| Cita | [BibTeX o cita en texto plano] | +| Licencia | [Licencia del modelo — ej., Apache 2.0, MIT, propietaria] | + +## Uso Previsto + +### Usos Principales Previstos + +- [Caso de uso principal 1] +- [Caso de uso principal 2] + +### Usuarios Principales Previstos + +- [Grupo de usuarios 1] +- [Grupo de usuarios 2] + +### Usos Fuera del Alcance + +- [Caso de uso para el que el modelo NO está diseñado 1] +- [Caso de uso para el que el modelo NO está diseñado 2] + +## Datos de Entrenamiento + +> Para interoperabilidad con SBOM, considerar alinear con los campos de CycloneDX `modelCard.modelParameters`. + +| Campo | Valor | +|-------|-------| +| Nombre del Dataset | [Nombre del dataset de entrenamiento] | +| Fuente | [Dónde se obtuvieron los datos] | +| Tamaño | [Número de muestras, tokens o tamaño de almacenamiento] | +| Metodología de Recolección | [Cómo se recolectaron los datos] | +| Preprocesamiento | [Pasos de limpieza, filtrado y aumento aplicados] | +| Limitaciones Conocidas | [Sesgos, vacíos o problemas de calidad en los datos] | +| Evaluación de PII | [Si hay PII presente y cómo se manejó] | +| Licencia | [Licencia que rige los datos de entrenamiento] | + +## Métricas de Rendimiento + +| Métrica | Valor | Dataset de Prueba | Intervalo de Confianza | Condiciones | +|---------|:-----:|-------------------|:----------------------:|-------------| +| [Accuracy / F1 / BLEU / etc.] | [Valor] | [Nombre del dataset y split] | [Rango IC 95%] | [Condiciones o configuración] | +| [Métrica 2] | [Valor] | [Nombre del dataset y split] | [Rango IC 95%] | [Condiciones o configuración] | +| [Métrica 3] | [Valor] | [Nombre del dataset y split] | [Rango IC 95%] | [Condiciones o configuración] | + +### Evaluación Desagregada + +> Reportar rendimiento desglosado por subgrupos relevantes cuando aplique. + +| Subgrupo | Métrica | Valor | Comparación con Línea Base | +|----------|---------|:-----:|:--------------------------:| +| [Subgrupo 1] | [Métrica] | [Valor] | [+/- vs general] | +| [Subgrupo 2] | [Métrica] | [Valor] | [+/- vs general] | + +## Evaluación de Sesgo y Equidad + +| Grupo Demográfico | Métrica | Rendimiento | Disparidad vs Línea Base | Mitigación Aplicada | +|--------------------|---------|:-----------:|:------------------------:|--------------------| +| [Grupo 1 — ej., rango de edad, género, etnia] | [Métrica] | [Valor] | [+/- porcentaje o absoluto] | [Descripción de mitigación] | +| [Grupo 2] | [Métrica] | [Valor] | [+/- porcentaje o absoluto] | [Descripción de mitigación] | +| [Grupo 3] | [Métrica] | [Valor] | [+/- porcentaje o absoluto] | [Descripción de mitigación] | + +## Impacto Ambiental + +| Métrica | Valor | Notas | +|---------|-------|-------| +| Energía de Entrenamiento (kWh) | [Valor] | [Metodología o fuente de estimación] | +| Equivalente de CO2 (toneladas) | [Valor] | [Intensidad de carbono de la red utilizada] | +| Hardware Utilizado | [GPUs/TPUs, cantidad, modelo] | [Proveedor de nube / región] | +| Duración del Entrenamiento | [Horas / días] | [Tiempo total de cómputo] | +| Costo de Inferencia | [Costo por solicitud o por 1K tokens] | [Promedio / pico] | +| Región / Intensidad de Carbono de la Red | [Nombre de la región] | [gCO2/kWh] | + +## Consideraciones de Seguridad + +| Preocupación | Evaluación | Detalles | +|--------------|:----------:|---------| +| Vulnerabilidades Conocidas | [Ninguna / Descripción] | [Referencias CVE o descripción de problemas conocidos] | +| Robustez Adversarial | [Baja / Media / Alta] | [Metodología de evaluación y resultados] | +| Riesgo de Inyección de Prompt | [Bajo / Medio / Alto] | [Evaluación de susceptibilidad a inyección de prompt] | +| Riesgo de Envenenamiento de Datos | [Bajo / Medio / Alto] | [Evaluación de integridad de datos de entrenamiento] | +| Riesgo de Extracción del Modelo | [Bajo / Medio / Alto] | [Riesgo de que los pesos o comportamiento del modelo sean extraídos] | + +## Consideraciones Éticas + +- **Datos Sensibles Utilizados**: [Si se usaron datos sensibles o personales en el entrenamiento y cómo se manejaron] +- **Sujetos Humanos en Entrenamiento**: [Si se involucraron sujetos humanos en la recolección de datos; estado de revisión IRB o comité de ética] +- **Potencial de Uso Dual**: [Si el modelo podría reutilizarse para aplicaciones dañinas; salvaguardas implementadas] +- **Evaluación de Impacto Social**: [Implicaciones sociales más amplias — positivas y negativas] + +## Limitaciones y Recomendaciones + +### Limitaciones Conocidas + +- [Limitación 1 — ej., bajo rendimiento en idiomas o dominios específicos] +- [Limitación 2 — ej., restricciones de ventana de contexto] +- [Limitación 3 — ej., tendencia a alucinar en escenarios específicos] + +### Modos de Falla + +- [Modo de falla 1 — condiciones bajo las cuales el modelo falla de manera predecible] +- [Modo de falla 2 — casos extremos o entradas adversariales] + +### Recomendaciones para Implementadores + +- [Recomendación 1 — ej., implementar filtrado de salidas] +- [Recomendación 2 — ej., configurar humano-en-el-bucle para decisiones de alto riesgo] +- [Recomendación 3 — ej., monitorear la degradación a lo largo del tiempo] + +--- + +## Aprobación + +| Campo | Valor | +|-------|-------| +| Aprobado por | [Nombre] | +| Fecha | [YYYY-MM-DD] | +| Decisión | [APROBADO / RECHAZADO / CONDICIONAL] | +| Condiciones | [Si aplica] | + + diff --git a/dist/.devtrail/templates/i18n/es/TEMPLATE-SBOM.md b/dist/.devtrail/templates/i18n/es/TEMPLATE-SBOM.md new file mode 100644 index 0000000..fbd1884 --- /dev/null +++ b/dist/.devtrail/templates/i18n/es/TEMPLATE-SBOM.md @@ -0,0 +1,77 @@ +--- +id: SBOM-YYYY-MM-DD-NNN +title: "[Sistema/Componente] SBOM de IA" +status: accepted +created: YYYY-MM-DD +agent: [agent-name] +confidence: high +review_required: false # Inventario factual +risk_level: low +iso_42001_clause: [8] +sbom_format_reference: SPDX-3.0 | CycloneDX-1.6 | custom +system_name: "" +tags: [sbom, supply-chain] +related: [] +--- + +# SBOM: [Sistema/Componente] Lista de Materiales de Software para IA + +## Componentes de IA/ML + +> Esta sección se mapea a CycloneDX `component` con `type: machine-learning-model`. + +| Nombre del Componente | Versión | Proveedor | Tipo | Licencia | Nivel de Riesgo | Estado de Vulnerabilidades | Última Auditoría | +|-----------------------|---------|-----------|------|----------|-----------------|---------------------------|------------------| +| [Componente 1] | [x.y.z] | [Proveedor] | modelo | [Licencia] | [Bajo/Medio/Alto] | [Limpio/Vulnerable] | [YYYY-MM-DD] | +| [Componente 2] | [x.y.z] | [Proveedor] | librería | [Licencia] | [Bajo/Medio/Alto] | [Limpio/Vulnerable] | [YYYY-MM-DD] | +| [Componente 3] | [x.y.z] | [Proveedor] | servicio | [Licencia] | [Bajo/Medio/Alto] | [Limpio/Vulnerable] | [YYYY-MM-DD] | +| [Componente 4] | [x.y.z] | [Proveedor] | dataset | [Licencia] | [Bajo/Medio/Alto] | [Limpio/Vulnerable] | [YYYY-MM-DD] | + +## Fuentes de Datos de Entrenamiento + +> Alineado con ISO 42001 Anexo A.7 (Datos para Sistemas de IA). + +| Dataset | Fuente | Licencia | PII Incluida | Resumen de Evaluación de Sesgo | Procedencia de Datos | Política de Retención | +|---------|--------|----------|--------------|-------------------------------|---------------------|----------------------| +| [Dataset 1] | [Fuente] | [Licencia] | [Sí/No] | [Resumen] | [Procedencia] | [Política] | +| [Dataset 2] | [Fuente] | [Licencia] | [Sí/No] | [Resumen] | [Procedencia] | [Política] | + +## Servicios de IA de Terceros + +| Servicio | Proveedor | Propósito | Datos Compartidos | DPA Vigente | SLA | Región | Certificaciones de Cumplimiento | +|----------|-----------|-----------|-------------------|-------------|-----|--------|--------------------------------| +| [Servicio 1] | [Proveedor] | [Propósito] | [Tipos de datos] | [Sí/No] | [Términos SLA] | [Región] | [SOC2, ISO 27001, etc.] | +| [Servicio 2] | [Proveedor] | [Propósito] | [Tipos de datos] | [Sí/No] | [Términos SLA] | [Región] | [SOC2, ISO 27001, etc.] | + +## Dependencias de Software + +> Considerar generar esta sección automáticamente con herramientas como `syft` o `trivy`. + +| Paquete | Versión | Licencia | Vulnerabilidades Conocidas | Última Actualización | +|---------|---------|----------|---------------------------|---------------------| +| [Paquete 1] | [x.y.z] | [Licencia] | [CVE-YYYY-NNNNN, ...] | [YYYY-MM-DD] | +| [Paquete 2] | [x.y.z] | [Licencia] | [Ninguna] | [YYYY-MM-DD] | +| [Paquete 3] | [x.y.z] | [Licencia] | [CVE-YYYY-NNNNN] | [YYYY-MM-DD] | + +## Evaluación de Riesgo de Cadena de Suministro + +> Alineado con NIST AI 600-1 Categoría 12: Cadena de Valor e Integración de Componentes. + +- **Nivel de Riesgo General**: [Bajo/Medio/Alto/Crítico] + +- **Riesgos Clave Identificados**: + - [Riesgo 1: Descripción] + - [Riesgo 2: Descripción] + - [Riesgo 3: Descripción] + +- **Mitigaciones**: + - [Mitigación 1: Descripción] + - [Mitigación 2: Descripción] + - [Mitigación 3: Descripción] + +- **Plan de Monitoreo**: + - [Actividad de monitoreo 1: Frecuencia y responsable] + - [Actividad de monitoreo 2: Frecuencia y responsable] + - [Actividad de monitoreo 3: Frecuencia y responsable] + + diff --git a/dist/.devtrail/templates/i18n/es/TEMPLATE-SEC.md b/dist/.devtrail/templates/i18n/es/TEMPLATE-SEC.md new file mode 100644 index 0000000..dbb6136 --- /dev/null +++ b/dist/.devtrail/templates/i18n/es/TEMPLATE-SEC.md @@ -0,0 +1,171 @@ +--- +id: SEC-YYYY-MM-DD-NNN +title: "[Sistema/Componente] Evaluación de Seguridad" +status: draft +created: YYYY-MM-DD +agent: [agent-name] +confidence: medium +review_required: true +risk_level: high +eu_ai_act_risk: not_applicable # unacceptable | high | limited | minimal | not_applicable +iso_42001_clause: [6, 8] +threat_model_methodology: STRIDE # STRIDE | PASTA | LINDDUN | custom +owasp_asvs_level: 1 # 1 | 2 | 3 +tags: [security] +related: [] +--- + +# SEC: [Sistema/Componente] Evaluación de Seguridad + +> **IMPORTANTE**: Este documento es un BORRADOR creado por un agente de IA. +> Requiere revisión y aprobación humana antes de proceder. + +## Alcance y Objetivos + +| Campo | Valor | +|-------|-------| +| Sistema Evaluado | [Nombre y versión del sistema o componente] | +| Tipo de Evaluación | [revisión de diseño / revisión de código / prueba de penetración / modelo de amenazas] | +| Fecha de Evaluación | [YYYY-MM-DD] | +| Evaluador | [Nombre del agente o evaluador humano] | + +**Objetivos**: + +- [Objetivo principal de esta evaluación de seguridad] +- [Objetivo secundario, si aplica] + +**Dentro del Alcance**: + +- [Componente, servicio o frontera incluido] +- [Componente, servicio o frontera incluido] + +**Fuera del Alcance**: + +- [Componente, servicio o frontera excluido] +- [Componente, servicio o frontera excluido] + +## Modelo de Amenazas + +> Metodología: **STRIDE** (Suplantación, Manipulación, Repudio, Divulgación de Información, Denegación de Servicio, Elevación de Privilegios). +> Reemplazar con PASTA, LINDDUN o personalizado según se indique en el frontmatter. + +### Suplantación (Spoofing) + +| ID Amenaza | Descripción | Probabilidad (1-5) | Impacto (1-5) | Puntuación de Riesgo | Mitigación | +|------------|-------------|:-------------------:|:-------------:|:--------------------:|------------| +| S-001 | [Descripción de la amenaza] | [1-5] | [1-5] | [P x I] | [Mitigación propuesta] | +| S-002 | [Descripción de la amenaza] | [1-5] | [1-5] | [P x I] | [Mitigación propuesta] | + +### Manipulación (Tampering) + +| ID Amenaza | Descripción | Probabilidad (1-5) | Impacto (1-5) | Puntuación de Riesgo | Mitigación | +|------------|-------------|:-------------------:|:-------------:|:--------------------:|------------| +| T-001 | [Descripción de la amenaza] | [1-5] | [1-5] | [P x I] | [Mitigación propuesta] | +| T-002 | [Descripción de la amenaza] | [1-5] | [1-5] | [P x I] | [Mitigación propuesta] | + +### Repudio (Repudiation) + +| ID Amenaza | Descripción | Probabilidad (1-5) | Impacto (1-5) | Puntuación de Riesgo | Mitigación | +|------------|-------------|:-------------------:|:-------------:|:--------------------:|------------| +| R-001 | [Descripción de la amenaza] | [1-5] | [1-5] | [P x I] | [Mitigación propuesta] | +| R-002 | [Descripción de la amenaza] | [1-5] | [1-5] | [P x I] | [Mitigación propuesta] | + +### Divulgación de Información (Information Disclosure) + +| ID Amenaza | Descripción | Probabilidad (1-5) | Impacto (1-5) | Puntuación de Riesgo | Mitigación | +|------------|-------------|:-------------------:|:-------------:|:--------------------:|------------| +| I-001 | [Descripción de la amenaza] | [1-5] | [1-5] | [P x I] | [Mitigación propuesta] | +| I-002 | [Descripción de la amenaza] | [1-5] | [1-5] | [P x I] | [Mitigación propuesta] | + +### Denegación de Servicio (Denial of Service) + +| ID Amenaza | Descripción | Probabilidad (1-5) | Impacto (1-5) | Puntuación de Riesgo | Mitigación | +|------------|-------------|:-------------------:|:-------------:|:--------------------:|------------| +| D-001 | [Descripción de la amenaza] | [1-5] | [1-5] | [P x I] | [Mitigación propuesta] | +| D-002 | [Descripción de la amenaza] | [1-5] | [1-5] | [P x I] | [Mitigación propuesta] | + +### Elevación de Privilegios (Elevation of Privilege) + +| ID Amenaza | Descripción | Probabilidad (1-5) | Impacto (1-5) | Puntuación de Riesgo | Mitigación | +|------------|-------------|:-------------------:|:-------------:|:--------------------:|------------| +| E-001 | [Descripción de la amenaza] | [1-5] | [1-5] | [P x I] | [Mitigación propuesta] | +| E-002 | [Descripción de la amenaza] | [1-5] | [1-5] | [P x I] | [Mitigación propuesta] | + +## Cumplimiento OWASP ASVS + +> Referencia: OWASP Application Security Verification Standard (ASVS) 5.0. +> Verificar controles al nivel indicado en el frontmatter (`owasp_asvs_level`). + +| ID Control | Descripción | Nivel (L1/L2/L3) | Estado | Evidencia | Notas | +|------------|-------------|:-----------------:|:------:|-----------|-------| +| V1.1.1 | [Arquitectura — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V2.1.1 | [Autenticación — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V3.1.1 | [Gestión de Sesiones — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V4.1.1 | [Control de Acceso — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V5.1.1 | [Validación — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V6.1.1 | [Criptografía Almacenada — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V7.1.1 | [Manejo de Errores y Registro — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V8.1.1 | [Protección de Datos — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V9.1.1 | [Comunicaciones — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V10.1.1 | [Código Malicioso — descripción del control] | L2 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V11.1.1 | [Lógica de Negocio — descripción del control] | L2 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V12.1.1 | [Archivos y Recursos — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V13.1.1 | [API y Servicios Web — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V14.1.1 | [Configuración — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V50.1.1 | [OAuth y OIDC — descripción del control] | L1 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V51.1.1 | [Tokens Autocontenidos — descripción del control] | L2 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | +| V52.1.1 | [SAML — descripción del control] | L2 | [Pasa / Falla / NA] | [Enlace o referencia] | [Notas] | + +> Agregar o eliminar filas según sea necesario. Enfocarse en los controles relevantes para el sistema evaluado. + +## Vulnerabilidades Encontradas + +| ID Vuln | CWE | Severidad (CVSS) | Descripción | Componente Afectado | Remediación | Estado | +|---------|-----|:----------------:|-------------|---------------------|-------------|:------:| +| VULN-001 | [CWE-XXX] | [0.0-10.0] | [Descripción de la vulnerabilidad] | [Componente o módulo] | [Pasos de remediación] | [abierta / mitigada / aceptada] | +| VULN-002 | [CWE-XXX] | [0.0-10.0] | [Descripción de la vulnerabilidad] | [Componente o módulo] | [Pasos de remediación] | [abierta / mitigada / aceptada] | +| VULN-003 | [CWE-XXX] | [0.0-10.0] | [Descripción de la vulnerabilidad] | [Componente o módulo] | [Pasos de remediación] | [abierta / mitigada / aceptada] | + +## Controles de Seguridad + +> Referencia: OWASP Software Assurance Maturity Model (SAMM). + +| Función de Negocio | Práctica | Nivel de Madurez (1-3) | Estado Actual | Brechas | +|---------------------|----------|:----------------------:|---------------|---------| +| Gobernanza | Estrategia y Métricas | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Gobernanza | Política y Cumplimiento | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Gobernanza | Educación y Orientación | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Diseño | Evaluación de Amenazas | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Diseño | Requisitos de Seguridad | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Diseño | Arquitectura de Seguridad | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Implementación | Construcción Segura | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Implementación | Despliegue Seguro | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Implementación | Gestión de Defectos | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Verificación | Evaluación de Arquitectura | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Verificación | Pruebas Basadas en Requisitos | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Verificación | Pruebas de Seguridad | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Operaciones | Gestión de Incidentes | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Operaciones | Gestión de Entorno | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | +| Operaciones | Gestión Operativa | [1-3] | [Descripción del estado actual] | [Brechas identificadas] | + +## Recomendaciones + +| Prioridad | Descripción | Esfuerzo | Impacto | +|:---------:|-------------|:--------:|:-------:| +| Crítica | [Descripción de la recomendación] | [Bajo / Medio / Alto] | [Bajo / Medio / Alto] | +| Alta | [Descripción de la recomendación] | [Bajo / Medio / Alto] | [Bajo / Medio / Alto] | +| Media | [Descripción de la recomendación] | [Bajo / Medio / Alto] | [Bajo / Medio / Alto] | +| Baja | [Descripción de la recomendación] | [Bajo / Medio / Alto] | [Bajo / Medio / Alto] | + +--- + +## Aprobación + +| Campo | Valor | +|-------|-------| +| Aprobado por | [Nombre] | +| Fecha | [YYYY-MM-DD] | +| Decisión | [APROBADO / RECHAZADO / CONDICIONAL] | +| Condiciones | [Si aplica] | + + diff --git a/dist/.gemini/skills/devtrail-mcard/SKILL.md b/dist/.gemini/skills/devtrail-mcard/SKILL.md new file mode 100644 index 0000000..5fba11b --- /dev/null +++ b/dist/.gemini/skills/devtrail-mcard/SKILL.md @@ -0,0 +1,320 @@ +--- +name: devtrail-mcard +description: Create a Model/System Card (MCARD) document through an interactive step-by-step flow. Guides the user through each section with specific questions and example responses. +--- + +# DevTrail MCARD Skill + +Create AI Model/System Card documentation through an interactive guided flow. + +## Instructions + +When invoked, follow these steps: + +### 1. Check for Parameters + +If the user specified a model name (e.g., `/devtrail-mcard GPT-4o`), use it as the model name and proceed to step 2 asking only for the model type. + +If no parameter is given, proceed to step 2 asking for both model name and type. + +### 2. Gather Model Identity + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ DevTrail MCARD — Model/System Card ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Step 1/7: Model Identity ║ +║ ║ +║ Please provide the following: ║ +║ ║ +║ 1. Model name: [e.g., "GPT-4o", "BERT-base-uncased"] ║ +║ 2. Model type: ║ +║ • LLM — Large Language Model ║ +║ • classifier — Classification model ║ +║ • regressor — Regression model ║ +║ • generator — Generative model (image, audio, etc.) ║ +║ • recommender — Recommendation system ║ +║ • other — Specify ║ +║ 3. Provider: [e.g., "OpenAI", "Google", "Hugging Face"] ║ +║ 4. Version: [e.g., "2024-05-13", "v1.0", "gpt-4o-2024-05-13"] ║ +║ 5. License: [e.g., "Proprietary", "Apache 2.0", "MIT"] ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 3. Gather Intended Use + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 2/7: Intended Use ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ 1. Primary intended uses: ║ +║ Example: "Code generation", "Customer support chatbot", ║ +║ "Sentiment analysis on product reviews" ║ +║ ║ +║ 2. Primary intended users: ║ +║ Example: "Internal engineering team", "End users via API", ║ +║ "Data science team" ║ +║ ║ +║ 3. Out-of-scope uses (what the model should NOT be used for): ║ +║ Example: "Medical diagnosis", "Legal advice", ║ +║ "Autonomous decision-making without human review" ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 4. Gather Training Data Details + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 3/7: Training Data ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ 1. Dataset name: [e.g., "Common Crawl", "Internal corpus v3"] ║ +║ 2. Source: [e.g., "Web scraping", "Licensed data provider"] ║ +║ 3. Size: [e.g., "1.5T tokens", "500K samples", "200GB"] ║ +║ 4. Collection methodology: ║ +║ Example: "Web crawling with quality filters" ║ +║ 5. Preprocessing steps: ║ +║ Example: "Deduplication, PII removal, language filtering" ║ +║ 6. Known limitations in the data: ║ +║ Example: "English-centric, underrepresents African languages" ║ +║ 7. PII assessment: ║ +║ Example: "PII filtered using regex + NER; residual risk low" ║ +║ 8. Data license: [e.g., "CC-BY-4.0", "Proprietary"] ║ +║ ║ +║ Type "unknown" or "N/A" for fields you cannot fill. ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 5. Gather Performance and Evaluation + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 4/7: Performance & Evaluation ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Performance Metrics (provide at least one): ║ +║ Format: Metric | Value | Test Dataset | Conditions ║ +║ Example: "Accuracy | 92.3% | MMLU | 5-shot" ║ +║ "F1 | 0.87 | SQuAD v2 | zero-shot" ║ +║ "BLEU | 34.2 | WMT-22 en-de | beam search k=5" ║ +║ ║ +║ Disaggregated evaluation (optional): ║ +║ Format: Subgroup | Metric | Value ║ +║ Example: "English | Accuracy | 95.1%" ║ +║ "Spanish | Accuracy | 88.4%" ║ +║ ║ +║ Type "unknown" if metrics are not available. ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 6. Gather Bias, Security, and Ethics + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 5/7: Bias, Security & Ethics ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Bias & Fairness (if evaluated): ║ +║ Format: Group | Metric | Performance | Mitigation ║ +║ Example: "Female | Toxicity | 0.02 | Content filter applied" ║ +║ Type "not evaluated" if no bias analysis was performed. ║ +║ ║ +║ Security Concerns: ║ +║ • Known vulnerabilities: [None / describe] ║ +║ • Adversarial robustness: [Low / Medium / High] ║ +║ • Prompt injection risk: [Low / Medium / High / N/A] ║ +║ • Data poisoning risk: [Low / Medium / High] ║ +║ • Model extraction risk: [Low / Medium / High] ║ +║ ║ +║ Ethical Considerations: ║ +║ • Was sensitive data used in training? [Yes / No / Unknown] ║ +║ • Human subjects involved? [Yes / No / Unknown] ║ +║ • Dual-use potential? [Yes / No] ║ +║ • Societal impact notes: [Brief description] ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 7. Gather Environmental Impact + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 6/7: Environmental Impact ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ 1. Training energy (kWh): [e.g., "1,287 kWh", "Unknown"] ║ +║ 2. CO2 equivalent (tons): [e.g., "0.58 tCO2", "Unknown"] ║ +║ 3. Hardware used: [e.g., "8x NVIDIA A100 80GB"] ║ +║ 4. Training duration: [e.g., "72 hours", "Unknown"] ║ +║ 5. Inference cost: [e.g., "$0.005 per 1K tokens", "Unknown"] ║ +║ 6. Region / Grid carbon intensity: [e.g., "US-East", "Unknown"] ║ +║ ║ +║ Type "unknown" for fields you cannot fill. ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 8. Gather Limitations and Recommendations + +Ask the user: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ Step 7/7: Limitations & Recommendations ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Known limitations: ║ +║ Example: "Poor performance on low-resource languages", ║ +║ "Context window limited to 128K tokens", ║ +║ "Hallucination rate ~5% on factual queries" ║ +║ ║ +║ Known failure modes: ║ +║ Example: "Produces incorrect math on multi-step problems", ║ +║ "May refuse safe queries due to over-filtering" ║ +║ ║ +║ Recommendations for deployers: ║ +║ Example: "Implement output filtering for PII", ║ +║ "Use human-in-the-loop for high-stakes decisions", ║ +║ "Monitor for performance drift monthly" ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ +``` + +Wait for user response before proceeding. + +### 9. Determine Regulatory Classifications + +Based on the gathered information, determine: + +- **EU AI Act risk level**: Classify based on intended use: + - `unacceptable`: social scoring, real-time biometric identification + - `high`: employment decisions, credit scoring, law enforcement, education + - `limited`: chatbots, emotion recognition, deepfake generation + - `minimal`: spam filters, game AI, search optimization + - `not_applicable`: no EU deployment planned + +- **NIST GenAI risks**: Select applicable risks from: + `privacy`, `bias`, `confabulation`, `cbrn`, `dangerous_content`, `environmental`, `human_ai_config`, `information_integrity`, `information_security`, `intellectual_property`, `obscene_content`, `value_chain` + +- **Overall risk level**: `low`, `medium`, `high`, or `critical` + +### 10. Check Language Configuration + +Read `.devtrail/config.yml` to determine language: + +```yaml +language: en # or es +``` + +Use template path based on language: +- `en` (default): `.devtrail/templates/TEMPLATE-MCARD.md` +- `es`: `.devtrail/templates/i18n/es/TEMPLATE-MCARD.md` + +### 11. Generate Document ID + +Determine the next sequence number: + +```bash +# Get current date +date +%Y-%m-%d + +# Find existing MCARD documents for today +ls .devtrail/09-ai-models/MCARD-$(date +%Y-%m-%d)-*.md 2>/dev/null | wc -l +``` + +ID format: `MCARD-YYYY-MM-DD-NNN` + +### 12. Confirm Before Creating + +Display a summary and ask for confirmation: + +``` +╔══════════════════════════════════════════════════════════════════╗ +║ DevTrail MCARD — Summary ║ +╠══════════════════════════════════════════════════════════════════╣ +║ ║ +║ Model: [model_name] ([model_type]) ║ +║ Provider: [provider] — Version: [version] ║ +║ EU AI Act Risk: [risk classification] ║ +║ NIST GenAI Risks: [applicable risks] ║ +║ Overall Risk: [risk level] ║ +║ ║ +║ Proposed filename: ║ +║ MCARD-YYYY-MM-DD-NNN-[model-name-slug].md ║ +║ ║ +║ Location: ║ +║ .devtrail/09-ai-models/ ║ +║ ║ +║ Review required: YES ║ +║ ║ +╚══════════════════════════════════════════════════════════════════╝ + +Confirm creation? [Y/n]: +``` + +Wait for user confirmation before proceeding. + +### 13. Load Template and Create Document + +1. Read the appropriate template (EN or ES based on config) +2. Replace placeholders: + - `YYYY-MM-DD` -> Current date + - `NNN` -> Sequence number (001, 002, etc.) + - `[agent-name]` -> `gemini-cli-v1.0` + - `[Model Name]` -> User-provided model name +3. Fill in all sections with the gathered information +4. Set `review_required: true` in the frontmatter +5. Save to `.devtrail/09-ai-models/MCARD-YYYY-MM-DD-NNN-[model-name-slug].md` + +### 14. Report Result + +After creation, display: + +``` +DevTrail MCARD created: + .devtrail/09-ai-models/MCARD-YYYY-MM-DD-NNN-[description].md + + Model: [model_name] ([model_type]) + Provider: [provider] + Review required: yes + Risk level: [risk_level] + EU AI Act: [classification] +``` + +## Edge Cases + +1. **No `.devtrail/09-ai-models/` directory**: Create it before saving +2. **User provides partial information**: Fill known fields, mark unknown fields with `[To be determined]` +3. **User declines confirmation**: Acknowledge and exit gracefully +4. **Third-party model with limited info**: Mark unknown sections with `[Information not publicly available]` and note in limitations +5. **No `.devtrail/config.yml`**: Default to English (`en`) diff --git a/dist/.gemini/skills/devtrail-new/SKILL.md b/dist/.gemini/skills/devtrail-new/SKILL.md index 0ca7ba5..0459dd4 100644 --- a/dist/.gemini/skills/devtrail-new/SKILL.md +++ b/dist/.gemini/skills/devtrail-new/SKILL.md @@ -15,7 +15,7 @@ When invoked, follow these steps: If the user specified a document type (e.g., `/devtrail-new ailog`), skip to step 4 using that type. -Valid types: `ailog`, `aidec`, `adr`, `eth`, `req`, `tes`, `inc`, `tde` +Valid types: `ailog`, `aidec`, `adr`, `eth`, `req`, `tes`, `inc`, `tde`, `sec`, `mcard`, `sbom`, `dpia` ### 2. Analyze Context @@ -41,7 +41,7 @@ Based on the analysis, suggest a document type: | Pattern | Suggested Type | |---------|---------------| -| New code in `src/`, `lib/`, `app/` (>10 lines) | AILOG | +| New code in `src/`, `lib/`, `app/` (>20 lines) | AILOG | | Multiple implementation alternatives discussed | AIDEC | | Structural/architectural changes, new modules | ADR | | Files with `auth`, `user`, `privacy`, `gdpr` | ETH (draft) | @@ -120,6 +120,10 @@ ID format: `[TYPE]-YYYY-MM-DD-NNN` | TES | `.devtrail/04-testing/` | | INC | `.devtrail/05-operations/incidents/` | | TDE | `.devtrail/06-evolution/technical-debt/` | +| SEC | `.devtrail/08-security/` | +| MCARD | `.devtrail/09-ai-models/` | +| SBOM | `.devtrail/07-ai-audit/` | +| DPIA | `.devtrail/07-ai-audit/ethical-reviews/` | ### 8. Report Result @@ -145,6 +149,10 @@ After creation, display: | `tes` | Test Plan | Test strategies and plans | | `inc` | Incident Post-mortem | Incident analysis | | `tde` | Technical Debt | Identified technical debt | +| `sec` | Security Assessment | Threat modeling and security controls | +| `mcard` | Model/System Card | AI model documentation | +| `sbom` | Software Bill of Materials | AI component inventory | +| `dpia` | Data Protection Impact Assessment | Privacy impact analysis | ## Edge Cases diff --git a/dist/.gemini/skills/devtrail-sec/SKILL.md b/dist/.gemini/skills/devtrail-sec/SKILL.md new file mode 100644 index 0000000..64dc89c --- /dev/null +++ b/dist/.gemini/skills/devtrail-sec/SKILL.md @@ -0,0 +1,296 @@ +--- +name: devtrail-sec +description: Create a DevTrail Security Assessment (SEC) document. Interactive step-by-step flow that gathers scope, threat model methodology, and OWASP ASVS level, then generates a pre-filled SEC document based on code context. Always marks as draft with review_required. +--- + +# DevTrail Security Assessment Skill + +Create a Security Assessment document with threat modeling and OWASP ASVS compliance checks. + +## Instructions + +When invoked via `/devtrail-sec [component-name]`, follow these steps: + +### 1. Gather Assessment Scope + +If the user provided a `[component-name]`, use it as the system/component under assessment. + +If no component was specified, **ask the user**: + +``` +What system or component would you like to assess? +Examples: "authentication API", "payment gateway", "user data pipeline" +``` + +Wait for the user to respond before proceeding. + +### 2. Ask Threat Model Methodology + +Present the available methodologies and ask the user to choose: + +``` +Which threat modeling methodology would you like to use? + + 1. STRIDE (recommended) - Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege + 2. PASTA - Process for Attack Simulation and Threat Analysis + 3. LINDDUN - Linkability, Identifiability, Non-repudiation, Detectability, Disclosure, Unawareness, Non-compliance + 4. Custom - Define your own methodology + +Select [1/2/3/4] (default: 1): +``` + +Wait for the user to respond before proceeding. + +### 3. Ask Target OWASP ASVS Level + +Ask the user to select the verification level: + +``` +Which OWASP ASVS verification level should be targeted? + + L1 - Opportunistic: Basic security controls (default for most apps) + L2 - Standard: For apps handling sensitive data + L3 - Advanced: For critical infrastructure, medical, financial systems + +Select [L1/L2/L3] (default: L1): +``` + +Wait for the user to respond before proceeding. + +### 4. Analyze Code Context + +Gather information about the component: + +```bash +# Get current date +date +%Y-%m-%d + +# Get modified files (staged and unstaged) +git status --porcelain + +# Get recent changes summary +git diff --stat HEAD~1 2>/dev/null || git diff --stat + +# Count lines changed +git diff --numstat HEAD~1 2>/dev/null || git diff --numstat +``` + +Also scan the codebase for security-relevant patterns in the component area: +- Authentication/authorization code +- Input validation +- Cryptographic operations +- Network/API endpoints +- Data storage and access patterns +- Dependency files (package.json, Cargo.toml, requirements.txt, etc.) + +### 5. Confirm with User + +**Always display this confirmation before creating:** + +``` ++------------------------------------------------------------------+ +| DevTrail Security Assessment | ++------------------------------------------------------------------+ +| | +| Component: [component-name] | +| Methodology: [STRIDE / PASTA / LINDDUN / custom] | +| ASVS Level: [L1 / L2 / L3] | +| | +| Code Context: | +| Files scanned: [N] | +| Security-relevant patterns: [list] | +| | +| Proposed filename: | +| SEC-YYYY-MM-DD-NNN-[description].md | +| | ++------------------------------------------------------------------+ + +Confirm creation? [Y/n]: +``` + +Wait for user confirmation before proceeding. + +### 6. Check Language Configuration + +Read `.devtrail/config.yml` to determine language: + +```yaml +language: en # or es +``` + +Use template path based on language: +- `en` (default): `.devtrail/templates/TEMPLATE-SEC.md` +- `es`: `.devtrail/templates/i18n/es/TEMPLATE-SEC.md` + +### 7. Generate Document ID + +Determine the next sequence number: + +```bash +# Find existing SEC documents for today +ls .devtrail/08-security/SEC-$(date +%Y-%m-%d)-*.md 2>/dev/null | wc -l +``` + +ID format: `SEC-YYYY-MM-DD-NNN` + +### 8. Load Template and Create Document + +1. Read the appropriate template +2. Replace placeholders: + - `YYYY-MM-DD` -> Current date + - `NNN` -> Sequence number (001, 002, etc.) + - `[agent-name]` -> `gemini-cli-v1.0` + - `[System/Component]` -> The component name from step 1 + - `threat_model_methodology: STRIDE` -> The methodology chosen in step 2 + - `owasp_asvs_level: 1` -> The ASVS level chosen in step 3 +3. Pre-fill fields based on code context analysis: + - Populate "Scope and Objectives" with detected component boundaries + - Fill threat model rows with identified threats from code patterns + - Mark relevant OWASP ASVS controls based on detected patterns + - List discovered vulnerabilities or potential weaknesses +4. Ensure frontmatter contains: + - `status: draft` + - `review_required: true` + - `risk_level: high` + - `confidence: medium` +5. Save to: `.devtrail/08-security/SEC-YYYY-MM-DD-NNN-[description].md` + +### 9. Report Result + +After creation, display: + +``` +DevTrail Security Assessment created: + .devtrail/08-security/SEC-YYYY-MM-DD-NNN-description.md + + Status: draft + Review required: yes + Risk level: high + Methodology: [STRIDE / PASTA / LINDDUN / custom] + ASVS Level: [L1 / L2 / L3] + + IMPORTANT: This is a DRAFT. A qualified security reviewer must + validate all findings before any remediation decisions are made. +``` + +## Expected Output Example + +For invocation `/devtrail-sec authentication-api`, after the interactive flow selects STRIDE and L1, the generated document would look like: + +```markdown +--- +id: SEC-2026-03-24-001 +title: "Authentication API Security Assessment" +status: draft +created: 2026-03-24 +agent: gemini-cli-v1.0 +confidence: medium +review_required: true +risk_level: high +eu_ai_act_risk: not_applicable +iso_42001_clause: [6, 8] +threat_model_methodology: STRIDE +owasp_asvs_level: 1 +tags: [security] +related: [] +--- + +# SEC: Authentication API Security Assessment + +> **IMPORTANT**: This document is a DRAFT created by an AI agent. +> It requires human review and approval before proceeding. + +## Scope and Objectives + +| Field | Value | +|-------|-------| +| System Under Assessment | Authentication API v1.0 | +| Assessment Type | code review / threat model | +| Assessment Date | 2026-03-24 | +| Assessor | gemini-cli-v1.0 | + +**Objectives**: + +- Identify authentication and session management vulnerabilities +- Validate input handling on login and token endpoints + +**In Scope**: + +- /api/auth/* endpoints +- JWT token generation and validation +- Password hashing and storage + +**Out of Scope**: + +- Frontend client code +- Third-party OAuth providers + +## Threat Model + +> Methodology: **STRIDE** + +### Spoofing + +| Threat ID | Description | Likelihood (1-5) | Impact (1-5) | Risk Score | Mitigation | +|-----------|-------------|:-----------------:|:------------:|:----------:|------------| +| S-001 | Credential stuffing on login endpoint | 4 | 4 | 16 | Rate limiting, account lockout | +| S-002 | JWT token forgery via weak signing key | 2 | 5 | 10 | Use RS256 with rotated keys | + +### Tampering + +| Threat ID | Description | Likelihood (1-5) | Impact (1-5) | Risk Score | Mitigation | +|-----------|-------------|:-----------------:|:------------:|:----------:|------------| +| T-001 | Parameter manipulation on password reset | 3 | 4 | 12 | Server-side validation, signed tokens | + +(... remaining STRIDE categories ...) + +## OWASP ASVS Compliance + +| Control ID | Description | Level (L1/L2/L3) | Status | Evidence | Notes | +|------------|-------------|:-----------------:|:------:|----------|-------| +| V2.1.1 | Verify password length >= 12 chars | L1 | Fail | src/auth/validation.rs:45 | Min length set to 8 | +| V3.1.1 | Verify session token generation uses CSPRNG | L1 | Pass | src/auth/session.rs:12 | Uses ring::rand | + +(... remaining relevant controls ...) + +## Vulnerabilities Found + +| Vuln ID | CWE | Severity (CVSS) | Description | Affected Component | Remediation | Status | +|---------|-----|:----------------:|-------------|-------------------|-------------|:------:| +| VULN-001 | CWE-521 | 5.3 | Weak password policy (min 8 chars) | auth/validation.rs | Enforce min 12 chars | open | + +## Security Controls + +| Business Function | Practice | Maturity Level (1-3) | Current Status | Gaps | +|-------------------|----------|:--------------------:|----------------|------| +| Implementation | Secure Build | 1 | Basic dependency scanning | No SAST configured | + +## Recommendations + +| Priority | Description | Effort | Impact | +|:--------:|-------------|:------:|:------:| +| High | Increase minimum password length to 12 characters | Low | Medium | +| High | Implement rate limiting on authentication endpoints | Medium | High | +| Medium | Add SAST to CI pipeline | Medium | Medium | + +--- + +## Approval + +| Field | Value | +|-------|-------| +| Approved by | [Name] | +| Date | [YYYY-MM-DD] | +| Decision | [APPROVED / REJECTED / CONDITIONAL] | +| Conditions | [If applicable] | + + +``` + +## Edge Cases + +1. **No git repository**: Inform user that git is required for context analysis +2. **Component not found in codebase**: Proceed with a generic assessment, note limited code context +3. **User declines**: Acknowledge and exit gracefully +4. **No security-relevant code found**: Generate template with empty threat rows for manual completion +5. **Multiple components match**: Ask user to clarify which specific component to assess diff --git a/dist/.gemini/skills/devtrail-status/SKILL.md b/dist/.gemini/skills/devtrail-status/SKILL.md index e61b95d..68299f2 100644 --- a/dist/.gemini/skills/devtrail-status/SKILL.md +++ b/dist/.gemini/skills/devtrail-status/SKILL.md @@ -20,10 +20,23 @@ Search for DevTrail documents created or modified in the last hour: git log --since="1 hour ago" --name-only --pretty=format: -- ".devtrail/**/*.md" | sort -u | grep -v "^$" ``` -If git is not available or the directory is not a git repo, use file modification times: -- Check `.devtrail/07-ai-audit/agent-logs/` for recent AILOG files -- Check `.devtrail/07-ai-audit/decisions/` for recent AIDEC files -- Check `.devtrail/07-ai-audit/ethical-reviews/` for recent ETH files +If git is not available or the directory is not a git repo, use file modification times. +Check these directories for each document type: + +| Type | Prefix | Directory | +|------|--------|-----------| +| AILOG | `AILOG-` | `.devtrail/07-ai-audit/agent-logs/` | +| AIDEC | `AIDEC-` | `.devtrail/07-ai-audit/decisions/` | +| ADR | `ADR-` | `.devtrail/04-architecture/decisions/` | +| ETH | `ETH-` | `.devtrail/07-ai-audit/ethical-reviews/` | +| REQ | `REQ-` | `.devtrail/03-requirements/` | +| TES | `TES-` | `.devtrail/05-testing/` | +| INC | `INC-` | `.devtrail/06-operations/incidents/` | +| TDE | `TDE-` | `.devtrail/06-operations/tech-debt/` | +| SEC | `SEC-` | `.devtrail/08-security/` | +| MCARD | `MCARD-` | `.devtrail/09-ai-models/` | +| SBOM | `SBOM-` | `.devtrail/07-ai-audit/` | +| DPIA | `DPIA-` | `.devtrail/07-ai-audit/ethical-reviews/` | ### 2. Find Modified Source Files @@ -42,7 +55,13 @@ Filter to show only files that might need documentation: For each modified source file, check if there's a corresponding DevTrail document: - Files with >10 lines of changes in business logic folders should have an AILOG -- Security-related files should have documentation with `risk_level: high` +- Security-related files (auth, crypto, secrets) should have a SEC assessment +- Architecture/structural changes should have an ADR +- AI/ML model changes should have a MCARD +- Dependency changes (`package.json`, `Cargo.toml`, `go.mod`, etc.) should have an SBOM +- Changes involving personal data processing should have a DPIA +- Test files should have a TES record +- Bug fixes or incidents should have an INC record ### 4. Display Results diff --git a/dist/.github/workflows/docs-validation.yml b/dist/.github/workflows/docs-validation.yml index 759fa46..b6714a7 100644 --- a/dist/.github/workflows/docs-validation.yml +++ b/dist/.github/workflows/docs-validation.yml @@ -37,7 +37,7 @@ jobs: # Checkout # ========================================================================= - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 # Required to compare with base branch @@ -45,7 +45,7 @@ jobs: # Setup Node.js (for markdownlint) # ========================================================================= - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: '20' @@ -286,6 +286,174 @@ jobs: echo "" echo "Files validated: ${{ steps.changed-files.outputs.all_changed_files_count }}" + # =========================================================================== + # Job: Compliance check + # =========================================================================== + compliance-check: + name: Compliance Check + runs-on: ubuntu-latest + needs: validate-docs + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v44 + with: + files: | + .devtrail/**/*.md + + - name: Verify high-risk documents have ETH reference + if: steps.changed-files.outputs.any_changed == 'true' + run: | + echo "📋 Checking compliance: high-risk documents must reference an ETH..." + ERRORS=0 + + EXCLUDED="PRINCIPLES.md|DOCUMENTATION-POLICY.md|AGENT-RULES.md|TEMPLATE-.*\.md|README.md|QUICK-REFERENCE.md|INDEX.md|GIT-BRANCHING-STRATEGY.md" + + for file in ${{ steps.changed-files.outputs.all_changed_files }}; do + filename=$(basename "$file") + + if echo "$filename" | grep -qE "$EXCLUDED"; then + continue + fi + + FRONTMATTER=$(sed -n '/^---$/,/^---$/p' "$file" | sed '1d;$d') + if [ -z "$FRONTMATTER" ]; then + continue + fi + + RISK_LEVEL=$(echo "$FRONTMATTER" | grep "^risk_level:" | head -1 | sed 's/risk_level: *//' | tr -d '\r' || true) + + if [ "$RISK_LEVEL" = "high" ] || [ "$RISK_LEVEL" = "critical" ]; then + RELATED=$(echo "$FRONTMATTER" | grep -A20 "^related:" | grep "^ *-" || true) + HAS_ETH=$(echo "$RELATED" | grep -i "ETH-" || true) + + if [ -z "$HAS_ETH" ]; then + echo "::warning file=$file::High-risk document ($RISK_LEVEL) has no ETH reference in 'related:'" + fi + fi + done + + echo "✅ Compliance check completed" + + - name: Verify EU AI Act high-risk documents have required section + if: steps.changed-files.outputs.any_changed == 'true' + run: | + echo "📋 Checking EU AI Act compliance..." + + EXCLUDED="PRINCIPLES.md|DOCUMENTATION-POLICY.md|AGENT-RULES.md|TEMPLATE-.*\.md|README.md|QUICK-REFERENCE.md|INDEX.md|GIT-BRANCHING-STRATEGY.md" + + for file in ${{ steps.changed-files.outputs.all_changed_files }}; do + filename=$(basename "$file") + + if echo "$filename" | grep -qE "$EXCLUDED"; then + continue + fi + + FRONTMATTER=$(sed -n '/^---$/,/^---$/p' "$file" | sed '1d;$d') + if [ -z "$FRONTMATTER" ]; then + continue + fi + + EU_RISK=$(echo "$FRONTMATTER" | grep "^eu_ai_act_risk:" | head -1 | sed 's/eu_ai_act_risk: *//' | tr -d '\r' || true) + + if [ "$EU_RISK" = "high" ]; then + BODY=$(sed -n '/^---$/,/^---$/!p' "$file" | tail -n +2) + if ! echo "$BODY" | grep -qi "EU AI Act"; then + echo "::warning file=$file::eu_ai_act_risk is 'high' but document lacks 'EU AI Act Considerations' section" + fi + fi + done + + echo "✅ EU AI Act compliance check completed" + + # =========================================================================== + # Job: Governance metrics (only on push to main) + # =========================================================================== + governance-metrics: + name: Governance Metrics + runs-on: ubuntu-latest + needs: validate-docs + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Generate governance metrics report + run: | + echo "📊 Generating governance metrics..." + + DEVTRAIL_DIR=".devtrail" + TYPES=("AILOG" "AIDEC" "ADR" "ETH" "REQ" "TES" "INC" "TDE" "SEC" "MCARD" "SBOM" "DPIA") + + # Header + echo "## DevTrail Governance Metrics" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "Generated: $(date -u +"%Y-%m-%d %H:%M UTC")" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + + # Document counts by type + echo "### Documents by Type" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "| Type | Count |" >> "$GITHUB_STEP_SUMMARY" + echo "|------|------:|" >> "$GITHUB_STEP_SUMMARY" + + TOTAL=0 + for TYPE in "${TYPES[@]}"; do + COUNT=$(find "$DEVTRAIL_DIR" -name "${TYPE}-*.md" -not -path "*/templates/*" 2>/dev/null | wc -l) + TOTAL=$((TOTAL + COUNT)) + echo "| $TYPE | $COUNT |" >> "$GITHUB_STEP_SUMMARY" + done + echo "| **TOTAL** | **$TOTAL** |" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + + # Documents from the last 7 days + echo "### Recent Documents (last 7 days)" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + WEEK_AGO=$(date -u -d "7 days ago" +%Y-%m-%d 2>/dev/null || date -u -v-7d +%Y-%m-%d 2>/dev/null || echo "0000-00-00") + RECENT=$(find "$DEVTRAIL_DIR" -name "*.md" -not -path "*/templates/*" -newer <(date -d "$WEEK_AGO" +%s 2>/dev/null || echo /dev/null) 2>/dev/null | wc -l || echo 0) + echo "Documents created/modified in the last 7 days: **$RECENT**" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + + # Risk level distribution + echo "### Risk Level Distribution" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "| Risk Level | Count |" >> "$GITHUB_STEP_SUMMARY" + echo "|------------|------:|" >> "$GITHUB_STEP_SUMMARY" + + for RISK in low medium high critical; do + RISK_COUNT=$(grep -rl "^risk_level: *$RISK" "$DEVTRAIL_DIR" --include="*.md" 2>/dev/null | grep -v templates | wc -l) + echo "| $RISK | $RISK_COUNT |" >> "$GITHUB_STEP_SUMMARY" + done + echo "" >> "$GITHUB_STEP_SUMMARY" + + # Review compliance rate + echo "### Review Compliance" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + HIGH_RISK_DOCS=$(grep -rl "^risk_level: *\(high\|critical\)" "$DEVTRAIL_DIR" --include="*.md" 2>/dev/null | grep -v templates || true) + HIGH_COUNT=$(echo "$HIGH_RISK_DOCS" | grep -c . 2>/dev/null || echo 0) + if [ "$HIGH_COUNT" -gt 0 ]; then + REVIEWED=0 + for doc in $HIGH_RISK_DOCS; do + if grep -q "^review_required: *true" "$doc" 2>/dev/null; then + REVIEWED=$((REVIEWED + 1)) + fi + done + RATE=$((REVIEWED * 100 / HIGH_COUNT)) + echo "High/critical risk documents with review_required: true: **$REVIEWED / $HIGH_COUNT ($RATE%)**" >> "$GITHUB_STEP_SUMMARY" + else + echo "No high/critical risk documents found." >> "$GITHUB_STEP_SUMMARY" + fi + + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "✅ Governance metrics generated" + # =========================================================================== # Job: Generate documentation index (only on main) # =========================================================================== @@ -297,7 +465,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Generate documentation index run: | diff --git a/dist/dist-manifest.yml b/dist/dist-manifest.yml index 1466b56..983df9c 100644 --- a/dist/dist-manifest.yml +++ b/dist/dist-manifest.yml @@ -1,4 +1,4 @@ -version: "3.0.0" +version: "3.1.0" description: "DevTrail distribution manifest" repository: "https://github.com/StrangeDaysTech/devtrail" diff --git a/dist/scripts/devtrail-new.sh b/dist/scripts/devtrail-new.sh index 1ec07eb..d964f0e 100644 --- a/dist/scripts/devtrail-new.sh +++ b/dist/scripts/devtrail-new.sh @@ -1,7 +1,7 @@ #!/bin/bash # devtrail-new.sh - Create DevTrail documentation manually # Usage: ./scripts/devtrail-new.sh [type] [title] [slug] -# Types: ailog, aidec, adr, eth, req, tes, inc, tde +# Types: ailog, aidec, adr, eth, req, tes, inc, tde, sec, mcard, sbom, dpia # # Examples: # ./scripts/devtrail-new.sh # fully interactive @@ -33,6 +33,10 @@ declare -A DOC_PATHS=( ["tes"]="$DEVTRAIL_DIR/04-testing" ["inc"]="$DEVTRAIL_DIR/05-operations/incidents" ["tde"]="$DEVTRAIL_DIR/06-evolution/technical-debt" + ["sec"]="$DEVTRAIL_DIR/08-security" + ["mcard"]="$DEVTRAIL_DIR/09-ai-models" + ["sbom"]="$DEVTRAIL_DIR/07-ai-audit" + ["dpia"]="$DEVTRAIL_DIR/07-ai-audit/ethical-reviews" ) declare -A DOC_NAMES=( @@ -44,6 +48,10 @@ declare -A DOC_NAMES=( ["tes"]="Test Plan" ["inc"]="Incident Post-mortem" ["tde"]="Technical Debt" + ["sec"]="Security Assessment" + ["mcard"]="Model/System Card" + ["sbom"]="Software Bill of Materials" + ["dpia"]="Data Protection Impact Assessment" ) # Check if .devtrail exists @@ -121,11 +129,15 @@ select_type() { echo -e "${BLUE}║ 6. tes - Test Plan ║${NC}" echo -e "${BLUE}║ 7. inc - Incident Post-mortem ║${NC}" echo -e "${BLUE}║ 8. tde - Technical Debt ║${NC}" + echo -e "${BLUE}║ 9. sec - Security Assessment ║${NC}" + echo -e "${BLUE}║ 10. mcard - Model/System Card ║${NC}" + echo -e "${BLUE}║ 11. sbom - Software Bill of Materials ║${NC}" + echo -e "${BLUE}║ 12. dpia - Data Protection Impact Assessment ║${NC}" echo -e "${BLUE}║ ║${NC}" echo -e "${BLUE}╚══════════════════════════════════════════════════════════════════╝${NC}" echo "" - read -p "Select type (1-8 or name): " type_input - + read -p "Select type (1-12 or name): " type_input + case $type_input in 1|ailog) echo "ailog" ;; 2|aidec) echo "aidec" ;; @@ -135,6 +147,10 @@ select_type() { 6|tes) echo "tes" ;; 7|inc) echo "inc" ;; 8|tde) echo "tde" ;; + 9|sec) echo "sec" ;; + 10|mcard) echo "mcard" ;; + 11|sbom) echo "sbom" ;; + 12|dpia) echo "dpia" ;; *) echo "" ;; esac } @@ -204,7 +220,7 @@ main() { # Validate type if [ -z "${DOC_PATHS[$type]}" ]; then echo -e "${RED}Error: Invalid type '$type'${NC}" - echo "Valid types: ailog, aidec, adr, eth, req, tes, inc, tde" + echo "Valid types: ailog, aidec, adr, eth, req, tes, inc, tde, sec, mcard, sbom, dpia" exit 1 fi diff --git a/dist/scripts/pre-commit-docs.sh b/dist/scripts/pre-commit-docs.sh index acdbff5..039761f 100644 --- a/dist/scripts/pre-commit-docs.sh +++ b/dist/scripts/pre-commit-docs.sh @@ -336,7 +336,76 @@ done echo "" # ============================================================================= -# 10. Run markdownlint if available +# 10. Validate related: references exist +# ============================================================================= + +echo "📋 Validating related document references..." + +for file in $STAGED_DOCS; do + filename=$(basename "$file") + + # Skip excluded files + if echo "$filename" | grep -qE "$EXCLUDED_FILES"; then + continue + fi + + FRONTMATTER=$(sed -n '/^---$/,/^---$/p' "$file" | sed '1d;$d') + + if [ -z "$FRONTMATTER" ]; then + continue + fi + + # Extract related items (lines starting with " - " after "related:") + RELATED=$(echo "$FRONTMATTER" | sed -n '/^related:/,/^[a-z]/p' | grep "^ *-" | sed 's/^ *- *//' | tr -d '\r') + + for ref in $RELATED; do + # Skip empty refs + if [ -z "$ref" ] || [ "$ref" = "[]" ]; then + continue + fi + + # Search for a file matching this reference + FOUND=$(find .devtrail -name "${ref}*" -not -path "*/templates/*" 2>/dev/null | head -1) + if [ -z "$FOUND" ]; then + echo -e " ${YELLOW}⚠ $filename: related document '$ref' not found in .devtrail/${NC}" + ((WARNINGS++)) + fi + done +done + +echo "" + +# ============================================================================= +# 11. Detect code changes without same-day AILOG (warning) +# ============================================================================= + +echo "📋 Checking for code changes without AILOG..." + +TODAY=$(date +%Y-%m-%d) + +# Check if there are staged code files (non-.devtrail, non-.md) +STAGED_CODE=$(git diff --cached --name-only --diff-filter=ACM | grep -vE "^\.devtrail/|\.md$|\.yml$|\.json$|\.gitkeep$" || true) + +if [ -n "$STAGED_CODE" ]; then + # Check if there's an AILOG for today + TODAY_AILOG=$(find .devtrail -name "AILOG-${TODAY}-*.md" -not -path "*/templates/*" 2>/dev/null | head -1) + + if [ -z "$TODAY_AILOG" ]; then + # Also check staged files for an AILOG + STAGED_AILOG=$(echo "$STAGED_DOCS" | grep "AILOG-${TODAY}" || true) + + if [ -z "$STAGED_AILOG" ]; then + echo -e " ${YELLOW}⚠ Code changes detected but no AILOG for today ($TODAY)${NC}" + echo -e " Consider creating one with: ./scripts/devtrail-new.sh ailog" + ((WARNINGS++)) + fi + fi +fi + +echo "" + +# ============================================================================= +# 12. Run markdownlint if available # ============================================================================= if command -v markdownlint &> /dev/null; then @@ -356,7 +425,7 @@ fi echo "" # ============================================================================= -# 11. Summary and result +# 13. Summary and result # ============================================================================= echo "═══════════════════════════════════════════════════════════════════════════" diff --git a/dist/scripts/validate-docs.ps1 b/dist/scripts/validate-docs.ps1 index c3121b0..3db1157 100644 --- a/dist/scripts/validate-docs.ps1 +++ b/dist/scripts/validate-docs.ps1 @@ -379,7 +379,85 @@ foreach ($file in $MarkdownFiles) { Write-Host "" # ============================================================================= -# 12. Summary +# 12. Validate related document references exist +# ============================================================================= + +Write-Host "📋 Validating related document references..." -ForegroundColor Cyan + +foreach ($file in $MarkdownFiles) { + $fileName = $file.Name + + if (Test-ExcludedFile -FileName $fileName) { + continue + } + + $content = Get-Content -Path $file.FullName -Raw -ErrorAction SilentlyContinue + + if (-not $content) { continue } + + if ($content -match "(?s)^---\r?\n(.+?)\r?\n---") { + $frontmatter = $Matches[1] + + # Extract related references + $relatedMatches = [regex]::Matches($frontmatter, "(?m)^\s*-\s+(\S+)") + $inRelated = $false + + foreach ($line in $frontmatter -split "`n") { + if ($line -match "^related:") { + $inRelated = $true + continue + } + if ($inRelated -and $line -match "^\s*-\s+(.+)$") { + $ref = $Matches[1].Trim() + if ($ref -eq "[]" -or [string]::IsNullOrWhiteSpace($ref)) { + continue + } + + $found = Get-ChildItem -Path $Path -Filter "$ref*" -Recurse -ErrorAction SilentlyContinue | + Where-Object { $_.FullName -notlike "*templates*" } | + Select-Object -First 1 + + if (-not $found) { + Write-Host " ⚠ $fileName`: related document '$ref' not found in .devtrail/" -ForegroundColor Yellow + $WarningCount++ + } + } elseif ($inRelated -and $line -match "^[a-z]") { + $inRelated = $false + } + } + } +} + +Write-Host "" + +# ============================================================================= +# 13. Detect code changes without same-day AILOG (warning) +# ============================================================================= + +Write-Host "📋 Checking for code changes without AILOG..." -ForegroundColor Cyan + +$today = Get-Date -Format "yyyy-MM-dd" + +# Check for staged code files (via git) +$stagedCode = git diff --cached --name-only --diff-filter=ACM 2>$null | + Where-Object { $_ -notmatch "^\.devtrail/" -and $_ -notmatch "\.(md|yml|json)$" -and $_ -ne ".gitkeep" } + +if ($stagedCode) { + $todayAilog = Get-ChildItem -Path $Path -Filter "AILOG-$today-*.md" -Recurse -ErrorAction SilentlyContinue | + Where-Object { $_.FullName -notlike "*templates*" } | + Select-Object -First 1 + + if (-not $todayAilog) { + Write-Host " ⚠ Code changes detected but no AILOG for today ($today)" -ForegroundColor Yellow + Write-Host " Consider creating one with: .\scripts\devtrail-new.sh ailog" -ForegroundColor Gray + $WarningCount++ + } +} + +Write-Host "" + +# ============================================================================= +# 14. Summary # ============================================================================= Write-Host "═══════════════════════════════════════════════════════════════════════════" -ForegroundColor Cyan diff --git a/evolution/plan-implementacion.md b/evolution/plan-implementacion.md index 140eb66..c3b8ee1 100644 --- a/evolution/plan-implementacion.md +++ b/evolution/plan-implementacion.md @@ -339,7 +339,7 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. ### F2.FW.01 — Crear TEMPLATE-SEC.md (Security Assessment) `P0` -- [ ] **F2.FW.01.01** — Diseñar frontmatter: +- [x] **F2.FW.01.01** — Diseñar frontmatter: ```yaml id: SEC-YYYY-MM-DD-NNN title: "[System/Component] Security Assessment" @@ -356,17 +356,17 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. tags: [security] related: [] ``` -- [ ] **F2.FW.01.02** — Crear sección `## Scope and Objectives` con: System Under Assessment, Assessment Type (design review/code review/penetration test/threat model), Assessment Date, Assessor -- [ ] **F2.FW.01.03** — Crear sección `## Threat Model` con subsecciones según metodología STRIDE: Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege. Cada una con tabla: Threat ID, Description, Likelihood (1-5), Impact (1-5), Risk Score, Mitigation -- [ ] **F2.FW.01.04** — Crear sección `## OWASP ASVS Compliance` con tabla de verificación de controles ASVS organizados por los 17 capítulos de ASVS 5.0. Campos: Control ID, Description, Level (L1/L2/L3), Status (Pass/Fail/NA), Evidence, Notes -- [ ] **F2.FW.01.05** — Crear sección `## Vulnerabilities Found` con tabla: Vuln ID, CWE, Severity (CVSS), Description, Affected Component, Remediation, Status (open/mitigated/accepted) -- [ ] **F2.FW.01.06** — Crear sección `## Security Controls` con tabla basada en OWASP SAMM: Business Function (Governance/Design/Implementation/Verification/Operations), Practice, Maturity Level (1-3), Current Status, Gaps -- [ ] **F2.FW.01.07** — Crear sección `## Recommendations` con: Priority, Description, Effort, Impact -- [ ] **F2.FW.01.08** — Crear versión ES del template +- [x] **F2.FW.01.02** — Crear sección `## Scope and Objectives` con: System Under Assessment, Assessment Type (design review/code review/penetration test/threat model), Assessment Date, Assessor +- [x] **F2.FW.01.03** — Crear sección `## Threat Model` con subsecciones según metodología STRIDE: Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege. Cada una con tabla: Threat ID, Description, Likelihood (1-5), Impact (1-5), Risk Score, Mitigation +- [x] **F2.FW.01.04** — Crear sección `## OWASP ASVS Compliance` con tabla de verificación de controles ASVS organizados por los 17 capítulos de ASVS 5.0. Campos: Control ID, Description, Level (L1/L2/L3), Status (Pass/Fail/NA), Evidence, Notes +- [x] **F2.FW.01.05** — Crear sección `## Vulnerabilities Found` con tabla: Vuln ID, CWE, Severity (CVSS), Description, Affected Component, Remediation, Status (open/mitigated/accepted) +- [x] **F2.FW.01.06** — Crear sección `## Security Controls` con tabla basada en OWASP SAMM: Business Function (Governance/Design/Implementation/Verification/Operations), Practice, Maturity Level (1-3), Current Status, Gaps +- [x] **F2.FW.01.07** — Crear sección `## Recommendations` con: Priority, Description, Effort, Impact +- [x] **F2.FW.01.08** — Crear versión ES del template ### F2.FW.02 — Crear TEMPLATE-MCARD.md (Model/System Card) `P0` -- [ ] **F2.FW.02.01** — Diseñar frontmatter: +- [x] **F2.FW.02.01** — Diseñar frontmatter: ```yaml id: MCARD-YYYY-MM-DD-NNN title: "[Model Name] Card" @@ -387,20 +387,20 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. tags: [ai-model] related: [] ``` -- [ ] **F2.FW.02.02** — Crear sección `## Model Details` (basada en Mitchell et al. 2019): Developer, Model Date, Model Version, Model Type, Training Algorithms, Base Model (if fine-tuned), Paper/Resource, Citation, License -- [ ] **F2.FW.02.03** — Crear sección `## Intended Use` con: Primary Intended Uses, Primary Intended Users, Out-of-Scope Uses -- [ ] **F2.FW.02.04** — Crear sección `## Training Data` con: Dataset Name, Source, Size, Collection Methodology, Preprocessing, Known Limitations, PII Assessment, License. Incluir nota sobre CycloneDX modelCard.modelParameters para interoperabilidad con SBOM -- [ ] **F2.FW.02.05** — Crear sección `## Performance Metrics` con tabla: Metric, Value, Test Dataset, Confidence Interval, Conditions. Separar por disaggregated evaluation si aplica -- [ ] **F2.FW.02.06** — Crear sección `## Bias and Fairness Evaluation` con tabla: Demographic Group, Metric, Performance, Disparity vs Baseline, Mitigation Applied -- [ ] **F2.FW.02.07** — Crear sección `## Environmental Impact` con: Training Energy (kWh), CO2 Equivalent, Hardware Used, Training Duration, Inference Cost, Region/Grid Carbon Intensity -- [ ] **F2.FW.02.08** — Crear sección `## Security Considerations` con: Known Vulnerabilities, Adversarial Robustness Assessment, Prompt Injection Risk (Low/Med/High), Data Poisoning Risk, Model Extraction Risk -- [ ] **F2.FW.02.09** — Crear sección `## Ethical Considerations` con: Sensitive Data Used, Human Subjects in Training, Dual-Use Potential, Societal Impact Assessment -- [ ] **F2.FW.02.10** — Crear sección `## Limitations and Recommendations` con: Known Limitations, Failure Modes, Recommendations for Deployers -- [ ] **F2.FW.02.11** — Crear versión ES del template +- [x] **F2.FW.02.02** — Crear sección `## Model Details` (basada en Mitchell et al. 2019): Developer, Model Date, Model Version, Model Type, Training Algorithms, Base Model (if fine-tuned), Paper/Resource, Citation, License +- [x] **F2.FW.02.03** — Crear sección `## Intended Use` con: Primary Intended Uses, Primary Intended Users, Out-of-Scope Uses +- [x] **F2.FW.02.04** — Crear sección `## Training Data` con: Dataset Name, Source, Size, Collection Methodology, Preprocessing, Known Limitations, PII Assessment, License. Incluir nota sobre CycloneDX modelCard.modelParameters para interoperabilidad con SBOM +- [x] **F2.FW.02.05** — Crear sección `## Performance Metrics` con tabla: Metric, Value, Test Dataset, Confidence Interval, Conditions. Separar por disaggregated evaluation si aplica +- [x] **F2.FW.02.06** — Crear sección `## Bias and Fairness Evaluation` con tabla: Demographic Group, Metric, Performance, Disparity vs Baseline, Mitigation Applied +- [x] **F2.FW.02.07** — Crear sección `## Environmental Impact` con: Training Energy (kWh), CO2 Equivalent, Hardware Used, Training Duration, Inference Cost, Region/Grid Carbon Intensity +- [x] **F2.FW.02.08** — Crear sección `## Security Considerations` con: Known Vulnerabilities, Adversarial Robustness Assessment, Prompt Injection Risk (Low/Med/High), Data Poisoning Risk, Model Extraction Risk +- [x] **F2.FW.02.09** — Crear sección `## Ethical Considerations` con: Sensitive Data Used, Human Subjects in Training, Dual-Use Potential, Societal Impact Assessment +- [x] **F2.FW.02.10** — Crear sección `## Limitations and Recommendations` con: Known Limitations, Failure Modes, Recommendations for Deployers +- [x] **F2.FW.02.11** — Crear versión ES del template ### F2.FW.03 — Crear TEMPLATE-SBOM.md (Software Bill of Materials para IA) `P0` -- [ ] **F2.FW.03.01** — Diseñar frontmatter: +- [x] **F2.FW.03.01** — Diseñar frontmatter: ```yaml id: SBOM-YYYY-MM-DD-NNN title: "[System/Component] AI SBOM" @@ -416,16 +416,16 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. tags: [sbom, supply-chain] related: [] ``` -- [ ] **F2.FW.03.02** — Crear sección `## AI/ML Components` con tabla: Component Name, Version, Provider, Type (model/library/service/dataset), License, Risk Level, Vulnerability Status, Last Audit Date. Nota: "This section maps to CycloneDX `component` with `type: machine-learning-model`" -- [ ] **F2.FW.03.03** — Crear sección `## Training Data Sources` con tabla: Dataset, Source, License, PII Included (Yes/No), Bias Assessment Summary, Data Provenance, Retention Policy. Nota: "Aligns with ISO 42001 Annex A.7 (Data for AI Systems)" -- [ ] **F2.FW.03.04** — Crear sección `## Third-Party AI Services` con tabla: Service, Provider, Purpose, Data Shared, DPA in Place (Yes/No), SLA, Region, Compliance Certifications -- [ ] **F2.FW.03.05** — Crear sección `## Software Dependencies` con tabla: Package, Version, License, Known Vulnerabilities (CVE list), Last Updated. Nota: "Consider generating this section automatically with tools like `syft` or `trivy`" -- [ ] **F2.FW.03.06** — Crear sección `## Supply Chain Risk Assessment` con: Overall Risk Level, Key Risks Identified, Mitigations, Monitoring Plan. Nota: "Aligns with NIST AI 600-1 Category 12: Value Chain and Component Integration" -- [ ] **F2.FW.03.07** — Crear versión ES del template +- [x] **F2.FW.03.02** — Crear sección `## AI/ML Components` con tabla: Component Name, Version, Provider, Type (model/library/service/dataset), License, Risk Level, Vulnerability Status, Last Audit Date. Nota: "This section maps to CycloneDX `component` with `type: machine-learning-model`" +- [x] **F2.FW.03.03** — Crear sección `## Training Data Sources` con tabla: Dataset, Source, License, PII Included (Yes/No), Bias Assessment Summary, Data Provenance, Retention Policy. Nota: "Aligns with ISO 42001 Annex A.7 (Data for AI Systems)" +- [x] **F2.FW.03.04** — Crear sección `## Third-Party AI Services` con tabla: Service, Provider, Purpose, Data Shared, DPA in Place (Yes/No), SLA, Region, Compliance Certifications +- [x] **F2.FW.03.05** — Crear sección `## Software Dependencies` con tabla: Package, Version, License, Known Vulnerabilities (CVE list), Last Updated. Nota: "Consider generating this section automatically with tools like `syft` or `trivy`" +- [x] **F2.FW.03.06** — Crear sección `## Supply Chain Risk Assessment` con: Overall Risk Level, Key Risks Identified, Mitigations, Monitoring Plan. Nota: "Aligns with NIST AI 600-1 Category 12: Value Chain and Component Integration" +- [x] **F2.FW.03.07** — Crear versión ES del template ### F2.FW.04 — Crear TEMPLATE-DPIA.md (Data Protection Impact Assessment) `P0` -- [ ] **F2.FW.04.01** — Diseñar frontmatter: +- [x] **F2.FW.04.01** — Diseñar frontmatter: ```yaml id: DPIA-YYYY-MM-DD-NNN title: "[System/Process] Data Protection Impact Assessment" @@ -443,24 +443,24 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. tags: [privacy, gdpr, dpia] related: [] ``` -- [ ] **F2.FW.04.02** — Crear sección `## Processing Description` con: Nature of Processing, Scope, Context, Purpose, Legal Basis (Art. 6 GDPR), Categories of Data Subjects, Categories of Personal Data, Recipients, International Transfers, Retention Period -- [ ] **F2.FW.04.03** — Crear sección `## Necessity and Proportionality` con: Necessity Assessment, Purpose Limitation, Data Minimization, Storage Limitation, Data Quality -- [ ] **F2.FW.04.04** — Crear sección `## Risk Assessment` con tabla: Risk, Likelihood (Low/Med/High), Severity (Low/Med/High), Risk Level, Source of Risk, Nature of Impact (physical/material/non-material). Separar por categorías: Risks to Data Subjects, Risks to Rights and Freedoms -- [ ] **F2.FW.04.05** — Crear sección `## Measures to Mitigate Risks` con tabla: Risk, Measure, Type (technical/organizational/legal), Residual Risk, Responsible -- [ ] **F2.FW.04.06** — Crear sección `## Consultation` con: Data Protection Officer Opinion, Data Subjects Consulted (Yes/No, methodology), Supervisory Authority Consulted (Yes/No, reference). Nota: "If residual risk remains high after mitigation, consultation with the supervisory authority is mandatory per Art. 36 GDPR" -- [ ] **F2.FW.04.07** — Crear sección `## AI-Specific Considerations` (cuando aplique EU AI Act): Automated Decision-Making (Art. 22 GDPR), Right to Explanation, Human Oversight Measures, Transparency to Data Subjects -- [ ] **F2.FW.04.08** — Crear sección `## Review Schedule` con: Next Review Date, Review Trigger Events, Review Responsible -- [ ] **F2.FW.04.09** — Crear versión ES del template +- [x] **F2.FW.04.02** — Crear sección `## Processing Description` con: Nature of Processing, Scope, Context, Purpose, Legal Basis (Art. 6 GDPR), Categories of Data Subjects, Categories of Personal Data, Recipients, International Transfers, Retention Period +- [x] **F2.FW.04.03** — Crear sección `## Necessity and Proportionality` con: Necessity Assessment, Purpose Limitation, Data Minimization, Storage Limitation, Data Quality +- [x] **F2.FW.04.04** — Crear sección `## Risk Assessment` con tabla: Risk, Likelihood (Low/Med/High), Severity (Low/Med/High), Risk Level, Source of Risk, Nature of Impact (physical/material/non-material). Separar por categorías: Risks to Data Subjects, Risks to Rights and Freedoms +- [x] **F2.FW.04.05** — Crear sección `## Measures to Mitigate Risks` con tabla: Risk, Measure, Type (technical/organizational/legal), Residual Risk, Responsible +- [x] **F2.FW.04.06** — Crear sección `## Consultation` con: Data Protection Officer Opinion, Data Subjects Consulted (Yes/No, methodology), Supervisory Authority Consulted (Yes/No, reference). Nota: "If residual risk remains high after mitigation, consultation with the supervisory authority is mandatory per Art. 36 GDPR" +- [x] **F2.FW.04.07** — Crear sección `## AI-Specific Considerations` (cuando aplique EU AI Act): Automated Decision-Making (Art. 22 GDPR), Right to Explanation, Human Oversight Measures, Transparency to Data Subjects +- [x] **F2.FW.04.08** — Crear sección `## Review Schedule` con: Next Review Date, Review Trigger Events, Review Responsible +- [x] **F2.FW.04.09** — Crear versión ES del template ### F2.FW.05 — Actualizar estructura de carpetas en dist/ `P1` > → depende de F2.FW.01 a F2.FW.04 -- [ ] **F2.FW.05.01** — Crear `dist/.devtrail/08-security/.gitkeep` -- [ ] **F2.FW.05.02** — Crear `dist/.devtrail/09-ai-models/.gitkeep` -- [ ] **F2.FW.05.03** — Agregar los 4 nuevos templates EN a `dist/.devtrail/templates/` -- [ ] **F2.FW.05.04** — Agregar los 4 nuevos templates ES a `dist/.devtrail/templates/i18n/es/` -- [ ] **F2.FW.05.05** — Actualizar `dist/dist-manifest.yml` con los nuevos archivos en sección `files` +- [x] **F2.FW.05.01** — Crear `dist/.devtrail/08-security/.gitkeep` +- [x] **F2.FW.05.02** — Crear `dist/.devtrail/09-ai-models/.gitkeep` +- [x] **F2.FW.05.03** — Agregar los 4 nuevos templates EN a `dist/.devtrail/templates/` +- [x] **F2.FW.05.04** — Agregar los 4 nuevos templates ES a `dist/.devtrail/templates/i18n/es/` +- [x] **F2.FW.05.05** — Actualizar `dist/dist-manifest.yml` con los nuevos archivos en sección `files` --- @@ -468,37 +468,37 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. ### F2.SK.01 — Crear skill `devtrail-sec` (Security Assessment) `P1` -- [ ] **F2.SK.01.01** — Crear `dist/.claude/skills/devtrail-sec/SKILL.md` con: +- [x] **F2.SK.01.01** — Crear `dist/.claude/skills/devtrail-sec/SKILL.md` con: - Invocación: `/devtrail-sec [component-name]` - Flujo interactivo paso a paso: (1) Preguntar alcance del assessment, (2) Preguntar metodología de threat model (STRIDE recomendado), (3) Preguntar nivel OWASP ASVS objetivo (L1/L2/L3), (4) Generar documento con campos pre-llenados basándose en el contexto del código, (5) Marcar como draft con review_required: true - Allowed tools: Read, Write, Glob, Bash (git, date) - Ejemplo completo de output esperado -- [ ] **F2.SK.01.02** — Crear `dist/.gemini/skills/devtrail-sec/SKILL.md` adaptado al formato Gemini -- [ ] **F2.SK.01.03** — Crear `dist/.agent/workflows/devtrail-sec.md` como workflow genérico +- [x] **F2.SK.01.02** — Crear `dist/.gemini/skills/devtrail-sec/SKILL.md` adaptado al formato Gemini +- [x] **F2.SK.01.03** — Crear `dist/.agent/workflows/devtrail-sec.md` como workflow genérico ### F2.SK.02 — Crear skill `devtrail-mcard` (Model Card) `P1` -- [ ] **F2.SK.02.01** — Crear `dist/.claude/skills/devtrail-mcard/SKILL.md` con: +- [x] **F2.SK.02.01** — Crear `dist/.claude/skills/devtrail-mcard/SKILL.md` con: - Invocación: `/devtrail-mcard [model-name]` - Flujo interactivo: (1) Preguntar nombre y tipo del modelo, (2) Preguntar proveedor y versión, (3) Preguntar usos previstos, (4) Guiar al usuario por cada sección con preguntas específicas y ejemplos de respuesta, (5) Generar documento con review_required: true - Incluir ejemplos de respuestas bien formadas para cada sección -- [ ] **F2.SK.02.02** — Crear versión Gemini -- [ ] **F2.SK.02.03** — Crear workflow genérico +- [x] **F2.SK.02.02** — Crear versión Gemini +- [x] **F2.SK.02.03** — Crear workflow genérico ### F2.SK.03 — Actualizar skill `devtrail-new` para 12 tipos `P1` -- [ ] **F2.SK.03.01** — En `dist/.claude/skills/devtrail-new/SKILL.md`: agregar SEC, MCARD, SBOM, DPIA al listado de tipos disponibles con descripciones y carpetas destino -- [ ] **F2.SK.03.02** — Replicar en `dist/.gemini/skills/devtrail-new/SKILL.md` -- [ ] **F2.SK.03.03** — Replicar en `dist/.agent/workflows/devtrail-new.md` +- [x] **F2.SK.03.01** — En `dist/.claude/skills/devtrail-new/SKILL.md`: agregar SEC, MCARD, SBOM, DPIA al listado de tipos disponibles con descripciones y carpetas destino +- [x] **F2.SK.03.02** — Replicar en `dist/.gemini/skills/devtrail-new/SKILL.md` +- [x] **F2.SK.03.03** — Replicar en `dist/.agent/workflows/devtrail-new.md` ### F2.SK.04 — Actualizar skill `devtrail-status` para 12 tipos `P1` -- [ ] **F2.SK.04.01** — Actualizar skills de status en las 3 plataformas para buscar y contar los 12 tipos +- [x] **F2.SK.04.01** — Actualizar skills de status en las 3 plataformas para buscar y contar los 12 tipos ### F2.SK.05 — Actualizar script `devtrail-new.sh` `P2` -- [ ] **F2.SK.05.01** — Agregar los 4 nuevos tipos al menú interactivo del script bash -- [ ] **F2.SK.05.02** — Agregar las carpetas destino correctas para cada nuevo tipo +- [x] **F2.SK.05.01** — Agregar los 4 nuevos tipos al menú interactivo del script bash +- [x] **F2.SK.05.02** — Agregar las carpetas destino correctas para cada nuevo tipo --- @@ -508,7 +508,7 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. > Este módulo será compartido por validate, compliance, metrics y audit. -- [ ] **F2.CLI.01.01** — Crear `cli/src/document.rs` con struct `DevTrailDocument`: +- [x] **F2.CLI.01.01** — Crear `cli/src/document.rs` con struct `DevTrailDocument`: ```rust pub struct DevTrailDocument { pub path: PathBuf, @@ -518,8 +518,8 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. pub body: String, } ``` -- [ ] **F2.CLI.01.02** — Crear enum `DocType` con los 12 tipos: AILOG, AIDEC, ADR, ETH, REQ, TES, INC, TDE, SEC, MCARD, SBOM, DPIA -- [ ] **F2.CLI.01.03** — Crear struct `Frontmatter` con todos los campos (obligatorios como `Option` para que el validador reporte cuáles faltan): +- [x] **F2.CLI.01.02** — Crear enum `DocType` con los 12 tipos: AILOG, AIDEC, ADR, ETH, REQ, TES, INC, TDE, SEC, MCARD, SBOM, DPIA +- [x] **F2.CLI.01.03** — Crear struct `Frontmatter` con todos los campos (obligatorios como `Option` para que el validador reporte cuáles faltan): ```rust pub struct Frontmatter { pub id: Option, @@ -538,15 +538,15 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. // ... campos adicionales por tipo } ``` -- [ ] **F2.CLI.01.04** — Implementar función `parse_document(path: &Path) -> Result` que: lea el archivo, extraiga frontmatter YAML entre `---`, parsee con serde_yaml, determine DocType por prefijo del filename -- [ ] **F2.CLI.01.05** — Implementar función `discover_documents(root: &Path) -> Vec` que recorra `.devtrail/` recursivamente y retorne archivos que matcheen el patrón de naming `TYPE-YYYY-MM-DD-NNN-*.md`, excluyendo templates y archivos de gobernanza -- [ ] **F2.CLI.01.06** — Agregar `pub mod document;` a `cli/src/main.rs` +- [x] **F2.CLI.01.04** — Implementar función `parse_document(path: &Path) -> Result` que: lea el archivo, extraiga frontmatter YAML entre `---`, parsee con serde_yaml, determine DocType por prefijo del filename +- [x] **F2.CLI.01.05** — Implementar función `discover_documents(root: &Path) -> Vec` que recorra `.devtrail/` recursivamente y retorne archivos que matcheen el patrón de naming `TYPE-YYYY-MM-DD-NNN-*.md`, excluyendo templates y archivos de gobernanza +- [x] **F2.CLI.01.06** — Agregar `pub mod document;` a `cli/src/main.rs` ### F2.CLI.02 — Implementar motor de validación `P0` > → depende de F2.CLI.01 -- [ ] **F2.CLI.02.01** — Crear `cli/src/validation.rs` con struct `ValidationResult`: +- [x] **F2.CLI.02.01** — Crear `cli/src/validation.rs` con struct `ValidationResult`: ```rust pub struct ValidationResult { pub errors: Vec, @@ -560,49 +560,49 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. pub fix_hint: Option, } ``` -- [ ] **F2.CLI.02.02** — Implementar regla `NAMING-001`: verificar que el nombre del archivo sigue el patrón `TYPE-YYYY-MM-DD-NNN-description.md` con TYPE en los 12 tipos válidos -- [ ] **F2.CLI.02.03** — Implementar regla `META-001`: verificar presencia de campos obligatorios: id, title, status, created, agent, confidence, review_required, risk_level -- [ ] **F2.CLI.02.04** — Implementar regla `META-002`: verificar que el campo `id` del frontmatter coincida con el prefijo del nombre de archivo -- [ ] **F2.CLI.02.05** — Implementar regla `META-003`: verificar que `status` tenga un valor válido según DOCUMENTATION-POLICY.md -- [ ] **F2.CLI.02.06** — Implementar regla `CROSS-001`: si `risk_level` es `high` o `critical`, `review_required` DEBE ser `true` -- [ ] **F2.CLI.02.07** — Implementar regla `CROSS-002`: si `eu_ai_act_risk` es `high`, `review_required` DEBE ser `true` -- [ ] **F2.CLI.02.08** — Implementar regla `CROSS-003`: para tipos SEC, MCARD, DPIA, `review_required` DEBE ser `true` -- [ ] **F2.CLI.02.09** — Implementar regla `TYPE-001`: INC debe tener campo `severity` -- [ ] **F2.CLI.02.10** — Implementar regla `TYPE-002`: ETH debe tener campo `gdpr_legal_basis` si contiene la sección "Data Privacy" -- [ ] **F2.CLI.02.11** — Implementar regla `REF-001`: verificar que todos los documentos listados en `related:` existan en `.devtrail/`. Emitir warning si no se encuentran -- [ ] **F2.CLI.02.12** — Implementar regla `SEC-001`: buscar patrones de información sensible (password, api_key, secret, token, private_key, credentials, Bearer) en todo el documento. Emitir error si se encuentran -- [ ] **F2.CLI.02.13** — Implementar regla `OBS-001` (warning): si el documento tiene tag `observabilidad`, verificar que contenga al menos una sección de alcance de instrumentación o riesgos de observabilidad. Emitir warning si no se encuentra -- [ ] **F2.CLI.02.14** — Implementar función `validate_all(root: &Path) -> ValidationResult` que aplique todas las reglas a todos los documentos descubiertos +- [x] **F2.CLI.02.02** — Implementar regla `NAMING-001`: verificar que el nombre del archivo sigue el patrón `TYPE-YYYY-MM-DD-NNN-description.md` con TYPE en los 12 tipos válidos +- [x] **F2.CLI.02.03** — Implementar regla `META-001`: verificar presencia de campos obligatorios: id, title, status, created, agent, confidence, review_required, risk_level +- [x] **F2.CLI.02.04** — Implementar regla `META-002`: verificar que el campo `id` del frontmatter coincida con el prefijo del nombre de archivo +- [x] **F2.CLI.02.05** — Implementar regla `META-003`: verificar que `status` tenga un valor válido según DOCUMENTATION-POLICY.md +- [x] **F2.CLI.02.06** — Implementar regla `CROSS-001`: si `risk_level` es `high` o `critical`, `review_required` DEBE ser `true` +- [x] **F2.CLI.02.07** — Implementar regla `CROSS-002`: si `eu_ai_act_risk` es `high`, `review_required` DEBE ser `true` +- [x] **F2.CLI.02.08** — Implementar regla `CROSS-003`: para tipos SEC, MCARD, DPIA, `review_required` DEBE ser `true` +- [x] **F2.CLI.02.09** — Implementar regla `TYPE-001`: INC debe tener campo `severity` +- [x] **F2.CLI.02.10** — Implementar regla `TYPE-002`: ETH debe tener campo `gdpr_legal_basis` si contiene la sección "Data Privacy" +- [x] **F2.CLI.02.11** — Implementar regla `REF-001`: verificar que todos los documentos listados en `related:` existan en `.devtrail/`. Emitir warning si no se encuentran +- [x] **F2.CLI.02.12** — Implementar regla `SEC-001`: buscar patrones de información sensible (password, api_key, secret, token, private_key, credentials, Bearer) en todo el documento. Emitir error si se encuentran +- [x] **F2.CLI.02.13** — Implementar regla `OBS-001` (warning): si el documento tiene tag `observabilidad`, verificar que contenga al menos una sección de alcance de instrumentación o riesgos de observabilidad. Emitir warning si no se encuentra +- [x] **F2.CLI.02.14** — Implementar función `validate_all(root: &Path) -> ValidationResult` que aplique todas las reglas a todos los documentos descubiertos ### F2.CLI.03 — Implementar comando `devtrail validate` `P0` > → depende de F2.CLI.02 -- [ ] **F2.CLI.03.01** — Crear `cli/src/commands/validate.rs` con función `pub fn run(path: &str, fix: bool) -> Result<()>` -- [ ] **F2.CLI.03.02** — Agregar variante `Validate` al enum `Commands` en main.rs con args: `path` (default "."), `--fix` (flag booleano) -- [ ] **F2.CLI.03.03** — Agregar `pub mod validate;` en `commands/mod.rs` -- [ ] **F2.CLI.03.04** — Implementar output formateado: header con ruta, luego errores agrupados por archivo (rojo), luego warnings (amarillo), luego resumen final: "X errors, Y warnings in Z documents" -- [ ] **F2.CLI.03.05** — Implementar `--fix` para correcciones automáticas simples: agregar `review_required: true` a documentos de alto riesgo que no lo tengan, corregir `id` si no coincide con filename -- [ ] **F2.CLI.03.06** — Exit code: 0 si no hay errores (warnings OK), 1 si hay errores -- [ ] **F2.CLI.03.07** — Agregar al routing en main.rs match statement +- [x] **F2.CLI.03.01** — Crear `cli/src/commands/validate.rs` con función `pub fn run(path: &str, fix: bool) -> Result<()>` +- [x] **F2.CLI.03.02** — Agregar variante `Validate` al enum `Commands` en main.rs con args: `path` (default "."), `--fix` (flag booleano) +- [x] **F2.CLI.03.03** — Agregar `pub mod validate;` en `commands/mod.rs` +- [x] **F2.CLI.03.04** — Implementar output formateado: header con ruta, luego errores agrupados por archivo (rojo), luego warnings (amarillo), luego resumen final: "X errors, Y warnings in Z documents" +- [x] **F2.CLI.03.05** — Implementar `--fix` para correcciones automáticas simples: agregar `review_required: true` a documentos de alto riesgo que no lo tengan, corregir `id` si no coincide con filename +- [x] **F2.CLI.03.06** — Exit code: 0 si no hay errores (warnings OK), 1 si hay errores +- [x] **F2.CLI.03.07** — Agregar al routing en main.rs match statement ### F2.CLI.04 — Integración de Lizard para complejidad ciclomática `P2` -- [ ] **F2.CLI.04.01** — Crear `cli/src/complexity.rs` con función `pub fn analyze_complexity(paths: &[PathBuf]) -> Result` -- [ ] **F2.CLI.04.02** — Implementar detección de `lizard` en el PATH del sistema -- [ ] **F2.CLI.04.03** — Implementar ejecución de `lizard --csv ` y parseo del output CSV (lizard no soporta JSON nativo; CSV es el formato más portable). Campos a parsear: NLOC, CCN (cyclomatic complexity number), token, param, length, filename, function name -- [ ] **F2.CLI.04.04** — Crear struct `ComplexityReport` con: functions analizadas, delta CCN vs baseline, funciones que exceden umbral (CCN > 5 delta) -- [ ] **F2.CLI.04.05** — Implementar output JSON del reporte para que los skills de agentes puedan consumirlo: `devtrail analyze-complexity --json ` -- [ ] **F2.CLI.04.06** — Implementar fallback cuando lizard no está disponible: emitir warning con instrucciones de instalación (`pip install lizard`) y sugerir usar criterios cualitativos +- [x] **F2.CLI.04.01** — Crear `cli/src/complexity.rs` con función `pub fn analyze_complexity(paths: &[PathBuf]) -> Result` +- [x] **F2.CLI.04.02** — Implementar detección de `lizard` en el PATH del sistema +- [x] **F2.CLI.04.03** — Implementar ejecución de `lizard --csv ` y parseo del output CSV (lizard no soporta JSON nativo; CSV es el formato más portable). Campos a parsear: NLOC, CCN (cyclomatic complexity number), token, param, length, filename, function name +- [x] **F2.CLI.04.04** — Crear struct `ComplexityReport` con: functions analizadas, delta CCN vs baseline, funciones que exceden umbral (CCN > 5 delta) +- [x] **F2.CLI.04.05** — Implementar output JSON del reporte para que los skills de agentes puedan consumirlo: `devtrail analyze-complexity --json ` +- [x] **F2.CLI.04.06** — Implementar fallback cuando lizard no está disponible: emitir warning con instrucciones de instalación (`pip install lizard`) y sugerir usar criterios cualitativos ### F2.CLI.05 — Bump de versiones Fase 2 `P0` > → depende de F2.CLI.01 a F2.CLI.04 -- [ ] **F2.CLI.05.01** — Editar `cli/Cargo.toml`: cambiar version a `"1.4.0"` -- [ ] **F2.CLI.05.02** — Ejecutar `cargo check` -- [ ] **F2.CLI.05.03** — Editar `dist/dist-manifest.yml`: cambiar version a `"3.1.0"` -- [ ] **F2.CLI.05.04** — Actualizar `dist-manifest.yml` sección files con todos los archivos nuevos +- [x] **F2.CLI.05.01** — Editar `cli/Cargo.toml`: cambiar version a `"1.4.0"` +- [x] **F2.CLI.05.02** — Ejecutar `cargo check` +- [x] **F2.CLI.05.03** — Editar `dist/dist-manifest.yml`: cambiar version a `"3.1.0"` +- [x] **F2.CLI.05.04** — Actualizar `dist-manifest.yml` sección files con todos los archivos nuevos --- @@ -610,14 +610,14 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. ### F2.CI.01 — Agregar jobs de compliance a `docs-validation.yml` `P1` -- [ ] **F2.CI.01.01** — Agregar job `compliance-check` que verifique: documentos de alto riesgo (`risk_level: high|critical`) tienen ETH asociado en `related:`, documentos con `eu_ai_act_risk: high` tienen sección "EU AI Act Considerations" -- [ ] **F2.CI.01.02** — Agregar job `governance-metrics` (solo en push a main) que genere reporte en `$GITHUB_STEP_SUMMARY`: conteo de documentos por tipo, documentos de la semana, distribución de risk_level, tasa de review compliance +- [x] **F2.CI.01.01** — Agregar job `compliance-check` que verifique: documentos de alto riesgo (`risk_level: high|critical`) tienen ETH asociado en `related:`, documentos con `eu_ai_act_risk: high` tienen sección "EU AI Act Considerations" +- [x] **F2.CI.01.02** — Agregar job `governance-metrics` (solo en push a main) que genere reporte en `$GITHUB_STEP_SUMMARY`: conteo de documentos por tipo, documentos de la semana, distribución de risk_level, tasa de review compliance ### F2.CI.02 — Agregar validación de referencias cruzadas `P2` -- [ ] **F2.CI.02.01** — En `pre-commit-docs.sh`: agregar validación de que documentos en `related:` existen en `.devtrail/` -- [ ] **F2.CI.02.02** — En `pre-commit-docs.sh`: agregar detección de cambios de código sin AILOG del mismo día (warning, no error) -- [ ] **F2.CI.02.03** — Replicar ambas validaciones en `validate-docs.ps1` +- [x] **F2.CI.02.01** — En `pre-commit-docs.sh`: agregar validación de que documentos en `related:` existen en `.devtrail/` +- [x] **F2.CI.02.02** — En `pre-commit-docs.sh`: agregar detección de cambios de código sin AILOG del mismo día (warning, no error) +- [x] **F2.CI.02.03** — Replicar ambas validaciones en `validate-docs.ps1` --- @@ -625,7 +625,7 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. ### F2.QA.01 — Tests para `devtrail validate` `P0` -- [ ] **F2.QA.01.01** — Crear `cli/tests/validate_test.rs` con tests: +- [x] **F2.QA.01.01** — Crear `cli/tests/validate_test.rs` con tests: - Test con directorio sin DevTrail → mensaje de error apropiado - Test con documentos válidos → exit code 0, "0 errors" - Test con naming incorrecto → error NAMING-001 @@ -636,14 +636,14 @@ Se indican como `→ depende de F1.FW.01` tras la subtarea. - Test con related inexistente → warning REF-001 - Test con --fix corrigiendo review_required → archivo modificado correctamente - Test con tag `observabilidad` sin sección de alcance → warning OBS-001 -- [ ] **F2.QA.01.02** — Ejecutar `cargo test` completo -- [ ] **F2.QA.01.03** — Verificar `cargo clippy` sin warnings +- [x] **F2.QA.01.02** — Ejecutar `cargo test` completo +- [x] **F2.QA.01.03** — Verificar `cargo clippy` sin warnings ### F2.QA.02 — Verificación de templates nuevos `P1` -- [ ] **F2.QA.02.01** — Crear un documento de prueba para cada nuevo tipo (SEC, MCARD, SBOM, DPIA) y validar con `devtrail validate` -- [ ] **F2.QA.02.02** — Verificar que `devtrail-new.sh` crea correctamente documentos de los 4 nuevos tipos -- [ ] **F2.QA.02.03** — Verificar que `devtrail init` en directorio vacío incluye los 4 nuevos templates y las nuevas carpetas +- [x] **F2.QA.02.01** — Crear un documento de prueba para cada nuevo tipo (SEC, MCARD, SBOM, DPIA) y validar con `devtrail validate` +- [x] **F2.QA.02.02** — Verificar que `devtrail-new.sh` crea correctamente documentos de los 4 nuevos tipos +- [x] **F2.QA.02.03** — Verificar que `devtrail init` en directorio vacío incluye los 4 nuevos templates y las nuevas carpetas ---