From f5f5cd1ba69967ce36e2794942dd3008ded0b0fc Mon Sep 17 00:00:00 2001 From: Tauan BF <11513929+tauanbinato@users.noreply.github.com> Date: Fri, 25 Sep 2026 23:32:13 -0300 Subject: [PATCH] Keep the report's structure in a module of its own schema/report.rs holds the report, file results, findings, dimensions and stage metrics; schema/mod.rs keeps the versions, statuses, answers, judgments and hashes and re-exports the rest, so no path changes. The self-check suggested the split. --- src/schema/mod.rs | 91 +++++++++++++++++++++++++++++ src/{schema.rs => schema/report.rs} | 88 ++-------------------------- 2 files changed, 95 insertions(+), 84 deletions(-) create mode 100644 src/schema/mod.rs rename src/{schema.rs => schema/report.rs} (83%) diff --git a/src/schema/mod.rs b/src/schema/mod.rs new file mode 100644 index 0000000..a2e76cd --- /dev/null +++ b/src/schema/mod.rs @@ -0,0 +1,91 @@ +//! The report schema's versions, statuses, raw answers and judgments, and the +//! hash that names cached answers; `report` holds the report's structure. +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +mod report; +pub use report::*; + +pub const RUBRIC: &str = "jevgate-units-v1"; +/// Changes how saved answers become a status. Included in the report identity +/// and not in the judgment cache, so unchanged questions are not sent again. +pub const COMPOSITION: &str = "unit-composition-v12"; +pub const SCHEMA_VERSION: u32 = 2; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "kebab-case")] +pub enum Status { + Pending, + NotApplicable, + Clear, + Consider, + Review, + /// Only optional improvements: the code reads well as it is. + Note, + Uncertain, + NeedsContext, + Error, + Skipped, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +#[serde(rename_all = "kebab-case")] +pub enum Pass { + First, + Recheck, + /// A follow-up that locates the part of a finding to act on. + Locate, + /// A follow-up that judges where a security concern's values come from. + Trace, + /// A follow-up that asks where an undecided security check's URL comes + /// from or its output goes, and can only clear that check. + Settle, +} + +/// A raw typed answer, kept exactly as the provider returned it. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(tag = "type", rename_all = "lowercase")] +pub enum Answer { + Noul { + noul: f64, + }, + Choice { + choice: String, + confidence: f64, + probabilities: BTreeMap, + }, + Score { + score: f64, + confidence: f64, + probabilities: BTreeMap, + }, +} + +/// One answer about one unit. First-pass and recheck answers are both kept. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct Judgment { + pub rule: String, + pub unit: String, + pub question: String, + pub version: String, + pub pass: Pass, + pub answer: Answer, +} + +pub fn now() -> u64 { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_secs() +} + +/// Joins the parts of a hashed identity; it cannot occur in a path or in source. +pub const HASH_SEPARATOR: &str = "\u{0}"; + +pub fn hash(bytes: &[u8]) -> String { + use sha2::{Digest, Sha256}; + Sha256::digest(bytes) + .iter() + .map(|byte| format!("{byte:02x}")) + .collect() +} diff --git a/src/schema.rs b/src/schema/report.rs similarity index 83% rename from src/schema.rs rename to src/schema/report.rs index cb3af9b..d742dde 100644 --- a/src/schema.rs +++ b/src/schema/report.rs @@ -1,29 +1,11 @@ +//! The report's structure: per-file results, findings and their locations, +//! per-rule dimensions, stage metrics and the report itself, as `--format +//! json` and `.jevgate/latest.json` write it. +use super::{Judgment, Status}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; use std::path::PathBuf; -pub const RUBRIC: &str = "jevgate-units-v1"; -/// Changes how saved answers become a status. Included in the report identity -/// and not in the judgment cache, so unchanged questions are not sent again. -pub const COMPOSITION: &str = "unit-composition-v12"; -pub const SCHEMA_VERSION: u32 = 2; - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "kebab-case")] -pub enum Status { - Pending, - NotApplicable, - Clear, - Consider, - Review, - /// Only optional improvements: the code reads well as it is. - Note, - Uncertain, - NeedsContext, - Error, - Skipped, -} - /// One rule's composed result for a file, over every unit it judged. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Dimension { @@ -70,50 +52,6 @@ pub struct UnitCounts { pub covered: usize, } -#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] -#[serde(rename_all = "kebab-case")] -pub enum Pass { - First, - Recheck, - /// A follow-up that locates the part of a finding to act on. - Locate, - /// A follow-up that judges where a security concern's values come from. - Trace, - /// A follow-up that asks where an undecided security check's URL comes - /// from or its output goes, and can only clear that check. - Settle, -} - -/// A raw typed answer, kept exactly as the provider returned it. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(tag = "type", rename_all = "lowercase")] -pub enum Answer { - Noul { - noul: f64, - }, - Choice { - choice: String, - confidence: f64, - probabilities: BTreeMap, - }, - Score { - score: f64, - confidence: f64, - probabilities: BTreeMap, - }, -} - -/// One answer about one unit. First-pass and recheck answers are both kept. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct Judgment { - pub rule: String, - pub unit: String, - pub question: String, - pub version: String, - pub pass: Pass, - pub answer: Answer, -} - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub struct Location { pub path: PathBuf, @@ -381,24 +319,6 @@ pub struct PathFailOn { pub rules: BTreeMap>, } -pub fn now() -> u64 { - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap_or_default() - .as_secs() -} - -/// Joins the parts of a hashed identity; it cannot occur in a path or in source. -pub const HASH_SEPARATOR: &str = "\u{0}"; - -pub fn hash(bytes: &[u8]) -> String { - use sha2::{Digest, Sha256}; - Sha256::digest(bytes) - .iter() - .map(|byte| format!("{byte:02x}")) - .collect() -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ContextNeed { pub rule: String,