diff --git a/docs/WORKSPACE_ACCESS_AUDIT.md b/docs/WORKSPACE_ACCESS_AUDIT.md index 1f05bc6..493c055 100644 --- a/docs/WORKSPACE_ACCESS_AUDIT.md +++ b/docs/WORKSPACE_ACCESS_AUDIT.md @@ -6,7 +6,8 @@ scans the Simplicio-owned source scopes and emits `simplicio.workspace-access-manifest/v1`. Every direct filesystem, process, or tree-walk call site must have an owner, -rationale, and classification. `violation` and unclassified findings fail the +rationale, and classification. The audit rejects manifest rules that omit a +non-empty owner or rationale before scanning source. `violation` and unclassified findings fail the gate; test fixtures and the short bootstrap allowlist remain explicit. The manifest intentionally records the current `xai-grok-workspace` bypasses as violations so the audit cannot be mistaken for proof that the migration is diff --git a/scripts/audit_workspace_access.py b/scripts/audit_workspace_access.py index b1fe804..da81bf6 100644 --- a/scripts/audit_workspace_access.py +++ b/scripts/audit_workspace_access.py @@ -40,6 +40,11 @@ def audit(root: Path, manifest: Path) -> dict[str, Any]: rules = spec.get("rules") if not isinstance(rules, list): raise ValueError("manifest rules must be a list") + for index, rule in enumerate(rules): + if not isinstance(rule, dict): + raise ValueError(f"manifest rule {index} must be an object") + if not str(rule.get("owner", "")).strip() or not str(rule.get("rationale", "")).strip(): + raise ValueError(f"manifest rule {index} requires owner and rationale") findings: list[dict[str, Any]] = [] for scope in spec.get("scopes", ["crates/codegen"]): diff --git a/scripts/tests/test_workspace_access_audit.py b/scripts/tests/test_workspace_access_audit.py index 3789779..462c351 100644 --- a/scripts/tests/test_workspace_access_audit.py +++ b/scripts/tests/test_workspace_access_audit.py @@ -93,6 +93,7 @@ def test_baseline_allows_removing_an_occurrence(tmp_path): [ ({"schema": "wrong"}, "unsupported manifest schema"), ({"rules": {}}, "manifest rules must be a list"), + ({"rules": [{"path": "src/**", "kind": "process", "classification": "bootstrap-allowlisted", "owner": ""}]}, "requires owner and rationale"), ({"baseline": {}}, "manifest baseline must be a list"), ({"baseline": ["bad"]}, "baseline entries must be objects"), ({"baseline": [{}]}, "baseline entries require"),