Download crates/notebook-orchestrator/src/tests.rs from Snapkitty/rowm-polymorphic-notebook: direct link, hf CLI and curl.
- Browser
- Download file 13.9 kB
-
https://huggingface.co/Snapkitty/rowm-polymorphic-notebook/resolve/main/crates/notebook-orchestrator/src/tests.rs
- Command line
-
hf download hf://Snapkitty/rowm-polymorphic-notebook/crates/notebook-orchestrator/src/tests.rs
-
curl -L -o tests.rs https://huggingface.co/Snapkitty/rowm-polymorphic-notebook/resolve/main/crates/notebook-orchestrator/src/tests.rs
13.9 kB
| // PHASE 9: Comprehensive Testing Suite | |
| // Unit, integration, property-based, fuzz, tamper, and replay tests | |
| mod tests { | |
| use crate::*; | |
| use std::collections::HashMap; | |
| // ============ UNIT TESTS ============ | |
| fn test_ed25519_keypair_generation() { | |
| let kp = Ed25519KeyPair::generate(); | |
| let private_hex = kp.private_key_hex(); | |
| let public_hex = kp.public_key_hex(); | |
| assert_eq!(private_hex.len(), 64); // 32 bytes = 64 hex | |
| assert_eq!(public_hex.len(), 64); | |
| } | |
| fn test_ed25519_sign_and_verify() { | |
| let kp = Ed25519KeyPair::generate(); | |
| let message = b"test message"; | |
| let signature = kp.sign(message); | |
| let verified = Ed25519KeyPair::verify(&kp.public_key_hex(), message, &signature) | |
| .expect("Verify failed"); | |
| assert!(verified); | |
| } | |
| fn test_receipt_v2_canonical_hash_deterministic() { | |
| let r1 = ReceiptV2::new( | |
| 0, "agent1".to_string(), "cap1".to_string(), "instr1".to_string(), | |
| "dispatch".to_string(), "input1".to_string(), "output1".to_string(), | |
| "rust".to_string(), "1.0.0".to_string(), "abc123".to_string(), | |
| "env1".to_string(), "0".repeat(128), 100, "nonce1".to_string(), | |
| "context1".to_string(), | |
| ); | |
| let r2 = ReceiptV2::new( | |
| 0, "agent1".to_string(), "cap1".to_string(), "instr1".to_string(), | |
| "dispatch".to_string(), "input1".to_string(), "output1".to_string(), | |
| "rust".to_string(), "1.0.0".to_string(), "abc123".to_string(), | |
| "env1".to_string(), "0".repeat(128), 100, "nonce1".to_string(), | |
| "context1".to_string(), | |
| ); | |
| assert_eq!(r1.receipt_hash, r2.receipt_hash); | |
| } | |
| fn test_replay_detector_rejects_duplicate_nonce() { | |
| let mut detector = ReplayDetector::new("test".to_string(), 3600); | |
| assert!(detector.check_and_record("nonce1", 100).is_ok()); | |
| assert!(detector.check_and_record("nonce1", 101).is_err()); // Duplicate | |
| } | |
| fn test_replay_detector_enforces_monotonic_counter() { | |
| let mut detector = ReplayDetector::new("test".to_string(), 3600); | |
| assert!(detector.check_and_record("nonce1", 100).is_ok()); | |
| assert!(detector.check_and_record("nonce2", 99).is_err()); // Non-monotonic | |
| } | |
| fn test_notebook_cell_hash_deterministic() { | |
| let cell1 = NotebookCell::new( | |
| 0, "code".to_string(), "x = 1".to_string(), Some(1), | |
| "".to_string(), "{}".to_string(), 1000, "0".repeat(128), | |
| ); | |
| let cell2 = NotebookCell::new( | |
| 0, "code".to_string(), "x = 1".to_string(), Some(1), | |
| "".to_string(), "{}".to_string(), 1000, "0".repeat(128), | |
| ); | |
| assert_eq!(cell1.cell_hash, cell2.cell_hash); | |
| } | |
| fn test_notebook_cell_tampering_detected() { | |
| let mut cell = NotebookCell::new( | |
| 0, "code".to_string(), "x = 1".to_string(), Some(1), | |
| "".to_string(), "{}".to_string(), 1000, "0".repeat(128), | |
| ); | |
| assert!(cell.verify_hash()); | |
| cell.source = "x = 2".to_string(); | |
| assert!(!cell.verify_hash()); | |
| } | |
| fn test_self_modification_pattern_detection() { | |
| let writes = vec![ | |
| MemoryWrite { | |
| address: 0, | |
| value: 100, | |
| writes_instruction_field: true, | |
| pc: 0, | |
| cycle: 0, | |
| }, | |
| MemoryWrite { | |
| address: 3, | |
| value: 200, | |
| writes_instruction_field: true, | |
| pc: 1, | |
| cycle: 1, | |
| }, | |
| ]; | |
| let analyzer = SelfModificationAnalyzer::new(1); | |
| let result = analyzer.analyze(&writes); | |
| assert!(result.patterns.contains(&ModificationPattern::CodeGeneration)); | |
| } | |
| // ============ INTEGRATION TESTS ============ | |
| fn test_receipt_chain_append_and_verify() { | |
| let mut chain = ReceiptChainV2::new(); | |
| let r1 = ReceiptV2::new( | |
| 0, "loc".to_string(), "cap001".to_string(), "instr1".to_string(), | |
| "dispatch".to_string(), "inp1".to_string(), "out1".to_string(), | |
| "rust".to_string(), "1.0.0".to_string(), "src1".to_string(), | |
| "env1".to_string(), "0".repeat(128), 100, "nonce001".to_string(), | |
| "global".to_string(), | |
| ); | |
| assert!(chain.append(r1.clone()).is_ok()); | |
| assert!(chain.verify_chain()); | |
| } | |
| fn test_notebook_merkle_tree_chain_linkage() { | |
| let mut tree = NotebookMerkleTree::new(); | |
| let cell0 = NotebookCell::new( | |
| 0, "code".to_string(), "x = 1".to_string(), Some(1), | |
| "".to_string(), "{}".to_string(), 1000, "0".repeat(128), | |
| ); | |
| assert!(tree.add_cell(cell0.clone()).is_ok()); | |
| let cell1 = NotebookCell::new( | |
| 1, "code".to_string(), "print(x)".to_string(), Some(1), | |
| "1\n".to_string(), "{}".to_string(), 1001, cell0.cell_hash.clone(), | |
| ); | |
| assert!(tree.add_cell(cell1).is_ok()); | |
| assert!(tree.verify_integrity()); | |
| } | |
| fn test_global_replay_protection_multiple_contexts() { | |
| let mut protection = GlobalReplayProtection::new(3600); | |
| assert!(protection.check_and_record("ctx1", "nonce1", 1).is_ok()); | |
| assert!(protection.check_and_record("ctx1", "nonce2", 2).is_ok()); | |
| assert!(protection.check_and_record("ctx2", "nonce1", 1).is_ok()); // OK in different context | |
| assert!(protection.check_and_record("ctx1", "nonce1", 3).is_err()); // Duplicate nonce | |
| } | |
| fn test_keystore_rotation() { | |
| let mut store = KeyStore::new(); | |
| let now = std::time::SystemTime::now() | |
| .duration_since(std::time::UNIX_EPOCH) | |
| .unwrap() | |
| .as_secs(); | |
| let (v1, _) = store.generate_key("agent1".to_string(), now, now + 3600) | |
| .expect("Generate v1 failed"); | |
| assert_eq!(v1, 1); | |
| let (v2, _) = store.rotate_key("agent1", now, now + 7200) | |
| .expect("Rotate failed"); | |
| assert_eq!(v2, 2); | |
| let (current, _) = store.get_current_key("agent1").expect("Get current failed"); | |
| assert_eq!(current, v2); | |
| let old_key = store.get_key("agent1", v1).expect("Get old key failed"); | |
| assert_eq!(old_key.status, KeyStatus::Revoked); | |
| } | |
| // ============ PROPERTY-BASED TESTS ============ | |
| fn test_receipt_hash_stability() { | |
| // Property: Receipt hash is deterministic (same input always produces same hash) | |
| for _ in 0..10 { | |
| let r1 = ReceiptV2::new( | |
| 0, "agent".to_string(), "cap".to_string(), "instr".to_string(), | |
| "action".to_string(), "input".to_string(), "output".to_string(), | |
| "runtime".to_string(), "1.0".to_string(), "src".to_string(), | |
| "env".to_string(), "0".repeat(128), 100, "nonce".to_string(), | |
| "context".to_string(), | |
| ); | |
| let r2 = ReceiptV2::new( | |
| 0, "agent".to_string(), "cap".to_string(), "instr".to_string(), | |
| "action".to_string(), "input".to_string(), "output".to_string(), | |
| "runtime".to_string(), "1.0".to_string(), "src".to_string(), | |
| "env".to_string(), "0".repeat(128), 100, "nonce".to_string(), | |
| "context".to_string(), | |
| ); | |
| assert_eq!(r1.receipt_hash, r2.receipt_hash); | |
| } | |
| } | |
| fn test_monotonic_counter_invariant() { | |
| // Property: Monotonic counter never decreases in sequence | |
| let mut detector = ReplayDetector::new("test".to_string(), 3600); | |
| let mut last_counter = 0; | |
| for i in 1..100 { | |
| assert!(detector.check_and_record(&format!("nonce-{}", i), i as u64).is_ok()); | |
| last_counter = i as u64; | |
| } | |
| assert_eq!(detector.last_counter(), last_counter); | |
| } | |
| // ============ FUZZ TESTS ============ | |
| fn test_malformed_hash_rejected() { | |
| let mut cell = NotebookCell::new( | |
| 0, "code".to_string(), "x = 1".to_string(), Some(1), | |
| "".to_string(), "{}".to_string(), 1000, "0".repeat(128), | |
| ); | |
| // Tamper with hash | |
| cell.cell_hash = "invalid_hash".to_string(); | |
| assert!(!cell.verify_hash()); | |
| } | |
| fn test_malformed_signature_rejected() { | |
| let kp = Ed25519KeyPair::generate(); | |
| let message = b"test"; | |
| let result = Ed25519KeyPair::verify(&kp.public_key_hex(), message, "invalid_sig"); | |
| assert!(result.is_err()); | |
| } | |
| fn test_invalid_nonce_format_rejected() { | |
| assert!(!NonceGenerator::is_valid_format("invalid")); | |
| assert!(!NonceGenerator::is_valid_format("")); | |
| } | |
| // ============ TAMPER TESTS ============ | |
| fn test_receipt_tampering_detection() { | |
| let mut r = ReceiptV2::new( | |
| 0, "agent".to_string(), "cap".to_string(), "instr".to_string(), | |
| "action".to_string(), "input".to_string(), "output".to_string(), | |
| "runtime".to_string(), "1.0".to_string(), "src".to_string(), | |
| "env".to_string(), "0".repeat(128), 100, "nonce".to_string(), | |
| "context".to_string(), | |
| ); | |
| let original_hash = r.receipt_hash.clone(); | |
| assert!(r.verify_hash()); | |
| // Tamper with agent ID | |
| r.agent_id = "hacker".to_string(); | |
| assert!(!r.verify_hash()); | |
| assert_ne!(r.receipt_hash, original_hash); | |
| } | |
| fn test_notebook_cell_reordering_detection() { | |
| let mut tree = NotebookMerkleTree::new(); | |
| let cell0 = NotebookCell::new( | |
| 0, "code".to_string(), "x = 1".to_string(), Some(1), | |
| "".to_string(), "{}".to_string(), 1000, "0".repeat(128), | |
| ); | |
| assert!(tree.add_cell(cell0.clone()).is_ok()); | |
| // Try to add cell with wrong index (reordering attack) | |
| let bad_cell = NotebookCell::new( | |
| 0, // Should be 1 | |
| "code".to_string(), "y = 2".to_string(), Some(1), | |
| "".to_string(), "{}".to_string(), 1001, cell0.cell_hash.clone(), | |
| ); | |
| assert!(tree.add_cell(bad_cell).is_err()); | |
| } | |
| // ============ REPLAY TESTS ============ | |
| fn test_replay_attack_detection() { | |
| let mut chain = ReceiptChainV2::new(); | |
| let r1 = ReceiptV2::new( | |
| 0, "loc".to_string(), "cap001".to_string(), "instr1".to_string(), | |
| "dispatch".to_string(), "inp1".to_string(), "out1".to_string(), | |
| "rust".to_string(), "1.0.0".to_string(), "src1".to_string(), | |
| "env1".to_string(), "0".repeat(128), 100, "nonce-001".to_string(), | |
| "global".to_string(), | |
| ); | |
| assert!(chain.append(r1.clone()).is_ok()); | |
| // Attempt to replay: same nonce + context | |
| let r2 = ReceiptV2::new( | |
| 1, "loc".to_string(), "cap001".to_string(), "instr2".to_string(), | |
| "dispatch".to_string(), "inp2".to_string(), "out2".to_string(), | |
| "rust".to_string(), "1.0.0".to_string(), "src2".to_string(), | |
| "env2".to_string(), r1.receipt_hash.clone(), 200, | |
| "nonce-001".to_string(), // DUPLICATE NONCE | |
| "global".to_string(), // DUPLICATE CONTEXT | |
| ); | |
| assert!(chain.append(r2).is_err()); | |
| } | |
| fn test_cross_context_nonce_isolation() { | |
| let mut protection = GlobalReplayProtection::new(3600); | |
| // Same nonce in different contexts: should succeed | |
| assert!(protection.check_and_record("context-A", "shared-nonce", 1).is_ok()); | |
| assert!(protection.check_and_record("context-B", "shared-nonce", 1).is_ok()); | |
| // But duplicate within same context: should fail | |
| assert!(protection.check_and_record("context-A", "shared-nonce", 2).is_err()); | |
| } | |
| fn test_monotonic_counter_prevents_reordering() { | |
| let mut detector = ReplayDetector::new("test".to_string(), 3600); | |
| assert!(detector.check_and_record("n1", 100).is_ok()); | |
| assert!(detector.check_and_record("n2", 101).is_ok()); | |
| // Try to insert out-of-order | |
| assert!(detector.check_and_record("n3", 101).is_err()); // Not increasing | |
| assert!(detector.check_and_record("n4", 99).is_err()); // Going backward | |
| } | |
| // ============ REGRESSION TESTS ============ | |
| fn test_all_receipt_v2_tests_still_passing() { | |
| // Ensure existing receipt_v2 tests don't regress | |
| assert!(ReceiptV2::new( | |
| 0, "a".to_string(), "b".to_string(), "c".to_string(), | |
| "d".to_string(), "e".to_string(), "f".to_string(), | |
| "g".to_string(), "h".to_string(), "i".to_string(), | |
| "j".to_string(), "0".repeat(128), 1, "n".to_string(), | |
| "ctx".to_string(), | |
| ).verify_hash()); | |
| } | |
| fn test_all_ed25519_tests_still_passing() { | |
| let kp = Ed25519KeyPair::generate(); | |
| let msg = b"test"; | |
| let sig = kp.sign(msg); | |
| assert!(Ed25519KeyPair::verify(&kp.public_key_hex(), msg, &sig).unwrap()); | |
| } | |
| fn test_all_replay_protection_tests_still_passing() { | |
| let mut protection = GlobalReplayProtection::new(3600); | |
| assert!(protection.check_and_record("ctx", "nonce", 1).is_ok()); | |
| } | |
| } | |