|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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;
|
|
|
|
|
| pub type GateResult = (bool, Vec<String>);
|
|
|
|
|
|
|
|
|
| pub struct EreEngine;
|
|
|
| impl EreEngine {
|
| pub fn new() -> Self {
|
| Self
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| pub fn run_all(
|
| &self,
|
| artifact_id: &str,
|
| artifact: &str,
|
| intent: &str,
|
| ) -> Result<EreReceipt> {
|
|
|
| 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);
|
|
|
|
|
| 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);
|
| }
|
| }
|
|
|
|
|
| p5_hash::compute_p5(artifact_id, artifact, intent, p1, p2, p3, p4)
|
| }
|
|
|
|
|
| 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());
|
| }
|
| }
|
|
|