feat(casan): establish assurance kernel and harden control plane
This commit is contained in:
@@ -40,8 +40,23 @@ import sys
|
||||
import time
|
||||
import uuid
|
||||
|
||||
SCHEMA_VERSION = "20.1"
|
||||
ADAPTER_DEFAULT_VERSION = "20.1.0"
|
||||
HARNESS_PACKAGE_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
if HARNESS_PACKAGE_ROOT not in sys.path:
|
||||
sys.path.insert(0, HARNESS_PACKAGE_ROOT)
|
||||
|
||||
from kernel.adapters import AgenticBridgeAdapter
|
||||
from kernel.contracts import validate_bundle
|
||||
from kernel.policy import (
|
||||
H2GateContext,
|
||||
evaluate_failure_policy,
|
||||
evaluate_h2_gate,
|
||||
evaluate_registry_configuration,
|
||||
evaluate_risk,
|
||||
evaluate_trust_capabilities,
|
||||
)
|
||||
|
||||
SCHEMA_VERSION = "20.2"
|
||||
ADAPTER_DEFAULT_VERSION = "20.2.0"
|
||||
|
||||
# ── Certification strength ranking (higher == stronger) ──────────────────────
|
||||
STRENGTH_RANK = {
|
||||
@@ -77,6 +92,20 @@ TOOL_REGISTRY_ACTION = {
|
||||
"str_replace_editor": "write_file",
|
||||
}
|
||||
|
||||
REGISTRY_ACTION_BY_CLASS = {
|
||||
"write": "write_file",
|
||||
"delete": "delete_file",
|
||||
"database_mutation": "db_write",
|
||||
"migration": "migration",
|
||||
"deployment": "deploy",
|
||||
"release": "deploy",
|
||||
"credential_access": "credential_access",
|
||||
"identity_permission_modification": "identity_change",
|
||||
"external_network_side_effect": "external_api",
|
||||
"infrastructure_modification": "deploy",
|
||||
"unknown": "unknown_tool",
|
||||
}
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Path resolution (mirrors scripts/bash/casan-paths.sh so state lands in the
|
||||
@@ -145,6 +174,12 @@ def trace_event_dir():
|
||||
return d
|
||||
|
||||
|
||||
def kernel_trace_dir():
|
||||
d = os.path.join(state_root(), "logs", "kernel")
|
||||
os.makedirs(d, exist_ok=True)
|
||||
return d
|
||||
|
||||
|
||||
def metrics_log():
|
||||
override = os.environ.get("CASAN_TELEMETRY_METRICS_LOG") or os.environ.get(
|
||||
"CASAN_METRICS_LOG"
|
||||
@@ -612,28 +647,52 @@ def h4_scan(text, mode="input"):
|
||||
pass
|
||||
|
||||
|
||||
def h2_registry_gate(action, idempotency_key):
|
||||
"""H2 tool-registry gate for a mapped side-effect action."""
|
||||
script = os.path.join(gates_dir(), "tool-registry-gate.sh")
|
||||
if not os.path.exists(script) or not bash_available():
|
||||
return True, "h2_gate_missing"
|
||||
env = dict(os.environ)
|
||||
env["CASAN_IDEMPOTENCY_KEY"] = idempotency_key
|
||||
def h2_registry_gate(action, tool, actor, execution_id, idempotency_key):
|
||||
"""Return a structured H2 policy decision for every dependency outcome."""
|
||||
script = os.environ.get("CASAN_H2_GATE_PATH") or os.path.join(
|
||||
gates_dir(), "tool-registry-gate.sh")
|
||||
context = H2GateContext(
|
||||
mode=enforcement_mode(),
|
||||
actor=actor or "",
|
||||
action=action,
|
||||
tool=tool or action,
|
||||
execution_id=execution_id,
|
||||
enforcement_path="agentic_bridge.pre_tool.h2_registry",
|
||||
idempotency_key=idempotency_key,
|
||||
timeout_seconds=internal_timeout(),
|
||||
)
|
||||
return evaluate_h2_gate(
|
||||
script,
|
||||
context,
|
||||
env=os.environ,
|
||||
bash_path=bash_bin(),
|
||||
)
|
||||
|
||||
|
||||
def h5_governance_gate(action, content):
|
||||
"""Invoke the existing H5 gate for action-floor approval decisions."""
|
||||
script = os.path.join(gates_dir(), "governance-check.sh")
|
||||
if not os.path.isfile(script) or not bash_available():
|
||||
return {"approved": False, "reason_code": "h5_gate_unavailable", "detail": "governance gate unavailable"}
|
||||
tmpin = os.path.join(sessions_dir(), ".h5-in-%s" % uuid.uuid4().hex[:8])
|
||||
tmpout = os.path.join(sessions_dir(), ".h5-out-%s" % uuid.uuid4().hex[:8])
|
||||
try:
|
||||
proc = subprocess.run(
|
||||
[bash_bin(), script, action],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
timeout=internal_timeout(),
|
||||
env=env,
|
||||
)
|
||||
if proc.returncode == 0:
|
||||
return True, "h2_ok"
|
||||
return False, "h2_denied"
|
||||
except subprocess.TimeoutExpired:
|
||||
return False, "h2_internal_timeout"
|
||||
except (OSError, ValueError) as exc:
|
||||
return False, "h2_error:%s" % exc
|
||||
with open(tmpin, "w", encoding="utf-8") as handle:
|
||||
handle.write(content or "")
|
||||
rc, stdout, stderr = _run_gate([bash_bin(), script, tmpin, tmpout, action])
|
||||
if rc == 0 and "GOVERNANCE_APPROVED" in stdout:
|
||||
return {"approved": True, "reason_code": "h5_approval_verified", "detail": stdout.strip()}
|
||||
if rc == 124:
|
||||
return {"approved": False, "reason_code": "h5_gate_timeout", "detail": "governance gate timed out"}
|
||||
if rc == 125:
|
||||
return {"approved": False, "reason_code": "h5_gate_internal_error", "detail": stderr}
|
||||
return {"approved": False, "reason_code": "h5_approval_required", "detail": stderr or stdout}
|
||||
finally:
|
||||
for path in (tmpin, tmpout):
|
||||
try:
|
||||
os.unlink(path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -692,6 +751,8 @@ def write_trace_events(rec, evidence):
|
||||
"kind": evidence.get("kind"),
|
||||
"decision": evidence.get("decision"),
|
||||
"detail": evidence.get("detail"),
|
||||
"category": evidence.get("category"),
|
||||
"facts": evidence.get("facts", {}),
|
||||
"certification_strength": rec.get(
|
||||
"certification_strength"),
|
||||
},
|
||||
@@ -700,13 +761,16 @@ def write_trace_events(rec, evidence):
|
||||
event, ensure_ascii=False, separators=(",", ":")) + "\n")
|
||||
|
||||
|
||||
def add_evidence(rec, h, kind, decision, detail):
|
||||
def add_evidence(rec, h, kind, decision, detail, facts=None, category="runtime_control"):
|
||||
evidence = {
|
||||
"evidence_id": "%s:%s" % (rec.get("trace_id", "trace"), len(rec.get("evidence", [])) + 1),
|
||||
"h": h,
|
||||
"category": category,
|
||||
"kind": kind,
|
||||
"decision": decision,
|
||||
"at": now_iso(),
|
||||
"detail": redact(detail, 160),
|
||||
"facts": facts if isinstance(facts, dict) else {},
|
||||
}
|
||||
rec.setdefault("evidence", []).append(evidence)
|
||||
write_trace_events(rec, evidence)
|
||||
@@ -828,6 +892,27 @@ def write_h6_record(rec, status, quality, warnings, missing):
|
||||
return record
|
||||
|
||||
|
||||
def write_kernel_bundle(rec):
|
||||
"""Dual-emit the canonical contract without changing legacy trace readers."""
|
||||
event = dict(rec)
|
||||
event.update({
|
||||
"mode": enforcement_mode(),
|
||||
"execution_status": rec.get("execution_status", "unknown"),
|
||||
"assurance_status": rec.get("assurance_status", "unknown"),
|
||||
"environment": os.environ.get("CASAN_PROFILE", "development"),
|
||||
"completed_at": rec.get("finalized_at") or now_iso(),
|
||||
"policy_decisions": rec.get("policy_decisions", []),
|
||||
})
|
||||
bundle = AgenticBridgeAdapter().map_execution(event)
|
||||
errors = validate_bundle(bundle)
|
||||
if errors:
|
||||
raise ValueError("kernel_contract_invalid:%s" % ",".join(errors))
|
||||
path = os.path.join(kernel_trace_dir(), "%s.json" % rec.get("trace_id"))
|
||||
atomic_write_json(path, bundle)
|
||||
rec["kernel_contract_ref"] = path
|
||||
return path
|
||||
|
||||
|
||||
def write_trace_file(rec, certified, reasons):
|
||||
path = os.path.join(trace_dir(), "agentic-%s.json" % rec.get("trace_id"))
|
||||
payload = {
|
||||
@@ -851,6 +936,9 @@ def write_trace_file(rec, certified, reasons):
|
||||
"failures": rec.get("failures", 0),
|
||||
"certified": certified,
|
||||
"certification_reasons": reasons,
|
||||
"execution_outcome": rec.get("execution_status"),
|
||||
"assurance_outcome": rec.get("assurance_status"),
|
||||
"kernel_contract_ref": rec.get("kernel_contract_ref"),
|
||||
"evidence": rec.get("evidence", []),
|
||||
}
|
||||
atomic_write_json(path, payload)
|
||||
@@ -886,6 +974,8 @@ def op_begin(req):
|
||||
"client": client,
|
||||
"client_version": req.get("client_version"),
|
||||
"adapter_version": req.get("adapter_version") or ADAPTER_DEFAULT_VERSION,
|
||||
"actor": req.get("actor") or os.environ.get("CASAN_ACTOR") or os.environ.get("CASAN_AGENT") or "",
|
||||
"mode": enforcement_mode(),
|
||||
"project_root": project,
|
||||
"project_id": project_id(project),
|
||||
"session_id_hash": salted_hash(req.get("session")),
|
||||
@@ -900,8 +990,10 @@ def op_begin(req):
|
||||
"state": "Admitted",
|
||||
"tool_calls": 0,
|
||||
"failures": 0,
|
||||
"side_effect_failures": 0,
|
||||
"retries": 0,
|
||||
"evidence": [],
|
||||
"policy_decisions": [],
|
||||
"telemetry": {},
|
||||
"bypass_signal": False,
|
||||
"finalized": False,
|
||||
@@ -1012,30 +1104,109 @@ def op_pre_tool(req):
|
||||
# record the degradation but do not block the developer.
|
||||
add_evidence(rec, "H4", "pre-tool", "degraded", "%s:gate_unavailable_no_bash" % tool)
|
||||
|
||||
# H2 registry gate for mapped side-effect actions. Opt-in via
|
||||
# CASAN_AGENTIC_H2_REGISTRY=1: the tool-registry is keyed on NAMED CASAN
|
||||
# agent identities, which the transparent developer flow does not carry, so
|
||||
# enabling it unconditionally would deny every write. The always-on H2
|
||||
# equivalent for this flow is the admission gate above (a side effect
|
||||
# without a valid admission is denied). Managed deployments that define
|
||||
# agent identities can turn the registry gate on for defence in depth.
|
||||
registry_on = os.environ.get("CASAN_AGENTIC_H2_REGISTRY", "0") in ("1", "true", "yes")
|
||||
if side_effect and registry_on and enforcement_mode() == "enforce":
|
||||
action = TOOL_REGISTRY_ACTION.get((tool or "").strip().lower())
|
||||
if action:
|
||||
key = plain_hash("%s|%s|%s" % (rec["trace_id"], tool, redact(tool_input_text)))[:24]
|
||||
ok, reason = h2_registry_gate(action, key)
|
||||
if not ok:
|
||||
add_evidence(rec, "H2", "pre-tool", "deny", "%s:%s" % (tool, reason))
|
||||
save_admission(rec)
|
||||
return _base_response("pre-tool", "deny", admission_id=admission_id,
|
||||
trace_id=rec.get("trace_id"), reason=reason)
|
||||
tool_input_string = tool_input_text if isinstance(tool_input_text, str) else json.dumps(
|
||||
tool_input_text, ensure_ascii=False, sort_keys=True) if tool_input_text is not None else ""
|
||||
# Native hook payloads commonly wrap a shell command in {"command": ...}.
|
||||
# Classify the actual command while retaining the complete serialized input
|
||||
# for scanning, governance evidence and hashing.
|
||||
risk_command = tool_input_string
|
||||
if isinstance(tool_input_text, dict) and isinstance(tool_input_text.get("command"), str):
|
||||
risk_command = tool_input_text["command"]
|
||||
risk = evaluate_risk(
|
||||
action=str(req.get("action") or ""),
|
||||
tool=tool,
|
||||
resource=str(req.get("resource") or ""),
|
||||
command=risk_command,
|
||||
content=tool_input_string,
|
||||
actor=rec.get("actor", ""),
|
||||
environment=os.environ.get("CASAN_PROFILE", "development"),
|
||||
)
|
||||
# The canonical classifier can prove a shell command read-only; unknown
|
||||
# shell commands remain side-effecting/high-risk by construction.
|
||||
side_effect = bool(risk["side_effecting"])
|
||||
action = REGISTRY_ACTION_BY_CLASS.get(risk["action_class"], TOOL_REGISTRY_ACTION.get((tool or "").strip().lower(), "unknown_tool"))
|
||||
rec["last_tool"] = tool
|
||||
rec["last_action"] = action
|
||||
rec["last_risk"] = risk
|
||||
rec.setdefault("policy_decisions", []).append(risk)
|
||||
add_evidence(
|
||||
rec, "H5", "action-risk", risk["decision"],
|
||||
"class=%s effective=%s" % (risk["action_class"], risk["effective_risk"]),
|
||||
facts=risk,
|
||||
)
|
||||
|
||||
if side_effect and risk["decision"] == "deny":
|
||||
reason = risk["reason_codes"][-1]
|
||||
add_evidence(rec, "H5", "pre-tool", "deny", reason, facts=risk)
|
||||
save_admission(rec)
|
||||
return _base_response("pre-tool", "deny", admission_id=admission_id,
|
||||
trace_id=rec.get("trace_id"), reason=reason,
|
||||
policy_decision=risk)
|
||||
|
||||
if side_effect and risk["decision"] == "require_approval":
|
||||
approval = h5_governance_gate(action, tool_input_string)
|
||||
add_evidence(
|
||||
rec, "H5", "approval", "allow" if approval["approved"] else "require_approval",
|
||||
approval["reason_code"], facts={"risk": risk, "approval": approval},
|
||||
)
|
||||
if not approval["approved"]:
|
||||
save_admission(rec)
|
||||
return _base_response("pre-tool", "require_approval", admission_id=admission_id,
|
||||
trace_id=rec.get("trace_id"), reason=approval["reason_code"],
|
||||
policy_decision=risk)
|
||||
|
||||
registry = evaluate_registry_configuration(
|
||||
enforcement_mode(),
|
||||
os.environ.get("CASAN_PROFILE", "development"),
|
||||
os.environ.get("CASAN_AGENTIC_H2_REGISTRY") if "CASAN_AGENTIC_H2_REGISTRY" in os.environ else None,
|
||||
)
|
||||
if side_effect and not registry["valid"]:
|
||||
add_evidence(rec, "H2", "registry-configuration", "deny", registry["reason_code"], facts=registry)
|
||||
save_admission(rec)
|
||||
return _base_response("pre-tool", "deny", admission_id=admission_id,
|
||||
trace_id=rec.get("trace_id"), reason=registry["reason_code"])
|
||||
if side_effect and registry["unsafe_bypass"]:
|
||||
rec["integration_mode"] = "observed_only"
|
||||
rec["certification_strength"] = "observed_only"
|
||||
add_evidence(rec, "H2", "registry-configuration", "degraded", registry["reason_code"], facts=registry)
|
||||
|
||||
if side_effect and registry["enabled"]:
|
||||
key = plain_hash("%s|%s|%s" % (rec["trace_id"], tool, redact(tool_input_text)))[:24]
|
||||
h2_decision = h2_registry_gate(action, tool, rec.get("actor", ""), rec["trace_id"], key)
|
||||
rec.setdefault("policy_decisions", []).append(h2_decision)
|
||||
add_evidence(
|
||||
rec, "H2", "tool-registry", h2_decision["decision"],
|
||||
h2_decision["reason_code"], facts=h2_decision,
|
||||
)
|
||||
if not h2_decision["execution_allowed"]:
|
||||
save_admission(rec)
|
||||
return _base_response("pre-tool", "deny", admission_id=admission_id,
|
||||
trace_id=rec.get("trace_id"), reason=h2_decision["reason_code"],
|
||||
policy_decision=h2_decision)
|
||||
if not h2_decision["certifiable"]:
|
||||
rec["integration_mode"] = "observed_only"
|
||||
rec["certification_strength"] = "observed_only"
|
||||
|
||||
add_evidence(rec, "H2/H4", "pre-tool", "allow",
|
||||
"tool=%s side_effect=%s" % (tool, side_effect))
|
||||
"tool=%s side_effect=%s action=%s" % (tool, side_effect, action),
|
||||
facts={"action_risk": risk, "registry": registry})
|
||||
save_admission(rec)
|
||||
return _base_response("pre-tool", "allow", admission_id=admission_id,
|
||||
trace_id=rec.get("trace_id"), reason="allowed")
|
||||
response = _base_response("pre-tool", "allow", admission_id=admission_id,
|
||||
trace_id=rec.get("trace_id"), reason="allowed",
|
||||
policy_decision=risk)
|
||||
if registry["unsafe_bypass"]:
|
||||
response["warnings"].append("HIGH: H2 registry bypass active in development/test; execution is not certifiable")
|
||||
return response
|
||||
|
||||
|
||||
def single_step_failure_policy(side_effect):
|
||||
decision = evaluate_failure_policy(
|
||||
side_effecting=side_effect,
|
||||
mode=enforcement_mode(),
|
||||
profile=os.environ.get("CASAN_PROFILE", "development"),
|
||||
configured=os.environ.get("CASAN_SINGLE_STEP_FAILURE_POLICY"),
|
||||
)
|
||||
return decision["failure_policy"], decision["source"]
|
||||
|
||||
|
||||
def op_post_tool(req):
|
||||
@@ -1045,11 +1216,52 @@ def op_post_tool(req):
|
||||
reason="no_admission")
|
||||
rec["tool_calls"] = rec.get("tool_calls", 0) + 1
|
||||
status = req.get("status") or "success"
|
||||
if status in ("error", "timeout"):
|
||||
risk = evaluate_risk(
|
||||
action=str(rec.get("last_action") or ""),
|
||||
tool=str(req.get("tool") or rec.get("last_tool") or ""),
|
||||
command=str(req.get("command") or ""),
|
||||
actor=rec.get("actor", ""),
|
||||
environment=os.environ.get("CASAN_PROFILE", "development"),
|
||||
)
|
||||
side_effect = bool(risk["side_effecting"])
|
||||
if status in ("error", "timeout", "denied", "failed"):
|
||||
rec["failures"] = rec.get("failures", 0) + 1
|
||||
if side_effect:
|
||||
rec["side_effect_failures"] = rec.get("side_effect_failures", 0) + 1
|
||||
policy, source = single_step_failure_policy(side_effect)
|
||||
rec["failure_policy"] = policy
|
||||
rec["execution_status"] = "failed"
|
||||
rec["assurance_status"] = "failed"
|
||||
add_evidence(
|
||||
rec, "H6", "failure-policy", policy,
|
||||
"tool=%s status=%s policy=%s" % (req.get("tool"), status, policy),
|
||||
facts={
|
||||
"command_executed": status not in ("denied",),
|
||||
"command_outcome": status,
|
||||
"telemetry_recorded": True,
|
||||
"assurance_may_continue": policy == "record_only",
|
||||
"failure_policy": policy,
|
||||
"policy_source": source,
|
||||
"side_effecting": side_effect,
|
||||
},
|
||||
)
|
||||
add_evidence(rec, "H5", "post-tool", status,
|
||||
"tool=%s dur_ms=%s result=%s" % (req.get("tool"), req.get("duration_ms"),
|
||||
redact(req.get("result"), 80)),
|
||||
facts={"risk": risk, "failure_policy": policy})
|
||||
save_admission(rec)
|
||||
decision = "recorded" if policy == "record_only" else policy
|
||||
return _base_response(
|
||||
"post-tool", decision, admission_id=rec["admission_id"],
|
||||
trace_id=rec.get("trace_id"), reason="tool_failed:%s" % policy,
|
||||
execution_outcome="failed", assurance_outcome="failed",
|
||||
assurance_may_continue=policy == "record_only",
|
||||
)
|
||||
rec["execution_status"] = rec.get("execution_status") or "success"
|
||||
add_evidence(rec, "H5", "post-tool", status,
|
||||
"tool=%s dur_ms=%s result=%s" % (req.get("tool"), req.get("duration_ms"),
|
||||
redact(req.get("result"), 80)))
|
||||
redact(req.get("result"), 80)),
|
||||
facts={"risk": risk, "command_outcome": status, "telemetry_recorded": True})
|
||||
save_admission(rec)
|
||||
return _base_response("post-tool", "recorded", admission_id=rec["admission_id"],
|
||||
trace_id=rec.get("trace_id"), reason="evidence_appended")
|
||||
@@ -1092,6 +1304,10 @@ def op_finalize(req):
|
||||
rec["summary_hash"] = salted_hash(req.get("assistant_summary"))
|
||||
stop_reason = req.get("stop_reason") or "completed"
|
||||
status = "success" if stop_reason in ("completed", "max_turns") else "failed"
|
||||
if rec.get("failures", 0) > 0:
|
||||
# Telemetry success is not execution success. A failed tool remains a
|
||||
# failed execution even if the client later emits Stop(completed).
|
||||
status = "failed"
|
||||
|
||||
observed_harnesses = {
|
||||
harness
|
||||
@@ -1110,6 +1326,8 @@ def op_finalize(req):
|
||||
# H3/H5/H7 finalize controls: run the H4 output filter over the assistant
|
||||
# summary as the closing verification control.
|
||||
reasons = []
|
||||
if rec.get("failures", 0) > 0:
|
||||
reasons.append("tool_execution_failed")
|
||||
if req.get("assistant_summary"):
|
||||
h4 = h4_scan(req.get("assistant_summary"), "output")
|
||||
if h4 == "ok":
|
||||
@@ -1158,7 +1376,17 @@ def op_finalize(req):
|
||||
reasons.append("coverage_bypass")
|
||||
if status != "success":
|
||||
certified = False
|
||||
reasons.append("stop_%s" % stop_reason)
|
||||
failure_reason = "failed_tool_outcome" if rec.get("failures", 0) > 0 else "stop_%s" % stop_reason
|
||||
if failure_reason not in reasons:
|
||||
reasons.append(failure_reason)
|
||||
trust = evaluate_trust_capabilities()
|
||||
add_evidence(
|
||||
rec, "H7", "trust-capability", "pass" if trust["certifiable"] else "degraded",
|
||||
",".join(trust["reason_codes"]), facts=trust, category="readiness_check",
|
||||
)
|
||||
if trust["production"] and not trust["certifiable"]:
|
||||
certified = False
|
||||
reasons.extend(reason for reason in trust["reason_codes"] if reason not in reasons)
|
||||
if not certified and not reasons:
|
||||
reasons.append("unknown")
|
||||
if certified:
|
||||
@@ -1168,12 +1396,15 @@ def op_finalize(req):
|
||||
rec["certified"] = certified
|
||||
rec["finalized"] = True
|
||||
rec["finalized_at"] = now_iso()
|
||||
rec["execution_status"] = status
|
||||
rec["assurance_status"] = "passed" if certified else "failed" if rec.get("failures", 0) else "degraded"
|
||||
add_evidence(
|
||||
rec,
|
||||
"H7",
|
||||
"certification",
|
||||
"certified" if certified else "non_certified",
|
||||
",".join(reasons),
|
||||
category="certification_claim",
|
||||
)
|
||||
|
||||
quality, warnings, missing = classify_telemetry(rec)
|
||||
@@ -1185,13 +1416,26 @@ def op_finalize(req):
|
||||
",".join(warnings) if warnings else "provider_usage_complete",
|
||||
)
|
||||
h6_record = write_h6_record(rec, status, quality, warnings, missing)
|
||||
try:
|
||||
write_kernel_bundle(rec)
|
||||
except (OSError, ValueError, TypeError) as exc:
|
||||
certified = False
|
||||
rec["certified"] = False
|
||||
rec["state"] = "NonCertified"
|
||||
rec["assurance_status"] = "failed"
|
||||
if "kernel_contract_emission_failed" not in reasons:
|
||||
reasons.append("kernel_contract_emission_failed")
|
||||
add_evidence(rec, "H7", "kernel-contract", "failed",
|
||||
"kernel_contract_emission_failed:%s" % type(exc).__name__)
|
||||
trace_path = write_trace_file(rec, certified, reasons)
|
||||
save_admission(rec)
|
||||
|
||||
resp = _base_response("finalize", "certified" if certified else "non_certified",
|
||||
admission_id=rec["admission_id"], trace_id=rec.get("trace_id"),
|
||||
certification_strength=strength, telemetry_quality=quality,
|
||||
reason=",".join(reasons))
|
||||
reason=",".join(reasons), execution_outcome=status,
|
||||
assurance_outcome=rec.get("assurance_status"),
|
||||
certification_outcome="certified" if certified else "non_certified")
|
||||
resp["warnings"].extend(warnings)
|
||||
resp["context"] = "trace=%s certified=%s" % (os.path.basename(trace_path), certified)
|
||||
report_url = dashboard_url(rec.get("trace_id"))
|
||||
|
||||
Reference in New Issue
Block a user