Implement KG-WP-0002 posture pilot scaffold

This commit is contained in:
codex 2026-07-24 00:24:53 +02:00
parent 6cee3503da
commit 3c549d9b78
22 changed files with 1418 additions and 25 deletions

View file

@ -0,0 +1 @@
__version__ = "0.1.0"

View file

@ -0,0 +1,3 @@
from kings_guard.adapters.qonto_assistant import observation_from_audit_event
__all__ = ["observation_from_audit_event"]

View file

@ -0,0 +1,49 @@
from __future__ import annotations
from collections.abc import Mapping
from typing import Any
from kings_guard.contracts import ImmuneObservation, ObservationDecision
def observation_from_audit_event(
event: Mapping[str, Any],
*,
subject_id: str,
capability_scope: str,
identity_binding: str,
egress_destination: str | None,
) -> ImmuneObservation:
"""Normalize qonto-assistant's audit stream into Kings Guard's observation contract."""
return ImmuneObservation(
observation_id=str(event["request_id"]),
source_system="qonto-assistant",
timestamp=str(event["timestamp"]),
tenant_id=str(event["tenant_id"]),
subject_id=subject_id,
actor_id=str(event["actor"]),
capability=capability_scope,
resource_scope=_optional_str(event.get("capability")),
protocol=str(event["protocol"]),
decision=ObservationDecision(str(event["decision"])),
deny_reason=_optional_str(event.get("deny_reason")),
identity_binding=identity_binding,
egress_destination=egress_destination,
latency_ms=_optional_int(event.get("latency_ms")),
result_count=_optional_int(event.get("result_count")),
policy_version=_optional_int(event.get("policy_version")),
upstream_status=_optional_int(event.get("qonto_http_status")),
)
def _optional_int(value: Any) -> int | None:
if value is None:
return None
return int(value)
def _optional_str(value: Any) -> str | None:
if value is None:
return None
text = str(value)
return text if text else None

View file

