Spaces:
Running
Running
chore(sync): mirror backend .py + Dockerfile to Space (hf-sync-backend)
Browse filesAutomated 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.
- Dockerfile +14 -0
- 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))
|