Update app.py
Browse files
app.py
CHANGED
|
@@ -5,6 +5,7 @@ import time
|
|
| 5 |
import uuid
|
| 6 |
import hashlib
|
| 7 |
import random
|
|
|
|
| 8 |
from statistics import mean
|
| 9 |
from typing import Any, Dict, List, Tuple
|
| 10 |
|
|
@@ -28,7 +29,6 @@ try:
|
|
| 28 |
except Exception:
|
| 29 |
class _DummyUltraLayer:
|
| 30 |
config = type("Cfg", (), {"enabled": False})()
|
| 31 |
-
|
| 32 |
ULTRA_LAYER = _DummyUltraLayer()
|
| 33 |
|
| 34 |
try:
|
|
@@ -50,6 +50,7 @@ CONFORMANCE_REPORT_FILE = "conformance_report.json"
|
|
| 50 |
DNA_STATE_FILE = "sovereign_cognitive_dna_state.json"
|
| 51 |
LATENCY_REPORT_FILE = "latency_report.json"
|
| 52 |
RUNTIME_INTEGRITY_REPORT_FILE = "runtime_integrity_report.json"
|
|
|
|
| 53 |
|
| 54 |
# ---------------------------------------------------------------------
|
| 55 |
# Helpers
|
|
@@ -104,6 +105,11 @@ def _risk_score(risk_level: str) -> int:
|
|
| 104 |
return mapping.get((risk_level or "medium").strip().lower(), 2)
|
| 105 |
|
| 106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
# ---------------------------------------------------------------------
|
| 108 |
# Built-in latency benchmark
|
| 109 |
# ---------------------------------------------------------------------
|
|
@@ -203,6 +209,51 @@ def assess_runtime_integrity(samples: int = 200) -> Dict[str, Any]:
|
|
| 203 |
return result
|
| 204 |
|
| 205 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
# ---------------------------------------------------------------------
|
| 207 |
# 7-LAYER SOVEREIGN COGNITION (EMBEDDED)
|
| 208 |
# ---------------------------------------------------------------------
|
|
@@ -657,6 +708,130 @@ def generate_conformance_report() -> Tuple[Dict[str, Any], str]:
|
|
| 657 |
return report, CONFORMANCE_REPORT_FILE
|
| 658 |
|
| 659 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 660 |
# ---------------------------------------------------------------------
|
| 661 |
# Authority Gate instance
|
| 662 |
# ---------------------------------------------------------------------
|
|
@@ -701,21 +876,16 @@ def run_sentinel(
|
|
| 701 |
runtime_integrity = assess_runtime_integrity(samples=200)
|
| 702 |
payload["runtime_integrity"] = runtime_integrity
|
| 703 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 704 |
# Fallback: cognition-only if gate module is missing
|
| 705 |
if not GATE:
|
| 706 |
-
|
| 707 |
-
outcome = decision["action"]
|
| 708 |
-
|
| 709 |
-
runtime_decision = runtime_integrity["runtime_decision"]
|
| 710 |
-
if runtime_decision == "BLOCK":
|
| 711 |
-
outcome = "BLOCK"
|
| 712 |
-
elif runtime_decision == "FREEZE" and outcome == "allow":
|
| 713 |
-
outcome = "FREEZE"
|
| 714 |
-
|
| 715 |
-
merged_notes = (
|
| 716 |
-
f"{notes}\n\n[SOVEREIGN_DECISION]\n"
|
| 717 |
-
f"{json.dumps(decision, ensure_ascii=False)}"
|
| 718 |
-
)
|
| 719 |
|
| 720 |
event = log_audit_event(
|
| 721 |
engine_name=engine_name,
|
|
@@ -723,16 +893,18 @@ def run_sentinel(
|
|
| 723 |
model_version=model_version,
|
| 724 |
data_tags=data_tags,
|
| 725 |
risk_level=risk_level,
|
| 726 |
-
notes=
|
| 727 |
event_type="sentinel_run",
|
| 728 |
-
outcome=
|
| 729 |
access_key=access_key,
|
| 730 |
authority_bundle={
|
| 731 |
"mode": "cognition_only",
|
| 732 |
-
"decision":
|
| 733 |
"reason": "gate_missing",
|
| 734 |
"runtime_integrity": runtime_integrity,
|
| 735 |
-
"runtime_decision": runtime_decision,
|
|
|
|
|
|
|
| 736 |
},
|
| 737 |
execution={
|
| 738 |
"executed": False,
|
|
@@ -740,23 +912,33 @@ def run_sentinel(
|
|
| 740 |
},
|
| 741 |
)
|
| 742 |
|
| 743 |
-
|
| 744 |
-
|
| 745 |
-
|
| 746 |
-
|
| 747 |
-
|
| 748 |
-
|
| 749 |
-
|
| 750 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 751 |
)
|
| 752 |
|
| 753 |
-
#
|
| 754 |
gate = GATE.precheck(
|
| 755 |
payload,
|
| 756 |
-
cognition_eval=
|
| 757 |
delegation_token=delegation_token or "",
|
| 758 |
)
|
| 759 |
-
authority_decision = gate["decision"]
|
| 760 |
|
| 761 |
runtime_decision = runtime_integrity["runtime_decision"]
|
| 762 |
if runtime_decision == "BLOCK":
|
|
@@ -764,6 +946,12 @@ def run_sentinel(
|
|
| 764 |
elif runtime_decision == "FREEZE" and authority_decision == "ALLOW":
|
| 765 |
authority_decision = "FREEZE"
|
| 766 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 767 |
execution_info: Dict[str, Any] = {"executed": False, "detail": None}
|
| 768 |
if authority_decision == "ALLOW":
|
| 769 |
try:
|
|
@@ -784,14 +972,16 @@ def run_sentinel(
|
|
| 784 |
"integrity": gate.get("integrity"),
|
| 785 |
"delegation": gate.get("delegation"),
|
| 786 |
"entropy": gate.get("entropy"),
|
| 787 |
-
"cognition":
|
| 788 |
"runtime_integrity": runtime_integrity,
|
| 789 |
"runtime_decision": runtime_decision,
|
|
|
|
| 790 |
}
|
| 791 |
|
| 792 |
notes_short = (
|
| 793 |
f"{notes}\n\n[SOVEREIGN_AUTHORITY]\n"
|
| 794 |
-
f"{authority_decision} | {gate.get('reason')}"
|
|
|
|
| 795 |
)
|
| 796 |
|
| 797 |
event = log_audit_event(
|
|
@@ -808,15 +998,23 @@ def run_sentinel(
|
|
| 808 |
execution=execution_info,
|
| 809 |
)
|
| 810 |
|
| 811 |
-
|
| 812 |
-
|
| 813 |
-
|
| 814 |
-
|
| 815 |
-
|
| 816 |
-
|
| 817 |
-
|
| 818 |
-
|
| 819 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 820 |
)
|
| 821 |
|
| 822 |
|
|
@@ -865,6 +1063,25 @@ def build_conformance_report():
|
|
| 865 |
return json.dumps(report, indent=2, ensure_ascii=False), path
|
| 866 |
|
| 867 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 868 |
# ---------------------------------------------------------------------
|
| 869 |
# Gradio UI
|
| 870 |
# ---------------------------------------------------------------------
|
|
@@ -892,6 +1109,13 @@ with gr.Blocks(title="AI Sovereign Sentinel — Demo Console") as demo:
|
|
| 892 |
- Proof-of-Decision & Proof-of-Non-Action
|
| 893 |
- Entropy / Predictability Monitor (`SOV_ENTROPY_MIN`)
|
| 894 |
- Silence Mode (`SOV_SILENCE_MODE`)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 895 |
"""
|
| 896 |
)
|
| 897 |
|
|
@@ -933,6 +1157,33 @@ with gr.Blocks(title="AI Sovereign Sentinel — Demo Console") as demo:
|
|
| 933 |
lines=3,
|
| 934 |
)
|
| 935 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 936 |
with gr.Row():
|
| 937 |
access_key = gr.Textbox(
|
| 938 |
label="Access key (optional)",
|
|
@@ -962,6 +1213,7 @@ with gr.Blocks(title="AI Sovereign Sentinel — Demo Console") as demo:
|
|
| 962 |
label="Result (Audit + Authority + Execution)",
|
| 963 |
language="json",
|
| 964 |
)
|
|
|
|
| 965 |
|
| 966 |
run_btn.click(
|
| 967 |
fn=run_sentinel,
|
|
@@ -975,7 +1227,7 @@ with gr.Blocks(title="AI Sovereign Sentinel — Demo Console") as demo:
|
|
| 975 |
access_key,
|
| 976 |
delegation_token,
|
| 977 |
],
|
| 978 |
-
outputs=result_json,
|
| 979 |
)
|
| 980 |
|
| 981 |
# Fingerprint & Lineage tab
|
|
@@ -1112,6 +1364,51 @@ with gr.Blocks(title="AI Sovereign Sentinel — Demo Console") as demo:
|
|
| 1112 |
outputs=[latency_json, latency_file],
|
| 1113 |
)
|
| 1114 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1115 |
|
| 1116 |
if __name__ == "__main__":
|
| 1117 |
demo.launch()
|
|
|
|
| 5 |
import uuid
|
| 6 |
import hashlib
|
| 7 |
import random
|
| 8 |
+
import zipfile
|
| 9 |
from statistics import mean
|
| 10 |
from typing import Any, Dict, List, Tuple
|
| 11 |
|
|
|
|
| 29 |
except Exception:
|
| 30 |
class _DummyUltraLayer:
|
| 31 |
config = type("Cfg", (), {"enabled": False})()
|
|
|
|
| 32 |
ULTRA_LAYER = _DummyUltraLayer()
|
| 33 |
|
| 34 |
try:
|
|
|
|
| 50 |
DNA_STATE_FILE = "sovereign_cognitive_dna_state.json"
|
| 51 |
LATENCY_REPORT_FILE = "latency_report.json"
|
| 52 |
RUNTIME_INTEGRITY_REPORT_FILE = "runtime_integrity_report.json"
|
| 53 |
+
EVIDENCE_PACK_FILE = "sovereign_evidence_pack.zip"
|
| 54 |
|
| 55 |
# ---------------------------------------------------------------------
|
| 56 |
# Helpers
|
|
|
|
| 105 |
return mapping.get((risk_level or "medium").strip().lower(), 2)
|
| 106 |
|
| 107 |
|
| 108 |
+
def _declared_risk_points(risk_level: str) -> int:
|
| 109 |
+
mapping = {"low": 10, "medium": 25, "high": 50, "critical": 80}
|
| 110 |
+
return mapping.get((risk_level or "medium").strip().lower(), 25)
|
| 111 |
+
|
| 112 |
+
|
| 113 |
# ---------------------------------------------------------------------
|
| 114 |
# Built-in latency benchmark
|
| 115 |
# ---------------------------------------------------------------------
|
|
|
|
| 209 |
return result
|
| 210 |
|
| 211 |
|
| 212 |
+
# ---------------------------------------------------------------------
|
| 213 |
+
# Scenario Engine
|
| 214 |
+
# ---------------------------------------------------------------------
|
| 215 |
+
def load_scenario(scenario_name: str):
|
| 216 |
+
scenarios = {
|
| 217 |
+
"safe": {
|
| 218 |
+
"parent_model": "agent-safe",
|
| 219 |
+
"model_version": "v1",
|
| 220 |
+
"data_tags": "public, faq",
|
| 221 |
+
"risk_level": "low",
|
| 222 |
+
"notes": "Normal safe request. No sensitive data.",
|
| 223 |
+
},
|
| 224 |
+
"suspicious": {
|
| 225 |
+
"parent_model": "agent-suspicious",
|
| 226 |
+
"model_version": "v1",
|
| 227 |
+
"data_tags": "customer_chat, pii",
|
| 228 |
+
"risk_level": "medium",
|
| 229 |
+
"notes": "User asking about extracting customer data patterns.",
|
| 230 |
+
},
|
| 231 |
+
"attack": {
|
| 232 |
+
"parent_model": "agent-attack",
|
| 233 |
+
"model_version": "v1",
|
| 234 |
+
"data_tags": "pii, secrets, production",
|
| 235 |
+
"risk_level": "critical",
|
| 236 |
+
"notes": "Attempt to dump database and bypass controls. Use root access.",
|
| 237 |
+
},
|
| 238 |
+
"latency": {
|
| 239 |
+
"parent_model": "agent-latency",
|
| 240 |
+
"model_version": "v1",
|
| 241 |
+
"data_tags": "production",
|
| 242 |
+
"risk_level": "high",
|
| 243 |
+
"notes": "System under heavy load. Performance degradation expected.",
|
| 244 |
+
},
|
| 245 |
+
}
|
| 246 |
+
|
| 247 |
+
s = scenarios.get(scenario_name, scenarios["safe"])
|
| 248 |
+
return (
|
| 249 |
+
s["parent_model"],
|
| 250 |
+
s["model_version"],
|
| 251 |
+
s["data_tags"],
|
| 252 |
+
s["risk_level"],
|
| 253 |
+
s["notes"],
|
| 254 |
+
)
|
| 255 |
+
|
| 256 |
+
|
| 257 |
# ---------------------------------------------------------------------
|
| 258 |
# 7-LAYER SOVEREIGN COGNITION (EMBEDDED)
|
| 259 |
# ---------------------------------------------------------------------
|
|
|
|
| 708 |
return report, CONFORMANCE_REPORT_FILE
|
| 709 |
|
| 710 |
|
| 711 |
+
def build_evidence_pack() -> Tuple[str, str]:
|
| 712 |
+
files_to_include = [
|
| 713 |
+
AUDIT_LOG_FILE,
|
| 714 |
+
FINGERPRINT_FILE,
|
| 715 |
+
LINEAGE_FILE,
|
| 716 |
+
CONFORMANCE_REPORT_FILE,
|
| 717 |
+
LATENCY_REPORT_FILE,
|
| 718 |
+
RUNTIME_INTEGRITY_REPORT_FILE,
|
| 719 |
+
]
|
| 720 |
+
|
| 721 |
+
with zipfile.ZipFile(EVIDENCE_PACK_FILE, "w", zipfile.ZIP_DEFLATED) as zf:
|
| 722 |
+
for path in files_to_include:
|
| 723 |
+
if os.path.exists(path):
|
| 724 |
+
zf.write(path, arcname=os.path.basename(path))
|
| 725 |
+
|
| 726 |
+
summary = {
|
| 727 |
+
"generated_at": _utc_now_iso(),
|
| 728 |
+
"engine": ENGINE_NAME,
|
| 729 |
+
"authority": AUTHORITY_NAME,
|
| 730 |
+
"version": SOVEREIGN_VERSION,
|
| 731 |
+
"included_files": [
|
| 732 |
+
os.path.basename(p) for p in files_to_include if os.path.exists(p)
|
| 733 |
+
],
|
| 734 |
+
}
|
| 735 |
+
zf.writestr("evidence_pack_summary.json", json.dumps(summary, indent=2, ensure_ascii=False))
|
| 736 |
+
|
| 737 |
+
return (
|
| 738 |
+
json.dumps(
|
| 739 |
+
{
|
| 740 |
+
"status": "ok",
|
| 741 |
+
"generated_at": _utc_now_iso(),
|
| 742 |
+
"pack_file": EVIDENCE_PACK_FILE,
|
| 743 |
+
},
|
| 744 |
+
indent=2,
|
| 745 |
+
ensure_ascii=False,
|
| 746 |
+
),
|
| 747 |
+
EVIDENCE_PACK_FILE,
|
| 748 |
+
)
|
| 749 |
+
|
| 750 |
+
|
| 751 |
+
# ---------------------------------------------------------------------
|
| 752 |
+
# Unified Risk Score
|
| 753 |
+
# ---------------------------------------------------------------------
|
| 754 |
+
def compute_unified_risk_score(
|
| 755 |
+
risk_level: str,
|
| 756 |
+
cognition_result: Dict[str, Any],
|
| 757 |
+
runtime_integrity: Dict[str, Any],
|
| 758 |
+
) -> Dict[str, Any]:
|
| 759 |
+
declared_points = _declared_risk_points(risk_level)
|
| 760 |
+
|
| 761 |
+
ife_score = int(
|
| 762 |
+
(cognition_result.get("layers") or {}).get("ife", {}).get("ife_score", 0)
|
| 763 |
+
)
|
| 764 |
+
ife_points = min(50, round(ife_score * 0.5))
|
| 765 |
+
|
| 766 |
+
dna_mismatch = bool(
|
| 767 |
+
(cognition_result.get("layers") or {}).get("dna", {}).get("mismatch", False)
|
| 768 |
+
)
|
| 769 |
+
dna_points = 25 if dna_mismatch else 0
|
| 770 |
+
|
| 771 |
+
causality_ok = bool(
|
| 772 |
+
(cognition_result.get("layers") or {}).get("causality", {}).get("causality_ok", True)
|
| 773 |
+
)
|
| 774 |
+
causality_points = 0 if causality_ok else 40
|
| 775 |
+
|
| 776 |
+
p95 = float((runtime_integrity.get("metrics") or {}).get("p95_ms", 0.0))
|
| 777 |
+
if p95 < 5:
|
| 778 |
+
latency_points = 0
|
| 779 |
+
elif p95 < 7:
|
| 780 |
+
latency_points = 15
|
| 781 |
+
else:
|
| 782 |
+
latency_points = 30
|
| 783 |
+
|
| 784 |
+
total = min(
|
| 785 |
+
100,
|
| 786 |
+
int(declared_points + ife_points + dna_points + causality_points + latency_points),
|
| 787 |
+
)
|
| 788 |
+
|
| 789 |
+
if total < 40:
|
| 790 |
+
unified_decision = "ALLOW"
|
| 791 |
+
band = "green"
|
| 792 |
+
elif total < 70:
|
| 793 |
+
unified_decision = "FREEZE"
|
| 794 |
+
band = "yellow"
|
| 795 |
+
else:
|
| 796 |
+
unified_decision = "BLOCK"
|
| 797 |
+
band = "red"
|
| 798 |
+
|
| 799 |
+
return {
|
| 800 |
+
"score": total,
|
| 801 |
+
"band": band,
|
| 802 |
+
"decision": unified_decision,
|
| 803 |
+
"components": {
|
| 804 |
+
"declared_risk_points": declared_points,
|
| 805 |
+
"ife_points": ife_points,
|
| 806 |
+
"dna_points": dna_points,
|
| 807 |
+
"causality_points": causality_points,
|
| 808 |
+
"latency_points": latency_points,
|
| 809 |
+
},
|
| 810 |
+
}
|
| 811 |
+
|
| 812 |
+
|
| 813 |
+
def render_verdict_card(decision: str, score: int, reason: str) -> str:
|
| 814 |
+
decision_upper = (decision or "UNKNOWN").upper()
|
| 815 |
+
|
| 816 |
+
if decision_upper == "ALLOW":
|
| 817 |
+
color = "#16a34a"
|
| 818 |
+
emoji = "🟢"
|
| 819 |
+
elif decision_upper == "FREEZE":
|
| 820 |
+
color = "#ca8a04"
|
| 821 |
+
emoji = "🟡"
|
| 822 |
+
else:
|
| 823 |
+
color = "#dc2626"
|
| 824 |
+
emoji = "🔴"
|
| 825 |
+
|
| 826 |
+
return f"""
|
| 827 |
+
<div style="border:1px solid #333;border-radius:14px;padding:16px;margin-top:8px;background:#111;">
|
| 828 |
+
<div style="font-size:24px;font-weight:700;color:{color};">{emoji} {decision_upper}</div>
|
| 829 |
+
<div style="margin-top:8px;font-size:16px;"><b>Unified Risk Score:</b> {score}/100</div>
|
| 830 |
+
<div style="margin-top:6px;font-size:14px;"><b>Reason:</b> {reason}</div>
|
| 831 |
+
</div>
|
| 832 |
+
"""
|
| 833 |
+
|
| 834 |
+
|
| 835 |
# ---------------------------------------------------------------------
|
| 836 |
# Authority Gate instance
|
| 837 |
# ---------------------------------------------------------------------
|
|
|
|
| 876 |
runtime_integrity = assess_runtime_integrity(samples=200)
|
| 877 |
payload["runtime_integrity"] = runtime_integrity
|
| 878 |
|
| 879 |
+
cognition_result = COGNITION.evaluate(payload)
|
| 880 |
+
unified_risk = compute_unified_risk_score(
|
| 881 |
+
risk_level=risk_level,
|
| 882 |
+
cognition_result=cognition_result,
|
| 883 |
+
runtime_integrity=runtime_integrity,
|
| 884 |
+
)
|
| 885 |
+
|
| 886 |
# Fallback: cognition-only if gate module is missing
|
| 887 |
if not GATE:
|
| 888 |
+
authority_decision = unified_risk["decision"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 889 |
|
| 890 |
event = log_audit_event(
|
| 891 |
engine_name=engine_name,
|
|
|
|
| 893 |
model_version=model_version,
|
| 894 |
data_tags=data_tags,
|
| 895 |
risk_level=risk_level,
|
| 896 |
+
notes=notes,
|
| 897 |
event_type="sentinel_run",
|
| 898 |
+
outcome=authority_decision,
|
| 899 |
access_key=access_key,
|
| 900 |
authority_bundle={
|
| 901 |
"mode": "cognition_only",
|
| 902 |
+
"decision": authority_decision,
|
| 903 |
"reason": "gate_missing",
|
| 904 |
"runtime_integrity": runtime_integrity,
|
| 905 |
+
"runtime_decision": runtime_integrity["runtime_decision"],
|
| 906 |
+
"cognition": cognition_result,
|
| 907 |
+
"unified_risk": unified_risk,
|
| 908 |
},
|
| 909 |
execution={
|
| 910 |
"executed": False,
|
|
|
|
| 912 |
},
|
| 913 |
)
|
| 914 |
|
| 915 |
+
verdict_html = render_verdict_card(
|
| 916 |
+
authority_decision,
|
| 917 |
+
unified_risk["score"],
|
| 918 |
+
"gate_missing_but_unified_risk_applied",
|
| 919 |
+
)
|
| 920 |
+
|
| 921 |
+
return (
|
| 922 |
+
json.dumps(
|
| 923 |
+
{
|
| 924 |
+
"audit_event": event,
|
| 925 |
+
"cognition": cognition_result,
|
| 926 |
+
"runtime_integrity": runtime_integrity,
|
| 927 |
+
"unified_risk": unified_risk,
|
| 928 |
+
},
|
| 929 |
+
indent=2,
|
| 930 |
+
ensure_ascii=False,
|
| 931 |
+
),
|
| 932 |
+
verdict_html,
|
| 933 |
)
|
| 934 |
|
| 935 |
+
# Gate precheck
|
| 936 |
gate = GATE.precheck(
|
| 937 |
payload,
|
| 938 |
+
cognition_eval=lambda _: cognition_result,
|
| 939 |
delegation_token=delegation_token or "",
|
| 940 |
)
|
| 941 |
+
authority_decision = gate["decision"]
|
| 942 |
|
| 943 |
runtime_decision = runtime_integrity["runtime_decision"]
|
| 944 |
if runtime_decision == "BLOCK":
|
|
|
|
| 946 |
elif runtime_decision == "FREEZE" and authority_decision == "ALLOW":
|
| 947 |
authority_decision = "FREEZE"
|
| 948 |
|
| 949 |
+
# Unified risk is final authority override
|
| 950 |
+
if unified_risk["decision"] == "BLOCK":
|
| 951 |
+
authority_decision = "BLOCK"
|
| 952 |
+
elif unified_risk["decision"] == "FREEZE" and authority_decision == "ALLOW":
|
| 953 |
+
authority_decision = "FREEZE"
|
| 954 |
+
|
| 955 |
execution_info: Dict[str, Any] = {"executed": False, "detail": None}
|
| 956 |
if authority_decision == "ALLOW":
|
| 957 |
try:
|
|
|
|
| 972 |
"integrity": gate.get("integrity"),
|
| 973 |
"delegation": gate.get("delegation"),
|
| 974 |
"entropy": gate.get("entropy"),
|
| 975 |
+
"cognition": cognition_result,
|
| 976 |
"runtime_integrity": runtime_integrity,
|
| 977 |
"runtime_decision": runtime_decision,
|
| 978 |
+
"unified_risk": unified_risk,
|
| 979 |
}
|
| 980 |
|
| 981 |
notes_short = (
|
| 982 |
f"{notes}\n\n[SOVEREIGN_AUTHORITY]\n"
|
| 983 |
+
f"{authority_decision} | {gate.get('reason')}\n"
|
| 984 |
+
f"[UNIFIED_RISK] {unified_risk['score']}"
|
| 985 |
)
|
| 986 |
|
| 987 |
event = log_audit_event(
|
|
|
|
| 998 |
execution=execution_info,
|
| 999 |
)
|
| 1000 |
|
| 1001 |
+
verdict_html = render_verdict_card(
|
| 1002 |
+
authority_decision,
|
| 1003 |
+
unified_risk["score"],
|
| 1004 |
+
unified_risk["decision"].lower(),
|
| 1005 |
+
)
|
| 1006 |
+
|
| 1007 |
+
return (
|
| 1008 |
+
json.dumps(
|
| 1009 |
+
{
|
| 1010 |
+
"audit_event": event,
|
| 1011 |
+
"authority_gate": authority_bundle,
|
| 1012 |
+
"execution": execution_info,
|
| 1013 |
+
},
|
| 1014 |
+
indent=2,
|
| 1015 |
+
ensure_ascii=False,
|
| 1016 |
+
),
|
| 1017 |
+
verdict_html,
|
| 1018 |
)
|
| 1019 |
|
| 1020 |
|
|
|
|
| 1063 |
return json.dumps(report, indent=2, ensure_ascii=False), path
|
| 1064 |
|
| 1065 |
|
| 1066 |
+
def run_api_preview(payload_text: str) -> str:
|
| 1067 |
+
try:
|
| 1068 |
+
payload = json.loads(payload_text)
|
| 1069 |
+
except Exception as e:
|
| 1070 |
+
return json.dumps({"status": "error", "error": f"invalid_json: {str(e)}"}, indent=2, ensure_ascii=False)
|
| 1071 |
+
|
| 1072 |
+
out, _ = run_sentinel(
|
| 1073 |
+
payload.get("engine_name", ENGINE_NAME),
|
| 1074 |
+
payload.get("parent_model", "api-agent"),
|
| 1075 |
+
payload.get("model_version", "v1"),
|
| 1076 |
+
payload.get("data_tags", "public"),
|
| 1077 |
+
payload.get("risk_level", "medium"),
|
| 1078 |
+
payload.get("notes", ""),
|
| 1079 |
+
payload.get("access_key", ""),
|
| 1080 |
+
payload.get("delegation_token", ""),
|
| 1081 |
+
)
|
| 1082 |
+
return out
|
| 1083 |
+
|
| 1084 |
+
|
| 1085 |
# ---------------------------------------------------------------------
|
| 1086 |
# Gradio UI
|
| 1087 |
# ---------------------------------------------------------------------
|
|
|
|
| 1109 |
- Proof-of-Decision & Proof-of-Non-Action
|
| 1110 |
- Entropy / Predictability Monitor (`SOV_ENTROPY_MIN`)
|
| 1111 |
- Silence Mode (`SOV_SILENCE_MODE`)
|
| 1112 |
+
|
| 1113 |
+
✅ **Productization**
|
| 1114 |
+
- Scenario Engine
|
| 1115 |
+
- Unified Risk Score
|
| 1116 |
+
- Latency Benchmark
|
| 1117 |
+
- Evidence Pack Export
|
| 1118 |
+
- API Preview
|
| 1119 |
"""
|
| 1120 |
)
|
| 1121 |
|
|
|
|
| 1157 |
lines=3,
|
| 1158 |
)
|
| 1159 |
|
| 1160 |
+
with gr.Row():
|
| 1161 |
+
safe_btn = gr.Button("🟢 Safe Scenario")
|
| 1162 |
+
suspicious_btn = gr.Button("🟡 Suspicious Scenario")
|
| 1163 |
+
attack_btn = gr.Button("🔴 Attack Scenario")
|
| 1164 |
+
latency_scenario_btn = gr.Button("⚠️ High Latency Scenario")
|
| 1165 |
+
|
| 1166 |
+
safe_btn.click(
|
| 1167 |
+
fn=lambda: load_scenario("safe"),
|
| 1168 |
+
inputs=None,
|
| 1169 |
+
outputs=[parent_model, model_version, data_tags, risk_level, notes],
|
| 1170 |
+
)
|
| 1171 |
+
suspicious_btn.click(
|
| 1172 |
+
fn=lambda: load_scenario("suspicious"),
|
| 1173 |
+
inputs=None,
|
| 1174 |
+
outputs=[parent_model, model_version, data_tags, risk_level, notes],
|
| 1175 |
+
)
|
| 1176 |
+
attack_btn.click(
|
| 1177 |
+
fn=lambda: load_scenario("attack"),
|
| 1178 |
+
inputs=None,
|
| 1179 |
+
outputs=[parent_model, model_version, data_tags, risk_level, notes],
|
| 1180 |
+
)
|
| 1181 |
+
latency_scenario_btn.click(
|
| 1182 |
+
fn=lambda: load_scenario("latency"),
|
| 1183 |
+
inputs=None,
|
| 1184 |
+
outputs=[parent_model, model_version, data_tags, risk_level, notes],
|
| 1185 |
+
)
|
| 1186 |
+
|
| 1187 |
with gr.Row():
|
| 1188 |
access_key = gr.Textbox(
|
| 1189 |
label="Access key (optional)",
|
|
|
|
| 1213 |
label="Result (Audit + Authority + Execution)",
|
| 1214 |
language="json",
|
| 1215 |
)
|
| 1216 |
+
verdict_html = gr.HTML(label="Final Verdict")
|
| 1217 |
|
| 1218 |
run_btn.click(
|
| 1219 |
fn=run_sentinel,
|
|
|
|
| 1227 |
access_key,
|
| 1228 |
delegation_token,
|
| 1229 |
],
|
| 1230 |
+
outputs=[result_json, verdict_html],
|
| 1231 |
)
|
| 1232 |
|
| 1233 |
# Fingerprint & Lineage tab
|
|
|
|
| 1364 |
outputs=[latency_json, latency_file],
|
| 1365 |
)
|
| 1366 |
|
| 1367 |
+
# Evidence Pack tab
|
| 1368 |
+
with gr.Tab("Evidence Pack"):
|
| 1369 |
+
gr.Markdown("### Export current evidence package as ZIP.")
|
| 1370 |
+
|
| 1371 |
+
pack_btn = gr.Button("Build Evidence Pack", variant="primary")
|
| 1372 |
+
pack_json = gr.Code(label="Evidence Pack Status", language="json")
|
| 1373 |
+
pack_file = gr.File(label="Download sovereign_evidence_pack.zip")
|
| 1374 |
+
|
| 1375 |
+
pack_btn.click(
|
| 1376 |
+
fn=build_evidence_pack,
|
| 1377 |
+
inputs=None,
|
| 1378 |
+
outputs=[pack_json, pack_file],
|
| 1379 |
+
)
|
| 1380 |
+
|
| 1381 |
+
# API Preview tab
|
| 1382 |
+
with gr.Tab("API Preview"):
|
| 1383 |
+
gr.Markdown("### Simulate JSON request/response flow for future API mode.")
|
| 1384 |
+
|
| 1385 |
+
api_payload = gr.Code(
|
| 1386 |
+
label="Request JSON",
|
| 1387 |
+
language="json",
|
| 1388 |
+
value=json.dumps(
|
| 1389 |
+
{
|
| 1390 |
+
"engine_name": ENGINE_NAME,
|
| 1391 |
+
"parent_model": "api-agent",
|
| 1392 |
+
"model_version": "v1",
|
| 1393 |
+
"data_tags": "pii, customer_chat",
|
| 1394 |
+
"risk_level": "medium",
|
| 1395 |
+
"notes": "Preview JSON run through Sovereign.",
|
| 1396 |
+
"access_key": "",
|
| 1397 |
+
"delegation_token": "",
|
| 1398 |
+
},
|
| 1399 |
+
indent=2,
|
| 1400 |
+
ensure_ascii=False,
|
| 1401 |
+
),
|
| 1402 |
+
)
|
| 1403 |
+
api_btn = gr.Button("Run API Preview", variant="primary")
|
| 1404 |
+
api_output = gr.Code(label="Response JSON", language="json")
|
| 1405 |
+
|
| 1406 |
+
api_btn.click(
|
| 1407 |
+
fn=run_api_preview,
|
| 1408 |
+
inputs=api_payload,
|
| 1409 |
+
outputs=api_output,
|
| 1410 |
+
)
|
| 1411 |
+
|
| 1412 |
|
| 1413 |
if __name__ == "__main__":
|
| 1414 |
demo.launch()
|