qualia_core_db/modalities/logic/shacl_extensions/
config.rs1use crate::webizen::SlgOpcode;
8
9#[derive(Debug, Clone)]
13pub struct LogConfiguration {
14 pub max_memory_logs: u32,
15 pub max_disk_logs: u32,
16 pub flush_interval_ms: u32,
17}
18
19#[derive(Debug, Clone)]
21pub struct LogLevel {
22 pub allowed_levels: Vec<String>, }
24
25#[derive(Debug, Clone)]
27pub struct LogEntry {
28 pub require_timestamp: bool,
29 pub require_context: bool,
30 pub max_message_length: u32,
31 pub allow_data_payload: bool,
32}
33
34#[derive(Debug, Clone)]
36pub struct LogRetention {
37 pub max_age_days: u32,
38 pub max_size_mb: u32,
39 pub backup_before_cleanup: bool,
40}
41
42#[derive(Debug, Clone)]
44pub struct LogExportFormat {
45 pub allowed_formats: Vec<String>, pub max_export_size_mb: u32,
47}
48
49#[derive(Debug, Clone)]
53pub struct SystemTrayConfiguration {
54 pub max_menu_items: u8,
55 pub require_separator_logic: bool,
56 pub allow_nested_menus: bool,
57}
58
59#[derive(Debug, Clone)]
61pub struct TrayMenuItem {
62 pub require_label: bool,
63 pub require_action: bool,
64 pub max_label_length: u32,
65 pub allow_icons: bool,
66}
67
68#[derive(Debug, Clone)]
70pub struct TrayStatusIndicator {
71 pub allow_live_updates: bool,
72 pub update_interval_ms: u32,
73 pub max_status_length: u32,
74}
75
76#[derive(Debug, Clone)]
78pub struct TrayAction {
79 pub require_window_context: bool,
80 pub allow_async_actions: bool,
81 pub timeout_ms: u32,
82}
83
84#[derive(Debug, Clone)]
88pub struct StorageConfiguration {
89 pub min_quota_gb: u32,
90 pub max_quota_gb: u32,
91 pub require_absolute_path: bool,
92 pub allowed_path_patterns: Vec<String>,
93}
94
95#[derive(Debug, Clone)]
97pub struct NetworkConfiguration {
98 pub allowed_ports: Vec<u16>,
99 pub require_port_conflict_check: bool,
100 pub default_host: String,
101}
102
103#[derive(Debug, Clone)]
105pub struct TaxRecipientConfiguration {
106 pub require_ilp_address: bool,
107 pub min_share_percent: u8,
108 pub max_share_percent: u8,
109 pub allow_nym_routing: bool,
110 pub total_share_validation: bool,
111}
112
113#[derive(Debug, Clone)]
115pub struct SecurityConfiguration {
116 pub require_encryption: bool,
117 pub allowed_cipher_suites: Vec<String>,
118 pub min_key_length_bits: u16,
119}
120
121impl LogConfiguration {
124 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
125 vec![
126 SlgOpcode::CheckMaxInclusive(self.max_memory_logs as f64),
127 SlgOpcode::CheckMaxInclusive(self.max_disk_logs as f64),
128 SlgOpcode::CheckMinInclusive(self.flush_interval_ms as f64),
129 ]
130 }
131}
132
133impl LogLevel {
134 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
135 self.allowed_levels
137 .iter()
138 .map(|level| SlgOpcode::CheckHasValue(crate::q_hash(level)))
139 .collect()
140 }
141}
142
143impl LogEntry {
144 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
145 let mut opcodes = Vec::new();
146 if self.require_timestamp {
147 opcodes.push(SlgOpcode::CheckMinCount(1));
148 }
149 if self.require_context {
150 opcodes.push(SlgOpcode::CheckMinCount(1));
151 }
152 if self.max_message_length > 0 {
153 opcodes.push(SlgOpcode::CheckMaxLength(self.max_message_length));
154 }
155 if !self.allow_data_payload {
156 opcodes.push(SlgOpcode::CheckMaxCount(3)); }
158 opcodes
159 }
160}
161
162impl LogRetention {
163 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
164 vec![
165 SlgOpcode::CheckMaxInclusive(self.max_age_days as f64),
166 SlgOpcode::CheckMaxInclusive(self.max_size_mb as f64),
167 ]
168 }
169}
170
171impl LogExportFormat {
172 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
173 let mut opcodes = vec![SlgOpcode::CheckMaxInclusive(self.max_export_size_mb as f64)];
174 for format in &self.allowed_formats {
176 opcodes.push(SlgOpcode::CheckHasValue(crate::q_hash(format)));
177 }
178 opcodes
179 }
180}
181
182impl SystemTrayConfiguration {
183 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
184 vec![SlgOpcode::CheckMaxInclusive(self.max_menu_items as f64)]
185 }
186}
187
188impl TrayMenuItem {
189 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
190 let mut opcodes = Vec::new();
191 if self.require_label {
192 opcodes.push(SlgOpcode::CheckMinCount(1));
193 }
194 if self.require_action {
195 opcodes.push(SlgOpcode::CheckMinCount(1));
196 }
197 if self.max_label_length > 0 {
198 opcodes.push(SlgOpcode::CheckMaxLength(self.max_label_length));
199 }
200 opcodes
201 }
202}
203
204impl TrayStatusIndicator {
205 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
206 vec![
207 SlgOpcode::CheckMaxLength(self.max_status_length),
208 SlgOpcode::CheckMinInclusive(self.update_interval_ms as f64),
209 ]
210 }
211}
212
213impl TrayAction {
214 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
215 vec![SlgOpcode::CheckMaxInclusive(self.timeout_ms as f64)]
216 }
217}
218
219impl StorageConfiguration {
220 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
221 let mut opcodes = vec![
222 SlgOpcode::CheckMinInclusive(self.min_quota_gb as f64),
223 SlgOpcode::CheckMaxInclusive(self.max_quota_gb as f64),
224 ];
225 if self.require_absolute_path {
226 opcodes.push(SlgOpcode::CheckMinCount(1));
227 }
228 opcodes
229 }
230}
231
232impl NetworkConfiguration {
233 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
234 let mut opcodes = Vec::new();
235 for port in &self.allowed_ports {
236 opcodes.push(SlgOpcode::CheckHasValue(*port as u64));
237 }
238 opcodes
239 }
240}
241
242impl TaxRecipientConfiguration {
243 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
244 vec![
245 SlgOpcode::CheckMinInclusive(self.min_share_percent as f64),
246 SlgOpcode::CheckMaxInclusive(self.max_share_percent as f64),
247 ]
248 }
249}
250
251impl SecurityConfiguration {
252 pub fn to_opcodes(&self) -> Vec<SlgOpcode> {
253 vec![SlgOpcode::CheckMinInclusive(
254 self.min_key_length_bits as f64,
255 )]
256 }
257}
258
259pub fn get_shacl_extensions_ttl() -> &'static str {
263 r#"
264@prefix q42: <https://webizen.org/q42#> .
265@prefix sh: <http://www.w3.org/ns/shacl#> .
266@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
267
268# ── Logging System Constraints ─────────────────────────────────────────────
269
270q42:LogConfiguration a sh:NodeShape ;
271 sh:property [
272 sh:path q42:maxMemoryLogs ;
273 sh:datatype xsd:integer ;
274 sh:minInclusive 1 ;
275 sh:maxInclusive 100000 ;
276 sh:message "Maximum memory logs must be between 1 and 100000" ;
277 ] ;
278 sh:property [
279 sh:path q42:maxDiskLogs ;
280 sh:datatype xsd:integer ;
281 sh:minInclusive 1 ;
282 sh:maxInclusive 1000000 ;
283 sh:message "Maximum disk logs must be between 1 and 1000000" ;
284 ] ;
285 sh:property [
286 sh:path q42:flushIntervalMs ;
287 sh:datatype xsd:integer ;
288 sh:minInclusive 100 ;
289 sh:maxInclusive 60000 ;
290 sh:message "Flush interval must be between 100ms and 60000ms" ;
291 ] .
292
293q42:LogLevel a sh:NodeShape ;
294 sh:property [
295 sh:path q42:allowedLevels ;
296 sh:in ("DEBUG" "INFO" "WARN" "ERROR" "CRITICAL") ;
297 sh:message "Log level must be one of: DEBUG, INFO, WARN, ERROR, CRITICAL" ;
298 ] .
299
300q42:LogEntry a sh:NodeShape ;
301 sh:property [
302 sh:path q42:timestamp ;
303 sh:datatype xsd:dateTime ;
304 sh:minCount 1 ;
305 sh:message "Log entry must have a timestamp" ;
306 ] ;
307 sh:property [
308 sh:path q42:level ;
309 sh:datatype xsd:string ;
310 sh:minCount 1 ;
311 sh:message "Log entry must have a level" ;
312 ] ;
313 sh:property [
314 sh:path q42:message ;
315 sh:datatype xsd:string ;
316 sh:maxLength 10000 ;
317 sh:message "Log message must not exceed 10000 characters" ;
318 ] .
319
320q42:LogRetention a sh:NodeShape ;
321 sh:property [
322 sh:path q42:maxAgeDays ;
323 sh:datatype xsd:integer ;
324 sh:minInclusive 1 ;
325 sh:maxInclusive 365 ;
326 sh:message "Log retention age must be between 1 and 365 days" ;
327 ] ;
328 sh:property [
329 sh:path q42:maxSizeMb ;
330 sh:datatype xsd:integer ;
331 sh:minInclusive 1 ;
332 sh:maxInclusive 10240 ;
333 sh:message "Log retention size must be between 1MB and 10GB" ;
334 ] .
335
336# ── System Tray Constraints ─────────────────────────────────────────────────
337
338q42:SystemTrayConfiguration a sh:NodeShape ;
339 sh:property [
340 sh:path q42:maxMenuItems ;
341 sh:datatype xsd:integer ;
342 sh:minInclusive 1 ;
343 sh:maxInclusive 20 ;
344 sh:message "System tray can have at most 20 menu items" ;
345 ] .
346
347q42:TrayMenuItem a sh:NodeShape ;
348 sh:property [
349 sh:path q42:label ;
350 sh:datatype xsd:string ;
351 sh:minCount 1 ;
352 sh:maxLength 50 ;
353 sh:message "Tray menu item must have a label (max 50 characters)" ;
354 ] ;
355 sh:property [
356 sh:path q42:action ;
357 sh:datatype xsd:string ;
358 sh:minCount 1 ;
359 sh:message "Tray menu item must have an action" ;
360 ] .
361
362q42:TrayStatusIndicator a sh:NodeShape ;
363 sh:property [
364 sh:path q42:statusText ;
365 sh:datatype xsd:string ;
366 sh:maxLength 100 ;
367 sh:message "Status text must not exceed 100 characters" ;
368 ] ;
369 sh:property [
370 sh:path q42:updateIntervalMs ;
371 sh:datatype xsd:integer ;
372 sh:minInclusive 100 ;
373 sh:maxInclusive 10000 ;
374 sh:message "Update interval must be between 100ms and 10000ms" ;
375 ] .
376
377# ── Enhanced Settings Constraints ─────────────────────────────────────────────
378
379q42:StorageConfiguration a sh:NodeShape ;
380 sh:property [
381 sh:path q42:storageQuotaGb ;
382 sh:datatype xsd:integer ;
383 sh:minInclusive 1 ;
384 sh:maxInclusive 1000 ;
385 sh:message "Storage quota must be between 1GB and 1000GB" ;
386 ] ;
387 sh:property [
388 sh:path q42:storagePath ;
389 sh:datatype xsd:string ;
390 sh:minCount 1 ;
391 sh:pattern "^/" ;
392 sh:message "Storage path must be an absolute path" ;
393 ] .
394
395q42:NetworkConfiguration a sh:NodeShape ;
396 sh:property [
397 sh:path q42:daemonPort ;
398 sh:datatype xsd:integer ;
399 sh:minInclusive 1024 ;
400 sh:maxInclusive 65535 ;
401 sh:message "Daemon port must be between 1024 and 65535" ;
402 ] ;
403 sh:property [
404 sh:path q42:daemonHost ;
405 sh:datatype xsd:string ;
406 sh:pattern "^(localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0)$" ;
407 sh:message "Daemon host must be localhost, 127.0.0.1, or 0.0.0.0" ;
408 ] .
409
410q42:TaxRecipientConfiguration a sh:NodeShape ;
411 sh:property [
412 sh:path q42:sharePercent ;
413 sh:datatype xsd:integer ;
414 sh:minInclusive 0 ;
415 sh:maxInclusive 100 ;
416 sh:message "Share percent must be between 0 and 100" ;
417 ] ;
418 sh:property [
419 sh:path q42:ilpAddress ;
420 sh:datatype xsd:string ;
421 sh:minCount 1 ;
422 sh:pattern "^\\$ilp\\." ;
423 sh:message "ILP address must start with $ilp." ;
424 ] .
425
426q42:SecurityConfiguration a sh:NodeShape ;
427 sh:property [
428 sh:path q42:minKeyLengthBits ;
429 sh:datatype xsd:integer ;
430 sh:minInclusive 128 ;
431 sh:maxInclusive 4096 ;
432 sh:message "Key length must be between 128 and 4096 bits" ;
433 ] ;
434 sh:property [
435 sh:path q42:requireEncryption ;
436 sh:datatype xsd:boolean ;
437 sh:message "Require encryption must be a boolean" ;
438 ] .
439"#
440}