citadel-shield 3.0.2__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.
Files changed (63) hide show
  1. citadel_shield-3.0.2/LICENSE +21 -0
  2. citadel_shield-3.0.2/PKG-INFO +201 -0
  3. citadel_shield-3.0.2/README.md +178 -0
  4. citadel_shield-3.0.2/citadel_shield/__init__.py +33 -0
  5. citadel_shield-3.0.2/citadel_shield/middleware.py +173 -0
  6. citadel_shield-3.0.2/citadel_shield.egg-info/PKG-INFO +201 -0
  7. citadel_shield-3.0.2/citadel_shield.egg-info/SOURCES.txt +61 -0
  8. citadel_shield-3.0.2/citadel_shield.egg-info/dependency_links.txt +1 -0
  9. citadel_shield-3.0.2/citadel_shield.egg-info/requires.txt +6 -0
  10. citadel_shield-3.0.2/citadel_shield.egg-info/top_level.txt +2 -0
  11. citadel_shield-3.0.2/defense/advanced_mutation_fuzz.py +320 -0
  12. citadel_shield-3.0.2/defense/canary_manager.py +432 -0
  13. citadel_shield-3.0.2/defense/citadel_antibody_sync.py +190 -0
  14. citadel_shield-3.0.2/defense/citadel_bait_seeder.py +260 -0
  15. citadel_shield-3.0.2/defense/citadel_briefing.py +186 -0
  16. citadel_shield-3.0.2/defense/citadel_comprehensive_benchmark.py +443 -0
  17. citadel_shield-3.0.2/defense/confinement_smoke.py +327 -0
  18. citadel_shield-3.0.2/defense/evidence_truth_smoke.py +285 -0
  19. citadel_shield-3.0.2/defense/evidence_validation.py +201 -0
  20. citadel_shield-3.0.2/defense/mandala_kekkai.py +364 -0
  21. citadel_shield-3.0.2/defense/opencode_kekkai_launcher.py +407 -0
  22. citadel_shield-3.0.2/defense/practice_audit_battery.py +339 -0
  23. citadel_shield-3.0.2/defense/sangha.py +4120 -0
  24. citadel_shield-3.0.2/defense/sangha_citadel_unified_benchmark.py +512 -0
  25. citadel_shield-3.0.2/defense/sangha_invariant.py +163 -0
  26. citadel_shield-3.0.2/defense/sangha_iroh_swarm.py +402 -0
  27. citadel_shield-3.0.2/defense/sangha_kekkai.py +166 -0
  28. citadel_shield-3.0.2/defense/sangha_merkle.py +171 -0
  29. citadel_shield-3.0.2/defense/sangha_mesh.py +141 -0
  30. citadel_shield-3.0.2/defense/sangha_registry.py +277 -0
  31. citadel_shield-3.0.2/defense/sangha_route.py +415 -0
  32. citadel_shield-3.0.2/defense/sangha_swarm_benchmark.py +285 -0
  33. citadel_shield-3.0.2/defense/sangha_vcs.py +1215 -0
  34. citadel_shield-3.0.2/defense/sangha_watch.py +116 -0
  35. citadel_shield-3.0.2/defense/test_bait_seeder.py +49 -0
  36. citadel_shield-3.0.2/defense/test_bounty_ledger.py +181 -0
  37. citadel_shield-3.0.2/defense/test_citadel_benchmark.py +48 -0
  38. citadel_shield-3.0.2/defense/test_citadel_briefing.py +31 -0
  39. citadel_shield-3.0.2/defense/test_citadel_shield.py +300 -0
  40. citadel_shield-3.0.2/defense/test_gas_trap.py +38 -0
  41. citadel_shield-3.0.2/defense/test_kernel_sandbox_escape.py +164 -0
  42. citadel_shield-3.0.2/defense/test_live_sweeper.py +82 -0
  43. citadel_shield-3.0.2/defense/test_multichain_sweeper.py +145 -0
  44. citadel_shield-3.0.2/defense/test_pow_gate.py +195 -0
  45. citadel_shield-3.0.2/defense/test_pqc_claim_boundaries.py +62 -0
  46. citadel_shield-3.0.2/defense/test_practice_audit_reporting.py +165 -0
  47. citadel_shield-3.0.2/defense/violet_bounty_ledger.py +615 -0
  48. citadel_shield-3.0.2/defense/violet_cognitive_tarpit.py +228 -0
  49. citadel_shield-3.0.2/defense/violet_digital_twin.py +826 -0
  50. citadel_shield-3.0.2/defense/violet_gas_trap.py +139 -0
  51. citadel_shield-3.0.2/defense/violet_immunize.py +208 -0
  52. citadel_shield-3.0.2/defense/violet_insurability_pack.py +140 -0
  53. citadel_shield-3.0.2/defense/violet_live_sweeper.py +281 -0
  54. citadel_shield-3.0.2/defense/violet_mesh_event.py +201 -0
  55. citadel_shield-3.0.2/defense/violet_multichain_sweeper.py +507 -0
  56. citadel_shield-3.0.2/defense/violet_pow_gate.py +212 -0
  57. citadel_shield-3.0.2/defense/violet_pqc.py +350 -0
  58. citadel_shield-3.0.2/defense/violet_spa.py +186 -0
  59. citadel_shield-3.0.2/defense/violet_stress_test.py +476 -0
  60. citadel_shield-3.0.2/defense/violet_xdp_spa.py +205 -0
  61. citadel_shield-3.0.2/defense/wm_decoy_taxonomy.py +111 -0
  62. citadel_shield-3.0.2/pyproject.toml +43 -0
  63. citadel_shield-3.0.2/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lucas Bailey (WhiteMagic Labs)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,201 @@
