diff --git a/Makefile b/Makefile index 5356c57..8943bc0 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,16 @@ -.PHONY: validate validate-resource-contract validate-measurement validate-value-type validate-source-locator validate-sourceos-repo-manifest validate-mesh-action-registry validate-control-plane-examples validate-nlboot-examples validate-lattice-data-governai-examples validate-ops-history-examples validate-runtime-observability-examples validate-interpretability-examples validate-lifecycle-boundary-examples validate-svf-contracts validate-sync-cycle-receipts validate-onboarding-examples validate-runtime-causality-examples validate-agentic-os-examples validate-triparty-examples validate-labor-market-examples validate-supply-chain-risk-examples validate-reasoning-examples validate-mpcc-event-examples validate-knowledge-nugget-examples validate-semantic-action-examples validate-epistemic-kernel-examples validate-ab-update-examples validate-device-service-examples validate-duplicate-schema-ids validate-lawful-dispatch-receipt validate-architectural-building-block validate-agent-passport-examples validate-measurement +.PHONY: validate validate-resource-contract validate-measurement validate-value-type validate-source-locator validate-sourceos-repo-manifest validate-mesh-action-registry validate-control-plane-examples validate-nlboot-examples validate-lattice-data-governai-examples validate-ops-history-examples validate-runtime-observability-examples validate-interpretability-examples validate-lifecycle-boundary-examples validate-svf-contracts validate-sync-cycle-receipts validate-onboarding-examples validate-runtime-causality-examples validate-agentic-os-examples validate-triparty-examples validate-labor-market-examples validate-supply-chain-risk-examples validate-reasoning-examples validate-mpcc-event-examples validate-knowledge-nugget-examples validate-semantic-action-examples validate-epistemic-kernel-examples validate-ab-update-examples validate-device-service-examples validate-duplicate-schema-ids validate-lawful-dispatch-receipt validate-architectural-building-block validate-agent-passport-examples validate-seam-definition-examples validate-measurement -validate: validate-control-plane-examples validate-nlboot-examples validate-lattice-data-governai-examples validate-ops-history-examples validate-runtime-observability-examples validate-interpretability-examples validate-lifecycle-boundary-examples validate-svf-contracts validate-sync-cycle-receipts validate-onboarding-examples validate-runtime-causality-examples validate-agentic-os-examples validate-triparty-examples validate-labor-market-examples validate-supply-chain-risk-examples validate-reasoning-examples validate-mpcc-event-examples validate-knowledge-nugget-examples validate-semantic-action-examples validate-epistemic-kernel-examples validate-ab-update-examples validate-device-service-examples validate-duplicate-schema-ids validate-value-type validate-source-locator validate-sourceos-repo-manifest validate-mesh-action-registry validate-lawful-dispatch-receipt validate-architectural-building-block validate-agent-passport-examples validate-measurement validate-resource-contract +validate: validate-control-plane-examples validate-nlboot-examples validate-lattice-data-governai-examples validate-ops-history-examples validate-runtime-observability-examples validate-interpretability-examples validate-lifecycle-boundary-examples validate-svf-contracts validate-sync-cycle-receipts validate-onboarding-examples validate-runtime-causality-examples validate-agentic-os-examples validate-triparty-examples validate-labor-market-examples validate-supply-chain-risk-examples validate-reasoning-examples validate-mpcc-event-examples validate-knowledge-nugget-examples validate-semantic-action-examples validate-epistemic-kernel-examples validate-ab-update-examples validate-device-service-examples validate-duplicate-schema-ids validate-value-type validate-source-locator validate-sourceos-repo-manifest validate-mesh-action-registry validate-lawful-dispatch-receipt validate-architectural-building-block validate-agent-passport-examples validate-seam-definition-examples validate-measurement validate-resource-contract @echo "OK: validate" validate-agent-passport-examples: python3 -m pip install --user jsonschema >/dev/null python3 tools/validate_agent_passport_examples.py +validate-seam-definition-examples: + python3 -m pip install --user jsonschema >/dev/null + python3 tools/validate_seam_definition_examples.py + validate-source-locator: python3 tools/validate_source_locator.py diff --git a/examples/seam-definition.json b/examples/seam-definition.json new file mode 100644 index 0000000..e3541d6 --- /dev/null +++ b/examples/seam-definition.json @@ -0,0 +1,15 @@ +{ + "type": "SeamDefinition", + "seam_id": "SEAM-002", + "name": "MDM → usernoted", + "boundary_from": "MDM", + "boundary_to": "usernoted", + "attack_vector": "Unauthorized MDM enrollment (e.g. IBM MaaS360) grants a profile that suppresses user authorization on the notification server.", + "known_exploits": ["Unauthorized MaaS360 enrollment observed in diagnostic captures"], + "gate_requirements": ["MDM profile audit: flag unrecognized configuration profiles"], + "implementation_status": "open", + "linked_repos": ["SourceOS-Linux/agent-machine#T2-3"], + "priority": "critical", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" +} diff --git a/examples/seam-definition.seam-008.json b/examples/seam-definition.seam-008.json new file mode 100644 index 0000000..a3acda5 --- /dev/null +++ b/examples/seam-definition.seam-008.json @@ -0,0 +1,15 @@ +{ + "type": "SeamDefinition", + "seam_id": "SEAM-008", + "name": "ManagedSpace → Spatial Auth", + "boundary_from": "ManagedSpace", + "boundary_to": "SpatialAuthorization", + "attack_vector": "displayUUID instability from firmware manipulation can corrupt spatial authorization contexts (which spaces/windows an agent may present in).", + "known_exploits": ["ANOMALY-008 displayUUID instability"], + "gate_requirements": ["displayUUID stability check", "attestation timestamp required on spatial authorization"], + "implementation_status": "open", + "linked_repos": ["SourceOS-Linux/agent-machine#T2-3"], + "priority": "high", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" +} diff --git a/examples/seam-definition.seam-013.json b/examples/seam-definition.seam-013.json new file mode 100644 index 0000000..5f68445 --- /dev/null +++ b/examples/seam-definition.seam-013.json @@ -0,0 +1,15 @@ +{ + "type": "SeamDefinition", + "seam_id": "SEAM-013", + "name": "Claude Desktop Telemetry → Platform Data", + "boundary_from": "ClaudeDesktopTelemetry", + "boundary_to": "PlatformData", + "attack_vector": "sessionSampleRate:100 (100% of sessions sampled) means sensitive output can route through a fully-sampled telemetry surface before reaching an intended consumer.", + "known_exploits": ["sessionSampleRate:100", "20% error telemetry", "MASK_USER_INPUT client-controlled"], + "gate_requirements": ["Telemetry boundary check in ActivationDecision (advisory)", "sensitive output must not route through a 100%-sampled surface"], + "implementation_status": "open", + "linked_repos": ["SourceOS-Linux/agent-machine#T2-1"], + "priority": "high", + "first_identified": "2026-06-09", + "last_reviewed": "2026-06-09" +} diff --git a/schemas/SeamDefinition.json b/schemas/SeamDefinition.json new file mode 100644 index 0000000..5a93f11 --- /dev/null +++ b/schemas/SeamDefinition.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/SeamDefinition.json", + "title": "SeamDefinition", + "description": "A typed architectural seam: an ungated boundary between two system layers that represents an attack surface. Seams are the estate's threat-model spine — each names where trust is not yet enforced, the vector that exploits it, and the gate that would close it. Canonical instance URN: urn:srcos:seam-definition:. Schema version 1.0.0.", + "type": "object", + "additionalProperties": false, + "required": [ + "seam_id", + "name", + "boundary_from", + "boundary_to", + "attack_vector", + "gate_requirements", + "implementation_status", + "priority" + ], + "properties": { + "type": { + "const": "SeamDefinition", + "description": "Object discriminator, matching the repo convention (examples are mapped to their schema by this field). Optional." + }, + "seam_id": { + "type": "string", + "minLength": 1, + "pattern": "^SEAM-[0-9]{3}$", + "description": "Stable seam identifier, e.g. SEAM-013. Slugged into the URN urn:srcos:seam-definition:." + }, + "name": { "type": "string", "minLength": 1, "description": "Human-readable seam name." }, + "boundary_from": { "type": "string", "minLength": 1, "description": "The layer the seam originates at (e.g. MDM)." }, + "boundary_to": { "type": "string", "minLength": 1, "description": "The layer the seam crosses into (e.g. usernoted)." }, + "attack_vector": { "type": "string", "minLength": 1, "description": "How the ungated boundary is exploited." }, + "known_exploits": { + "type": "array", + "items": { "type": "string" }, + "description": "Concrete observed exploits or indicators for this seam." + }, + "gate_requirements": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "description": "What must be enforced to close the seam. Required and non-empty: a seam with no stated gate is not actionable." + }, + "implementation_status": { + "type": "string", + "enum": ["open", "designed", "partially_gated", "implemented"], + "description": "Gate maturity for this seam." + }, + "linked_repos": { + "type": "array", + "items": { "type": "string" }, + "description": "Repos (and optionally issues) that own the gate work." + }, + "priority": { + "type": "string", + "enum": ["critical", "high", "medium"], + "description": "Remediation priority." + }, + "first_identified": { + "type": "string", + "format": "date", + "description": "Date the seam was first identified." + }, + "last_reviewed": { + "type": "string", + "format": "date", + "description": "Date the seam was last reviewed." + } + } +} diff --git a/tools/validate_seam_definition_examples.py b/tools/validate_seam_definition_examples.py new file mode 100644 index 0000000..eaaf89a --- /dev/null +++ b/tools/validate_seam_definition_examples.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +"""Validate SeamDefinition: typed architectural-seam registry objects (T0-2). + +A seam names an ungated boundary that is an attack surface. The invariants that +make a seam actionable are asserted BY REJECTION — a control never observed +refusing is indistinguishable from no control. + +Positive: every examples/seam-definition*.json validates; the set covers >= 3 +distinct seams. + +Negative (each fed to the SCHEMA; each MUST be rejected): + R1 implementation_status not one of the four allowed values + R2 empty gate_requirements (a seam with no stated gate is not actionable) + R3 missing seam_id (no stable identity) + R4 malformed seam_id (not SEAM-###) + R5 priority outside {critical, high, medium} +""" + +from __future__ import annotations + +import copy +import json +import sys +from pathlib import Path +from typing import Any + +try: + from jsonschema import Draft202012Validator +except ImportError: # pragma: no cover - installed by the Makefile target + print("FAIL: jsonschema is not installed; run `python3 -m pip install jsonschema`") + sys.exit(1) + +REPO_ROOT = Path(__file__).resolve().parents[1] +SCHEMA_PATH = REPO_ROOT / "schemas" / "SeamDefinition.json" +EXAMPLE_GLOB = "seam-definition*.json" +EXPECTED_STATUS = {"open", "designed", "partially_gated", "implemented"} + + +def load(path: Path) -> Any: + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + + +def fail(msg: str) -> None: + print(f"FAIL: {msg}") + sys.exit(1) + + +def main() -> int: + schema = load(SCHEMA_PATH) + Draft202012Validator.check_schema(schema) + validator = Draft202012Validator(schema) + + status_enum = ( + schema.get("properties", {}).get("implementation_status", {}).get("enum") + if isinstance(schema, dict) + else None + ) + if not isinstance(status_enum, list) or set(status_enum) != EXPECTED_STATUS: + fail(f"implementation_status enum must be exactly {sorted(EXPECTED_STATUS)}") + + example_paths = sorted((REPO_ROOT / "examples").glob(EXAMPLE_GLOB)) + if not example_paths: + fail(f"no example files matched examples/{EXAMPLE_GLOB}") + + seam_ids = set() + for path in example_paths: + seam = load(path) + if not isinstance(seam, dict): + fail(f"{path.name}: each example must be a single SeamDefinition object") + errors = sorted(validator.iter_errors(seam), key=lambda e: list(e.path)) + if errors: + lines = [f"{path.name} ({seam.get('seam_id', '?')}) failed validation:"] + for e in errors: + loc = ".".join(str(p) for p in e.path) or "" + lines.append(f" - {loc}: {e.message}") + fail("\n".join(lines)) + seam_ids.add(seam.get("seam_id")) + + if len(seam_ids) < 3: + fail(f"examples must cover at least three distinct seams, found {sorted(seam_ids)}") + + base = { + "seam_id": "SEAM-999", + "name": "Example seam", + "boundary_from": "A", + "boundary_to": "B", + "attack_vector": "example vector", + "gate_requirements": ["example gate"], + "implementation_status": "open", + "priority": "high", + } + + def must_reject(label: str, doc: dict[str, Any]) -> None: + if validator.is_valid(doc): + fail(f"{label}: document was ACCEPTED but must be rejected: {json.dumps(doc)}") + + r1 = copy.deepcopy(base); r1["implementation_status"] = "mostly_gated" + must_reject("R1 bad implementation_status", r1) + + r2 = copy.deepcopy(base); r2["gate_requirements"] = [] + must_reject("R2 empty gate_requirements", r2) + + r3 = copy.deepcopy(base); del r3["seam_id"] + must_reject("R3 missing seam_id", r3) + + r4 = copy.deepcopy(base); r4["seam_id"] = "seam-13" + must_reject("R4 malformed seam_id", r4) + + r5 = copy.deepcopy(base); r5["priority"] = "trivial" + must_reject("R5 bad priority", r5) + + print( + f"OK: SeamDefinition schema valid; {len(example_paths)} seams validated " + f"({', '.join(sorted(s for s in seam_ids if s))}); " + f"5 rejection invariants enforced (R1-R5)" + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())