File size: 5,584 Bytes
224e773 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | //! HyperKitty ERE - Execution Regulation Engine
//!
//! Five-gate proof protocol for code safety:
//! - P1: NO_SECRETS - detects hardcoded credentials
//! - P2: NO_EVAL - detects dynamic code execution
//! - P3: NO_INFINITE_LOOPS - detects unbounded iteration
//! - P4: NO_TELEMETRY - detects analytics and tracking
//! - P5: AUDIT_HASH - issues receipts when all gates pass
pub mod p1_secrets;
pub mod p2_eval;
pub mod p3_loops;
pub mod p4_telemetry;
pub mod p5_hash;
pub use p5_hash::EreReceipt;
pub use hyperkitty_core::Result;
/// Gate check result: (passed, findings)
pub type GateResult = (bool, Vec<String>);
/// Execution Regulation Engine
///
/// Runs all five gates to verify artifact safety
pub struct EreEngine;
impl EreEngine {
pub fn new() -> Self {
Self
}
/// Run all five ERE gates
///
/// # Arguments
/// * `artifact_id` - Unique identifier for the artifact
/// * `artifact` - Code to inspect
/// * `intent` - Declared purpose of the code
///
/// # Returns
/// Ok(EreReceipt) if all gates pass, Err(ProofFailed) otherwise
pub fn run_all(
&self,
artifact_id: &str,
artifact: &str,
intent: &str,
) -> Result<EreReceipt> {
// Run all gates in sequence
let (p1, p1_findings) = p1_secrets::check_secrets(artifact);
let (p2, p2_findings) = p2_eval::check_eval(artifact);
let (p3, p3_findings) = p3_loops::check_loops(artifact);
let (p4, p4_findings) = p4_telemetry::check_telemetry(artifact);
// Log findings if any gate failed
if !p1 || !p2 || !p3 || !p4 {
let mut all_findings = Vec::new();
if !p1 { all_findings.extend(p1_findings.iter().cloned()); }
if !p2 { all_findings.extend(p2_findings.iter().cloned()); }
if !p3 { all_findings.extend(p3_findings.iter().cloned()); }
if !p4 { all_findings.extend(p4_findings.iter().cloned()); }
eprintln!("ERE gates failed:");
for finding in all_findings {
eprintln!(" - {}", finding);
}
}
// Compute P5 receipt (fails if any gate failed)
p5_hash::compute_p5(artifact_id, artifact, intent, p1, p2, p3, p4)
}
/// Run gates individually and return detailed results
pub fn run_detailed(
&self,
artifact: &str,
) -> (GateResult, GateResult, GateResult, GateResult) {
(
p1_secrets::check_secrets(artifact),
p2_eval::check_eval(artifact),
p3_loops::check_loops(artifact),
p4_telemetry::check_telemetry(artifact),
)
}
}
impl Default for EreEngine {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ere_engine_clean_artifact() {
let engine = EreEngine::new();
let artifact = "function add(a, b) { return a + b; }";
let result = engine.run_all("test_id", artifact, "pure_function");
assert!(result.is_ok());
let receipt = result.unwrap();
assert!(receipt.verify());
assert_eq!(receipt.artifact_id, "test_id");
}
#[test]
fn test_ere_engine_with_secret() {
let engine = EreEngine::new();
let artifact = "const api_key = 'sk-1234567890';";
let result = engine.run_all("test_id", artifact, "fetch_data");
assert!(matches!(result, Err(hyperkitty_core::Error::ProofFailed)));
}
#[test]
fn test_ere_engine_with_eval() {
let engine = EreEngine::new();
let artifact = "eval(userInput);";
let result = engine.run_all("test_id", artifact, "user_defined");
assert!(matches!(result, Err(hyperkitty_core::Error::ProofFailed)));
}
#[test]
fn test_ere_engine_with_infinite_loop() {
let engine = EreEngine::new();
let artifact = "while(true) { console.log('loop'); }";
let result = engine.run_all("test_id", artifact, "infinite");
assert!(matches!(result, Err(hyperkitty_core::Error::ProofFailed)));
}
#[test]
fn test_ere_engine_with_telemetry() {
let engine = EreEngine::new();
let artifact = "navigator.sendBeacon('/track', data);";
let result = engine.run_all("test_id", artifact, "tracking");
assert!(matches!(result, Err(hyperkitty_core::Error::ProofFailed)));
}
#[test]
fn test_ere_engine_detailed_checks() {
let engine = EreEngine::new();
let artifact = "function safe() { return 42; }";
let (p1, p2, p3, p4) = engine.run_detailed(artifact);
assert!(p1.0, "P1 (secrets) should pass");
assert!(p2.0, "P2 (eval) should pass");
assert!(p3.0, "P3 (loops) should pass");
assert!(p4.0, "P4 (telemetry) should pass");
assert!(p1.1.is_empty());
assert!(p2.1.is_empty());
assert!(p3.1.is_empty());
assert!(p4.1.is_empty());
}
#[test]
fn test_ere_receipt_properties() {
let engine = EreEngine::new();
let artifact = "const x = 1;";
let receipt = engine.run_all("my_artifact", artifact, "simple").unwrap();
assert_eq!(receipt.artifact_id, "my_artifact");
assert!(receipt.p1_pass);
assert!(receipt.p2_pass);
assert!(receipt.p3_pass);
assert!(receipt.p4_pass);
assert!(receipt.verify());
}
}
|