1
+ Metadata-Version: 2.4
2
+ Name: citadel-shield
3
+ Version: 3.0.2
4
+ Summary: Thermodynamic, negative-expected-value (-EV) active cyberdefense framework for modern web and decentralized infrastructure.
5
+ Author-email: Lucas Bailey & WhiteMagic Sangha <ops@whitemagic.dev>
6
+ Project-URL: Homepage, https://github.com/lbailey94/citadel-defense
7
+ Project-URL: Whitepaper, https://github.com/lbailey94/citadel-defense/blob/main/docs/CITADEL_THEORY_AND_ARCHITECTURE.md
8
+ Project-URL: Live Telemetry, https://mcp.whitemagic.dev/defense
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: POSIX :: Linux
12
+ Classifier: Topic :: Security
13
+ Classifier: Topic :: Internet :: Proxy Servers
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: eth-account>=0.8.0
18
+ Requires-Dist: cryptography>=42.0
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=8.0; extra == "dev"
21
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
22
+ Dynamic: license-file
23
+
24
+ # The Citadel
25
+
26
+ Experimental security tools for agent workflows: Linux confinement, environment
27
+ filtering, signed single-packet authorization, decoy services, receipt tooling,
28
+ and small Bend algebraic examples. Code is MIT licensed.
29
+
30
+ Start with [audit scope and evidence boundaries](docs/AUDIT_SCOPE.md). The old
31
+ [practice audit report](docs/PRACTICE_AUDIT_REPORT.md) is withdrawn as an assurance
32
+ claim. No independent security audit or production qualification is established
33
+ by this repository's internal checks.
34
+
35
+ ## What each part currently demonstrates
36
+
37
+ | Area | Artifact | Evidence boundary |
38
+ |---|---|---|
39
+ | Signature experiments | `defense/violet_pqc.py` | Ed25519 plus custom hash-chain code. This is not a complete SLH-DSA implementation, a FIPS conformance claim, or a measured quantum-security margin. |
40
+ | Single-packet authorization | `defense/violet_spa.py`, `defense/violet_xdp_spa.py`, `defense/violet_xdp_spa.c` | The Python benchmark exercises signed knocks, replay/tamper cases, and a Python packet-table simulation. Compiling a BPF ELF does not load it into a kernel. Its Python timings are not NIC/driver drop latency. |
41
+ | Proof-of-work puzzle gate | `defense/violet_pow_gate.py`, `citadel_shield/middleware.py` | HMAC-SHA256 challenge issuance, bounded solution verification and process-local single-use admission. Expected brute-force solving takes 16^difficulty hashes; this does not measure an operator's cost or establish general attack prevention. Solvers run locally in tests. |
42
+ | Web3 sweeper gas-trap | `defense/violet_gas_trap.py` | Deceptive zero-native-gas honeypot wallet and front-running simulation. Dual-hash forensic ledger of captured attacker gas. Simulates mempool counter-drains under controlled conditions. |
43
+ | Monetized lanes & bounty ledger | `defense/violet_bounty_ledger.py` | Tamper-evident dual-hash accounting ledger tracking on-chain gas sweeps, cognitive token burns, forced PoW hashes, and x402 revenue extracted from adversaries. |
44
+ | Comprehensive benchmark | `defense/citadel_comprehensive_benchmark.py` | Six-track micro-benchmark of PoW gates, LLM token sponges, canary minting/verification, Web3 traps, flytrap taxonomy, and SPA knock generation. Metrics reflect local host throughput. |
45
+ | Theory & architecture | `docs/CITADEL_THEORY_AND_ARCHITECTURE.md` | Comprehensive theoretical foundation and operational blueprint detailing biomimetic defense, counter-economics, and line-rate hardware defenses. |
46
+ | Decoys and canaries | `defense/violet_digital_twin.py` | Controlled decoy and token-detection exercises. Detection rates apply to the supplied cases. The historical economic ratio used assumed token and CPU prices; it is not evidence of adversaries' real costs or general defensive advantage. |
47
+ | Replay filters | `defense/violet_immunize.py` | Deterministic rule generation and replay against a finite corpus. No general zero-false-positive guarantee follows. |
48
+ | Peer notifications and chunks | `defense/violet_mesh_event.py`, `defense/sangha_iroh_swarm.py` | Local protocol and chunk-integrity exercises. They do not establish independent multi-host coordination or a deployed network's behavior. |
49
+ | Confinement and airlock | `defense/mandala_kekkai.py`, `defense/sangha_kekkai.py`, `plugins/opencode-citadel-airlock.js` | Experimental filesystem/network restrictions and environment filtering. Qualification requires actual kernel/support identity, readable and writable positive controls, denied negative controls, subprocess startup evidence, and precise runtime integration. |
50
+ | Algebraic examples | `proofs/citta_pac_laws.bend` | Nine Bool/Nat lemmas. These do not prove implementation-level capability attenuation, anti-rollback correctness, safe fallback, or model-weight behavior. |
51
+ | Synthetic folds | `proofs/citta_pac_swarm.bend`, `proofs/cpr_batch.bend` | Fixed-depth U32 arithmetic tree folds. Leaves are not running agents or cryptographically verified receipts. |
52
+
53
+ The seven-ring arrangement is a design organization. It does not mean an
54
+ attacker must defeat every component or that touching one decoy prevents an
55
+ attack. Source modules may retain historical names; use the boundaries above
56
+ when interpreting those names and older reports.
57
+
58
+ ## Reproduce a bounded check
59
+
60
+ Requirements: Python 3.10+ and a compatible Bend compiler on `PATH` (the current
61
+ local reproduction used Bend 2.0.39). The report command does not import the
62
+ product modules, read personal keys, or mutate a personal WhiteMagic store.
63
+ Select an output directory outside this checkout to keep your working tree clean:
64
+
65
+ ```bash
66
+ python3 defense/practice_audit_battery.py --checks bend --output-dir /tmp/citadel-internal-checks
67
+ python3 -m unittest discover -s defense -p test_practice_audit_reporting.py -v
68
+ ```
69
+
70
+ To run the Citadel Comprehensive Benchmark across all defense and counter-economic tracks:
71
+
72
+ ```bash
73
+ python3 defense/citadel_comprehensive_benchmark.py
74
+ python3 -m pytest -v defense/test_citadel_benchmark.py defense/test_pow_gate.py defense/test_gas_trap.py
75
+ ```
76
+
77
+ With `cryptography` installed, `python3 -m unittest discover -s defense -p
78
+ test_pqc_claim_boundaries.py -v` also checks experimental output disclosures,
79
+ an isolated signature/tamper fixture, and failure exit status. It uses temporary
80
+ fixture keys and does not qualify the custom construction for security use.
81
+
82
+ The Bend selection runs both the front-end check and the separate `--verdict`
83
+ kernel recheck. The latter needs the kernel dependencies reported by Bend
84
+ (the local tool requests Lean 4.34.0 or a built `BENDTT` kernel). Missing kernel
85
+ infrastructure is `NOT_EVALUATED`, even if the front-end checker succeeds.
86
+
87
+ The paired JSON/Markdown reports record compiler and source hashes, command
88
+ outputs, process wall times, and synthetic leaves per second calculated from
89
+ the same measurement. Wall time includes compiler checking and startup.
90
+ `PASS` applies to the selected checks only; unsupported lanes remain
91
+ `NOT_EVALUATED` with reasons.
92
+
93
+ Exit status is `0` when all selected checks pass, `1` for an actual failed check,
94
+ and `2` when selected checks cannot be evaluated. Missing engines, matching
95
+ crashes, empty output, and malformed verifier results cannot create parity.
96
+
97
+ For a separate CPR agreement check, first build the Python/Rust/JavaScript
98
+ verifiers according to the selected CPR checkout's own instructions, then pass
99
+ its exact location explicitly:
100
+
101
+ ```bash
102
+ python3 defense/practice_audit_battery.py --checks differential --cpr-dir /path/to/continuity-receipt --output-dir /tmp/citadel-cpr-agreement
103
+ ```
104
+
105
+ This checks the three bundle manifests, honors their anchor options, and
106
+ compares verdicts and error codes against each other and the declared expected
107
+ outcomes. Manifests themselves are not counted as receipt fixtures.
108
+ Agreement between three implementations maintained in the same project is
109
+ useful consistency evidence; an independent oracle and source-to-binary build
110
+ provenance still need separate evidence.
111
+
112
+ ## Optional ASGI proof-of-work admission
113
+
114
+ Enable the gate explicitly with `CitadelShieldMiddleware(app, enable_pow_gate=True,
115
+ pow_difficulty=4)`. Difficulty is an integer from 1 through 8, measured in leading
116
+ hexadecimal zeros. The default is 4. Invalid settings or an enabled gate's
117
+ initialization failure stop startup rather than enabling passthrough.
118
+
119
+ Requests under `/api/heavy` receive HTTP 428 and a JSON `challenge`. Solve it with
120
+ `PoWGate.solve(challenge)`, then send `X-Citadel-PoW-Solution` containing a JSON
121
+ object `{"challenge": <the issued object>, "nonce": "<solver nonce>"}`. The
122
+ middleware verifies the signature, transport-peer IP, lifetime, configured
123
+ minimum difficulty and work before calling the application. The header is
124
+ limited to 4096 bytes; duplicate, malformed and invalid solutions receive a new
125
+ challenge. Each challenge admits one request, including when different valid
126
+ nonces are submitted concurrently. Ledger work counts remain estimates rather
127
+ than measured hashes performed by a client.
128
+
129
+ Replay custody is in memory for one `PoWGate` instance and has a bounded cache.
130
+ When full, it refuses new redemptions until entries expire; it does not evict
131
+ live entries to make replay possible. This is not shared multiworker replay
132
+ protection: workers using one signing secret require shared replay custody or
133
+ challenge routing to the issuing instance. Ephemeral fallback secrets also do
134
+ not survive process restarts. Proxy deployments must establish the trusted
135
+ transport peer upstream; this admission path does not trust client-supplied
136
+ `X-Forwarded-For`. No deployed service or outside attack resistance is qualified
137
+ by these local ASGI and gate tests.
138
+
139
+ ## Standalone launcher smoke
140
+
141
+ `defense/opencode_kekkai_launcher.py` uses Python's standard library. The
142
+ Linux backend needs x86_64 or arm64 and a kernel exposing Landlock; unsupported
143
+ hosts fail before spawning the child. Run a harmless owned-workspace fixture
144
+ with a deliberately minimal environment:
145
+
146
+ ```sh
147
+ scratch=$(mktemp -d) || exit 1
148
+ workspace="$scratch/workspace"
149
+ mkdir "$scratch/home" "$workspace"
150
+ printf '%s\n' 'owned launcher fixture' > "$workspace/probe.txt"
151
+ env -i PATH=/usr/bin:/bin HOME="$scratch/home" python3 \
152
+ defense/opencode_kekkai_launcher.py --workspace "$workspace" -- \
153
+ /usr/bin/cat "$workspace/probe.txt"
154
+ rm -r -- "$scratch"
155
+ ```
156
+
157
+ The launcher installs filesystem restrictions only. It inherits the child
158
+ environment and leaves networking unrestricted; it does not scrub credentials
159
+ or establish an OpenCode/Devin client integration. The fixture above only
160
+ checks child startup and an allowed read. Use the separate confinement
161
+ positive/negative controls before making a containment claim. macOS has a
162
+ separate Seatbelt path; this Linux fixture does not qualify it.
163
+
164
+ ## Demonstrations and integration work
165
+
166
+ [`arena/halo_ctf_visualizer.html`](arena/halo_ctf_visualizer.html) is an illustrative
167
+ animation. Its scripted scores, killfeed, and timing labels are not live
168
+ red-team telemetry. The legacy master benchmark and escape/mutation scripts
169
+ also need review before their printed success labels can serve as acceptance
170
+ criteria; see [the open review list](docs/AUDIT_SCOPE.md).
171
+
172
+ [`docs/OPENCODE_2_1_1_SECURITY_ALIGNMENT_REPORT.md`](docs/OPENCODE_2_1_1_SECURITY_ALIGNMENT_REPORT.md)
173
+ is a maintainer-authored study of a named historical version. The plugin and
174
+ launcher need qualification against the exact host/runtime being used. Installing
175
+ an environment filter alone does not establish protection of credentials,
176
+ transcripts, or every execution path.
177
+
178
+ ## License
179
+
180
+ [MIT](LICENSE) · Copyright (c) 2026 Lucas Bailey / WhiteMagic Labs.
181
+
182
+ ### Supported middleware deployment contract
183
+
184
+ Use one process with one `PoWGate` per admission domain. Multiple middleware
185
+ instances in that process may receive the same `pow_gate=` object, sharing
186
+ its atomic replay cache. Separate workers and restarts do not share consumed
187
+ challenges; shared signing keys alone do not solve that problem. A multiworker
188
+ or restart-persistent deployment needs an independently qualified shared atomic
189
+ consumption backend. The default ephemeral signing key invalidates old puzzles
190
+ on restart; do not infer this for an operator-supplied persistent key.
191
+
192
+ `protected_prefixes=("/api/heavy",)` matches that path and its child paths,
193
+ not `/api/heavy-other`. Configure other absolute path prefixes explicitly.
194
+ `admission_counts` exposes process-local outcome counts for application-owned
195
+ metrics; it contains no IPs, request bodies or solution tokens. Both puzzle
196
+ binding and decoy attribution use the ASGI peer. Configure any trusted proxy's
197
+ sanitized peer handling at the ASGI server; client-provided forwarded headers
198
+ are never trusted directly by this middleware.
199
+
200
+ The offline CI uses synthetic puzzles, fixtures and installed-package imports.
201
+ It does not run sweepers, contact targets, use wallets or qualify a live host.
@@ -0,0 +1,178 @@
1
+ # The Citadel
2
+
3
+ Experimental security tools for agent workflows: Linux confinement, environment
4
+ filtering, signed single-packet authorization, decoy services, receipt tooling,
5
+ and small Bend algebraic examples. Code is MIT licensed.
6
+
7
+ Start with [audit scope and evidence boundaries](docs/AUDIT_SCOPE.md). The old
8
+ [practice audit report](docs/PRACTICE_AUDIT_REPORT.md) is withdrawn as an assurance
9
+ claim. No independent security audit or production qualification is established
10
+ by this repository's internal checks.
11
+
12
+ ## What each part currently demonstrates
13
+
14
+ | Area | Artifact | Evidence boundary |
15
+ |---|---|---|
16
+ | Signature experiments | `defense/violet_pqc.py` | Ed25519 plus custom hash-chain code. This is not a complete SLH-DSA implementation, a FIPS conformance claim, or a measured quantum-security margin. |
17
+ | Single-packet authorization | `defense/violet_spa.py`, `defense/violet_xdp_spa.py`, `defense/violet_xdp_spa.c` | The Python benchmark exercises signed knocks, replay/tamper cases, and a Python packet-table simulation. Compiling a BPF ELF does not load it into a kernel. Its Python timings are not NIC/driver drop latency. |
18
+ | Proof-of-work puzzle gate | `defense/violet_pow_gate.py`, `citadel_shield/middleware.py` | HMAC-SHA256 challenge issuance, bounded solution verification and process-local single-use admission. Expected brute-force solving takes 16^difficulty hashes; this does not measure an operator's cost or establish general attack prevention. Solvers run locally in tests. |
19
+ | Web3 sweeper gas-trap | `defense/violet_gas_trap.py` | Deceptive zero-native-gas honeypot wallet and front-running simulation. Dual-hash forensic ledger of captured attacker gas. Simulates mempool counter-drains under controlled conditions. |
20
+ | Monetized lanes & bounty ledger | `defense/violet_bounty_ledger.py` | Tamper-evident dual-hash accounting ledger tracking on-chain gas sweeps, cognitive token burns, forced PoW hashes, and x402 revenue extracted from adversaries. |
21
+ | Comprehensive benchmark | `defense/citadel_comprehensive_benchmark.py` | Six-track micro-benchmark of PoW gates, LLM token sponges, canary minting/verification, Web3 traps, flytrap taxonomy, and SPA knock generation. Metrics reflect local host throughput. |
22
+ | Theory & architecture | `docs/CITADEL_THEORY_AND_ARCHITECTURE.md` | Comprehensive theoretical foundation and operational blueprint detailing biomimetic defense, counter-economics, and line-rate hardware defenses. |
23
+ | Decoys and canaries | `defense/violet_digital_twin.py` | Controlled decoy and token-detection exercises. Detection rates apply to the supplied cases. The historical economic ratio used assumed token and CPU prices; it is not evidence of adversaries' real costs or general defensive advantage. |
24
+ | Replay filters | `defense/violet_immunize.py` | Deterministic rule generation and replay against a finite corpus. No general zero-false-positive guarantee follows. |
25
+ | Peer notifications and chunks | `defense/violet_mesh_event.py`, `defense/sangha_iroh_swarm.py` | Local protocol and chunk-integrity exercises. They do not establish independent multi-host coordination or a deployed network's behavior. |
26
+ | Confinement and airlock | `defense/mandala_kekkai.py`, `defense/sangha_kekkai.py`, `plugins/opencode-citadel-airlock.js` | Experimental filesystem/network restrictions and environment filtering. Qualification requires actual kernel/support identity, readable and writable positive controls, denied negative controls, subprocess startup evidence, and precise runtime integration. |
27
+ | Algebraic examples | `proofs/citta_pac_laws.bend` | Nine Bool/Nat lemmas. These do not prove implementation-level capability attenuation, anti-rollback correctness, safe fallback, or model-weight behavior. |
28
+ | Synthetic folds | `proofs/citta_pac_swarm.bend`, `proofs/cpr_batch.bend` | Fixed-depth U32 arithmetic tree folds. Leaves are not running agents or cryptographically verified receipts. |
29
+
30
+ The seven-ring arrangement is a design organization. It does not mean an
31
+ attacker must defeat every component or that touching one decoy prevents an
32
+ attack. Source modules may retain historical names; use the boundaries above
33
+ when interpreting those names and older reports.
34
+
35
+ ## Reproduce a bounded check
36
+
37
+ Requirements: Python 3.10+ and a compatible Bend compiler on `PATH` (the current
38
+ local reproduction used Bend 2.0.39). The report command does not import the
39
+ product modules, read personal keys, or mutate a personal WhiteMagic store.
40
+ Select an output directory outside this checkout to keep your working tree clean:
41
+
42
+ ```bash
43
+ python3 defense/practice_audit_battery.py --checks bend --output-dir /tmp/citadel-internal-checks
44
+ python3 -m unittest discover -s defense -p test_practice_audit_reporting.py -v
45
+ ```
46
+
47
+ To run the Citadel Comprehensive Benchmark across all defense and counter-economic tracks:
48
+
49
+ ```bash
50
+ python3 defense/citadel_comprehensive_benchmark.py
51
+ python3 -m pytest -v defense/test_citadel_benchmark.py defense/test_pow_gate.py defense/test_gas_trap.py
52
+ ```
53
+
54
+ With `cryptography` installed, `python3 -m unittest discover -s defense -p
55
+ test_pqc_claim_boundaries.py -v` also checks experimental output disclosures,
56
+ an isolated signature/tamper fixture, and failure exit status. It uses temporary
57
+ fixture keys and does not qualify the custom construction for security use.
58
+
59
+ The Bend selection runs both the front-end check and the separate `--verdict`
60
+ kernel recheck. The latter needs the kernel dependencies reported by Bend
61
+ (the local tool requests Lean 4.34.0 or a built `BENDTT` kernel). Missing kernel
62
+ infrastructure is `NOT_EVALUATED`, even if the front-end checker succeeds.
63
+
64
+ The paired JSON/Markdown reports record compiler and source hashes, command
65
+ outputs, process wall times, and synthetic leaves per second calculated from
66
+ the same measurement. Wall time includes compiler checking and startup.
67
+ `PASS` applies to the selected checks only; unsupported lanes remain
68
+ `NOT_EVALUATED` with reasons.
69
+
70
+ Exit status is `0` when all selected checks pass, `1` for an actual failed check,
71
+ and `2` when selected checks cannot be evaluated. Missing engines, matching
72
+ crashes, empty output, and malformed verifier results cannot create parity.
73
+
74
+ For a separate CPR agreement check, first build the Python/Rust/JavaScript
75
+ verifiers according to the selected CPR checkout's own instructions, then pass
76
+ its exact location explicitly:
77
+
78
+ ```bash
79
+ python3 defense/practice_audit_battery.py --checks differential --cpr-dir /path/to/continuity-receipt --output-dir /tmp/citadel-cpr-agreement
80
+ ```
81
+
82
+ This checks the three bundle manifests, honors their anchor options, and
83
+ compares verdicts and error codes against each other and the declared expected
84
+ outcomes. Manifests themselves are not counted as receipt fixtures.
85
+ Agreement between three implementations maintained in the same project is
86
+ useful consistency evidence; an independent oracle and source-to-binary build
87
+ provenance still need separate evidence.
88
+
89
+ ## Optional ASGI proof-of-work admission
90
+
91
+ Enable the gate explicitly with `CitadelShieldMiddleware(app, enable_pow_gate=True,
92
+ pow_difficulty=4)`. Difficulty is an integer from 1 through 8, measured in leading
93
+ hexadecimal zeros. The default is 4. Invalid settings or an enabled gate's
94
+ initialization failure stop startup rather than enabling passthrough.
95
+
96
+ Requests under `/api/heavy` receive HTTP 428 and a JSON `challenge`. Solve it with
97
+ `PoWGate.solve(challenge)`, then send `X-Citadel-PoW-Solution` containing a JSON
98
+ object `{"challenge": <the issued object>, "nonce": "<solver nonce>"}`. The
99
+ middleware verifies the signature, transport-peer IP, lifetime, configured
100
+ minimum difficulty and work before calling the application. The header is
101
+ limited to 4096 bytes; duplicate, malformed and invalid solutions receive a new
102
+ challenge. Each challenge admits one request, including when different valid
103
+ nonces are submitted concurrently. Ledger work counts remain estimates rather
104
+ than measured hashes performed by a client.
105
+
106
+ Replay custody is in memory for one `PoWGate` instance and has a bounded cache.
107
+ When full, it refuses new redemptions until entries expire; it does not evict
108
+ live entries to make replay possible. This is not shared multiworker replay
109
+ protection: workers using one signing secret require shared replay custody or
110
+ challenge routing to the issuing instance. Ephemeral fallback secrets also do
111
+ not survive process restarts. Proxy deployments must establish the trusted
112
+ transport peer upstream; this admission path does not trust client-supplied
113
+ `X-Forwarded-For`. No deployed service or outside attack resistance is qualified
114
+ by these local ASGI and gate tests.
115
+
116
+ ## Standalone launcher smoke
117
+
118
+ `defense/opencode_kekkai_launcher.py` uses Python's standard library. The
119
+ Linux backend needs x86_64 or arm64 and a kernel exposing Landlock; unsupported
120
+ hosts fail before spawning the child. Run a harmless owned-workspace fixture
121
+ with a deliberately minimal environment:
122
+
123
+ ```sh
124
+ scratch=$(mktemp -d) || exit 1
125
+ workspace="$scratch/workspace"
126
+ mkdir "$scratch/home" "$workspace"
127
+ printf '%s\n' 'owned launcher fixture' > "$workspace/probe.txt"
128
+ env -i PATH=/usr/bin:/bin HOME="$scratch/home" python3 \
129
+ defense/opencode_kekkai_launcher.py --workspace "$workspace" -- \
130
+ /usr/bin/cat "$workspace/probe.txt"
131
+ rm -r -- "$scratch"
132
+ ```
133
+
134
+ The launcher installs filesystem restrictions only. It inherits the child
135
+ environment and leaves networking unrestricted; it does not scrub credentials
136
+ or establish an OpenCode/Devin client integration. The fixture above only
137
+ checks child startup and an allowed read. Use the separate confinement
138
+ positive/negative controls before making a containment claim. macOS has a
139
+ separate Seatbelt path; this Linux fixture does not qualify it.
140
+
141
+ ## Demonstrations and integration work
142
+
143
+ [`arena/halo_ctf_visualizer.html`](arena/halo_ctf_visualizer.html) is an illustrative
144
+ animation. Its scripted scores, killfeed, and timing labels are not live
145
+ red-team telemetry. The legacy master benchmark and escape/mutation scripts
146
+ also need review before their printed success labels can serve as acceptance
147
+ criteria; see [the open review list](docs/AUDIT_SCOPE.md).
148
+
149
+ [`docs/OPENCODE_2_1_1_SECURITY_ALIGNMENT_REPORT.md`](docs/OPENCODE_2_1_1_SECURITY_ALIGNMENT_REPORT.md)
150
+ is a maintainer-authored study of a named historical version. The plugin and
151
+ launcher need qualification against the exact host/runtime being used. Installing
152
+ an environment filter alone does not establish protection of credentials,
153
+ transcripts, or every execution path.
154
+
155
+ ## License
156
+
157
+ [MIT](LICENSE) · Copyright (c) 2026 Lucas Bailey / WhiteMagic Labs.
158
+
159
+ ### Supported middleware deployment contract
160
+
161
+ Use one process with one `PoWGate` per admission domain. Multiple middleware
162
+ instances in that process may receive the same `pow_gate=` object, sharing
163
+ its atomic replay cache. Separate workers and restarts do not share consumed
164
+ challenges; shared signing keys alone do not solve that problem. A multiworker
165
+ or restart-persistent deployment needs an independently qualified shared atomic
166
+ consumption backend. The default ephemeral signing key invalidates old puzzles
167
+ on restart; do not infer this for an operator-supplied persistent key.
168
+
169
+ `protected_prefixes=("/api/heavy",)` matches that path and its child paths,
170
+ not `/api/heavy-other`. Configure other absolute path prefixes explicitly.
171
+ `admission_counts` exposes process-local outcome counts for application-owned
172
+ metrics; it contains no IPs, request bodies or solution tokens. Both puzzle
173
+ binding and decoy attribution use the ASGI peer. Configure any trusted proxy's
174
+ sanitized peer handling at the ASGI server; client-provided forwarded headers
175
+ are never trusted directly by this middleware.
176
+
177
+ The offline CI uses synthetic puzzles, fixtures and installed-package imports.
178
+ It does not run sweepers, contact targets, use wallets or qualify a live host.
@@ -0,0 +1,33 @@
1
+ """citadel_shield — Negative Expected Value (-EV) Active Cyberdefense Framework."""
2
+ from __future__ import annotations
3
+
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ # Add defense directory to sys.path
8
+ DEFENSE_DIR = Path(__file__).resolve().parent.parent / "defense"
9
+ if str(DEFENSE_DIR) not in sys.path:
10
+ sys.path.insert(0, str(DEFENSE_DIR))
11
+
12
+ try:
13
+ from canary_manager import CanaryManager
14
+ from violet_bounty_ledger import BountyLedger
15
+ from violet_digital_twin import ProceduralDigitalTwin
16
+ from violet_gas_trap import GasTrapHoneypot
17
+ from violet_live_sweeper import LiveGasSweeper
18
+ from violet_pow_gate import PoWGate
19
+ except ImportError:
20
+ pass
21
+
22
+ from citadel_shield.middleware import CitadelShieldMiddleware
23
+
24
+ __version__ = "3.0.2"
25
+ __all__ = [
26
+ "CitadelShieldMiddleware",
27
+ "PoWGate",
28
+ "ProceduralDigitalTwin",
29
+ "CanaryManager",
30
+ "BountyLedger",
31
+ "GasTrapHoneypot",
32
+ "LiveGasSweeper",
33
+ ]
@@ -0,0 +1,173 @@
1
+ """citadel_shield.middleware — Drop-in ASGI / FastAPI Middleware for Citadel Active Defense.
2
+
3
+ Provides optional decoys and client puzzle admission for Python ASGI applications:
4
+ * Intercepts hostile probe paths (/.env, /wp-admin, /latest/meta-data, /api/v1/namespaces)
5
+ * Serves realistic procedural digital twin decoys with watermarked canaries
6
+ * Requires verified, single-use PoW solutions on /api/heavy routes when enabled
7
+
8
+ Usage:
9
+ from fastapi import FastAPI
10
+ from citadel_shield.middleware import CitadelShieldMiddleware
11
+
12
+ app = FastAPI()
13
+ app.add_middleware(CitadelShieldMiddleware, enable_pow_gate=True, pow_difficulty=4)
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import json
18
+ import logging
19
+ import os
20
+ import pathlib
21
+ import sys
22
+ from typing import Callable
23
+
24
+ # Ensure local imports resolve
25
+ sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent / "defense"))
26
+
27
+ try:
28
+ import violet_digital_twin as vdt
29
+ except ImportError:
30
+ vdt = None
31
+
32
+ from defense import violet_pow_gate as vpg
33
+
34
+ logger = logging.getLogger("citadel_shield")
35
+
36
+ DEFAULT_DECOY_PATHS = {
37
+ "/.env", "/.env.local", "/.env.production", "/latest/meta-data",
38
+ "/computeMetadata/v1", "/wp-admin", "/wp-login.php", "/xmlrpc.php",
39
+ "/api/v1/namespaces", "/v1.24/containers/json", "/aws/credentials"
40
+ }
41
+ MAX_POW_HEADER_BYTES = 4096
42
+
43
+
44
+ class CitadelShieldMiddleware:
45
+ """Drop-in ASGI middleware providing automated deception and client puzzles."""
46
+
47
+ def __init__(
48
+ self,
49
+ app: Callable,
50
+ enable_deception: bool = True,
51
+ enable_pow_gate: bool = False,
52
+ pow_difficulty: int = 4,
53
+ decoy_paths: set[str] | None = None,
54
+ state_dir: pathlib.Path | None = None,
55
+ protected_prefixes: tuple[str, ...] = ("/api/heavy",),
56
+ pow_gate: vpg.PoWGate | None = None,
57
+ ):
58
+ self.app = app
59
+ self.enable_deception = enable_deception
60
+ self.enable_pow_gate = enable_pow_gate
61
+ self.pow_difficulty = pow_difficulty
62
+ if (not isinstance(protected_prefixes, tuple) or not protected_prefixes or
63
+ any(not isinstance(prefix, str) or not prefix.startswith("/") or
64
+ "?" in prefix or "#" in prefix for prefix in protected_prefixes)):
65
+ raise ValueError("protected_prefixes must be a nonempty tuple of absolute path prefixes")
66
+ self.protected_prefixes = tuple(prefix.rstrip("/") or "/" for prefix in protected_prefixes)
67
+ self.admission_counts: dict[str, int] = {}
68
+ self.decoy_paths = decoy_paths or DEFAULT_DECOY_PATHS
69
+ self.state_dir = state_dir or pathlib.Path(os.environ.get("VIOLET_STATE_DIR", "/tmp/citadel"))
70
+
71
+ self.twin = None
72
+ self.pow_gate = None
73
+ if self.enable_deception:
74
+ try:
75
+ self.twin = vdt.ProceduralDigitalTwin()
76
+ except Exception as e:
77
+ logger.warning("Could not initialize ProceduralDigitalTwin: %s", e)
78
+
79
+ if self.enable_pow_gate:
80
+ if (type(pow_difficulty) is not int or
81
+ not vpg.MIN_POW_DIFFICULTY <= pow_difficulty <= vpg.MAX_POW_DIFFICULTY):
82
+ raise ValueError("pow_difficulty must be an integer between 1 and 8")
83
+ # An explicitly enabled protection must not silently become passthrough.
84
+ self.pow_gate = pow_gate if pow_gate is not None else vpg.PoWGate()
85
+
86
+ async def __call__(self, scope: dict, receive: Callable, send: Callable) -> None:
87
+ if scope["type"] != "http":
88
+ await self.app(scope, receive, send)
89
+ return
90
+
91
+ path = scope.get("path", "")
92
+
93
+ # 1. Inspect for decoy paths
94
+ if self.enable_deception and self.twin and (path in self.decoy_paths or path.startswith("/.env")):
95
+ # Resolve client IP
96
+ client_ip = scope.get("client", ("127.0.0.1", 0))[0]
97
+
98
+ if path.startswith("/.env"):
99
+ body = self.twin.get_env_file(src_ip=client_ip).encode("utf-8")
100
+ await self._send_response(send, 200, b"text/plain; charset=utf-8", body)
101
+ return
102
+
103
+ if "meta-data" in path or "computeMetadata" in path:
104
+ meta = self.twin.get_aws_metadata(path, src_ip=client_ip)
105
+ body = (json.dumps(meta) if isinstance(meta, dict) else str(meta)).encode("utf-8")
106
+ await self._send_response(send, 200, b"application/json", body)
107
+ return
108
+
109
+ # 2. Explicitly enabled PoW admission on the protected route prefix.
110
+ if self.enable_pow_gate and any(prefix == "/" or path == prefix or path.startswith(prefix + "/")
111
+ for prefix in self.protected_prefixes):
112
+ client = scope.get("client")
113
+ if not client or not isinstance(client[0], str) or self.pow_gate is None:
114
+ await self._send_response(send, 503, b"application/json", b'{"error":"PoW gate unavailable"}')
115
+ return
116
+ # Use the ASGI transport peer. Forwarded headers require a trusted proxy
117
+ # configuration outside this middleware; client-controlled XFF is not identity.
118
+ client_ip = client[0]
119
+ submitted = [value for name, value in scope.get("headers", [])
120
+ if name.lower() == b"x-citadel-pow-solution"]
121
+ verified, reason = False, "missing_solution"
122
+ if len(submitted) == 1:
123
+ if len(submitted[0]) > MAX_POW_HEADER_BYTES:
124
+ reason = "solution_too_large"
125
+ else:
126
+ try:
127
+ solution = json.loads(submitted[0].decode("utf-8"))
128
+ if not isinstance(solution, dict) or set(solution) != {"challenge", "nonce"}:
129
+ raise ValueError("expected challenge and nonce")
130
+ challenge, nonce = solution["challenge"], solution["nonce"]
131
+ if not isinstance(challenge, dict) or type(challenge.get("difficulty")) is not int:
132
+ raise ValueError("invalid challenge")
133
+ if challenge["difficulty"] < self.pow_difficulty:
134
+ reason = "difficulty_below_policy"
135
+ else:
136
+ verified, reason = self.pow_gate.verify_solution(
137
+ challenge, nonce, client_ip, check_replay=True,
138
+ )
139
+ except (ValueError, TypeError, UnicodeError, RecursionError):
140
+ reason = "malformed_solution"
141
+ elif submitted:
142
+ reason = "duplicate_solution_header"
143
+ self.admission_counts[reason] = self.admission_counts.get(reason, 0) + 1
144
+ if not verified:
145
+ challenge = self.pow_gate.generate_challenge(client_ip=client_ip, difficulty=self.pow_difficulty)
146
+ body = json.dumps({
147
+ "error": "PoW challenge required",
148
+ "reason": reason,
149
+ "challenge": challenge,
150
+ "header_required": "X-Citadel-PoW-Solution",
151
+ "solution_format": {"challenge": "the issued challenge object", "nonce": "solver nonce"},
152
+ }).encode("utf-8")
153
+ await self._send_response(send, 428, b"application/json", body)
154
+ return
155
+
156
+ # 3. Allow legitimate request to proceed
157
+ await self.app(scope, receive, send)
158
+
159
+ async def _send_response(self, send: Callable, status: int, content_type: bytes, body: bytes) -> None:
160
+ await send({
161
+ "type": "http.response.start",
162
+ "status": status,
163
+ "headers": [
164
+ (b"content-type", content_type),
165
+ (b"content-length", str(len(body)).encode("ascii")),
166
+ (b"server", b"Citadel-Shield/3.0"),
167
+ (b"x-citadel-defense", b"ACTIVE"),
168
+ ],
169
+ })
170
+ await send({
171
+ "type": "http.response.body",
172
+ "body": body,
173
+ })