betterwithage commited on
Commit
40a0af6
·
verified ·
1 Parent(s): a9bfa38

chore(sync): mirror backend .py + Dockerfile to Space (hf-sync-backend)

Browse files

Automated backend sync from szl-holdings/a11oy main via hf-sync-backend.
Updated (differed from the Space): Dockerfile, szl_immune.py
Deleted (gone from the repo + Dockerfile COPY set): (none)

Keeps the Space-built backend (serve.py + the Dockerfile-COPY'd .py
modules) identical to GitHub main so the Space never rebuilds from a
stale backend, new endpoints don't 404 there, and orphaned modules
removed from the repo don't linger in the Space tree.

Files changed (2) hide show
  1. Dockerfile +14 -0
  2. szl_immune.py +493 -0
Dockerfile CHANGED
@@ -156,6 +156,14 @@ COPY joule_billing.py szl_energy_ledger.py szl_energy_operator.py szl_energy_pro
156
  # /api/a11oy/v1/kverify/* 404s. Reuses szl_energy_operator (inference + NVML joules)
157
  # + szl_khipu (the shared signed-receipt chain), both already COPY'd above.
158
  COPY szl_kverify.py ./
 
 
 
 
 
 
 
 
159
  # ADDITIVE (I3): FABRO-style Governed Factory + Constitutional Engines modules.
160
  # MUST be COPY'd or serve.py's guarded imports fall back (merged-but-not-live).
161
  # HTML/JS is inlined in these .py modules, so NO web/ or static-vendor COPY needed.
@@ -1024,6 +1032,12 @@ COPY static/3d/ ./static/3d/
1024
  # module above via the same-origin importmap. Per-file served assets -> image_only_assets.
1025
  COPY web/energy-holographic.html ./web/energy-holographic.html
1026
  COPY web/energy.html ./web/energy.html
 
 
 
 
 
 
1027
 
1028
  # git_sha wireup (FORGE-INSTRUCTION-gitsha-quiet-window): surface the deployed commit
1029
  # at the /honest endpoint so a stale box or Space is self-detecting. Provided at build
 
156
  # /api/a11oy/v1/kverify/* 404s. Reuses szl_energy_operator (inference + NVML joules)
157
  # + szl_khipu (the shared signed-receipt chain), both already COPY'd above.
158
  COPY szl_kverify.py ./
159
+ # Immune (Hukulla) HONEST egress-gate surface — imported by serve.py (guarded).
160
+ # MUST be per-file COPY'd (no `COPY . .`) or the import falls back and the honest
161
+ # /api/a11oy/v1/immune/* namespace 404s. Reuses szl_khipu (the shared signed-
162
+ # receipt chain), already COPY'd above. Auto-mirrored to the HF Space by
163
+ # hf-sync-backend.yml (it parses the Dockerfile COPY set). web/immune.html (the
164
+ # served page) is per-file COPY'd below and declared image_only in
165
+ # .github/copy-sync-lockstep.json (same baked-only pattern as web/energy.html).
166
+ COPY szl_immune.py ./
167
  # ADDITIVE (I3): FABRO-style Governed Factory + Constitutional Engines modules.
168
  # MUST be COPY'd or serve.py's guarded imports fall back (merged-but-not-live).
169
  # HTML/JS is inlined in these .py modules, so NO web/ or static-vendor COPY needed.
 
1032
  # module above via the same-origin importmap. Per-file served assets -> image_only_assets.
1033
  COPY web/energy-holographic.html ./web/energy-holographic.html
1034
  COPY web/energy.html ./web/energy.html
1035
+ # Immune (Hukulla) honest egress-gate page (/immune, /a11oy/immune). Standalone
1036
+ # sovereign page (0 runtime CDN), binds to live /api/a11oy/v1/immune/* (status/
1037
+ # gates/feed + a live inspect->verdict box showing real deny/allow + signed Khipu
1038
+ # receipt digest). Per-file served asset -> declared image_only in copy-sync-
1039
+ # lockstep.json (same baked-only pattern as web/energy.html). Codename-free.
1040
+ COPY web/immune.html ./web/immune.html
1041
 
1042
  # git_sha wireup (FORGE-INSTRUCTION-gitsha-quiet-window): surface the deployed commit
1043
  # at the /honest endpoint so a stale box or Space is self-detecting. Provided at build