@ -0,0 +1,213 @@
from __future__ import annotations
from collections.abc import Mapping
from dataclasses import asdict, dataclass, field, is_dataclass
from enum import Enum
from typing import Any, Literal
ToleranceEffect = Literal["monitor", "ignore"]
AuthorityBoundary = Literal[
"advisory_only",
"metadata_only",
"local_service_owned",
"requires_human_approval",
]
class ObservationDecision(str, Enum):
ALLOW = "allow"
DENY = "deny"
ERROR = "error"
class PostureLevel(str, Enum):
HEALTHY = "healthy"
ELEVATED = "elevated"
INFLAMED = "inflamed"
COMPROMISED = "compromised"
class SignalKind(str, Enum):
POSTURE_HINT = "posture_hint"
OBSERVATION_ALERT = "observation_alert"
RECOVERY_REQUEST = "recovery_request"
@dataclass(frozen=True, slots=True)
class ToleranceRule:
tolerance_id: str
match_field: str
match_value: str
description: str
effect: ToleranceEffect = "monitor"
@classmethod
def from_dict(cls, data: Mapping[str, Any]) -> "ToleranceRule":
return cls(
tolerance_id=str(data["tolerance_id"]),
match_field=str(data["match_field"]),
match_value=str(data["match_value"]),
description=str(data["description"]),
effect=str(data.get("effect", "monitor")),
)
@dataclass(frozen=True, slots=True)
class SecurityGenome:
genome_id: str
version: str
subject_id: str
tenant_id: str
intended_purpose: str
permitted_capabilities: frozenset[str]
permitted_protocols: frozenset[str]
permitted_egress: frozenset[str]
data_classifications: tuple[str, ...] = ()
tolerances: tuple[ToleranceRule, ...] = ()
@classmethod
def from_dict(cls, data: Mapping[str, Any]) -> "SecurityGenome":
return cls(
genome_id=str(data["genome_id"]),
version=str(data["version"]),
subject_id=str(data["subject_id"]),
tenant_id=str(data["tenant_id"]),
intended_purpose=str(data["intended_purpose"]),
permitted_capabilities=frozenset(str(item) for item in data["permitted_capabilities"]),
permitted_protocols=frozenset(str(item) for item in data["permitted_protocols"]),
permitted_egress=frozenset(str(item) for item in data["permitted_egress"]),
data_classifications=tuple(str(item) for item in data.get("data_classifications", ())),
tolerances=tuple(
ToleranceRule.from_dict(item) for item in data.get("tolerances", ())
),
)
@dataclass(frozen=True, slots=True)
class ImmuneObservation:
observation_id: str
source_system: str
timestamp: str
tenant_id: str
subject_id: str
actor_id: str
capability: str
resource_scope: str | None
protocol: str
decision: ObservationDecision
deny_reason: str | None = None
identity_binding: str | None = None
egress_destination: str | None = None
latency_ms: int | None = None
result_count: int | None = None
policy_version: int | None = None
upstream_status: int | None = None
@classmethod
def from_dict(cls, data: Mapping[str, Any]) -> "ImmuneObservation":
return cls(
observation_id=str(data["observation_id"]),
source_system=str(data["source_system"]),
timestamp=str(data["timestamp"]),
tenant_id=str(data["tenant_id"]),
subject_id=str(data["subject_id"]),
actor_id=str(data["actor_id"]),
capability=str(data["capability"]),
resource_scope=_optional_str(data.get("resource_scope")),
protocol=str(data["protocol"]),
decision=ObservationDecision(str(data["decision"])),
deny_reason=_optional_str(data.get("deny_reason")),
identity_binding=_optional_str(data.get("identity_binding")),
egress_destination=_optional_str(data.get("egress_destination")),
latency_ms=_optional_int(data.get("latency_ms")),
result_count=_optional_int(data.get("result_count")),
policy_version=_optional_int(data.get("policy_version")),
upstream_status=_optional_int(data.get("upstream_status")),
)
@dataclass(frozen=True, slots=True)
class SecurityPhenotype:
subject_id: str
tenant_id: str
observed_capability: str
protocol: str
decision: ObservationDecision
active_findings: tuple[str, ...]
tolerated_findings: tuple[str, ...]
@dataclass(frozen=True, slots=True)
class PostureAssessment:
posture: PostureLevel
risk_score: int
confidence_score: int
findings: tuple[str, ...]
tolerated_findings: tuple[str, ...]
rationale: str
@dataclass(frozen=True, slots=True)
class EffectorRequest:
target_system: str
action: str
authority_boundary: AuthorityBoundary
reason: str
requires_human_approval: bool
@dataclass(frozen=True, slots=True)
class ImmuneSignal:
signal_id: str
signal_kind: SignalKind
posture: PostureLevel
summary: str
target_system: str
findings: tuple[str, ...]
effector_requests: tuple[EffectorRequest, ...] = ()
metadata: dict[str, str] = field(default_factory=dict)
@dataclass(frozen=True, slots=True)
class ImmuneMemoryEntry:
memory_id: str
subject_scope: str
summary: str
derived_from: tuple[str, ...]
recommended_countermeasures: tuple[str, ...]
confidentiality: str = "non-secret"
@dataclass(frozen=True, slots=True)
class PostureEvaluation:
phenotype: SecurityPhenotype
assessment: PostureAssessment
signals: tuple[ImmuneSignal, ...]
def as_jsonable(value: Any) -> Any:
"""Convert contract objects into JSON-safe primitives."""
if isinstance(value, Enum):
return value.value
if is_dataclass(value):
return {key: as_jsonable(item) for key, item in asdict(value).items()}
if isinstance(value, Mapping):
return {str(key): as_jsonable(item) for key, item in value.items()}
if isinstance(value, (list, tuple)):
return [as_jsonable(item) for item in value]
if isinstance(value, (set, frozenset)):
return [as_jsonable(item) for item in sorted(value)]
return value
def _optional_int(value: Any) -> int | None:
if value is None:
return None
return int(value)
def _optional_str(value: Any) -> str | None:
if value is None:
return None
text = str(value)
return text if text else None

