Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.PHONY: validate operations-decision-smoke operations-decision-api-smoke product-suite-policy-validate model-fabric-release-policy-validate
.PHONY: validate operations-decision-smoke operations-decision-api-smoke product-suite-policy-validate model-fabric-release-policy-validate lattice-data-governai-policy-subjects-validate

validate: operations-decision-smoke operations-decision-api-smoke product-suite-policy-validate model-fabric-release-policy-validate
validate: operations-decision-smoke operations-decision-api-smoke product-suite-policy-validate model-fabric-release-policy-validate lattice-data-governai-policy-subjects-validate
@echo "OK: validate"

operations-decision-smoke:
Expand All @@ -16,3 +16,6 @@ product-suite-policy-validate:

model-fabric-release-policy-validate:
python3 tools/validate_model_fabric_release_policy.py

lattice-data-governai-policy-subjects-validate:
python3 tools/validate_lattice_data_governai_policy_subjects.py
137 changes: 137 additions & 0 deletions examples/lattice-data-governai-policy-subjects.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
{
"apiVersion": "policy.socioprophet.dev/v1",
"kind": "LatticeDataGovernAIPolicySubjectPack",
"metadata": {
"name": "lattice-data-governai-policy-subjects",
"version": "0.1.0",
"description": "Policy subject pack for Lattice data, runtime, notebook, model, prompt, agent, evaluation, factsheet, and publication assets."
},
"spec": {
"sourceOfTruth": "SocioProphet/policy-fabric",
"trackingRefs": [
"SocioProphet/prophet-platform#291",
"SocioProphet/prophet-platform#292",
"SourceOS-Linux/sourceos-spec#75",
"SocioProphet/lattice-forge#10",
"SocioProphet/prophet-platform-fabric-mlops-ts-suite#33"
],
"subjectKinds": [
"DataProduct",
"DataContract",
"RuntimeAsset",
"NotebookSession",
"QueryRun",
"ModelAsset",
"ModelZooEntry",
"PromptAsset",
"RAGPipeline",
"AgentAsset",
"EvaluationBundle",
"Factsheet",
"PublicationArtifact",
"ResearchPackage"
],
"actions": [
"discover",
"request-access",
"query",
"launch-runtime",
"run-notebook",
"run-ray-job",
"run-beam-pipeline",
"promote-model",
"promote-prompt",
"publish-research-package",
"execute-agent",
"export-artifact"
],
"promotionGates": {
"dataProductAccess": [
"ownerRef-present",
"dataContract-present",
"qualityProfile-present",
"licensePolicy-present",
"policyRef-present",
"evidenceRef-present"
],
"runtimeEligibility": [
"runtimeAssetRef-present",
"lockfile-or-buildRef-present",
"sbomRef-present",
"signatureRef-present",
"scanRef-present"
],
"modelPromotion": [
"trainingData-lineage-present",
"evaluationData-lineage-present",
"EvaluationBundle-present",
"Factsheet-present",
"approvalWorkflow-present"
],
"publicationReview": [
"PublicationArtifact-present",
"reproductionRecipe-present",
"ReviewThread-present",
"evidenceRefs-present"
],
"agentExecution": [
"AgentAsset-present",
"tool-scope-present",
"runtime-isolation-present",
"policyRef-present",
"replay-evidence-required"
]
},
"decisions": [
{
"decisionId": "decision:lattice:data-product-query:allow",
"subjectRef": "urn:srcos:data-product:community_truth_demo",
"subjectKind": "DataProduct",
"action": "query",
"result": "allow",
"because": [
"dataContract-present",
"qualityProfile-present",
"queryAllowed=true",
"policyRef-present"
],
"evidenceRefs": ["urn:srcos:evidence:community_truth_demo_data_product"]
},
{
"decisionId": "decision:lattice:model-promotion:review",
"subjectRef": "urn:srcos:model:community_truth_demo_candidate",
"subjectKind": "ModelAsset",
"action": "promote-model",
"result": "review-required",
"because": [
"EvaluationBundle.verdict=needs-review",
"Factsheet.approval.state=needs-review",
"riskTier=medium"
],
"evidenceRefs": ["urn:srcos:evidence:community_truth_demo_model_eval"]
},
{
"decisionId": "decision:lattice:publication-export:deny",
"subjectRef": "urn:srcos:publication-artifact:community_truth_demo_report",
"subjectKind": "PublicationArtifact",
"action": "export-artifact",
"result": "deny",
"because": [
"review.state=under-review",
"export requires accepted publication state",
"policyRef missing for export grant"
],
"evidenceRefs": ["urn:srcos:evidence:community_truth_demo_report"]
}
],
"nonNegotiables": {
"noParallelMetadataSpines": true,
"canonicalSchemaOwner": "SourceOS-Linux/sourceos-spec",
"platformRecordProducer": "SocioProphet/prophet-platform",
"executionConsumer": "SocioProphet/agentplane",
"searchConsumer": "SocioProphet/sherlock-search",
"topicConsumer": "SocioProphet/slash-topics",
"semanticMembraneConsumer": "SocioProphet/new-hope"
}
}
}
113 changes: 113 additions & 0 deletions tools/validate_lattice_data_governai_policy_subjects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env python3
from __future__ import annotations

