oxidized-agentic-audit 0.6.0

Security scanning for AI agent skills — scans skill directories for dangerous bash patterns, prompt injection, supply chain risks, secret leakage, and frontmatter quality issues
Documentation
//! JSON output formatter.
//!
//! Produces a pretty-printed JSON document containing skill metadata, a
//! severity summary, active findings, and suppressed findings.

use crate::finding::ScanReport;

#[derive(serde::Serialize)]
struct JsonOutput<'a> {
    skill: &'a str,
    version: &'a Option<String>,
    scan_timestamp: &'a str,
    status: &'a crate::finding::ScanStatus,
    risk_level: &'a crate::finding::RiskLevel,
    security_score: u8,
    security_grade: &'a crate::finding::SecurityGrade,
    passed: bool,
    summary: Summary,
    findings: &'a [crate::finding::Finding],
    suppressed: &'a [crate::finding::Finding],
}

#[derive(serde::Serialize)]
struct Summary {
    errors: usize,
    warnings: usize,
    info: usize,
    suppressed: usize,
}

/// Formats a [`ScanReport`] as pretty-printed JSON.
///
/// The output includes skill metadata, a severity summary object, and the
/// full list of active and suppressed findings.
///
/// # Panics
///
/// Panics if the report cannot be serialized (should not happen with valid data).
pub fn format(report: &ScanReport) -> String {
    let output = JsonOutput {
        skill: &report.skill,
        version: &report.version,
        scan_timestamp: &report.scan_timestamp,
        status: &report.status,
        risk_level: &report.risk_level,
        security_score: report.security_score,
        security_grade: &report.security_grade,
        passed: report.passed,
        summary: {
            // Single pass over findings instead of three separate iterations.
            let (errors, warnings, info) = report.count_by_severity();
            Summary {
                errors,
                warnings,
                info,
                suppressed: report.suppressed.len(),
            }
        },
        findings: &report.findings,
        suppressed: &report.suppressed,
    };

    serde_json::to_string_pretty(&output).expect("JSON serialization failed")
}