Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions src/schema/mod.rs
Original file line number Diff line number Diff line change
@@ -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<String, f64>,
},
Score {
score: f64,
confidence: f64,
probabilities: BTreeMap<String, f64>,
},
}

/// 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()
}
88 changes: 4 additions & 84 deletions src/schema.rs → src/schema/report.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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<String, f64>,
},
Score {
score: f64,
confidence: f64,
probabilities: BTreeMap<String, f64>,
},
}

/// 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,
Expand Down Expand Up @@ -381,24 +319,6 @@ pub struct PathFailOn {
pub rules: BTreeMap<String, Vec<String>>,
}

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,
Expand Down
Loading