import json
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
EXAMPLE = ROOT / "examples" / "lattice-data-governai-policy-subjects.example.json"

REQUIRED_SUBJECTS = {
"DataProduct",
"DataContract",
"RuntimeAsset",
"NotebookSession",
"QueryRun",
"ModelAsset",
"ModelZooEntry",
"PromptAsset",
"RAGPipeline",
"AgentAsset",
"EvaluationBundle",
"Factsheet",
"PublicationArtifact",
"ResearchPackage",
}
REQUIRED_ACTIONS = {
"discover",
"request-access",
"query",
"launch-runtime",
"run-notebook",
"run-ray-job",
"run-beam-pipeline",
"promote-model",
"promote-prompt",
"publish-research-package",
"execute-agent",
"export-artifact",
}
REQUIRED_GATES = {
"dataProductAccess",
"runtimeEligibility",
"modelPromotion",
"publicationReview",
"agentExecution",
}
REQUIRED_RESULTS = {"allow", "deny", "review-required"}


def fail(message: str) -> int:
print(f"ERROR: {message}", file=sys.stderr)
return 1


def require(condition: bool, message: str) -> None:
if not condition:
raise ValueError(message)


def main() -> int:
if not EXAMPLE.exists():
return fail(f"missing {EXAMPLE}")
try:
data = json.loads(EXAMPLE.read_text(encoding="utf-8"))
require(data.get("apiVersion") == "policy.socioprophet.dev/v1", "apiVersion must be policy.socioprophet.dev/v1")
require(data.get("kind") == "LatticeDataGovernAIPolicySubjectPack", "kind must be LatticeDataGovernAIPolicySubjectPack")
metadata = data.get("metadata")
require(isinstance(metadata, dict), "metadata must be object")
require(metadata.get("name") == "lattice-data-governai-policy-subjects", "metadata.name mismatch")
spec = data.get("spec")
require(isinstance(spec, dict), "spec must be object")

missing_subjects = sorted(REQUIRED_SUBJECTS - set(spec.get("subjectKinds", [])))
require(not missing_subjects, f"missing subject kinds: {missing_subjects}")
missing_actions = sorted(REQUIRED_ACTIONS - set(spec.get("actions", [])))
require(not missing_actions, f"missing actions: {missing_actions}")
gates = spec.get("promotionGates")
require(isinstance(gates, dict), "promotionGates must be object")
missing_gates = sorted(REQUIRED_GATES - set(gates))
require(not missing_gates, f"missing promotion gates: {missing_gates}")
for gate_name, requirements in gates.items():
require(isinstance(requirements, list) and requirements, f"promotionGates.{gate_name} must be non-empty list")

decisions = spec.get("decisions")
require(isinstance(decisions, list) and len(decisions) >= 3, "decisions must include at least three examples")
result_set = set()
for decision in decisions:
require(isinstance(decision, dict), "decision entries must be objects")
for key in ["decisionId", "subjectRef", "subjectKind", "action", "result", "because", "evidenceRefs"]:
require(key in decision, f"decision missing {key}")
require(decision["subjectKind"] in REQUIRED_SUBJECTS, f"unknown decision subjectKind {decision['subjectKind']}")
require(decision["action"] in REQUIRED_ACTIONS, f"unknown decision action {decision['action']}")
require(decision["result"] in REQUIRED_RESULTS, f"unknown decision result {decision['result']}")
require(isinstance(decision["because"], list) and decision["because"], "decision.because must be non-empty")
require(isinstance(decision["evidenceRefs"], list) and decision["evidenceRefs"], "decision.evidenceRefs must be non-empty")
result_set.add(decision["result"])
missing_results = sorted(REQUIRED_RESULTS - result_set)
require(not missing_results, f"missing decision result examples: {missing_results}")

non_negotiables = spec.get("nonNegotiables")
require(isinstance(non_negotiables, dict), "nonNegotiables must be object")
require(non_negotiables.get("noParallelMetadataSpines") is True, "noParallelMetadataSpines must be true")
require(non_negotiables.get("canonicalSchemaOwner") == "SourceOS-Linux/sourceos-spec", "canonicalSchemaOwner mismatch")
except Exception as exc: # noqa: BLE001
return fail(str(exc))

print("OK: validated Lattice Data/GovernAI policy-subject pack")
return 0


if __name__ == "__main__":
raise SystemExit(main())
Loading