kanon-sentry 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,744 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "android_system_properties"
7
+ version = "0.1.5"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
10
+ dependencies = [
11
+ "libc",
12
+ ]
13
+
14
+ [[package]]
15
+ name = "autocfg"
16
+ version = "1.5.0"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
19
+
20
+ [[package]]
21
+ name = "base64ct"
22
+ version = "1.8.3"
23
+ source = "registry+https://github.com/rust-lang/crates.io-index"
24
+ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
25
+
26
+ [[package]]
27
+ name = "block-buffer"
28
+ version = "0.10.4"
29
+ source = "registry+https://github.com/rust-lang/crates.io-index"
30
+ checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
31
+ dependencies = [
32
+ "generic-array",
33
+ ]
34
+
35
+ [[package]]
36
+ name = "bumpalo"
37
+ version = "3.20.2"
38
+ source = "registry+https://github.com/rust-lang/crates.io-index"
39
+ checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
40
+
41
+ [[package]]
42
+ name = "cc"
43
+ version = "1.2.56"
44
+ source = "registry+https://github.com/rust-lang/crates.io-index"
45
+ checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
46
+ dependencies = [
47
+ "find-msvc-tools",
48
+ "shlex",
49
+ ]
50
+
51
+ [[package]]
52
+ name = "cfg-if"
53
+ version = "1.0.4"
54
+ source = "registry+https://github.com/rust-lang/crates.io-index"
55
+ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
56
+
57
+ [[package]]
58
+ name = "chrono"
59
+ version = "0.4.44"
60
+ source = "registry+https://github.com/rust-lang/crates.io-index"
61
+ checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
62
+ dependencies = [
63
+ "iana-time-zone",
64
+ "js-sys",
65
+ "num-traits",
66
+ "serde",
67
+ "wasm-bindgen",
68
+ "windows-link",
69
+ ]
70
+
71
+ [[package]]
72
+ name = "const-oid"
73
+ version = "0.9.6"
74
+ source = "registry+https://github.com/rust-lang/crates.io-index"
75
+ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
76
+
77
+ [[package]]
78
+ name = "core-foundation-sys"
79
+ version = "0.8.7"
80
+ source = "registry+https://github.com/rust-lang/crates.io-index"
81
+ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
82
+
83
+ [[package]]
84
+ name = "cpufeatures"
85
+ version = "0.2.17"
86
+ source = "registry+https://github.com/rust-lang/crates.io-index"
87
+ checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
88
+ dependencies = [
89
+ "libc",
90
+ ]
91
+
92
+ [[package]]
93
+ name = "crypto-common"
94
+ version = "0.1.7"
95
+ source = "registry+https://github.com/rust-lang/crates.io-index"
96
+ checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
97
+ dependencies = [
98
+ "generic-array",
99
+ "typenum",
100
+ ]
101
+
102
+ [[package]]
103
+ name = "curve25519-dalek"
104
+ version = "4.1.3"
105
+ source = "registry+https://github.com/rust-lang/crates.io-index"
106
+ checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
107
+ dependencies = [
108
+ "cfg-if",
109
+ "cpufeatures",
110
+ "curve25519-dalek-derive",
111
+ "digest",
112
+ "fiat-crypto",
113
+ "rustc_version",
114
+ "subtle",
115
+ "zeroize",
116
+ ]
117
+
118
+ [[package]]
119
+ name = "curve25519-dalek-derive"
120
+ version = "0.1.1"
121
+ source = "registry+https://github.com/rust-lang/crates.io-index"
122
+ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
123
+ dependencies = [
124
+ "proc-macro2",
125
+ "quote",
126
+ "syn",
127
+ ]
128
+
129
+ [[package]]
130
+ name = "der"
131
+ version = "0.7.10"
132
+ source = "registry+https://github.com/rust-lang/crates.io-index"
133
+ checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
134
+ dependencies = [
135
+ "const-oid",
136
+ "zeroize",
137
+ ]
138
+
139
+ [[package]]
140
+ name = "digest"
141
+ version = "0.10.7"
142
+ source = "registry+https://github.com/rust-lang/crates.io-index"
143
+ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
144
+ dependencies = [
145
+ "block-buffer",
146
+ "crypto-common",
147
+ ]
148
+
149
+ [[package]]
150
+ name = "ed25519"
151
+ version = "2.2.3"
152
+ source = "registry+https://github.com/rust-lang/crates.io-index"
153
+ checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
154
+ dependencies = [
155
+ "pkcs8",
156
+ "signature",
157
+ ]
158
+
159
+ [[package]]
160
+ name = "ed25519-dalek"
161
+ version = "2.2.0"
162
+ source = "registry+https://github.com/rust-lang/crates.io-index"
163
+ checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
164
+ dependencies = [
165
+ "curve25519-dalek",
166
+ "ed25519",
167
+ "rand_core",
168
+ "serde",
169
+ "sha2",
170
+ "subtle",
171
+ "zeroize",
172
+ ]
173
+
174
+ [[package]]
175
+ name = "fiat-crypto"
176
+ version = "0.2.9"
177
+ source = "registry+https://github.com/rust-lang/crates.io-index"
178
+ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
179
+
180
+ [[package]]
181
+ name = "find-msvc-tools"
182
+ version = "0.1.9"
183
+ source = "registry+https://github.com/rust-lang/crates.io-index"
184
+ checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
185
+
186
+ [[package]]
187
+ name = "generic-array"
188
+ version = "0.14.7"
189
+ source = "registry+https://github.com/rust-lang/crates.io-index"
190
+ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
191
+ dependencies = [
192
+ "typenum",
193
+ "version_check",
194
+ ]
195
+
196
+ [[package]]
197
+ name = "getrandom"
198
+ version = "0.2.17"
199
+ source = "registry+https://github.com/rust-lang/crates.io-index"
200
+ checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
201
+ dependencies = [
202
+ "cfg-if",
203
+ "libc",
204
+ "wasi",
205
+ ]
206
+
207
+ [[package]]
208
+ name = "heck"
209
+ version = "0.5.0"
210
+ source = "registry+https://github.com/rust-lang/crates.io-index"
211
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
212
+
213
+ [[package]]
214
+ name = "hex"
215
+ version = "0.4.3"
216
+ source = "registry+https://github.com/rust-lang/crates.io-index"
217
+ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
218
+
219
+ [[package]]
220
+ name = "iana-time-zone"
221
+ version = "0.1.65"
222
+ source = "registry+https://github.com/rust-lang/crates.io-index"
223
+ checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
224
+ dependencies = [
225
+ "android_system_properties",
226
+ "core-foundation-sys",
227
+ "iana-time-zone-haiku",
228
+ "js-sys",
229
+ "log",
230
+ "wasm-bindgen",
231
+ "windows-core",
232
+ ]
233
+
234
+ [[package]]
235
+ name = "iana-time-zone-haiku"
236
+ version = "0.1.2"
237
+ source = "registry+https://github.com/rust-lang/crates.io-index"
238
+ checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
239
+ dependencies = [
240
+ "cc",
241
+ ]
242
+
243
+ [[package]]
244
+ name = "indoc"
245
+ version = "2.0.7"
246
+ source = "registry+https://github.com/rust-lang/crates.io-index"
247
+ checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
248
+ dependencies = [
249
+ "rustversion",
250
+ ]
251
+
252
+ [[package]]
253
+ name = "itoa"
254
+ version = "1.0.17"
255
+ source = "registry+https://github.com/rust-lang/crates.io-index"
256
+ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
257
+
258
+ [[package]]
259
+ name = "js-sys"
260
+ version = "0.3.91"
261
+ source = "registry+https://github.com/rust-lang/crates.io-index"
262
+ checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
263
+ dependencies = [
264
+ "once_cell",
265
+ "wasm-bindgen",
266
+ ]
267
+
268
+ [[package]]
269
+ name = "kanon-core"
270
+ version = "0.1.0"
271
+ dependencies = [
272
+ "chrono",
273
+ "ed25519-dalek",
274
+ "hex",
275
+ "pyo3",
276
+ "rand",
277
+ "serde",
278
+ "serde_json",
279
+ ]
280
+
281
+ [[package]]
282
+ name = "libc"
283
+ version = "0.2.182"
284
+ source = "registry+https://github.com/rust-lang/crates.io-index"
285
+ checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
286
+
287
+ [[package]]
288
+ name = "log"
289
+ version = "0.4.29"
290
+ source = "registry+https://github.com/rust-lang/crates.io-index"
291
+ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
292
+
293
+ [[package]]
294
+ name = "memchr"
295
+ version = "2.8.0"
296
+ source = "registry+https://github.com/rust-lang/crates.io-index"
297
+ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
298
+
299
+ [[package]]
300
+ name = "memoffset"
301
+ version = "0.9.1"
302
+ source = "registry+https://github.com/rust-lang/crates.io-index"
303
+ checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
304
+ dependencies = [
305
+ "autocfg",
306
+ ]
307
+
308
+ [[package]]
309
+ name = "num-traits"
310
+ version = "0.2.19"
311
+ source = "registry+https://github.com/rust-lang/crates.io-index"
312
+ checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
313
+ dependencies = [
314
+ "autocfg",
315
+ ]
316
+
317
+ [[package]]
318
+ name = "once_cell"
319
+ version = "1.21.3"
320
+ source = "registry+https://github.com/rust-lang/crates.io-index"
321
+ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
322
+
323
+ [[package]]
324
+ name = "pkcs8"
325
+ version = "0.10.2"
326
+ source = "registry+https://github.com/rust-lang/crates.io-index"
327
+ checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
328
+ dependencies = [
329
+ "der",
330
+ "spki",
331
+ ]
332
+
333
+ [[package]]
334
+ name = "portable-atomic"
335
+ version = "1.13.1"
336
+ source = "registry+https://github.com/rust-lang/crates.io-index"
337
+ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
338
+
339
+ [[package]]
340
+ name = "ppv-lite86"
341
+ version = "0.2.21"
342
+ source = "registry+https://github.com/rust-lang/crates.io-index"
343
+ checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
344
+ dependencies = [
345
+ "zerocopy",
346
+ ]
347
+
348
+ [[package]]
349
+ name = "proc-macro2"
350
+ version = "1.0.106"
351
+ source = "registry+https://github.com/rust-lang/crates.io-index"
352
+ checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
353
+ dependencies = [
354
+ "unicode-ident",
355
+ ]
356
+
357
+ [[package]]
358
+ name = "pyo3"
359
+ version = "0.27.2"
360
+ source = "registry+https://github.com/rust-lang/crates.io-index"
361
+ checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d"
362
+ dependencies = [
363
+ "indoc",
364
+ "libc",
365
+ "memoffset",
366
+ "once_cell",
367
+ "portable-atomic",
368
+ "pyo3-build-config",
369
+ "pyo3-ffi",
370
+ "pyo3-macros",
371
+ "unindent",
372
+ ]
373
+
374
+ [[package]]
375
+ name = "pyo3-build-config"
376
+ version = "0.27.2"
377
+ source = "registry+https://github.com/rust-lang/crates.io-index"
378
+ checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6"
379
+ dependencies = [
380
+ "target-lexicon",
381
+ ]
382
+
383
+ [[package]]
384
+ name = "pyo3-ffi"
385
+ version = "0.27.2"
386
+ source = "registry+https://github.com/rust-lang/crates.io-index"
387
+ checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089"
388
+ dependencies = [
389
+ "libc",
390
+ "pyo3-build-config",
391
+ ]
392
+
393
+ [[package]]
394
+ name = "pyo3-macros"
395
+ version = "0.27.2"
396
+ source = "registry+https://github.com/rust-lang/crates.io-index"
397
+ checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02"
398
+ dependencies = [
399
+ "proc-macro2",
400
+ "pyo3-macros-backend",
401
+ "quote",
402
+ "syn",
403
+ ]
404
+
405
+ [[package]]
406
+ name = "pyo3-macros-backend"
407
+ version = "0.27.2"
408
+ source = "registry+https://github.com/rust-lang/crates.io-index"
409
+ checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9"
410
+ dependencies = [
411
+ "heck",
412
+ "proc-macro2",
413
+ "pyo3-build-config",
414
+ "quote",
415
+ "syn",
416
+ ]
417
+
418
+ [[package]]
419
+ name = "quote"
420
+ version = "1.0.45"
421
+ source = "registry+https://github.com/rust-lang/crates.io-index"
422
+ checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
423
+ dependencies = [
424
+ "proc-macro2",
425
+ ]
426
+
427
+ [[package]]
428
+ name = "rand"
429
+ version = "0.8.5"
430
+ source = "registry+https://github.com/rust-lang/crates.io-index"
431
+ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
432
+ dependencies = [
433
+ "libc",
434
+ "rand_chacha",
435
+ "rand_core",
436
+ ]
437
+
438
+ [[package]]
439
+ name = "rand_chacha"
440
+ version = "0.3.1"
441
+ source = "registry+https://github.com/rust-lang/crates.io-index"
442
+ checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
443
+ dependencies = [
444
+ "ppv-lite86",
445
+ "rand_core",
446
+ ]
447
+
448
+ [[package]]
449
+ name = "rand_core"
450
+ version = "0.6.4"
451
+ source = "registry+https://github.com/rust-lang/crates.io-index"
452
+ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
453
+ dependencies = [
454
+ "getrandom",
455
+ ]
456
+
457
+ [[package]]
458
+ name = "rustc_version"
459
+ version = "0.4.1"
460
+ source = "registry+https://github.com/rust-lang/crates.io-index"
461
+ checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
462
+ dependencies = [
463
+ "semver",
464
+ ]
465
+
466
+ [[package]]
467
+ name = "rustversion"
468
+ version = "1.0.22"
469
+ source = "registry+https://github.com/rust-lang/crates.io-index"
470
+ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
471
+
472
+ [[package]]
473
+ name = "semver"
474
+ version = "1.0.27"
475
+ source = "registry+https://github.com/rust-lang/crates.io-index"
476
+ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
477
+
478
+ [[package]]
479
+ name = "serde"
480
+ version = "1.0.228"
481
+ source = "registry+https://github.com/rust-lang/crates.io-index"
482
+ checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
483
+ dependencies = [
484
+ "serde_core",
485
+ "serde_derive",
486
+ ]
487
+
488
+ [[package]]
489
+ name = "serde_core"
490
+ version = "1.0.228"
491
+ source = "registry+https://github.com/rust-lang/crates.io-index"
492
+ checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
493
+ dependencies = [
494
+ "serde_derive",
495
+ ]
496
+
497
+ [[package]]
498
+ name = "serde_derive"
499
+ version = "1.0.228"
500
+ source = "registry+https://github.com/rust-lang/crates.io-index"
501
+ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
502
+ dependencies = [
503
+ "proc-macro2",
504
+ "quote",
505
+ "syn",
506
+ ]
507
+
508
+ [[package]]
509
+ name = "serde_json"
510
+ version = "1.0.149"
511
+ source = "registry+https://github.com/rust-lang/crates.io-index"
512
+ checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
513
+ dependencies = [
514
+ "itoa",
515
+ "memchr",
516
+ "serde",
517
+ "serde_core",
518
+ "zmij",
519
+ ]
520
+
521
+ [[package]]
522
+ name = "sha2"
523
+ version = "0.10.9"
524
+ source = "registry+https://github.com/rust-lang/crates.io-index"
525
+ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
526
+ dependencies = [
527
+ "cfg-if",
528
+ "cpufeatures",
529
+ "digest",
530
+ ]
531
+
532
+ [[package]]
533
+ name = "shlex"
534
+ version = "1.3.0"
535
+ source = "registry+https://github.com/rust-lang/crates.io-index"
536
+ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
537
+
538
+ [[package]]
539
+ name = "signature"
540
+ version = "2.2.0"
541
+ source = "registry+https://github.com/rust-lang/crates.io-index"
542
+ checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
543
+ dependencies = [
544
+ "rand_core",
545
+ ]
546
+
547
+ [[package]]
548
+ name = "spki"
549
+ version = "0.7.3"
550
+ source = "registry+https://github.com/rust-lang/crates.io-index"
551
+ checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
552
+ dependencies = [
553
+ "base64ct",
554
+ "der",
555
+ ]
556
+
557
+ [[package]]
558
+ name = "subtle"
559
+ version = "2.6.1"
560
+ source = "registry+https://github.com/rust-lang/crates.io-index"
561
+ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
562
+
563
+ [[package]]
564
+ name = "syn"
565
+ version = "2.0.117"
566
+ source = "registry+https://github.com/rust-lang/crates.io-index"
567
+ checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
568
+ dependencies = [
569
+ "proc-macro2",
570
+ "quote",
571
+ "unicode-ident",
572
+ ]
573
+
574
+ [[package]]
575
+ name = "target-lexicon"
576
+ version = "0.13.5"
577
+ source = "registry+https://github.com/rust-lang/crates.io-index"
578
+ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
579
+
580
+ [[package]]
581
+ name = "typenum"
582
+ version = "1.19.0"
583
+ source = "registry+https://github.com/rust-lang/crates.io-index"
584
+ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
585
+
586
+ [[package]]
587
+ name = "unicode-ident"
588
+ version = "1.0.24"
589
+ source = "registry+https://github.com/rust-lang/crates.io-index"
590
+ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
591
+
592
+ [[package]]
593
+ name = "unindent"
594
+ version = "0.2.4"
595
+ source = "registry+https://github.com/rust-lang/crates.io-index"
596
+ checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
597
+
598
+ [[package]]
599
+ name = "version_check"
600
+ version = "0.9.5"
601
+ source = "registry+https://github.com/rust-lang/crates.io-index"
602
+ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
603
+
604
+ [[package]]
605
+ name = "wasi"
606
+ version = "0.11.1+wasi-snapshot-preview1"
607
+ source = "registry+https://github.com/rust-lang/crates.io-index"
608
+ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
609
+
610
+ [[package]]
611
+ name = "wasm-bindgen"
612
+ version = "0.2.114"
613
+ source = "registry+https://github.com/rust-lang/crates.io-index"
614
+ checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e"
615
+ dependencies = [
616
+ "cfg-if",
617
+ "once_cell",
618
+ "rustversion",
619
+ "wasm-bindgen-macro",
620
+ "wasm-bindgen-shared",
621
+ ]
622
+
623
+ [[package]]
624
+ name = "wasm-bindgen-macro"
625
+ version = "0.2.114"
626
+ source = "registry+https://github.com/rust-lang/crates.io-index"
627
+ checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6"
628
+ dependencies = [
629
+ "quote",
630
+ "wasm-bindgen-macro-support",
631
+ ]
632
+
633
+ [[package]]
634
+ name = "wasm-bindgen-macro-support"
635
+ version = "0.2.114"
636
+ source = "registry+https://github.com/rust-lang/crates.io-index"
637
+ checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3"
638
+ dependencies = [
639
+ "bumpalo",
640
+ "proc-macro2",
641
+ "quote",
642
+ "syn",
643
+ "wasm-bindgen-shared",
644
+ ]
645
+
646
+ [[package]]
647
+ name = "wasm-bindgen-shared"
648
+ version = "0.2.114"
649
+ source = "registry+https://github.com/rust-lang/crates.io-index"
650
+ checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16"
651
+ dependencies = [
652
+ "unicode-ident",
653
+ ]
654
+
655
+ [[package]]
656
+ name = "windows-core"
657
+ version = "0.62.2"
658
+ source = "registry+https://github.com/rust-lang/crates.io-index"
659
+ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
660
+ dependencies = [
661
+ "windows-implement",
662
+ "windows-interface",
663
+ "windows-link",
664
+ "windows-result",
665
+ "windows-strings",
666
+ ]
667
+
668
+ [[package]]
669
+ name = "windows-implement"
670
+ version = "0.60.2"
671
+ source = "registry+https://github.com/rust-lang/crates.io-index"
672
+ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
673
+ dependencies = [
674
+ "proc-macro2",
675
+ "quote",
676
+ "syn",
677
+ ]
678
+
679
+ [[package]]
680
+ name = "windows-interface"
681
+ version = "0.59.3"
682
+ source = "registry+https://github.com/rust-lang/crates.io-index"
683
+ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
684
+ dependencies = [
685
+ "proc-macro2",
686
+ "quote",
687
+ "syn",
688
+ ]
689
+
690
+ [[package]]
691
+ name = "windows-link"
692
+ version = "0.2.1"
693
+ source = "registry+https://github.com/rust-lang/crates.io-index"
694
+ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
695
+
696
+ [[package]]
697
+ name = "windows-result"
698
+ version = "0.4.1"
699
+ source = "registry+https://github.com/rust-lang/crates.io-index"
700
+ checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
701
+ dependencies = [
702
+ "windows-link",
703
+ ]
704
+
705
+ [[package]]
706
+ name = "windows-strings"
707
+ version = "0.5.1"
708
+ source = "registry+https://github.com/rust-lang/crates.io-index"
709
+ checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
710
+ dependencies = [
711
+ "windows-link",
712
+ ]
713
+
714
+ [[package]]
715
+ name = "zerocopy"
716
+ version = "0.8.40"
717
+ source = "registry+https://github.com/rust-lang/crates.io-index"
718
+ checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5"
719
+ dependencies = [
720
+ "zerocopy-derive",
721
+ ]
722
+
723
+ [[package]]
724
+ name = "zerocopy-derive"
725
+ version = "0.8.40"
726
+ source = "registry+https://github.com/rust-lang/crates.io-index"
727
+ checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953"
728
+ dependencies = [
729
+ "proc-macro2",
730
+ "quote",
731
+ "syn",
732
+ ]
733
+
734
+ [[package]]
735
+ name = "zeroize"
736
+ version = "1.8.2"
737
+ source = "registry+https://github.com/rust-lang/crates.io-index"
738
+ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
739
+
740
+ [[package]]
741
+ name = "zmij"
742
+ version = "1.0.21"
743
+ source = "registry+https://github.com/rust-lang/crates.io-index"
744
+ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
@@ -0,0 +1,3 @@
1
+ [workspace]
2
+ members = ["src/kanon_core"]
3
+ resolver = "2"
@@ -0,0 +1,44 @@
1
+ Metadata-Version: 2.4
2
+ Name: kanon-sentry
3
+ Version: 0.1.0
4
+ Classifier: Programming Language :: Python :: 3
5
+ Classifier: Programming Language :: Rust
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: Topic :: Security
9
+ Requires-Dist: pydantic
10
+ Requires-Dist: nicegui
11
+ Summary: A deterministic, local-first safety layer for agentic AI.
12
+ Author-email: Mabel Seese <your-email@example.com>
13
+ License-Expression: MIT
14
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
15
+ Project-URL: Bug Tracker, https://github.com/rootedresilientshop-pixel/Kanon-Sentry/issues
16
+ Project-URL: Homepage, https://github.com/rootedresilientshop-pixel/Kanon-Sentry
17
+
18
+ # Kanon Sentry
19
+
20
+ Kanon Sentry is a deterministic, local-first safety layer for agentic AI. It is designed for developers who prioritize cryptographic accountability and on-device enforcement over cloud-based alignment.
21
+
22
+ This repository is the **Phase 1: Sovereign** release. The focus is a minimal, inspectable kernel with an auditable trail of every enforcement decision. Expect sharp edges; the goal is correctness and traceability first.
23
+
24
+ ## What It Does
25
+ - Validates actions against explicit intent constraints.
26
+ - Emits signed audit log entries for every decision.
27
+ - Keeps enforcement logic deterministic and transparent.
28
+
29
+ ## Quick Start
30
+ 1. Set the signing seed:
31
+ - `KANON_SEED` must be a 64-hex-character value (32 bytes).
32
+ 2. Install locally:
33
+ - `pip install -e .`
34
+ 3. Run the example:
35
+ - `python test_enforcement.py`
36
+
37
+ ## Philosophy
38
+ - **Local-First Sovereignty:** The kernel should run and be verifiable on your machine.
39
+ - **Deterministic Safety:** The rules are explicit; outcomes are reproducible.
40
+ - **Cryptographic Accountability:** Audit logs are signed and verifiable.
41
+
42
+ ## Status
43
+ Phase 1: Sovereign. Built for builders who want a practical, auditable safety kernel today, not a promise of future alignment.
44
+
@@ -0,0 +1,26 @@
1
+ # Kanon Sentry
2
+
3
+ Kanon Sentry is a deterministic, local-first safety layer for agentic AI. It is designed for developers who prioritize cryptographic accountability and on-device enforcement over cloud-based alignment.
4
+
5
+ This repository is the **Phase 1: Sovereign** release. The focus is a minimal, inspectable kernel with an auditable trail of every enforcement decision. Expect sharp edges; the goal is correctness and traceability first.
6
+
7
+ ## What It Does
8
+ - Validates actions against explicit intent constraints.
9
+ - Emits signed audit log entries for every decision.
10
+ - Keeps enforcement logic deterministic and transparent.
11
+
12
+ ## Quick Start
13
+ 1. Set the signing seed:
14
+ - `KANON_SEED` must be a 64-hex-character value (32 bytes).
15
+ 2. Install locally:
16
+ - `pip install -e .`
17
+ 3. Run the example:
18
+ - `python test_enforcement.py`
19
+
20
+ ## Philosophy
21
+ - **Local-First Sovereignty:** The kernel should run and be verifiable on your machine.
22
+ - **Deterministic Safety:** The rules are explicit; outcomes are reproducible.
23
+ - **Cryptographic Accountability:** Audit logs are signed and verifiable.
24
+
25
+ ## Status
26
+ Phase 1: Sovereign. Built for builders who want a practical, auditable safety kernel today, not a promise of future alignment.
@@ -0,0 +1,7 @@
1
+ from importlib import import_module as _import_module
2
+
3
+ _core = _import_module("kanon_core")
4
+
5
+ validate_intent_json = _core.validate_intent_json
6
+
7
+ __all__ = ["validate_intent_json"]
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["maturin>=1.5,<2.0"]
3
+ build-backend = "maturin"
4
+
5
+ [project]
6
+ name = "kanon-sentry"
7
+ version = "0.1.0"
8
+ authors = [{name = "Mabel Seese", email = "your-email@example.com"}]
9
+ description = "A deterministic, local-first safety layer for agentic AI."
10
+ readme = "README.md"
11
+ license = "MIT"
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3",
14
+ "Programming Language :: Rust",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Intended Audience :: Developers",
17
+ "Topic :: Security",
18
+ ]
19
+ urls = { "Homepage" = "https://github.com/rootedresilientshop-pixel/Kanon-Sentry", "Bug Tracker" = "https://github.com/rootedresilientshop-pixel/Kanon-Sentry/issues" }
20
+ dependencies = [
21
+ "pydantic",
22
+ "nicegui",
23
+ ]
24
+
25
+ [tool.maturin]
26
+ python-source = "kanon_sdk"
27
+ manifest-path = "src/kanon_core/Cargo.toml"
@@ -0,0 +1,18 @@
1
+ [package]
2
+ name = "kanon-core"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ readme = "README.md"
6
+
7
+ [lib]
8
+ name = "kanon_core"
9
+ crate-type = ["cdylib", "rlib"]
10
+
11
+ [dependencies]
12
+ serde = { version = "1.0", features = ["derive"] }
13
+ serde_json = "1.0"
14
+ pyo3 = { version = "0.27.0", features = ["extension-module", "abi3-py38"] }
15
+ chrono = { version = "0.4", features = ["serde"] }
16
+ ed25519-dalek = { version = "2.1", features = ["rand_core"] }
17
+ rand = "0.8"
18
+ hex = "0.4"
@@ -0,0 +1,9 @@
1
+ # Kanon
2
+ **The Universal Constraint Kernel for Intent-Based Agency.**
3
+
4
+ Kanon is an open-source framework designed to decouple high-level human intent from autonomous execution. It provides a deterministic "Safety Kernel" that governs probabilistic AI agents.
5
+
6
+ ### Core Philosophy
7
+ - **Intent-First:** Objectives and constraints are first-class executable constructs.
8
+ - **Deterministic Safety:** Intelligence suggests; the Kanon Kernel enforces.
9
+ - **Modular Governance:** Swap safety policies as easily as library imports.
@@ -0,0 +1,16 @@
1
+ from kanon_sdk.intent import Intent, Objective, Constraint
2
+
3
+ # Define a Mission: Optimize a marketing spend
4
+ marketing_mission = Intent(
5
+ id="mkt-001",
6
+ objective=Objective(name="ROAS", target="maximize", metric="revenue"),
7
+ constraints=[
8
+ Constraint(attribute="daily_budget", operator="<=", value=100.0),
9
+ Constraint(attribute="platform", operator="in", value=["instagram", "linkedin"]),
10
+ Constraint(attribute="risk_score", operator="<", value=0.2),
11
+ ],
12
+ mode="certification",
13
+ )
14
+
15
+ print(f"Generated Kanon Intent: {marketing_mission.id}")
16
+ print(marketing_mission.to_json())
@@ -0,0 +1,30 @@
1
+ import json
2
+ from kanon_sdk.intent import Intent, Objective, Constraint, validate_with_context
3
+ from kanon_sdk.observer import SafetyObserver
4
+
5
+
6
+ observer = SafetyObserver()
7
+
8
+ # Define Global Limit: Total Spend cannot exceed 500
9
+ intent = Intent(
10
+ id="global-guard-001",
11
+ objective=Objective(name="Safety", target="maintain", metric="stability"),
12
+ constraints=[
13
+ Constraint(attribute="total_daily_spend", operator="<=", value=500.0)
14
+ ],
15
+ )
16
+
17
+ # Current state of the world
18
+ world_state = {"values": {"current_spend": 450.0}}
19
+
20
+ # The AI tries to spend 60.0 (450 + 60 = 510, which should FAIL)
21
+ sneaky_action = {"params": {"amount": 60.0}}
22
+
23
+ print(f"Current Spend: {world_state['values']['current_spend']}")
24
+ print(f"Attempting to add: {sneaky_action['params']['amount']}")
25
+
26
+ try:
27
+ validate_with_context(intent, sneaky_action, world_state)
28
+ print("Action Allowed.")
29
+ except ValueError as e:
30
+ print(f"SENTRY DETECTED SALAMI ATTACK: {e}")
@@ -0,0 +1,288 @@
1
+ use pyo3::exceptions::PyValueError;
2
+ use pyo3::prelude::*;
3
+ use serde::{Deserialize, Serialize};
4
+ use std::collections::HashMap;
5
+ use std::env;
6
+ use std::fs::OpenOptions;
7
+ use std::io::Write;
8
+ use chrono::Utc;
9
+ use ed25519_dalek::{Signer, SigningKey};
10
+ use serde::de::Error as _;
11
+ use serde_json::Value as JsonValue;
12
+
13
+ #[derive(Debug, Serialize, Deserialize)]
14
+ pub struct Constraint {
15
+ pub attribute: String,
16
+ pub operator: String,
17
+ pub value: serde_json::Value,
18
+ pub priority: i32,
19
+ }
20
+
21
+ fn objective_from_any<'de, D>(deserializer: D) -> Result<String, D::Error>
22
+ where
23
+ D: serde::Deserializer<'de>,
24
+ {
25
+ let value = JsonValue::deserialize(deserializer)?;
26
+ match value {
27
+ JsonValue::String(s) => Ok(s),
28
+ other => serde_json::to_string(&other)
29
+ .map_err(D::Error::custom),
30
+ }
31
+ }
32
+
33
+ #[derive(Debug, Serialize, Deserialize)]
34
+ pub struct Intent {
35
+ pub id: String,
36
+ #[serde(deserialize_with = "objective_from_any")]
37
+ pub objective: String,
38
+ pub mode: String,
39
+ pub version: String,
40
+ pub constraints: Vec<Constraint>,
41
+ }
42
+
43
+ #[derive(Debug, Serialize, Deserialize)]
44
+ pub struct ProposedAction {
45
+ pub params: HashMap<String, serde_json::Value>,
46
+ }
47
+
48
+ #[derive(Debug, Serialize, Deserialize)]
49
+ pub struct State {
50
+ pub values: HashMap<String, serde_json::Value>,
51
+ }
52
+
53
+ #[derive(Serialize)]
54
+ struct AuditEntry {
55
+ timestamp: String,
56
+ intent_id: String,
57
+ objective: String,
58
+ mode: String,
59
+ version: String,
60
+ action_params: serde_json::Value,
61
+ result: String,
62
+ reason: Option<String>,
63
+ public_key: String,
64
+ signature: String,
65
+ }
66
+
67
+ // Sign a serialized payload and return a hex-encoded signature.
68
+ fn sign_entry(payload: &str, signing_key: &SigningKey) -> String {
69
+ let signature = signing_key.sign(payload.as_bytes());
70
+ hex::encode(signature.to_bytes())
71
+ }
72
+
73
+ #[derive(Debug)]
74
+ enum SafetyError {
75
+ UnsupportedOperator(String),
76
+ }
77
+
78
+ impl std::fmt::Display for SafetyError {
79
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80
+ match self {
81
+ SafetyError::UnsupportedOperator(op) => {
82
+ write!(f, "Unsupported operator: {}", op)
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ fn load_signing_key() -> SigningKey {
89
+ let seed_hex = env::var("KANON_SEED")
90
+ .expect("Sovereign Sentry requires KANON_SEED for integrity.");
91
+ let seed_bytes = hex::decode(seed_hex.trim())
92
+ .expect("Invalid KANON_SEED; expected hex string.");
93
+ let seed: [u8; 32] = seed_bytes
94
+ .as_slice()
95
+ .try_into()
96
+ .expect("Invalid KANON_SEED length; expected 32 bytes.");
97
+ SigningKey::from_bytes(&seed)
98
+ }
99
+
100
+ fn canonicalize_json(value: &JsonValue) -> JsonValue {
101
+ match value {
102
+ JsonValue::Object(map) => {
103
+ let mut keys: Vec<&String> = map.keys().collect();
104
+ keys.sort();
105
+ let mut new_map = serde_json::Map::new();
106
+ for key in keys {
107
+ if let Some(child) = map.get(key) {
108
+ new_map.insert(key.clone(), canonicalize_json(child));
109
+ }
110
+ }
111
+ JsonValue::Object(new_map)
112
+ }
113
+ JsonValue::Array(arr) => {
114
+ JsonValue::Array(arr.iter().map(canonicalize_json).collect())
115
+ }
116
+ _ => value.clone(),
117
+ }
118
+ }
119
+
120
+ pub struct Sentry;
121
+
122
+ impl Sentry {
123
+ /// The heart of Kanon: Checks if an action violates any intent constraints.
124
+ pub fn validate(intent: &Intent, action: &ProposedAction, state: &State) -> Result<bool, String> {
125
+ for constraint in &intent.constraints {
126
+ if constraint.attribute == "total_daily_spend" {
127
+ let current_spend = state
128
+ .values
129
+ .get("current_spend")
130
+ .and_then(|v| v.as_f64())
131
+ .unwrap_or(0.0);
132
+ let proposed_spend = action
133
+ .params
134
+ .get("amount")
135
+ .and_then(|v| v.as_f64())
136
+ .unwrap_or(0.0);
137
+ let limit = constraint.value.as_f64().unwrap_or(0.0);
138
+
139
+ if current_spend + proposed_spend > limit {
140
+ let err = format!(
141
+ "Dynamic Violation: Total spend would reach {}",
142
+ current_spend + proposed_spend
143
+ );
144
+ Self::log_event(intent, action, &Err(err.clone()));
145
+ return Err(err);
146
+ }
147
+ }
148
+ }
149
+
150
+ let mut result = Ok(true);
151
+
152
+ for constraint in &intent.constraints {
153
+ if constraint.attribute == "total_daily_spend" {
154
+ // This constraint is validated dynamically against current state.
155
+ continue;
156
+ }
157
+
158
+ let action_val = action.params.get(&constraint.attribute);
159
+
160
+ match action_val {
161
+ Some(val) => {
162
+ // Basic numeric comparison logic for Step 3
163
+ match Self::check_constraint(constraint, val) {
164
+ Ok(is_allowed) => {
165
+ if !is_allowed {
166
+ result = Err(format!(
167
+ "Constraint violation: {} {} {:?}",
168
+ constraint.attribute, constraint.operator, constraint.value
169
+ ));
170
+ break;
171
+ }
172
+ }
173
+ Err(e) => {
174
+ result = Err(e.to_string());
175
+ break;
176
+ }
177
+ }
178
+ }
179
+ None => {
180
+ // If a constraint exists but the action doesn't provide the value, block it.
181
+ result = Err(format!(
182
+ "Missing required attribute: {}",
183
+ constraint.attribute
184
+ ));
185
+ break;
186
+ }
187
+ }
188
+ }
189
+
190
+ // Always audit validation attempts, including failures.
191
+ Self::log_event(intent, action, &result);
192
+ result
193
+ }
194
+
195
+ fn log_event(intent: &Intent, action: &ProposedAction, result: &Result<bool, String>) {
196
+ let signing_key = load_signing_key();
197
+ let verifying_key = signing_key.verifying_key();
198
+
199
+ let timestamp = Utc::now().to_rfc3339();
200
+ let action_params = serde_json::to_value(&action.params).unwrap_or(serde_json::Value::Null);
201
+ let result_str = if result.is_ok() {
202
+ "PASS".to_string()
203
+ } else {
204
+ "FAIL".to_string()
205
+ };
206
+ let reason = result.as_ref().err().cloned();
207
+
208
+ let mut payload_map = serde_json::Map::new();
209
+ payload_map.insert("action_params".to_string(), action_params.clone());
210
+ payload_map.insert("intent_id".to_string(), JsonValue::String(intent.id.clone()));
211
+ payload_map.insert("mode".to_string(), JsonValue::String(intent.mode.clone()));
212
+ payload_map.insert("objective".to_string(), JsonValue::String(intent.objective.clone()));
213
+ payload_map.insert(
214
+ "reason".to_string(),
215
+ reason.clone()
216
+ .map(JsonValue::String)
217
+ .unwrap_or(JsonValue::Null),
218
+ );
219
+ payload_map.insert("result".to_string(), JsonValue::String(result_str.clone()));
220
+ payload_map.insert("timestamp".to_string(), JsonValue::String(timestamp.clone()));
221
+ payload_map.insert("version".to_string(), JsonValue::String(intent.version.clone()));
222
+
223
+ let payload = canonicalize_json(&JsonValue::Object(payload_map));
224
+
225
+ let payload_str = match serde_json::to_string(&payload) {
226
+ Ok(v) => v,
227
+ Err(_) => return,
228
+ };
229
+
230
+ let entry = AuditEntry {
231
+ timestamp,
232
+ intent_id: intent.id.clone(),
233
+ objective: intent.objective.clone(),
234
+ mode: intent.mode.clone(),
235
+ version: intent.version.clone(),
236
+ action_params,
237
+ result: result_str,
238
+ reason,
239
+ public_key: hex::encode(verifying_key.to_bytes()),
240
+ signature: sign_entry(&payload_str, &signing_key),
241
+ };
242
+
243
+ if let Ok(json) = serde_json::to_string(&entry) {
244
+ if let Ok(mut file) = OpenOptions::new()
245
+ .create(true)
246
+ .append(true)
247
+ .open("kanon_audit.log")
248
+ {
249
+ let _ = writeln!(file, "{}", json);
250
+ }
251
+ }
252
+ }
253
+
254
+ fn check_constraint(c: &Constraint, val: &serde_json::Value) -> Result<bool, SafetyError> {
255
+ // Simple numeric logic for MVP (we will expand this)
256
+ match c.operator.as_str() {
257
+ "<=" => Ok(val.as_f64().unwrap_or(0.0) <= c.value.as_f64().unwrap_or(-1.0)),
258
+ ">=" => Ok(val.as_f64().unwrap_or(0.0) >= c.value.as_f64().unwrap_or(0.0)),
259
+ "==" => Ok(val == &c.value),
260
+ _ => Err(SafetyError::UnsupportedOperator(c.operator.clone())),
261
+ }
262
+ }
263
+ }
264
+
265
+ #[pyfunction]
266
+ fn validate_intent_json(intent_json: String, action_json: String, state_json: String) -> PyResult<bool> {
267
+ // 1. Parse strings into Rust structs
268
+ let intent: Intent = serde_json::from_str(&intent_json)
269
+ .map_err(|e| PyValueError::new_err(format!("Invalid Intent JSON: {}", e)))?;
270
+
271
+ let action: ProposedAction = serde_json::from_str(&action_json)
272
+ .map_err(|e| PyValueError::new_err(format!("Invalid Action JSON: {}", e)))?;
273
+
274
+ let state: State = serde_json::from_str(&state_json)
275
+ .map_err(|e| PyValueError::new_err(format!("Invalid State JSON: {}", e)))?;
276
+
277
+ // 2. Execute the Sentry
278
+ match Sentry::validate(&intent, &action, &state) {
279
+ Ok(is_valid) => Ok(is_valid),
280
+ Err(e) => Err(PyValueError::new_err(e)),
281
+ }
282
+ }
283
+
284
+ #[pymodule]
285
+ fn kanon_core(m: &Bound<'_, PyModule>) -> PyResult<()> {
286
+ m.add_function(wrap_pyfunction!(validate_intent_json, m)?)?;
287
+ Ok(())
288
+ }