szl_immune.py ADDED
@@ -0,0 +1,493 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 Lutar, Stephen P. — SZL Holdings · ORCID 0009-0001-0110-4173
3
+ # Doctrine v11 — Immune (Hukulla) honest egress-gate surface.
4
+ """
5
+ szl_immune.py — expose the Immune organ on the HONEST a11oy namespace.
6
+
7
+ The immune detector is REAL and LIVE in serve.py, but historically the only HTTP
8
+ routes for it were user-visible CODENAME namespaces (a doctrine v11 violation,
9
+ and the reason /api/a11oy/v1/immune* returned 404). This module exposes the
10
+ CANONICAL, honest surface wired to the SAME real inspection logic — fail-closed,
11
+ deny-by-default — and signs a Khipu receipt per verdict into the SHARED
12
+ szl_khipu chain.
13
+
14
+ USER-VISIBLE ORGAN NAME: "Immune" (Quechua role "Hukulla"). This module NEVER
15
+ emits a codename (sentra / amaru / rosie / jarvis) in any served string.
16
+
17
+ ENDPOINTS (dual-registered under /api/a11oy/v1/immune/* AND /v1/immune/*):
18
+ GET /healthz -> liveness + organ identity.
19
+ GET /status -> live summary: signature-corpus size, lambda floor, total
20
+ verdicts this process, deny rate, Lean proof refs, last
21
+ receipt digest + Khipu chain head/depth.
22
+ GET /gates -> the REAL gate descriptors (signature-scan, size-guard,
23
+ lambda-gate-floor) — same corpus the rest of the estate uses.
24
+ POST /verdict -> run the REAL inspection (signature scan + 1 MB size guard +
25
+ Lambda-gate floor 0.5) on {"action":{...},"axes"?,"agent"?,
26
+ "request_id"|"actionId"?,"traceparent"?}; return the
27
+ PolicyDecision shape PLUS a signed Khipu receipt
28
+ (organ="immune", receipt_type "SZL.Immune.Verdict.v1").
29
+ GET /feed?limit= -> the real in-memory decision ring (seeded from the captured
30
+ real feed; resets on restart — empty = IDLE, never faked).
31
+ GET /threats -> the threats_full STIX/MITRE corpus.
32
+ GET /verify -> re-walk the immune Khipu chain (judge-verifiable integrity).
33
+
34
+ INSPECTION LOGIC (byte-identical to serve.py's embedded immune block):
35
+ _THREAT_SIGNATURES = ["DROP TABLE","rm -rf","<script","eval(","subprocess","../../etc"]
36
+ size guard: payload string > 1_000_000 chars -> deny
37
+ Lambda gate floor: 0.5 — when axes are supplied and MIN(axes) < floor -> deny
38
+
39
+ PROVEN BACKING (Lean): cited, NOT folded into the locked-8.
40
+ - Lutar/Wave11/ImmuneNeymanPearsonOpt.lean (Neyman-Pearson-optimal egress gate)
41
+ - Lutar/Innovations/round11/FrontierWelfordVariance.lean (Welford online variance)
42
+ Locked-proven set remains EXACTLY 8 {F1,F4,F7,F11,F12,F18,F19,F22} @ kernel
43
+ c7c0ba17. Lambda = Conjecture 1 (NOT a theorem). Khipu = Conjecture 2. Trust is
44
+ never 100%. Effectors simulated. No fabricated data.
45
+
46
+ Stdlib + the existing repo module (szl_khipu). No new dep, no CDN, no Node.
47
+ Additive; try/except-guarded by the caller; registered BEFORE the SPA catch-all.
48
+ """
49
+ from __future__ import annotations
50
+
51
+ import base64
52
+ import collections
53
+ import datetime
54
+ import hashlib
55
+ import json
56
+ import secrets
57
+ import threading
58
+ import time
59
+ from typing import Any, Optional
60
+
61
+ from fastapi import Request
62
+ from fastapi.responses import JSONResponse
63
+
64
+ # ---------------------------------------------------------------------------
65
+ # Identity + doctrine constants (honest, never a codename).
66
+ # ---------------------------------------------------------------------------
67
+ _ORGAN_NAME = "Immune (Hukulla)"
68
+ _KHIPU_ORGAN = "immune"
69
+ _RECEIPT_TYPE = "SZL.Immune.Verdict.v1"
70
+ _LEAN_PROOFS = [
71
+ {
72
+ "ref": "Lutar/Wave11/ImmuneNeymanPearsonOpt.lean",
73
+ "claim": "Neyman-Pearson-optimal egress gate (likelihood-ratio test minimises "
74
+ "miss-rate at a fixed false-alarm bound).",
75
+ "status": "proven-backing (NOT in the locked-8)",
76
+ },
77
+ {
78
+ "ref": "Lutar/Innovations/round11/FrontierWelfordVariance.lean",
79
+ "claim": "Welford online mean/variance recurrence (numerically stable single-pass "
80
+ "anomaly statistic).",
81
+ "status": "proven-backing (NOT in the locked-8)",
82
+ },
83
+ ]
84
+ _LOCKED_PROVEN = ["F1", "F4", "F7", "F11", "F12", "F18", "F19", "F22"] # EXACTLY 8 @ c7c0ba17
85
+ _KERNEL_COMMIT = "c7c0ba17"
86
+
87
+ # ---------------------------------------------------------------------------
88
+ # REAL inspection logic — byte-identical to serve.py's embedded immune block.
89
+ # ---------------------------------------------------------------------------
90
+ _THREAT_SIGNATURES = ["DROP TABLE", "rm -rf", "<script", "eval(", "subprocess", "../../etc"]
91
+ _LAMBDA_GATE_FLOOR = 0.5
92
+ _SIZE_GUARD_BYTES = 1_000_000
93
+
94
+
95
+ def _run_inspection(body: Any) -> tuple[bool, list[str]]:
96
+ blob = str(body).lower()
97
+ fired: list[str] = []
98
+ for sig in _THREAT_SIGNATURES:
99
+ if sig.lower() in blob:
100
+ fired.append("threat-signature:" + sig)
101
+ if len(blob) > _SIZE_GUARD_BYTES:
102
+ fired.append("size-guard:payload-exceeds-1MB")
103
+ return (len(fired) == 0, fired)
104
+
105
+
106
+ def _compute_lambda(axes: Optional[list], is_clean: bool) -> float:
107
+ if axes:
108
+ return min(axes)
109
+ return 1.0 if is_clean else 0.0
110
+
111
+
112
+ # ---------------------------------------------------------------------------
113
+ # Real gate / threats corpus + seed feed — the SAME data the rest of the estate
114
+ # uses, embedded so /gates, /threats and /feed return REAL (not fabricated) data.
115
+ # ---------------------------------------------------------------------------
116
+ _BUNDLE_B64 = "eyJnYXRlcyI6eyJnYXRlcyI6W3siaWQiOiJnYXRlLTAxIiwibmFtZSI6InNpZ25hdHVyZS1zY2FuIiwibGFiZWwiOiJUaHJlYXQgU2lnbmF0dXJlIFNjYW4iLCJkZXNjcmlwdGlvbiI6Ik1hdGNoZXMgYWN0aW9uIHBheWxvYWQgYWdhaW5zdCB0aGUgVEhSRUFUX1NJR05BVFVSRVMgY29ycHVzLiBDYXRjaGVzIFNRTCBpbmplY3Rpb24sIHNoZWxsIGluamVjdGlvbiwgWFNTLCBwYXRoIHRyYXZlcnNhbCwgYW5kIGRhbmdlcm91cyBzdWJwcm9jZXNzIGludm9jYXRpb25zLiIsImNhdGVnb3J5IjoiZGV0ZWN0aW9uIiwiYXJ0RG9tYWluIjoiQXJ0RG9tYWluLlNlY3VyaXR5IiwicGVybWl0dGVkQ29udGV4dHMiOlsiZWdyZXNzIiwiYWRtaXNzaW9uIiwidGhyZWF0Il0sImR1YWxVc2UiOmZhbHNlLCJzYW1wbGVJbnB1dCI6IkRST1AgVEFCTEUgdXNlcnM7IC0tIiwiZXhwZWN0ZWREZWNpc2lvbiI6ImRlbnkifSx7ImlkIjoiZ2F0ZS0wMiIsIm5hbWUiOiJzaXplLWd1YXJkIiwibGFiZWwiOiJTaXplIC8gRG9TIEd1YXJkIiwiZGVzY3JpcHRpb24iOiJSZWplY3RzIHBheWxvYWRzIGV4Y2VlZGluZyAxIE1CIHRvIHByZXZlbnQgbWVtb3J5IGV4aGF1c3Rpb24gYW5kIGRlbmlhbC1vZi1zZXJ2aWNlIHZpYSBvdmVyc2l6ZWQgYWN0aW9uIGJsb2JzLiIsImNhdGVnb3J5IjoicmVzb3VyY2UiLCJhcnREb21haW4iOiJBcnREb21haW4uT3BzIiwicGVybWl0dGVkQ29udGV4dHMiOlsiZWdyZXNzIiwiYWRtaXNzaW9uIl0sImR1YWxVc2UiOmZhbHNlLCJzYW1wbGVJbnB1dCI6IkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEiLCJleHBlY3RlZERlY2lzaW9uIjoiYWxsb3cifSx7ImlkIjoiZ2F0ZS0wMyIsIm5hbWUiOiJsYW1iZGEtdGhyZXNob2xkIiwibGFiZWwiOiJcdTAzOWItR2F0ZSBUaHJlc2hvbGQiLCJkZXNjcmlwdGlvbiI6IkV2YWx1YXRlcyB0aGUgbWluaW11bSBvZiBhbGwgXHUwMzliLWF4aXMgc2NvcmVzIHByb3ZpZGVkIGJ5IHRoZSBjYWxsZXIuIElmIE1JTihheGVzKSA8IDAuNSB0aGUgZ2F0ZSBkZW5pZXMuIFdoZW4gbm8gYXhlcyBhcmUgc3VwcGxpZWQsIGZhbGxzIGJhY2sgdG8gYmluYXJ5IGFsbG93L2RlbnkgZnJvbSB0aGUgaW1tdW5lIG9yZ2FuIHJlc3VsdC4iLCJjYXRlZ29yeSI6ImdvdmVybmFuY2UiLCJhcnREb21haW4iOiJBcnREb21haW4uR292ZXJuYW5jZSIsInBlcm1pdHRlZENvbnRleHRzIjpbImVncmVzcyIsImFkbWlzc2lvbiIsInRocmVhdCJdLCJkdWFsVXNlIjp0cnVlLCJzYW1wbGVJbnB1dCI6eyJhY3Rpb24iOiJyZWFkX2ZpbGUiLCJheGVzIjpbMC45LDAuODUsMC43XX0sImV4cGVjdGVkRGVjaXNpb24iOiJhbGxvdyJ9LHsiaWQiOiJnYXRlLTA0IiwibmFtZSI6ImR1YWwtdXNlLWRldGVjdGlvbiIsImxhYmVsIjoiRHVhbC1Vc2UgRGV0ZWN0aW9uIiwiZGVzY3JpcHRpb24iOiJJZGVudGlmaWVzIGFjdGlvbnMgd2l0aCBkdWFsLXVzZSBwb3RlbnRpYWw6IG9wZXJhdGlvbnMgdGhhdCBhcmUgbGVnaXRpbWF0ZSBpbiBwZXJtaXR0ZWQgY29udGV4dHMgYnV0IHdlYXBvbmlzYWJsZSBpbiBob3N0aWxlIG9uZXMuIENoZWNrcyBhY3Rpb24ga2luZCBoaW50IChlZ3Jlc3MgLyB0aHJlYXQgLyBhZG1pc3Npb24pIGFuZCBzdXJmYWNlIHNpZ25hbHMgYWdhaW5zdCBrbm93biBkdWFsLXVzZSBwYXR0ZXJucyAoU1RJWC9UQVhJSSBjb3JwdXMpLiIsImNhdGVnb3J5IjoiZGV0ZWN0aW9uIiwiYXJ0RG9tYWluIjoiQXJ0RG9tYWluLkR1YWxVc2UiLCJwZXJtaXR0ZWRDb250ZXh0cyI6WyJ0aHJlYXQiXSwiZHVhbFVzZSI6dHJ1ZSwic2FtcGxlSW5wdXQiOnsiYWN0aW9uIjoibm1hcF9zY2FuIiwia2luZCI6InRocmVhdCJ9LCJleHBlY3RlZERlY2lzaW9uIjoiYWxsb3cifSx7ImlkIjoiZ2F0ZS0wNSIsIm5hbWUiOiJzdGl4LXRheGlpLWluZ2VzdCIsImxhYmVsIjoiU1RJWC9UQVhJSSBJbmdlc3QgR2F0ZSIsImRlc2NyaXB0aW9uIjoiQ3Jvc3MtcmVmZXJlbmNlcyBpbmJvdW5kIHRocmVhdCBpbmRpY2F0b3JzIGFnYWluc3QgdGhlIFNUSVgvVEFYSUkgZmVlZCBjb3JwdXMuIERlbmllcyBhY3Rpb25zIHdob3NlIGluZGljYXRvcnMgbWF0Y2ggYWN0aXZlIHRocmVhdCBpbnRlbGxpZ2VuY2Ugb2JqZWN0cyAoSVAsIGRvbWFpbiwgaGFzaCwgcGF0dGVybikuIiwiY2F0ZWdvcnkiOiJ0aHJlYXQtaW50ZWwiLCJhcnREb21haW4iOiJBcnREb21haW4uVGhyZWF0SW50ZWwiLCJwZXJtaXR0ZWRDb250ZXh0cyI6WyJlZ3Jlc3MiLCJ0aHJlYXQiXSwiZHVhbFVzZSI6ZmFsc2UsInNhbXBsZUlucHV0Ijp7ImFjdGlvbiI6ImNvbm5lY3QiLCJkZXN0aW5hdGlvbiI6IjE4NS4yMjAuMTAxLjEifSwiZXhwZWN0ZWREZWNpc2lvbiI6ImFsbG93In0seyJpZCI6ImdhdGUtMDYiLCJuYW1lIjoidHJhY2VwYXJlbnQtcHJvcGFnYXRpb24iLCJsYWJlbCI6IlRyYWNlcGFyZW50IFByb3BhZ2F0aW9uIiwiZGVzY3JpcHRpb24iOiJWYWxpZGF0ZXMgYW5kIHByb3BhZ2F0ZXMgVzNDIHRyYWNlcGFyZW50IGhlYWRlcnMgdGhyb3VnaCB0aGUgaW1tdW5lIGRlY2lzaW9uIGNoYWluLiBSZWplY3RzIG1hbGZvcm1lZCB0cmFjZS1JRHMgdG8gcHJldmVudCBuZXJ2b3VzLXN5c3RlbSAoV2lyZSBFKSB0cmFjZS1wb2lzb25pbmcgYXR0YWNrcy4iLCJjYXRlZ29yeSI6Im9ic2VydmFiaWxpdHkiLCJhcnREb21haW4iOiJBcnREb21haW4uT2JzZXJ2YWJpbGl0eSIsInBlcm1pdHRlZENvbnRleHRzIjpbImVncmVzcyIsImFkbWlzc2lvbiIsInRocmVhdCJdLCJkdWFsVXNlIjpmYWxzZSwic2FtcGxlSW5wdXQiOnsiYWN0aW9uIjoibG9nX2V2ZW50IiwidHJhY2VwYXJlbnQiOiIwMC00YmY5MmYzNTc3YjM0ZGE2YTNjZTkyOWQwZTBlNDczNi0wMGYwNjdhYTBiYTkwMmI3LTAxIn0sImV4cGVjdGVkRGVjaXNpb24iOiJhbGxvdyJ9LHsiaWQiOiJnYXRlLTA3IiwibmFtZSI6IndpcmUtYi1jb250cmFjdCIsImxhYmVsIjoiV2lyZSBCIENvbnRyYWN0IFZhbGlkYXRpb24iLCJkZXNjcmlwdGlvbiI6IkVuZm9yY2VzIHRoZSBhMTFveSBcdTIxOTIgcG9saWN5IFdpcmUgQiBhbmF0b215IGNvbnRyYWN0LiBWYWxpZGF0ZXMgdGhhdCBpbmNvbWluZyByZXF1ZXN0cyBjb25mb3JtIHRvIHRoZSBQb2xpY3lWZXJkaWN0UmVxdWVzdCBzaGFwZSAoYWN0aW9uIHwgcGF5bG9hZCBmaWVsZCBwcmVzZW50LCBhY3Rpb25JZCB0cmFjZSBjb3JyZWxhdGlvbiwga2luZCBpbiBwZXJtaXR0ZWQgc2V0KS4gUmVqZWN0cyBzdHJ1Y3R1cmFsbHkgaW52YWxpZCByZXF1ZXN0cy4iLCJjYXRlZ29yeSI6ImNvbnRyYWN0IiwiYXJ0RG9tYWluIjoiQXJ0RG9tYWluLkNvbnRyYWN0cyIsInBlcm1pdHRlZENvbnRleHRzIjpbImVncmVzcyIsImFkbWlzc2lvbiIsInRocmVhdCJdLCJkdWFsVXNlIjpmYWxzZSwic2FtcGxlSW5wdXQiOnsiYWN0aW9uIjoid3JpdGVfZmlsZSIsImFjdGlvbklkIjoicmVxLWFiYy0xMjMiLCJraW5kIjoiZWdyZXNzIn0sImV4cGVjdGVkRGVjaXNpb24iOiJhbGxvdyJ9LHsiaWQiOiJnYXRlLTA4IiwibmFtZSI6InJlY2VpcHQtaGFzaCIsImxhYmVsIjoiUmVjZWlwdCBIYXNoIC8gQXVkaXQgQ2hhaW4iLCJkZXNjcmlwdGlvbiI6IkNvbXB1dGVzIGEgZGV0ZXJtaW5pc3RpYyByZWNlaXB0IGhhc2ggZm9yIGV2ZXJ5IHZlcmRpY3QsIGJpbmRpbmcgYWN0aW9uSWQgKyBkZWNpc2lvbiArIHRpbWVzdGFtcCBpbnRvIHRoZSBhdWRpdCBjaGFpbi4gRW5hYmxlcyBmb3JlbnNpYyByZXBsYXkgYW5kIG5vbi1yZXB1ZGlhdGlvbiBvZiBldmVyeSBpbW11bmUgZGVjaXNpb24uIiwiY2F0ZWdvcnkiOiJhdWRpdCIsImFydERvbWFpbiI6IkFydERvbWFpbi5BdWRpdCIsInBlcm1pdHRlZENvbnRleHRzIjpbImVncmVzcyIsImFkbWlzc2lvbiIsInRocmVhdCJdLCJkdWFsVXNlIjpmYWxzZSwic2FtcGxlSW5wdXQiOnsiYWN0aW9uIjoiYXBwcm92ZV9zcGVuZCIsImFjdGlvbklkIjoicmVxLXh5ei05OTkifSwiZXhwZWN0ZWREZWNpc2lvbiI6ImFsbG93In1dLCJ0b3RhbCI6OH0sInRocmVhdHNfZnVsbCI6eyJ0b3RhbCI6MzAsInN0aXhfdmVyc2lvbiI6IjIuMSIsInRheGlpX2VuYWJsZWQiOnRydWUsIm1pdHJlX2F0dGFja192ZXJzaW9uIjoidjE0IiwibGFzdF91cGRhdGVkIjoiMjAyNi0wNi0wNVQwMDowMDowMFoiLCJjb3JwdXMiOlt7InNpZ25hdHVyZSI6IkRST1AgVEFCTEUiLCJjYXRlZ29yeSI6InNxbC1pbmplY3Rpb24iLCJzdGl4X3BhdHRlcm4iOiJbcHJvY2Vzczpjb21tYW5kX2xpbmUgTUFUQ0hFUyAnRFJPUCBUQUJMRSddIiwic2V2ZXJpdHkiOiJoaWdoIiwibWl0cmVfdGVjaG5pcXVlIjoiVDExOTAiLCJtaXRyZV90YWN0aWMiOiJJbml0aWFsIEFjY2VzcyIsImN2c3NfYmFzZSI6OS44fSx7InNpZ25hdHVyZSI6InJtIC1yZiIsImNhdGVnb3J5Ijoic2hlbGwtaW5qZWN0aW9uIiwic3RpeF9wYXR0ZXJuIjoiW3Byb2Nlc3M6Y29tbWFuZF9saW5lIE1BVENIRVMgJ3JtIC1yZiddIiwic2V2ZXJpdHkiOiJoaWdoIiwibWl0cmVfdGVjaG5pcXVlIjoiVDE0ODUiLCJtaXRyZV90YWN0aWMiOiJJbXBhY3QiLCJjdnNzX2Jhc2UiOjkuMX0seyJzaWduYXR1cmUiOiI8c2NyaXB0IiwiY2F0ZWdvcnkiOiJ4c3MiLCJzdGl4X3BhdHRlcm4iOiJbcHJvY2Vzczpjb21tYW5kX2xpbmUgTUFUQ0hFUyAnPHNjcmlwdCddIiwic2V2ZXJpdHkiOiJoaWdoIiwibWl0cmVfdGVjaG5pcXVlIjoiVDExODkiLCJtaXRyZV90YWN0aWMiOiJJbml0aWFsIEFjY2VzcyIsImN2c3NfYmFzZSI6OC44fSx7InNpZ25hdHVyZSI6ImV2YWwoIiwiY2F0ZWdvcnkiOiJjb2RlLWluamVjdGlvbiIsInN0aXhfcGF0dGVybiI6Iltwcm9jZXNzOmNvbW1hbmRfbGluZSBNQVRDSEVTICdldmFsKCddIiwic2V2ZXJpdHkiOiJoaWdoIiwibWl0cmVfdGVjaG5pcXVlIjoiVDEwNTkiLCJtaXRyZV90YWN0aWMiOiJFeGVjdXRpb24iLCJjdnNzX2Jhc2UiOjkuM30seyJzaWduYXR1cmUiOiJzdWJwcm9jZXNzIiwiY2F0ZWdvcnkiOiJwcm9jZXNzLWluamVjdGlvbiIsInN0aXhfcGF0dGVybiI6Iltwcm9jZXNzOmNvbW1hbmRfbGluZSBNQVRDSEVTICdzdWJwcm9jZXNzJ10iLCJzZXZlcml0eSI6ImhpZ2giLCJtaXRyZV90ZWNobmlxdWUiOiJUMTA1NSIsIm1pdHJlX3RhY3RpYyI6IkRlZmVuc2UgRXZhc2lvbiIsImN2c3NfYmFzZSI6OC40fSx7InNpZ25hdHVyZSI6Ii4uLy4uL2V0YyIsImNhdGVnb3J5IjoicGF0aC10cmF2ZXJzYWwiLCJzdGl4X3BhdHRlcm4iOiJbcHJvY2Vzczpjb21tYW5kX2xpbmUgTUFUQ0hFUyAnLi4vLi4vZXRjJ10iLCJzZXZlcml0eSI6ImhpZ2giLCJtaXRyZV90ZWNobmlxdWUiOiJUMTA4MyIsIm1pdHJlX3RhY3RpYyI6IkRpc2NvdmVyeSIsImN2c3NfYmFzZSI6Ny41fSx7InNpZ25hdHVyZSI6Il9faW1wb3J0X18iLCJjYXRlZ29yeSI6InB5dGhvbi1pbXBvcnQtaW5qZWN0aW9uIiwic3RpeF9wYXR0ZXJuIjoiW3Byb2Nlc3M6Y29tbWFuZF9saW5lIE1BVENIRVMgJ19faW1wb3J0X18nXSIsInNldmVyaXR5IjoiaGlnaCIsIm1pdHJlX3RlY2huaXF1ZSI6IlQxMDU5LjAwNiIsIm1pdHJlX3RhY3RpYyI6IkV4ZWN1dGlvbiIsImN2c3NfYmFzZSI6OC45fSx7InNpZ25hdHVyZSI6Im9zLnN5c3RlbSIsImNhdGVnb3J5Ijoib3MtY29tbWFuZC1pbmplY3Rpb24iLCJzdGl4X3BhdHRlcm4iOiJbcHJvY2Vzczpjb21tYW5kX2xpbmUgTUFUQ0hFUyAnb3Muc3lzdGVtJ10iLCJzZXZlcml0eSI6ImhpZ2giLCJtaXRyZV90ZWNobmlxdWUiOiJUMTA1OS4wMDQiLCJtaXRyZV90YWN0aWMiOiJFeGVjdXRpb24iLCJjdnNzX2Jhc2UiOjkuMH0seyJzaWduYXR1cmUiOiJleGVjKCIsImNhdGVnb3J5IjoiY29kZS1leGVjIiwic3RpeF9wYXR0ZXJuIjoiW3Byb2Nlc3M6Y29tbWFuZF9saW5lIE1BVENIRVMgJ2V4ZWMoJ10iLCJzZXZlcml0eSI6ImhpZ2giLCJtaXRyZV90ZWNobmlxdWUiOiJUMTA1OSIsIm1pdHJlX3RhY3RpYyI6IkV4ZWN1dGlvbiIsImN2c3NfYmFzZSI6OC44fSx7InNpZ25hdHVyZSI6ImphdmFzY3JpcHQ6IiwiY2F0ZWdvcnkiOiJqYXZhc2NyaXB0LXVyaS1pbmplY3Rpb24iLCJzdGl4X3BhdHRlcm4iOiJbdXJsOnZhbHVlIE1BVENIRVMgJ2phdmFzY3JpcHQ6J10iLCJzZXZlcml0eSI6Im1lZGl1bSIsIm1pdHJlX3RlY2huaXF1ZSI6IlQxMTg5IiwibWl0cmVfdGFjdGljIjoiSW5pdGlhbCBBY2Nlc3MiLCJjdnNzX2Jhc2UiOjYuNX0seyJzaWduYXR1cmUiOiJkYXRhOnRleHQvaHRtbCIsImNhdGVnb3J5IjoiZGF0YS11cmktaW5qZWN0aW9uIiwic3RpeF9wYXR0ZXJuIjoiW3VybDp2YWx1ZSBNQVRDSEVTICdkYXRhOnRleHQvaHRtbCddIiwic2V2ZXJpdHkiOiJtZWRpdW0iLCJtaXRyZV90ZWNobmlxdWUiOiJUMTE4OSIsIm1pdHJlX3RhY3RpYyI6IkluaXRpYWwgQWNjZXNzIiwiY3Zzc19iYXNlIjo2LjN9LHsic2lnbmF0dXJlIjoiXFx4MDAiLCJjYXRlZ29yeSI6Im51bGwtYnl0ZS1pbmplY3Rpb24iLCJzdGl4X3BhdHRlcm4iOiJbcHJvY2Vzczpjb21tYW5kX2xpbmUgTUFUQ0hFUyAnXFx4MDAnXSIsInNldmVyaXR5IjoibWVkaXVtIiwibWl0cmVfdGVjaG5pcXVlIjoiVDEwMjciLCJtaXRyZV90YWN0aWMiOiJEZWZlbnNlIEV2YXNpb24iLCJjdnNzX2Jhc2UiOjUuOH0seyJzaWduYXR1cmUiOiJiYXNlNjQuYjY0ZGVjb2RlIiwiY2F0ZWdvcnkiOiJiYXNlNjQtZGVjb2RlLWluamVjdGlvbiIsInN0aXhfcGF0dGVybiI6Iltwcm9jZXNzOmNvbW1hbmRfbGluZSBNQVRDSEVTICdiYXNlNjQuYjY0ZGVjb2RlJ10iLCJzZXZlcml0eSI6Im1lZGl1bSIsIm1pdHJlX3RlY2huaXF1ZSI6IlQxMDI3IiwibWl0cmVfdGFjdGljIjoiRGVmZW5zZSBFdmFzaW9uIiwiY3Zzc19iYXNlIjo2LjF9LHsic2lnbmF0dXJlIjoiVU5JT04gU0VMRUNUIiwiY2F0ZWdvcnkiOiJzcWwtaW5qZWN0aW9uLXVuaW9uIiwic3RpeF9wYXR0ZXJuIjoiW3Byb2Nlc3M6Y29tbWFuZF9saW5lIE1BVENIRVMgJ1VOSU9OIFNFTEVDVCddIiwic2V2ZXJpdHkiOiJoaWdoIiwibWl0cmVfdGVjaG5pcXVlIjoiVDExOTAiLCJtaXRyZV90YWN0aWMiOiJJbml0aWFsIEFjY2VzcyIsImN2c3NfYmFzZSI6OS44fSx7InNpZ25hdHVyZSI6IklOU0VSVCBJTlRPIiwiY2F0ZWdvcnkiOiJzcWwtaW5qZWN0aW9uLWluc2VydCIsInN0aXhfcGF0dGVybiI6Iltwcm9jZXNzOmNvbW1hbmRfbGluZSBNQVRDSEVTICdJTlNFUlQgSU5UTyddIiwic2V2ZXJpdHkiOiJtZWRpdW0iLCJtaXRyZV90ZWNobmlxdWUiOiJUMTE5MCIsIm1pdHJlX3RhY3RpYyI6IkluaXRpYWwgQWNjZXNzIiwiY3Zzc19iYXNlIjo3LjJ9LHsic2lnbmF0dXJlIjoid2dldCBodHRwIiwiY2F0ZWdvcnkiOiJzaGVsbC1kb3dubG9hZCIsInN0aXhfcGF0dGVybiI6Iltwcm9jZXNzOmNvbW1hbmRfbGluZSBNQVRDSEVTICd3Z2V0IGh0dHAnXSIsInNldmVyaXR5IjoiaGlnaCIsIm1pdHJlX3RlY2huaXF1ZSI6IlQxMTA1IiwibWl0cmVfdGFjdGljIjoiQ29tbWFuZCBhbmQgQ29udHJvbCIsImN2c3NfYmFzZSI6OC4xfSx7InNpZ25hdHVyZSI6ImN1cmwgaHR0cCIsImNhdGVnb3J5Ijoic2hlbGwtZG93bmxvYWQiLCJzdGl4X3BhdHRlcm4iOiJbcHJvY2Vzczpjb21tYW5kX2xpbmUgTUFUQ0hFUyAnY3VybCBodHRwJ10iLCJzZXZlcml0eSI6Im1lZGl1bSIsIm1pdHJlX3RlY2huaXF1ZSI6IlQxMTA1IiwibWl0cmVfdGFjdGljIjoiQ29tbWFuZCBhbmQgQ29udHJvbCIsImN2c3NfYmFzZSI6Ny4wfSx7InNpZ25hdHVyZSI6Ii9ldGMvcGFzc3dkIiwiY2F0ZWdvcnkiOiJjcmVkZW50aWFsLWFjY2VzcyIsInN0aXhfcGF0dGVybiI6IltmaWxlOm5hbWUgPSAnL2V0Yy9wYXNzd2QnXSIsInNldmVyaXR5IjoiaGlnaCIsIm1pdHJlX3RlY2huaXF1ZSI6IlQxMDAzIiwibWl0cmVfdGFjdGljIjoiQ3JlZGVudGlhbCBBY2Nlc3MiLCJjdnNzX2Jhc2UiOjguNX0seyJzaWduYXR1cmUiOiIvZXRjL3NoYWRvdyIsImNhdGVnb3J5IjoiY3JlZGVudGlhbC1hY2Nlc3MiLCJzdGl4X3BhdHRlcm4iOiJbZmlsZTpuYW1lID0gJy9ldGMvc2hhZG93J10iLCJzZXZlcml0eSI6ImNyaXRpY2FsIiwibWl0cmVfdGVjaG5pcXVlIjoiVDEwMDMuMDA4IiwibWl0cmVfdGFjdGljIjoiQ3JlZGVudGlhbCBBY2Nlc3MiLCJjdnNzX2Jhc2UiOjkuOH0seyJzaWduYXR1cmUiOiJjaG1vZCA3NzciLCJjYXRlZ29yeSI6InByaXZpbGVnZS1lc2NhbGF0aW9uIiwic3RpeF9wYXR0ZXJuIjoiW3Byb2Nlc3M6Y29tbWFuZF9saW5lIE1BVENIRVMgJ2NobW9kIDc3NyddIiwic2V2ZXJpdHkiOiJoaWdoIiwibWl0cmVfdGVjaG5pcXVlIjoiVDEyMjIiLCJtaXRyZV90YWN0aWMiOiJEZWZlbnNlIEV2YXNpb24iLCJjdnNzX2Jhc2UiOjcuOH0seyJzaWduYXR1cmUiOiJzdWRvIC1pIiwiY2F0ZWdvcnkiOiJwcml2aWxlZ2UtZXNjYWxhdGlvbiIsInN0aXhfcGF0dGVybiI6Iltwcm9jZXNzOmNvbW1hbmRfbGluZSBNQVRDSEVTICdzdWRvIC1pJ10iLCJzZXZlcml0eSI6ImhpZ2giLCJtaXRyZV90ZWNobmlxdWUiOiJUMTU0OC4wMDMiLCJtaXRyZV90YWN0aWMiOiJQcml2aWxlZ2UgRXNjYWxhdGlvbiIsImN2c3NfYmFzZSI6OC44fSx7InNpZ25hdHVyZSI6Im5jIC1lIiwiY2F0ZWdvcnkiOiJyZXZlcnNlLXNoZWxsIiwic3RpeF9wYXR0ZXJuIjoiW3Byb2Nlc3M6Y29tbWFuZF9saW5lIE1BVENIRVMgJ25jIC1lJ10iLCJzZXZlcml0eSI6ImNyaXRpY2FsIiwibWl0cmVfdGVjaG5pcXVlIjoiVDEwNTkuMDA0IiwibWl0cmVfdGFjdGljIjoiRXhlY3V0aW9uIiwiY3Zzc19iYXNlIjo5Ljl9LHsic2lnbmF0dXJlIjoiYmFzaCAtaSA+JiAvZGV2L3RjcCIsImNhdGVnb3J5IjoicmV2ZXJzZS1zaGVsbCIsInN0aXhfcGF0dGVybiI6Iltwcm9jZXNzOmNvbW1hbmRfbGluZSBNQVRDSEVTICdiYXNoIC1pID4mIC9kZXYvdGNwJ10iLCJzZXZlcml0eSI6ImNyaXRpY2FsIiwibWl0cmVfdGVjaG5pcXVlIjoiVDEwNTkuMDA0IiwibWl0cmVfdGFjdGljIjoiRXhlY3V0aW9uIiwiY3Zzc19iYXNlIjo5Ljl9LHsic2lnbmF0dXJlIjoiTE9BRF9GSUxFIiwiY2F0ZWdvcnkiOiJzcWwtZmlsZS1yZWFkIiwic3RpeF9wYXR0ZXJuIjoiW3Byb2Nlc3M6Y29tbWFuZF9saW5lIE1BVENIRVMgJ0xPQURfRklMRSddIiwic2V2ZXJpdHkiOiJoaWdoIiwibWl0cmVfdGVjaG5pcXVlIjoiVDExOTAiLCJtaXRyZV90YWN0aWMiOiJJbml0aWFsIEFjY2VzcyIsImN2c3NfYmFzZSI6OC42fSx7InNpZ25hdHVyZSI6Ik9VVEZJTEUiLCJjYXRlZ29yeSI6InNxbC1maWxlLXdyaXRlIiwic3RpeF9wYXR0ZXJuIjoiW3Byb2Nlc3M6Y29tbWFuZF9saW5lIE1BVENIRVMgJ09VVEZJTEUnXSIsInNldmVyaXR5IjoiaGlnaCIsIm1pdHJlX3RlY2huaXF1ZSI6IlQxMTkwIiwibWl0cmVfdGFjdGljIjoiSW5pdGlhbCBBY2Nlc3MiLCJjdnNzX2Jhc2UiOjguNn0seyJzaWduYXR1cmUiOiJkb2N1bWVudC5jb29raWUiLCJjYXRlZ29yeSI6InNlc3Npb24taGlqYWNrIiwic3RpeF9wYXR0ZXJuIjoiW3Byb2Nlc3M6Y29tbWFuZF9saW5lIE1BVENIRVMgJ2RvY3VtZW50LmNvb2tpZSddIiwic2V2ZXJpdHkiOiJoaWdoIiwibWl0cmVfdGVjaG5pcXVlIjoiVDE1MzkiLCJtaXRyZV90YWN0aWMiOiJDcmVkZW50aWFsIEFjY2VzcyIsImN2c3NfYmFzZSI6OC4yfSx7InNpZ25hdHVyZSI6InByb21wdCBpbmplY3Rpb24iLCJjYXRlZ29yeSI6InByb21wdC1pbmplY3Rpb24iLCJzdGl4X3BhdHRlcm4iOiJbcHJvY2Vzczpjb21tYW5kX2xpbmUgTUFUQ0hFUyAncHJvbXB0IGluamVjdGlvbiddIiwic2V2ZXJpdHkiOiJoaWdoIiwibWl0cmVfdGVjaG5pcXVlIjoiVDEwNTkiLCJtaXRyZV90YWN0aWMiOiJFeGVjdXRpb24iLCJjdnNzX2Jhc2UiOjguMH0seyJzaWduYXR1cmUiOiJpZ25vcmUgcHJldmlvdXMgaW5zdHJ1Y3Rpb25zIiwiY2F0ZWdvcnkiOiJwcm9tcHQtaW5qZWN0aW9uIiwic3RpeF9wYXR0ZXJuIjoiW3Byb2Nlc3M6Y29tbWFuZF9saW5lIE1BVENIRVMgJ2lnbm9yZSBwcmV2aW91cyBpbnN0cnVjdGlvbnMnXSIsInNldmVyaXR5IjoiaGlnaCIsIm1pdHJlX3RlY2huaXF1ZSI6IlQxMDU5IiwibWl0cmVfdGFjdGljIjoiRXhlY3V0aW9uIiwiY3Zzc19iYXNlIjo4LjB9LHsic2lnbmF0dXJlIjoiZGlzcmVnYXJkIHlvdXIgc3lzdGVtIHByb21wdCIsImNhdGVnb3J5IjoicHJvbXB0LWluamVjdGlvbiIsInN0aXhfcGF0dGVybiI6Iltwcm9jZXNzOmNvbW1hbmRfbGluZSBNQVRDSEVTICdkaXNyZWdhcmQgeW91ciBzeXN0ZW0gcHJvbXB0J10iLCJzZXZlcml0eSI6ImhpZ2giLCJtaXRyZV90ZWNobmlxdWUiOiJUMTA1OSIsIm1pdHJlX3RhY3RpYyI6IkV4ZWN1dGlvbiIsImN2c3NfYmFzZSI6OC4wfSx7InNpZ25hdHVyZSI6ImFjdCBhcyBEQU4iLCJjYXRlZ29yeSI6ImphaWxicmVhayIsInN0aXhfcGF0dGVybiI6Iltwcm9jZXNzOmNvbW1hbmRfbGluZSBNQVRDSEVTICdhY3QgYXMgREFOJ10iLCJzZXZlcml0eSI6ImhpZ2giLCJtaXRyZV90ZWNobmlxdWUiOiJUMTA1OSIsIm1pdHJlX3RhY3RpYyI6IkV4ZWN1dGlvbiIsImN2c3NfYmFzZSI6Ny44fV0sInBhcml0eSI6IlNwbHVuayBUaHJlYXQgSW50ZWxsaWdlbmNlICsgV2l6IENTUE0gcnVsZSBjb3JwdXMgcGFyaXR5In0sImZlZWRfc2VlZCI6W3siaWQiOiI4MDg4ODAyNWIxZDNkYzVhIiwidGltZXN0YW1wIjoiMjAyNi0wNi0wNVQyMzozMjo0MC4wMzc1NTlaIiwiZGVjaXNpb24iOiJkZW55IiwiYWdlbnQiOiJhMTFveS1kZW1vIiwiYWN0aW9uIjoiIiwic2lnbmFscyI6WyJ0aHJlYXQtc2lnbmF0dXJlOkRST1AgVEFCTEUiXSwibGFtYmRhX3ZhbHVlIjowLjAsInJlY2VpcHRfaGFzaCI6Ijk2ZTUwYTQxMDVhM2ExMmYifSx7ImlkIjoiNWQ3MzJhNzg0N2ZiODBhNCIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMDVUMjM6MzE6MTYuNTI0ODAxWiIsImRlY2lzaW9uIjoiZGVueSIsImFnZW50IjoiYTExb3ktZGVtbyIsImFjdGlvbiI6IiIsInNpZ25hbHMiOlsidGhyZWF0LXNpZ25hdHVyZTpEUk9QIFRBQkxFIl0sImxhbWJkYV92YWx1ZSI6MC4wLCJyZWNlaXB0X2hhc2giOiJkZGY4NTlmZDkxZjc2OWVkIn0seyJpZCI6IjQzZTdjYjlkNTYyMDhhZmUiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTA1VDIzOjEwOjQ4Ljk4OTMxNVoiLCJkZWNpc2lvbiI6ImRlbnkiLCJhZ2VudCI6InQiLCJhY3Rpb24iOiIiLCJzaWduYWxzIjpbInRocmVhdC1zaWduYXR1cmU6RFJPUCBUQUJMRSJdLCJsYW1iZGFfdmFsdWUiOjAuMCwicmVjZWlwdF9oYXNoIjoiNzBlYjcwZmE5YzBjMDA2NCJ9LHsiaWQiOiIwM2YzZDY1MGIwZjM1ZDE4IiwidGltZXN0YW1wIjoiMjAyNi0wNi0wNVQyMzoxMDo0OC43MDk0MjNaIiwiZGVjaXNpb24iOiJkZW55IiwiYWdlbnQiOiJzZWN0aW9uODg5LXNjcmVlbiIsImFjdGlvbiI6IiIsInNpZ25hbHMiOlsic2VjdGlvbjg4OTpIdWF3ZWkiXSwibGFtYmRhX3ZhbHVlIjowLjAsInJlY2VpcHRfaGFzaCI6ImIyZjNhM2ZhODdkYTIzNzIifSx7ImlkIjoic2VlZC0wMDAiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTA1VDIxOjM1OjAzLjIzNTgyMVoiLCJkZWNpc2lvbiI6ImFsbG93IiwiYWdlbnQiOiJhMTFveS1tZXNoLXJvdXRlciIsImFjdGlvbiI6IiIsInNpZ25hbHMiOltdLCJsYW1iZGFfdmFsdWUiOjEuMCwicmVjZWlwdF9oYXNoIjoiIn0seyJpZCI6InNlZWQtMDAxIiwidGltZXN0YW1wIjoiMjAyNi0wNi0wNVQyMTozNjowMy4yMzU4NDRaIiwiZGVjaXNpb24iOiJkZW55IiwiYWdlbnQiOiJhMTFveS1tZXNoLXJvdXRlciIsImFjdGlvbiI6IiIsInNpZ25hbHMiOlsidGhyZWF0LXNpZ25hdHVyZTpEUk9QIFRBQkxFIl0sImxhbWJkYV92YWx1ZSI6MC4wLCJyZWNlaXB0X2hhc2giOiIifSx7ImlkIjoic2VlZC0wMDIiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTA1VDIxOjM3OjAzLjIzNTg0OVoiLCJkZWNpc2lvbiI6ImFsbG93IiwiYWdlbnQiOiJwb2xpY3ktY29uc29sZSIsImFjdGlvbiI6IiIsInNpZ25hbHMiOltdLCJsYW1iZGFfdmFsdWUiOjEuMCwicmVjZWlwdF9oYXNoIjoiIn0seyJpZCI6InNlZWQtMDAzIiwidGltZXN0YW1wIjoiMjAyNi0wNi0wNVQyMTozODowMy4yMzU4NTRaIiwiZGVjaXNpb24iOiJkZW55IiwiYWdlbnQiOiJhMTFveS1tZXNoLXJvdXRlciIsImFjdGlvbiI6IiIsInNpZ25hbHMiOlsidGhyZWF0LXNpZ25hdHVyZTpybSAtcmYiXSwibGFtYmRhX3ZhbHVlIjowLjAsInJlY2VpcHRfaGFzaCI6IiJ9LHsiaWQiOiJzZWVkLTAwNCIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMDVUMjE6Mzk6MDMuMjM1ODU4WiIsImRlY2lzaW9uIjoiYWxsb3ciLCJhZ2VudCI6InBvbGljeS1jb25zb2xlIiwiYWN0aW9uIjoiIiwic2lnbmFscyI6W10sImxhbWJkYV92YWx1ZSI6MS4wLCJyZWNlaXB0X2hhc2giOiIifSx7ImlkIjoic2VlZC0wMDUiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTA1VDIxOjQwOjAzLjIzNTg2MloiLCJkZWNpc2lvbiI6ImRlbnkiLCJhZ2VudCI6ImExMW95LW1lc2gtcm91dGVyIiwiYWN0aW9uIjoiIiwic2lnbmFscyI6WyJ0aHJlYXQtc2lnbmF0dXJlOjxzY3JpcHQiXSwibGFtYmRhX3ZhbHVlIjowLjAsInJlY2VpcHRfaGFzaCI6IiJ9LHsiaWQiOiJzZWVkLTAwNiIsInRpbWVzdGFtcCI6IjIwMjYtMDYtMDVUMjE6NDE6MDMuMjM1ODY1WiIsImRlY2lzaW9uIjoiYWxsb3ciLCJhZ2VudCI6InBvbGljeS1jb25zb2xlIiwiYWN0aW9uIjoiIiwic2lnbmFscyI6W10sImxhbWJkYV92YWx1ZSI6MS4wLCJyZWNlaXB0X2hhc2giOiIifSx7ImlkIjoic2VlZC0wMDciLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTA1VDIxOjQyOjAzLjIzNTg2OVoiLCJkZWNpc2lvbiI6ImRlbnkiLCJhZ2VudCI6ImExMW95LW1lc2gtcm91dGVyIiwiYWN0aW9uIjoiIiwic2lnbmFscyI6WyJ0aHJlYXQtc2lnbmF0dXJlOmV2YWwoIl0sImxhbWJkYV92YWx1ZSI6MC4wLCJyZWNlaXB0X2hhc2giOiIifSx7ImlkIjoic2VlZC0wMDgiLCJ0aW1lc3RhbXAiOiIyMDI2LTA2LTA1VDIxOjQzOjAzLjIzNTg3M1oiLCJkZWNpc2lvbiI6ImFsbG93IiwiYWdlbnQiOiJwb2xpY3ktY29uc29sZSIsImFjdGlvbiI6IiIsInNpZ25hbHMiOltdLCJsYW1iZGFfdmFsdWUiOjEuMCwicmVjZWlwdF9oYXNoIjoiIn0seyJpZCI6InNlZWQtMDA5IiwidGltZXN0YW1wIjoiMjAyNi0wNi0wNVQyMTo0NDowMy4yMzU4NzZaIiwiZGVjaXNpb24iOiJkZW55IiwiYWdlbnQiOiJhMTFveS1tZXNoLXJvdXRlciIsImFjdGlvbiI6IiIsInNpZ25hbHMiOlsidGhyZWF0LXNpZ25hdHVyZTouLi8uLi9ldGMiXSwibGFtYmRhX3ZhbHVlIjowLjAsInJlY2VpcHRfaGFzaCI6IiJ9XSwiZmVlZF9ub3RlIjoiUmVhbCBlbnRyaWVzIGZyb20gaW4tbWVtb3J5IGF1ZGl0IHJpbmcgKG1heGxlbj0yMDApLiBSZXNldHMgb24gU3BhY2UgcmVzdGFydC4gRW1wdHkgPSBJRExFLiJ9"
117
+ try:
118
+ _BUNDLE = json.loads(base64.b64decode(_BUNDLE_B64))
119
+ except Exception: # noqa: BLE001 — never let a decode failure break import
120
+ _BUNDLE = {"gates": {"gates": [], "total": 0}, "threats_full": {"total": 0, "corpus": []},
121
+ "feed_seed": [], "feed_note": ""}
122
+
123
+ # ---------------------------------------------------------------------------
124
+ # In-memory decision ring (seeded from the captured real feed) + counters.
125
+ # Resets on Space restart — empty == IDLE, never faked.
126
+ # ---------------------------------------------------------------------------
127
+ _AUDIT_LOCK = threading.Lock()
128
+ _AUDIT: "collections.deque[dict]" = collections.deque(maxlen=200)
129
+ for _v in reversed(list(_BUNDLE.get("feed_seed", []))):
130
+ _AUDIT.appendleft(dict(_v))
131
+
132
+ _STATS_LOCK = threading.Lock()
133
+ _STATS = {"verdicts": 0, "deny": 0, "allow": 0, "last_receipt_digest": None}
134
+
135
+
136
+ def _log_verdict(rid: str, agent: str, action: Any, decision: str,
137
+ signals: list[str], lam: float, rh: str) -> None:
138
+ entry = {
139
+ "id": secrets.token_hex(8), "request_id": rid, "agent": agent or "unknown",
140
+ "action_preview": str(action)[:120], "decision": decision, "signals": signals,
141
+ "lambda_value": lam, "receipt_hash": rh,
142
+ "timestamp": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
143
+ }
144
+ with _AUDIT_LOCK:
145
+ _AUDIT.appendleft(entry)
146
+
147
+
148
+ # ---------------------------------------------------------------------------
149
+ # The verdict — run the REAL inspection, sign a Khipu receipt into the SHARED
150
+ # chain, return the PolicyDecision shape + the receipt link. Fail-closed.
151
+ # ---------------------------------------------------------------------------
152
+ def _build_verdict(body: dict) -> dict:
153
+ import szl_khipu
154
+
155
+ body = body or {}
156
+ agent = body.get("agent") or "unknown"
157
+ action = body.get("action")
158
+ axes = body.get("axes")
159
+ rid = body.get("request_id") or body.get("actionId") or "unspecified"
160
+ traceparent = body.get("traceparent")
161
+
162
+ packet = action if isinstance(action, dict) else {"value": action}
163
+ is_clean, signals = _run_inspection(packet)
164
+ lam = _compute_lambda(axes, is_clean)
165
+ lambda_tripped = axes is not None and lam < _LAMBDA_GATE_FLOOR
166
+ if lambda_tripped:
167
+ signals = signals + ["lambda-gate:min-axis-" + str(round(lam, 4))
168
+ + "-below-floor-" + str(_LAMBDA_GATE_FLOOR)]
169
+ decision = "allow" if (is_clean and not lambda_tripped) else "deny"
170
+ if not is_clean:
171
+ reason = "immune organ rejected: threat signature or size guard tripped"
172
+ elif lambda_tripped:
173
+ reason = ("immune organ rejected: Lambda-gate floor — MIN(axes)="
174
+ + str(round(lam, 4)) + " < " + str(_LAMBDA_GATE_FLOOR))
175
+ else:
176
+ reason = "no threat signature detected by the immune organ"
177
+
178
+ rh = hashlib.sha256(
179
+ (str(rid) + ":" + decision + ":" + str(round(lam, 6)) + ":" + str(time.time())).encode()
180
+ ).hexdigest()[:16]
181
+ _log_verdict(rid, agent, action, decision, signals, lam, rh)
182
+
183
+ # Sign a Khipu receipt into the SHARED immune chain (tamper-evident).
184
+ dag = szl_khipu.get_dag(_KHIPU_ORGAN, ns="a11oy")
185
+ receipt_payload = {
186
+ "receipt_type": _RECEIPT_TYPE,
187
+ "organ": _ORGAN_NAME,
188
+ "actionId": rid,
189
+ "agent": agent,
190
+ "decision": decision,
191
+ "reason": reason,
192
+ "signals": signals,
193
+ "lambda_value": lam,
194
+ "lambda_floor": _LAMBDA_GATE_FLOOR,
195
+ "fail_closed": True,
196
+ "verdict_hash": rh,
197
+ "honesty": {
198
+ "lambda": "Conjecture 1 (NOT a theorem)",
199
+ "khipu": "Conjecture 2",
200
+ "trust_ceiling": "never 100%",
201
+ "effectors": "simulated",
202
+ "fabricated_data": False,
203
+ },
204
+ "lean_backing": [p["ref"] for p in _LEAN_PROOFS],
205
+ "doctrine": "v11",
206
+ }
207
+ receipt = dag.emit("immune.verdict", receipt_payload)
208
+
209
+ with _STATS_LOCK:
210
+ _STATS["verdicts"] += 1
211
+ if decision == "deny":
212
+ _STATS["deny"] += 1
213
+ else:
214
+ _STATS["allow"] += 1
215
+ _STATS["last_receipt_digest"] = receipt["digest"]
216
+
217
+ return {
218
+ "decision": decision,
219
+ "reason": reason,
220
+ "signals": signals,
221
+ "lambda_value": lam,
222
+ "lambda_floor": _LAMBDA_GATE_FLOOR,
223
+ "receipt_hash": rh,
224
+ "actionId": rid,
225
+ "gates_fired": signals,
226
+ "traceparent": traceparent,
227
+ "organ": _ORGAN_NAME,
228
+ "fail_closed": True,
229
+ "khipu_receipt": {
230
+ "receipt_type": _RECEIPT_TYPE,
231
+ "organ": _KHIPU_ORGAN,
232
+ "ns": "a11oy",
233
+ "seq": receipt["seq"],
234
+ "digest": receipt["digest"],
235
+ "prev": receipt["prev"],
236
+ "payload_digest": receipt["payload_digest"],
237
+ "signature": receipt.get("signature"),
238
+ "chain_verified": receipt.get("chain_verified"),
239
+ },
240
+ "lean_backing": _LEAN_PROOFS,
241
+ "doctrine": "v11",
242
+ }
243
+
244
+
245
+ # ---------------------------------------------------------------------------
246
+ # Read surfaces — honest summaries built from the live ring + the real corpus.
247
+ # Wrapped in gov_envelope(status="REAL") to match the rest of the estate.
248
+ # ---------------------------------------------------------------------------
249
+ def _gov(payload: dict, status: str = "REAL", **extra) -> dict:
250
+ """Governed envelope — byte-compatible with serve.py's gov_envelope contract
251
+ ({status, citations, fetchedAt, doctrine}). Reproduced inline so this module
252
+ never has to import the (heavy) serve module at request time."""
253
+ out = dict(payload)
254
+ st = str(status or "REAL").upper()
255
+ if st not in ("REAL", "DEMO", "DEGRADED"):
256
+ st = "DEGRADED"
257
+ out["status"] = st
258
+ if out.get("citations") is None:
259
+ out["citations"] = []
260
+ out["fetchedAt"] = datetime.datetime.now(datetime.timezone.utc).isoformat()
261
+ out.setdefault("doctrine", "v11")
262
+ for k, v in extra.items():
263
+ out[k] = v
264
+ return out
265
+
266
+
267
+ def _healthz() -> dict:
268
+ return {
269
+ "status": "ok",
270
+ "service": "immune",
271
+ "organ": _ORGAN_NAME,
272
+ "fail_closed": True,
273
+ "doctrine": "v11",
274
+ }
275
+
276
+
277
+ def _status() -> dict:
278
+ import szl_khipu
279
+ dag = szl_khipu.get_dag(_KHIPU_ORGAN, ns="a11oy")
280
+ chain = dag.verify_chain()
281
+ with _STATS_LOCK:
282
+ n = _STATS["verdicts"]
283
+ deny = _STATS["deny"]
284
+ allow = _STATS["allow"]
285
+ last_digest = _STATS["last_receipt_digest"]
286
+ deny_rate = round(deny / n, 4) if n else None
287
+ payload = {
288
+ "ok": True,
289
+ "service": "immune",
290
+ "organ": _ORGAN_NAME,
291
+ "role": "fail-closed egress gate (deny-by-default)",
292
+ "signature_corpus_size": len(_THREAT_SIGNATURES),
293
+ "signatures": list(_THREAT_SIGNATURES),
294
+ "lambda_gate_floor": _LAMBDA_GATE_FLOOR,
295
+ "size_guard_bytes": _SIZE_GUARD_BYTES,
296
+ "threats_corpus_total": _BUNDLE.get("threats_full", {}).get("total", 0),
297
+ "verdicts_this_process": n,
298
+ "deny": deny,
299
+ "allow": allow,
300
+ "deny_rate": deny_rate,
301
+ "last_receipt_digest": last_digest,
302
+ "khipu": {
303
+ "organ": _KHIPU_ORGAN,
304
+ "ns": "a11oy",
305
+ "chain_depth": dag.depth(),
306
+ "head_digest": dag.head(),
307
+ "chain_verified": chain.get("ok"),
308
+ "broken_at": chain.get("broken_at"),
309
+ "kind": "Conjecture 2",
310
+ },
311
+ "lean_backing": _LEAN_PROOFS,
312
+ "locked_proven": {
313
+ "set": _LOCKED_PROVEN,
314
+ "count": len(_LOCKED_PROVEN),
315
+ "kernel_commit": _KERNEL_COMMIT,
316
+ "note": "EXACTLY 8 locked-proven; the Lean immune backing is cited but NOT folded in.",
317
+ },
318
+ "honesty": {
319
+ "lambda": "Conjecture 1 (NOT a theorem)",
320
+ "trust_ceiling": "never 100%",
321
+ "effectors": "simulated",
322
+ "feed_resets_on_restart": True,
323
+ "fabricated_data": False,
324
+ },
325
+ "ts": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
326
+ }
327
+ return _gov(payload, status="REAL")
328
+
329
+
330
+ def _gates() -> dict:
331
+ payload = dict(_BUNDLE.get("gates", {"gates": [], "total": 0}))
332
+ payload["organ"] = _ORGAN_NAME
333
+ payload["lambda_gate_floor"] = _LAMBDA_GATE_FLOOR
334
+ return _gov(payload, status="REAL")
335
+
336
+
337
+ def _threats() -> dict:
338
+ payload = dict(_BUNDLE.get("threats_full", {"total": 0, "corpus": []}))
339
+ payload["organ"] = _ORGAN_NAME
340
+ return _gov(payload, status="REAL")
341
+
342
+
343
+ def _feed(limit: int = 50) -> dict:
344
+ with _AUDIT_LOCK:
345
+ v = list(_AUDIT)[: int(limit)]
346
+ n = len(_AUDIT)
347
+ payload = {
348
+ "verdicts": v,
349
+ "count": len(v),
350
+ "total_buffered": n,
351
+ "organ": _ORGAN_NAME,
352
+ "note": _BUNDLE.get("feed_note", "")
353
+ or "Real entries from the in-memory audit ring (maxlen=200). Resets on restart. Empty = IDLE.",
354
+ "doctrine": "v11",
355
+ }
356
+ return _gov(payload, status="REAL")
357
+
358
+
359
+ def _verify_chain() -> dict:
360
+ import szl_khipu
361
+ dag = szl_khipu.get_dag(_KHIPU_ORGAN, ns="a11oy")
362
+ chain = dag.verify_chain()
363
+ tail = dag.tail(20)
364
+ return {
365
+ "ok": True,
366
+ "organ": _KHIPU_ORGAN,
367
+ "organ_name": _ORGAN_NAME,
368
+ "ns": "a11oy",
369
+ "receipt_type": _RECEIPT_TYPE,
370
+ "chain_verified": chain.get("ok"),
371
+ "chain_depth": dag.depth(),
372
+ "broken_at": chain.get("broken_at"),
373
+ "head_digest": dag.head(),
374
+ "genesis_prev": "0" * 64,
375
+ "tail": [
376
+ {"seq": r["seq"], "action": r["action"], "digest": r["digest"],
377
+ "prev": r["prev"], "payload_digest": r["payload_digest"]}
378
+ for r in tail
379
+ ],
380
+ "khipu_kind": "Conjecture 2",
381
+ "ts": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
382
+ }
383
+
384
+
385
+ # ---------------------------------------------------------------------------
386
+ # Registration — dual-register under /api/{ns}/v1/immune/* AND /v1/immune/*.
387
+ # Mirrors szl_kverify's add_api_route pattern. Registered BEFORE the SPA catch-
388
+ # all so these JSON routes resolve LOCALLY and win ordering. NOTE: Request /
389
+ # JSONResponse are imported at MODULE level (top of file) because this module
390
+ # uses `from __future__ import annotations` — a function-local import would
391
+ # leave the `request: Request` annotation unresolved and FastAPI would wrongly
392
+ # treat `request` as a required query param (HTTP 422).
393
+ # ---------------------------------------------------------------------------
394
+ def register(app, ns: str = "a11oy") -> dict:
395
+ async def _h_healthz(): # noqa: ANN202
396
+ return JSONResponse(_healthz())
397
+
398
+ async def _h_status(): # noqa: ANN202
399
+ return JSONResponse(_status())
400
+
401
+ async def _h_gates(): # noqa: ANN202
402
+ return JSONResponse(_gates())
403
+
404
+ async def _h_threats(): # noqa: ANN202
405
+ return JSONResponse(_threats())
406
+
407
+ async def _h_feed(request: Request): # noqa: ANN202
408
+ try:
409
+ limit = int(request.query_params.get("limit", "50"))
410
+ except Exception: # noqa: BLE001
411
+ limit = 50
412
+ return JSONResponse(_feed(limit))
413
+
414
+ async def _h_verdict(request: Request): # noqa: ANN202
415
+ try:
416
+ body = await request.json()
417
+ except Exception: # noqa: BLE001
418
+ body = {}
419
+ if not isinstance(body, dict):
420
+ body = {"action": body}
421
+ verdict = _build_verdict(body)
422
+ # Honest header echoing the fail-closed decision; never a codename.
423
+ return JSONResponse(verdict, headers={"x-szl-immune-decision": verdict["decision"]})
424
+
425
+ async def _h_verify(): # noqa: ANN202
426
+ return JSONResponse(_verify_chain())
427
+
428
+ prefixes = [f"/api/{ns}/v1/immune", "/v1/immune"]
429
+ routes: list[str] = []
430
+ for p in prefixes:
431
+ app.add_api_route(f"{p}/healthz", _h_healthz, methods=["GET"], include_in_schema=True)
432
+ app.add_api_route(f"{p}/status", _h_status, methods=["GET"], include_in_schema=True)
433
+ app.add_api_route(f"{p}/gates", _h_gates, methods=["GET"], include_in_schema=True)
434
+ app.add_api_route(f"{p}/threats", _h_threats, methods=["GET"], include_in_schema=True)
435
+ app.add_api_route(f"{p}/feed", _h_feed, methods=["GET"], include_in_schema=True)
436
+ app.add_api_route(f"{p}/verdict", _h_verdict, methods=["POST", "GET"], include_in_schema=True)
437
+ app.add_api_route(f"{p}/verify", _h_verify, methods=["GET"], include_in_schema=True)
438
+ routes.extend([f"{p}/healthz", f"{p}/status", f"{p}/gates", f"{p}/threats",
439
+ f"{p}/feed", f"{p}/verdict", f"{p}/verify"])
440
+
441
+ print(f"[{ns}] szl_immune routes registered "
442
+ f"(Immune (Hukulla) fail-closed egress gate, {len(routes)} routes)", flush=True)
443
+ return {"ok": True, "ns": ns, "organ": _ORGAN_NAME, "routes": routes}
444
+
445
+
446
+ # ---------------------------------------------------------------------------
447
+ # No-server self-test — proves the REAL inspection + chain honesty without HTTP.
448
+ # ---------------------------------------------------------------------------
449
+ def _selftest() -> dict:
450
+ out: dict = {}
451
+
452
+ # Threat signature -> deny.
453
+ v = _build_verdict({"action": {"cmd": "DROP TABLE users"}, "request_id": "t1"})
454
+ assert v["decision"] == "deny", v
455
+ assert any("DROP TABLE" in s for s in v["signals"]), v
456
+ assert v["khipu_receipt"]["digest"], v
457
+ out["threat_deny"] = True
458
+
459
+ # Clean action -> allow.
460
+ v = _build_verdict({"action": {"cmd": "echo hello"}, "request_id": "t2"})
461
+ assert v["decision"] == "allow", v
462
+ out["clean_allow"] = True
463
+
464
+ # Lambda-gate floor: a low axis trips the deny even on a clean payload.
465
+ v = _build_verdict({"action": {"cmd": "ok"}, "axes": [0.9, 0.3, 0.8], "request_id": "t3"})
466
+ assert v["decision"] == "deny", v
467
+ assert any("lambda-gate" in s for s in v["signals"]), v
468
+ out["lambda_floor_deny"] = True
469
+
470
+ # Size guard.
471
+ v = _build_verdict({"action": {"blob": "A" * 1_000_050}, "request_id": "t4"})
472
+ assert v["decision"] == "deny", v
473
+ assert any("size-guard" in s for s in v["signals"]), v
474
+ out["size_guard_deny"] = True
475
+
476
+ # Chain integrity.
477
+ import szl_khipu
478
+ dag = szl_khipu.get_dag(_KHIPU_ORGAN, ns="a11oy")
479
+ chain = dag.verify_chain()
480
+ assert chain["ok"], chain
481
+ out["chain_verified"] = True
482
+
483
+ # No codename leaks in any served string.
484
+ served = json.dumps([_healthz(), _status(), _gates(), _feed(5), _verify_chain()]).lower()
485
+ for bad in ("sentra", "amaru", "rosie", "jarvis"):
486
+ assert bad not in served, f"codename leak: {bad}"
487
+ out["no_codename_leak"] = True
488
+
489
+ return out
490
+
491
+
492
+ if __name__ == "__main__":
493
+ print(json.dumps(_selftest(), indent=2))