View file

@ -0,0 +1,31 @@
from __future__ import annotations
import json
from dataclasses import dataclass
from importlib.resources import files
from typing import Any
from kings_guard.contracts import SecurityGenome
@dataclass(frozen=True, slots=True)
class QontoAssistantPilotFixture:
genome: SecurityGenome
audit_event: dict[str, Any]
normalization_hints: dict[str, str]
source_notes: tuple[str, ...]
def load_qonto_assistant_pilot() -> QontoAssistantPilotFixture:
payload = _load_json_fixture("qonto_assistant_pilot.json")
return QontoAssistantPilotFixture(
genome=SecurityGenome.from_dict(payload["normalized_genome"]),
audit_event=dict(payload["qonto_audit_event"]),
normalization_hints={str(key): str(value) for key, value in payload["normalization_hints"].items()},
source_notes=tuple(str(item) for item in payload.get("source_notes", ())),
)
def _load_json_fixture(name: str) -> dict[str, Any]:
fixture_path = files("kings_guard").joinpath("fixtures").joinpath(name)
return json.loads(fixture_path.read_text(encoding="utf-8"))

View file

@ -0,0 +1,58 @@
{
"normalized_genome": {
"genome_id": "kg:genome:qonto-assistant",
"version": "0.1.0",
"subject_id": "qonto-assistant",
"tenant_id": "binky",
"intended_purpose": "Hold the company Qonto credential behind a governed read-only finance surface for authorized operators and agent harnesses.",
"permitted_capabilities": [
"finance.qonto.read"
],
"permitted_protocols": [
"rest",
"mcp"
],
"permitted_egress": [
"openbao",
"qonto-thirdparty-api"
],
"data_classifications": [
"tenant-confidential",
"financial"
],
"tolerances": [
{
"tolerance_id": "self-asserted-actor-claims",
"match_field": "identity_binding",
"match_value": "self_asserted",
"description": "Actor identity is still self-asserted until key-cape integration lands.",
"effect": "monitor"
}
]
},
"qonto_audit_event": {
"request_id": "req-qonto-deny-credential-exfil",
"timestamp": "2026-07-23T09:10:00Z",
"actor": "agt-laptop-risky",
"tenant_id": "binky",
"capability": "org_summary",
"protocol": "mcp",
"decision": "deny",
"deny_reason": "credential_exfil",
"policy_version": 1,
"latency_ms": 12,
"qonto_http_status": null,
"result_count": null
},
"normalization_hints": {
"subject_id": "qonto-assistant",
"capability_scope": "finance.qonto.read",
"identity_binding": "self_asserted",
"egress_destination": "qonto-thirdparty-api"
},
"source_notes": [
"Derived from qonto-assistant/specs/security-genome.yaml",
"Derived from qonto-assistant/src/qonto_assistant/contracts.py#AuditEvent",
"Pilot chooses qonto-assistant because it already ships an audit stream, a genome record, and a fast local loop."
]
}

49
src/kings_guard/main.py Normal file
View file

@ -0,0 +1,49 @@
from __future__ import annotations
import argparse
import json
from kings_guard.adapters import observation_from_audit_event
from kings_guard.contracts import as_jsonable
from kings_guard.fixtures import load_qonto_assistant_pilot
from kings_guard.posture import PostureEvaluator
def main() -> None:
parser = argparse.ArgumentParser(description="Run the Kings Guard pilot posture demo.")
parser.add_argument(
"--pilot",
default="qonto-assistant",
choices=["qonto-assistant"],
help="Pilot bundle to evaluate.",
)
args = parser.parse_args()
if args.pilot != "qonto-assistant":
raise SystemExit(f"Unsupported pilot: {args.pilot}")
fixture = load_qonto_assistant_pilot()
observation = observation_from_audit_event(
fixture.audit_event,
subject_id=fixture.normalization_hints["subject_id"],
capability_scope=fixture.normalization_hints["capability_scope"],
identity_binding=fixture.normalization_hints["identity_binding"],
egress_destination=fixture.normalization_hints["egress_destination"],
)
evaluation = PostureEvaluator().evaluate(fixture.genome, observation)
print(
json.dumps(
{
"pilot": args.pilot,
"source_notes": list(fixture.source_notes),
"observation": as_jsonable(observation),
"evaluation": as_jsonable(evaluation),
},
indent=2,
sort_keys=True,
)
)
if __name__ == "__main__":
main()

