sdkt_audit_example_rule/
lib.rs1#[cfg(not(target_arch = "wasm32"))]
13use sdkt_audit::{
14 register_rule, AuditContext, AuditReport, AuditRule, BoxedRule, Finding, FnScan, Severity,
15};
16
17#[cfg(not(target_arch = "wasm32"))]
22pub struct ExampleRule;
23
24#[cfg(not(target_arch = "wasm32"))]
25impl AuditRule for ExampleRule {
26 fn id(&self) -> &'static str {
27 "EXAMPLE-001"
28 }
29 fn severity(&self) -> Severity {
30 Severity::Info
31 }
32 fn description(&self) -> &'static str {
33 "Example rule: detects functions named sdkt_example_trigger"
34 }
35 fn check(&self, scans: &[FnScan], _ctx: &AuditContext, report: &mut AuditReport) {
36 for s in scans {
37 if s.fn_name.contains("sdkt_example_trigger") {
38 report.add(Finding {
39 file: None,
40 rule_id: self.id().to_string(),
41 severity: self.severity(),
42 message: format!("Example rule matched trigger function `{}`", s.fn_name),
43 location: Some(s.fn_name.clone()),
44 });
45 }
46 }
47 }
48}
49
50#[cfg(not(target_arch = "wasm32"))]
52pub fn register() {
53 register_rule(Box::new(ExampleRule) as BoxedRule);
54}
55
56#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
59mod plugin_abi;
60
61#[cfg(all(feature = "wasm-plugins", target_arch = "wasm32"))]
63mod plugin_abi_wasm;
64
65#[cfg(all(test, not(target_arch = "wasm32")))]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn example_rule_fires_on_trigger_function() {
71 let scans = vec![FnScan {
72 fn_name: "sdkt_example_trigger_admin".to_string(),
73 require_auth: 0,
74 invoke_contract: 0,
75 bound: Default::default(),
76 usage: Default::default(),
77 division_before_multiplication: false,
78 external_call_before_state_write: false,
79 }];
80 let ctx = AuditContext { spec: None };
81 let mut report = AuditReport::default();
82 ExampleRule.check(&scans, &ctx, &mut report);
83 assert_eq!(report.summary.total, 1);
84 assert_eq!(report.findings[0].rule_id, "EXAMPLE-001");
85 }
86
87 #[test]
88 fn example_rule_silent_on_normal_function() {
89 let scans = vec![FnScan {
90 fn_name: "balance_of".to_string(),
91 require_auth: 0,
92 invoke_contract: 0,
93 bound: Default::default(),
94 usage: Default::default(),
95 division_before_multiplication: false,
96 external_call_before_state_write: false,
97 }];
98 let ctx = AuditContext { spec: None };
99 let mut report = AuditReport::default();
100 ExampleRule.check(&scans, &ctx, &mut report);
101 assert!(report.is_clean());
102 }
103}