pipa_core/engine/contracts/
meta.rs1use crate::contracts::load_contract_for_file; use crate::engine::log_action; use crate::logging::AuditLogger;
6use glob; use std::path::Path;
8
9pub struct ContractList {
11 pub contracts: Vec<String>, }
13
14pub struct ContractInfo {
16 pub name: String, pub version: String, pub exists: bool, }
20
21pub struct ContractValidation {
23 pub valid: bool, pub error: Option<String>, }
26
27pub fn list_contracts<L: AuditLogger>(logger: &L) -> Result<(ContractList, String), String> {
30 let contracts: Vec<String> = match glob::glob("contracts/*.toml") {
31 Ok(paths) => paths
32 .filter_map(Result::ok)
33 .filter_map(|p| {
34 p.file_stem()
35 .and_then(|s| s.to_str())
36 .map(|s| s.to_string())
37 })
38 .collect(),
39 Err(_) => return Err("Failed to read contracts directory".to_string()),
40 };
41
42 let message = log_action(logger, "contracts_listed", None, None, None, None);
43 Ok((ContractList { contracts }, message))
44}
45
46pub fn get_contract<L: AuditLogger>(logger: &L, name: &str) -> (ContractInfo, String) {
49 let contract_path = format!("contracts/{}.toml", name);
50
51 if !Path::new(&contract_path).exists() {
52 let message = log_action(
53 logger,
54 "contract_retrieved",
55 Some("exists=false"),
56 Some(name),
57 None,
58 None,
59 );
60 return (
61 ContractInfo {
62 name: name.to_string(),
63 version: "".to_string(),
64 exists: false,
65 },
66 message,
67 );
68 }
69
70 let contract = load_contract_for_file(Path::new(&contract_path));
71 let message = log_action(
72 logger,
73 "contract_retrieved",
74 Some("exists=true"),
75 Some(&contract.contract.name),
76 Some(&contract.contract.version),
77 None,
78 );
79 (
80 ContractInfo {
81 name: contract.contract.name,
82 version: contract.contract.version,
83 exists: true,
84 },
85 message,
86 )
87}
88
89pub fn validate_contract<L: AuditLogger>(logger: &L, name: &str) -> (ContractValidation, String) {
93 let contract_path = format!("contracts/{}.toml", name);
94
95 if !Path::new(&contract_path).exists() {
96 let message = log_action(
97 logger,
98 "contract_validated",
99 Some("error=Contract not found"),
100 Some(name),
101 None,
102 None,
103 );
104 return (
105 ContractValidation {
106 valid: false,
107 error: Some("Contract not found".to_string()),
108 },
109 message,
110 );
111 }
112
113 match std::panic::catch_unwind(|| load_contract_for_file(Path::new(&contract_path))) {
114 Ok(contract) => {
115 let message = log_action(
116 logger,
117 "contract_validated",
118 Some("valid=true"),
119 Some(&contract.contract.name),
120 Some(&contract.contract.version),
121 None,
122 );
123 (
124 ContractValidation {
125 valid: true,
126 error: None,
127 },
128 message,
129 )
130 }
131 Err(_) => {
132 let message = log_action(
133 logger,
134 "contract_validated",
135 Some("error=Contract failed to parse"),
136 Some(name),
137 None,
138 None,
139 );
140 (
141 ContractValidation {
142 valid: false,
143 error: Some("Contract failed to parse".to_string()),
144 },
145 message,
146 )
147 }
148 }
149}