242
src/kings_guard/posture.py Normal file
View file

@ -0,0 +1,242 @@
from __future__ import annotations
from kings_guard.contracts import (
EffectorRequest,
ImmuneObservation,
ImmuneSignal,
PostureAssessment,
PostureEvaluation,
PostureLevel,
SecurityGenome,
SecurityPhenotype,
SignalKind,
)
CRITICAL_FINDINGS = frozenset(
{
"tenant_mismatch",
"undeclared_capability",
"unexpected_egress_destination",
"credential_exfil_probe",
}
)
ELEVATED_FINDINGS = frozenset(
{
"constraint_probe_or_boundary_trip",
"unexpected_protocol",
"unverified_identity_binding",
"control_plane_error",
}
)
RISK_WEIGHTS = {
"tenant_mismatch": 50,
"undeclared_capability": 40,
"unexpected_egress_destination": 50,
"credential_exfil_probe": 60,
"constraint_probe_or_boundary_trip": 25,
"unexpected_protocol": 15,
"unverified_identity_binding": 20,
"control_plane_error": 20,
}
class PostureEvaluator:
def evaluate(self, genome: SecurityGenome, observation: ImmuneObservation) -> PostureEvaluation:
phenotype = self._derive_phenotype(genome, observation)
assessment = self._assess(phenotype, observation)
signals = self._build_signals(observation, assessment)
return PostureEvaluation(phenotype=phenotype, assessment=assessment, signals=signals)
def _derive_phenotype(
self,
genome: SecurityGenome,
observation: ImmuneObservation,
) -> SecurityPhenotype:
findings: list[str] = []
tolerated: list[str] = []
if observation.tenant_id != genome.tenant_id:
findings.append("tenant_mismatch")
if observation.capability not in genome.permitted_capabilities:
findings.append("undeclared_capability")
if observation.protocol not in genome.permitted_protocols:
findings.append("unexpected_protocol")
if (
observation.egress_destination is not None
and observation.egress_destination not in genome.permitted_egress
):
findings.append("unexpected_egress_destination")
if observation.identity_binding and observation.identity_binding != "verified_token":
tolerance = _matching_tolerance(genome, "identity_binding", observation.identity_binding)
if tolerance is None:
findings.append("unverified_identity_binding")
else:
tolerated.append(f"tolerated:{tolerance.tolerance_id}")
if observation.decision.value == "deny" and observation.deny_reason == "credential_exfil":
findings.append("credential_exfil_probe")
elif observation.decision.value == "deny" and observation.deny_reason == "arg_constraint":
findings.append("constraint_probe_or_boundary_trip")
elif observation.decision.value == "error":
findings.append("control_plane_error")
return SecurityPhenotype(
subject_id=observation.subject_id,
tenant_id=observation.tenant_id,
observed_capability=observation.capability,
protocol=observation.protocol,
decision=observation.decision,
active_findings=tuple(findings),
tolerated_findings=tuple(tolerated),
)
def _assess(
self,
phenotype: SecurityPhenotype,
observation: ImmuneObservation,
) -> PostureAssessment:
findings = set(phenotype.active_findings)
posture = PostureLevel.HEALTHY
if findings & CRITICAL_FINDINGS:
posture = PostureLevel.INFLAMED
elif findings:
posture = PostureLevel.ELEVATED
if observation.decision.value == "allow" and "unexpected_egress_destination" in findings:
posture = PostureLevel.COMPROMISED
risk_score = 5 + sum(RISK_WEIGHTS.get(item, 10) for item in findings)
if posture is PostureLevel.ELEVATED:
risk_score = max(risk_score, 40)
elif posture is PostureLevel.INFLAMED:
risk_score = max(risk_score, 80)
elif posture is PostureLevel.COMPROMISED:
risk_score = max(risk_score, 95)
risk_score = min(risk_score, 100)
confidence_score = 70
if observation.policy_version is not None:
confidence_score += 10
if observation.latency_ms is not None:
confidence_score += 5
if observation.resource_scope:
confidence_score += 5
confidence_score = min(confidence_score, 95)
rationale = _build_rationale(
posture=posture,
findings=phenotype.active_findings,
tolerated_findings=phenotype.tolerated_findings,
)
return PostureAssessment(
posture=posture,
risk_score=risk_score,
confidence_score=confidence_score,
findings=phenotype.active_findings,
tolerated_findings=phenotype.tolerated_findings,
rationale=rationale,
)
def _build_signals(
self,
observation: ImmuneObservation,
assessment: PostureAssessment,
) -> tuple[ImmuneSignal, ...]:
if assessment.posture is PostureLevel.HEALTHY:
return ()
if observation.source_system == "qonto-assistant":
return (self._build_qonto_pilot_signal(observation, assessment),)
signal = ImmuneSignal(
signal_id=f"sig:{observation.observation_id}",
signal_kind=SignalKind.OBSERVATION_ALERT,
posture=assessment.posture,
summary=assessment.rationale,
target_system=observation.source_system,
findings=assessment.findings,
metadata={"source_system": observation.source_system},
)
return (signal,)
def _build_qonto_pilot_signal(
self,
observation: ImmuneObservation,
assessment: PostureAssessment,
) -> ImmuneSignal:
if "credential_exfil_probe" in assessment.findings:
action = "lock_actor_temporarily"
reason = (
"Observed a credential-exfil deny signal; qonto-assistant should activate "
"its fast local loop lockout and preserve metadata-only evidence."
)
else:
action = "tighten_actor_scrutiny"
reason = (
"Observed repeated policy-boundary pressure; qonto-assistant should tighten "
"local scrutiny without delegating final authorization to kings-guard."
)
return ImmuneSignal(
signal_id=f"sig:{observation.observation_id}",
signal_kind=SignalKind.POSTURE_HINT,
posture=assessment.posture,
summary=reason,
target_system="qonto-assistant",
findings=assessment.findings,
effector_requests=(
EffectorRequest(
target_system="qonto-assistant",
action=action,
authority_boundary="advisory_only",
reason=reason,
requires_human_approval=False,
),
EffectorRequest(
target_system="state-hub",
action="record_non_secret_incident_evidence",
authority_boundary="metadata_only",
reason="Preserve posture evidence without copying secret values.",
requires_human_approval=False,
),
),
metadata={
"pilot_lane": "qonto-assistant",
"resource_scope": observation.resource_scope or "unknown",
},
)
def _matching_tolerance(
genome: SecurityGenome,
field_name: str,
field_value: str,
):
for tolerance in genome.tolerances:
if tolerance.match_field == field_name and tolerance.match_value == field_value:
return tolerance
return None
def _build_rationale(
*,
posture: PostureLevel,
findings: tuple[str, ...],
tolerated_findings: tuple[str, ...],
) -> str:
if posture is PostureLevel.HEALTHY:
if tolerated_findings:
return (
"Healthy posture with tolerated deviations only: "
+ ", ".join(tolerated_findings)
)
return "Healthy posture: observation is compatible with declared intent."
detail = ", ".join(findings) if findings else "no active findings"
tolerated = (
f" Tolerated deviations still present: {', '.join(tolerated_findings)}."
if tolerated_findings
else ""
)
return f"{posture.value.title()} posture driven by {detail}.{tolerated}"