← Files VeraARCHIVED FILE
skills/privacy-surface-review/scripts/validate_privacy_surfaces.py
35.5 KB · Oct 4, 2026 · 12:28 UTC
#!/usr/bin/env python3
"""Validate Vera external-boundary coverage and source freshness.
The checks are deterministic because registration, JSON shape, confirmation
consistency, and byte fingerprints are mechanically verifiable. Purpose-based
data minimisation and legal compliance remain outside this validator.
"""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
from typing import Any, Iterable
__all__ = ["main", "validate_privacy_surfaces"]
SKIP_DIRS = {".git", ".mypy_cache", ".pytest_cache", ".ruff_cache", "__pycache__"}
SKIP_SUFFIXES = {".pyc", ".pyo"}
MODEL_CONTEXT_POLICY = "real_case_data_may_enter_selected_runtime_model_context"
BOUNDARY_KINDS = {
"public_research",
"hosted_service",
"external_connector",
"send_or_publish",
}
SERVICE_BOUNDARY_KINDS = {"hosted_service", "send_or_publish"}
ACCOUNT_REVIEW_ITEMS = [
"account_or_workspace_plan",
"model_training_data_controls",
"retention_and_deletion_controls",
]
ACCOUNT_BOUNDARY = {
"selected_by": "firm_or_user",
"vera_runtime_enforcement": "none",
"review_timing": "before_professional_use_and_when_account_or_terms_change",
"review_items": ACCOUNT_REVIEW_ITEMS,
"per_case_record_required": False,
}
EXPECTED_RUNTIME_PROFILES = {
"openai-codex": {
"provider": "OpenAI",
"runtime": "Codex",
"surfaces": ["codex"],
"account_boundary": ACCOUNT_BOUNDARY,
"model_processing": {
"scope": "ordinary_openai_codex_model_processing",
"destination": "OpenAI model processing used by Codex",
"account_arrangement": (
"existing_openai_codex_account_or_workspace_selected_by_firm_or_user"
),
"separate_vera_recipient": False,
"automatic_anonymization": False,
"local_only": False,
"local_filtering_or_aggregation": "only_when_useful_for_the_work",
},
},
"anthropic-cowork": {
"provider": "Anthropic",
"runtime": "Cowork",
"surfaces": ["cowork"],
"account_boundary": ACCOUNT_BOUNDARY,
"model_processing": {
"scope": "ordinary_anthropic_cowork_model_processing",
"destination": "Anthropic model processing used by Cowork",
"account_arrangement": (
"existing_anthropic_claude_account_or_workspace_selected_by_firm_or_user"
),
"separate_vera_recipient": False,
"automatic_anonymization": False,
"local_only": False,
"local_filtering_or_aggregation": "only_when_useful_for_the_work",
},
},
}
RUNTIME_PROFILE_IDS = list(EXPECTED_RUNTIME_PROFILES)
def _vera_root() -> Path:
return Path(__file__).resolve().parents[3]
def _components(vera_root: Path) -> tuple[set[str], dict[str, dict[str, Any]]]:
payload = json.loads((vera_root / "components.json").read_text(encoding="utf-8"))
names = set(payload["plugins"])
roles = payload.get("workflow_roles", {})
return names, roles
def _shared_services(vera_root: Path) -> set[str]:
payload = json.loads((vera_root / "components.json").read_text(encoding="utf-8"))
return set(payload.get("shared_services", []))
def _runtime_profile_errors(vera_root: Path) -> list[str]:
path = vera_root / "privacy" / "runtime-profiles.json"
try:
payload = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
return [f"runtime-profiles: cannot read profile catalog: {exc}"]
if not isinstance(payload, dict):
return ["runtime-profiles: catalog must be an object"]
errors: list[str] = []
if payload.get("schema_version") != 1:
errors.append("runtime-profiles: schema_version must be 1")
profiles = payload.get("profiles")
if not isinstance(profiles, list):
return [*errors, "runtime-profiles: profiles must be an array"]
profile_ids = [
str(profile.get("id", "")) if isinstance(profile, dict) else ""
for profile in profiles
]
if len(profile_ids) != len(set(profile_ids)):
errors.append("runtime-profiles: profile ids must be unique")
if profile_ids != RUNTIME_PROFILE_IDS:
errors.append(
"runtime-profiles: profiles must contain openai-codex and "
"anthropic-cowork in that order"
)
for index, profile in enumerate(profiles):
if not isinstance(profile, dict):
errors.append(f"runtime-profiles: profile[{index}] must be an object")
continue
profile_id = str(profile.get("id", ""))
expected = EXPECTED_RUNTIME_PROFILES.get(profile_id)
if expected is None:
errors.append(f"runtime-profiles: profile[{index}] has unknown id")
continue
actual = {key: value for key, value in profile.items() if key != "id"}
if actual != expected:
errors.append(
f"runtime-profiles: {profile_id} account or model-processing "
"boundary is inaccurate"
)
return errors
def _component_root(vera_root: Path, workstream: str) -> Path:
packaged = vera_root / "modules" / workstream
if packaged.is_dir():
return packaged
source = vera_root.parent / workstream
if source.is_dir():
return source
raise FileNotFoundError(f"component source not found: {workstream}")
def _governed_files(component_root: Path, paths: Iterable[str]) -> list[Path]:
files: set[Path] = set()
for relative in paths:
target = component_root / relative
if target.is_file():
files.add(target)
continue
if not target.is_dir():
raise FileNotFoundError(f"governed path not found: {target}")
for path in target.rglob("*"):
if not path.is_file():
continue
rel_parts = path.relative_to(component_root).parts
if any(part in SKIP_DIRS for part in rel_parts):
continue
if path.suffix in SKIP_SUFFIXES:
continue
files.add(path)
return sorted(files, key=lambda item: item.relative_to(component_root).as_posix())
def _shared_governed_files(
vera_root: Path, paths: Iterable[str], *, packaged: bool
) -> dict[str, Path]:
"""Resolve package-relative shared files from source or an installed Vera."""
logical_files: dict[str, Path] = {}
source_root = vera_root if packaged else vera_root.parent / "_shared"
resolved_source_root = source_root.resolve()
for value in paths:
relative = Path(value)
if relative.is_absolute() or ".." in relative.parts:
raise ValueError(f"governed shared path must be package-relative: {value}")
target = source_root / relative
if target.is_symlink():
raise ValueError(f"governed shared path must not be a symlink: {target}")
try:
target.resolve(strict=True).relative_to(resolved_source_root)
except (FileNotFoundError, ValueError) as exc:
raise FileNotFoundError(
f"governed shared path not found or outside source root: {target}"
) from exc
if target.is_file():
logical_files[f"vera-shared/{relative.as_posix()}"] = target
continue
if not target.is_dir():
raise FileNotFoundError(f"governed shared path not found: {target}")
for path in target.rglob("*"):
if path.is_symlink():
raise ValueError(
f"governed shared source must not use symlinks: {path}"
)
if not path.is_file():
continue
rel_parts = path.relative_to(target).parts
if any(part in SKIP_DIRS for part in rel_parts):
continue
if path.suffix in SKIP_SUFFIXES:
continue
logical_path = relative / path.relative_to(target)
logical_files[f"vera-shared/{logical_path.as_posix()}"] = path
return logical_files
def _repository_governed_files(
vera_root: Path,
paths: Iterable[str],
) -> dict[str, Path]:
"""Resolve repository-root-relative hosted service source without escapes."""
logical_files: dict[str, Path] = {}
repository_root = vera_root.parents[1]
resolved_repository_root = repository_root.resolve()
for value in paths:
relative = Path(value)
if relative.is_absolute() or ".." in relative.parts:
raise ValueError(
f"governed repository path must be repository-relative: {value}"
)
target = repository_root / relative
if target.is_symlink():
raise ValueError(
f"governed repository path must not be a symlink: {target}"
)
try:
target.resolve(strict=True).relative_to(resolved_repository_root)
except (FileNotFoundError, ValueError) as exc:
raise FileNotFoundError(
"governed repository path not found or outside repository: " f"{target}"
) from exc
if target.is_file():
logical_files[f"repository:{relative.as_posix()}"] = target
continue
if not target.is_dir():
raise FileNotFoundError(f"governed repository path not found: {target}")
for path in target.rglob("*"):
if path.is_symlink():
raise ValueError(
f"governed repository source must not use symlinks: {path}"
)
if not path.is_file():
continue
rel_parts = path.relative_to(target).parts
if any(part in SKIP_DIRS for part in rel_parts):
continue
if path.suffix in SKIP_SUFFIXES:
continue
logical_path = relative / path.relative_to(target)
logical_files[f"repository:{logical_path.as_posix()}"] = path
return logical_files
def _fingerprint(
component_root: Path,
paths: Iterable[str],
*,
wrapper: Path | None = None,
vera_root: Path | None = None,
shared_paths: Iterable[str] = (),
repository_paths: Iterable[str] = (),
) -> str:
governed_paths = tuple(paths)
logical_files = {
path.relative_to(component_root).as_posix(): path
for path in _governed_files(component_root, governed_paths)
}
shared_governed_paths = tuple(shared_paths)
if shared_governed_paths:
if vera_root is None:
raise ValueError("vera_root is required for governed shared paths")
try:
component_root.resolve().relative_to((vera_root / "modules").resolve())
packaged = True
except ValueError:
packaged = False
logical_files.update(
_shared_governed_files(vera_root, shared_governed_paths, packaged=packaged)
)
repository_governed_paths = tuple(repository_paths)
if repository_governed_paths:
if vera_root is None:
raise ValueError("vera_root is required for governed repository paths")
logical_files.update(
_repository_governed_files(vera_root, repository_governed_paths)
)
projected_review_server = "scripts/review_server.py"
adapter = component_root / "assets" / "review-workbench-adapter.json"
source_review_server = component_root / projected_review_server
scripts_are_governed = any(
relative == "scripts" or relative == projected_review_server
for relative in governed_paths
)
if (
adapter.is_file()
and json.loads(adapter.read_text(encoding="utf-8")).get("injectLocalServer")
is not False
and scripts_are_governed
and not source_review_server.is_file()
):
repository_root = component_root.parents[1]
shared_review_server = repository_root / "scripts" / "serve_review_workbench.py"
if not shared_review_server.is_file():
raise FileNotFoundError(
"shared review workbench source not found: " f"{shared_review_server}"
)
logical_files[projected_review_server] = shared_review_server
digest = hashlib.sha256()
for logical_path, path in sorted(logical_files.items()):
relative = logical_path.encode("utf-8")
digest.update(len(relative).to_bytes(4, "big"))
digest.update(relative)
content = path.read_bytes()
digest.update(len(content).to_bytes(8, "big"))
digest.update(content)
if wrapper is not None:
wrapper_root = wrapper.parent
wrapper_files = _governed_files(wrapper_root, (".",))
if wrapper not in wrapper_files:
raise FileNotFoundError(f"workflow wrapper not found: {wrapper}")
for path in wrapper_files:
logical_path = (
Path("vera-wrapper") / path.relative_to(wrapper_root)
).as_posix()
digest.update(logical_path.encode("utf-8"))
content = path.read_bytes()
digest.update(len(content).to_bytes(8, "big"))
digest.update(content)
return digest.hexdigest()
def _boundary_errors(
boundaries: Any,
*,
scope: str,
allowed_kinds: set[str],
manifest_runtime_profiles: Any,
require_retention: bool = False,
require_activation: bool = False,
) -> list[str]:
errors: list[str] = []
if not isinstance(boundaries, list):
return [f"{scope}: external_boundaries must be an array"]
available_profiles = (
set(manifest_runtime_profiles)
if isinstance(manifest_runtime_profiles, list)
else set()
)
boundary_ids: list[str] = []
for index, boundary in enumerate(boundaries):
if not isinstance(boundary, dict):
errors.append(f"{scope}: boundary[{index}] must be an object")
continue
fields = {
"id",
"kind",
"destination",
"purpose",
"content",
"optional",
"requires_confirmation",
"controls",
"runtime_profiles",
}
text_fields = ["id", "destination", "purpose", "content"]
if require_retention:
fields.add("retention")
text_fields.append("retention")
if require_activation:
fields.add("activation")
text_fields.append("activation")
if fields - boundary.keys():
errors.append(f"{scope}: boundary[{index}] is incomplete")
if not all(
isinstance(boundary.get(field), str) and boundary[field].strip()
for field in text_fields
):
errors.append(f"{scope}: boundary[{index}] text must be non-empty")
boundary_ids.append(str(boundary.get("id", "")))
if boundary.get("kind") not in allowed_kinds:
errors.append(f"{scope}: boundary[{index}] has invalid kind")
optional = boundary.get("optional")
confirmation = boundary.get("requires_confirmation")
if not isinstance(optional, bool) or not isinstance(confirmation, bool):
errors.append(f"{scope}: boundary[{index}] flags must be boolean")
elif confirmation and not optional:
errors.append(
f"{scope}: confirmation is allowed only for an optional boundary"
)
if require_activation:
activation = boundary.get("activation")
automatic = {
"automatic_session_start",
"automatic_on_first_use",
"automatic_after_prior_submission",
"automatic_after_prior_connection",
"automatic_per_durable_run",
}
if activation not in automatic | {"explicit_user_choice"}:
errors.append(f"{scope}: boundary[{index}] has invalid activation")
elif activation == "explicit_user_choice" and (
optional is not True or confirmation is not True
):
errors.append(
f"{scope}: explicit user choice must be optional and confirmed"
)
elif activation in automatic and (
optional is not False or confirmation is not False
):
errors.append(
f"{scope}: automatic boundary cannot request confirmation"
)
controls = boundary.get("controls")
if (
not isinstance(controls, list)
or not controls
or not all(isinstance(item, str) and item.strip() for item in controls)
):
errors.append(f"{scope}: boundary[{index}] controls must be non-empty")
profiles = boundary.get("runtime_profiles")
if (
not isinstance(profiles, list)
or not profiles
or not all(isinstance(item, str) and item for item in profiles)
):
errors.append(
f"{scope}: boundary[{index}] runtime_profiles must be non-empty strings"
)
elif len(profiles) != len(set(profiles)):
errors.append(f"{scope}: boundary[{index}] runtime_profiles must be unique")
elif not set(profiles) <= available_profiles:
errors.append(
f"{scope}: boundary[{index}] references a runtime outside the manifest"
)
if len(boundary_ids) != len(set(boundary_ids)):
errors.append(f"{scope}: boundary ids must be unique")
return errors
def _security_control_errors(
controls: Any,
*,
scope: str,
governed_paths: Iterable[str] = (),
require_implementation: bool = False,
) -> list[str]:
errors: list[str] = []
if not isinstance(controls, list):
return [f"{scope}: security_controls must be an array"]
control_ids: list[str] = []
for index, control in enumerate(controls):
if not isinstance(control, dict):
errors.append(f"{scope}: security_controls[{index}] must be an object")
continue
if not all(
isinstance(control.get(field), str) and control[field].strip()
for field in ("id", "control")
):
errors.append(f"{scope}: security_controls[{index}] is incomplete")
if require_implementation:
implementations = control.get("implemented_by")
on_violation = control.get("on_violation")
if (
not isinstance(implementations, list)
or not implementations
or not all(
isinstance(item, str) and item.strip() for item in implementations
)
or not isinstance(on_violation, str)
or not on_violation.strip()
):
errors.append(
f"{scope}: security_controls[{index}] lacks executable support"
)
else:
governed = tuple(governed_paths)
for implementation in implementations:
implementation_path = Path(implementation)
if (
implementation_path.is_absolute()
or ".." in implementation_path.parts
):
errors.append(
f"{scope}: security_controls[{index}] has unsafe implementation path"
)
continue
covered = any(
implementation == path
or implementation.startswith(path.rstrip("/") + "/")
for path in governed
)
if not covered:
errors.append(
f"{scope}: security_controls[{index}] implementation is not governed"
)
control_ids.append(str(control.get("id", "")))
if len(control_ids) != len(set(control_ids)):
errors.append(f"{scope}: security control ids must be unique")
return errors
def _runtime_profile_reference_errors(
profiles: Any,
*,
scope: str,
require_all: bool,
) -> list[str]:
if (
not isinstance(profiles, list)
or not profiles
or not all(isinstance(item, str) and item for item in profiles)
):
return [f"{scope}: runtime_profiles must be non-empty strings"]
errors: list[str] = []
if len(profiles) != len(set(profiles)):
errors.append(f"{scope}: runtime_profiles must be unique")
unknown = sorted(set(profiles) - set(RUNTIME_PROFILE_IDS))
if unknown:
errors.append(f"{scope}: unknown runtime_profiles: {', '.join(unknown)}")
if require_all and profiles != RUNTIME_PROFILE_IDS:
errors.append(
f"{scope}: every workstream must reference openai-codex and "
"anthropic-cowork in that order"
)
return errors
def _manifest_errors(
payload: dict[str, Any], *, workstream: str, expected_role: str
) -> list[str]:
errors: list[str] = []
required = {
"schema_version",
"workstream",
"display_name",
"role",
"governed_paths",
"runtime_profiles",
"model_context",
"external_boundaries",
"security_controls",
"review",
}
missing = sorted(required - payload.keys())
if missing:
return [f"{workstream}: missing fields: {', '.join(missing)}"]
if payload["schema_version"] != 3:
errors.append(f"{workstream}: schema_version must be 3")
if payload["workstream"] != workstream:
errors.append(f"{workstream}: manifest workstream does not match filename")
if (
not isinstance(payload["display_name"], str)
or not payload["display_name"].strip()
):
errors.append(f"{workstream}: display_name must be non-empty")
if payload["role"] != expected_role:
errors.append(f"{workstream}: role must be {expected_role}")
governed = payload["governed_paths"]
if (
not isinstance(governed, list)
or not governed
or not all(isinstance(item, str) and item for item in governed)
):
errors.append(f"{workstream}: governed_paths must be non-empty strings")
shared_governed = payload.get("governed_shared_paths", [])
if not isinstance(shared_governed, list) or not all(
isinstance(item, str) and item for item in shared_governed
):
errors.append(f"{workstream}: governed_shared_paths must be strings")
repository_governed = payload.get("governed_repository_paths", [])
if not isinstance(repository_governed, list) or not all(
isinstance(item, str) and item for item in repository_governed
):
errors.append(f"{workstream}: governed_repository_paths must be strings")
errors.extend(
_runtime_profile_reference_errors(
payload["runtime_profiles"],
scope=workstream,
require_all=True,
)
)
context = payload["model_context"]
if not isinstance(context, dict):
errors.append(f"{workstream}: model_context must be an object")
else:
if context.get("policy") != MODEL_CONTEXT_POLICY:
errors.append(f"{workstream}: unexpected model-context policy")
classes = context.get("classes")
if not isinstance(classes, list) or not classes:
errors.append(f"{workstream}: model_context.classes must be non-empty")
classes = []
context_ids: list[str] = []
for index, item in enumerate(classes):
if not isinstance(item, dict):
errors.append(
f"{workstream}: model_context.classes[{index}] must be an object"
)
continue
fields = {"id", "purpose", "content", "runtime_profiles"}
if fields - item.keys() or not all(
isinstance(item.get(field), str) and item[field].strip()
for field in ("id", "purpose", "content")
):
errors.append(
f"{workstream}: model_context.classes[{index}] is incomplete"
)
profiles = item.get("runtime_profiles")
if (
not isinstance(profiles, list)
or not profiles
or not all(isinstance(value, str) and value for value in profiles)
or len(profiles) != len(set(profiles))
or not set(profiles) <= set(payload["runtime_profiles"])
):
errors.append(
f"{workstream}: model_context.classes[{index}] has invalid "
"runtime_profiles"
)
context_ids.append(str(item.get("id", "")))
if len(context_ids) != len(set(context_ids)):
errors.append(f"{workstream}: model_context ids must be unique")
errors.extend(
_boundary_errors(
payload["external_boundaries"],
scope=workstream,
allowed_kinds=BOUNDARY_KINDS,
manifest_runtime_profiles=payload["runtime_profiles"],
)
)
errors.extend(
_security_control_errors(payload["security_controls"], scope=workstream)
)
review = payload["review"]
if not isinstance(review, dict):
errors.append(f"{workstream}: review must be an object")
else:
if review.get("reviewed_by") != "privacy-surface-review":
errors.append(f"{workstream}: unexpected reviewer")
if review.get("basis") != "external_boundary_review_of_workflow_source":
errors.append(f"{workstream}: unexpected external-boundary review basis")
fingerprint = review.get("source_fingerprint")
if not isinstance(fingerprint, str) or len(fingerprint) != 64:
errors.append(f"{workstream}: invalid source fingerprint")
return errors
def _service_manifest_errors(payload: dict[str, Any], *, service_id: str) -> list[str]:
errors: list[str] = []
required = {
"schema_version",
"service_id",
"display_name",
"governed_paths",
"runtime_profiles",
"external_boundaries",
"security_controls",
"review",
}
missing = sorted(required - payload.keys())
if missing:
return [f"{service_id}: missing fields: {', '.join(missing)}"]
if payload["schema_version"] != 2:
errors.append(f"{service_id}: schema_version must be 2")
if payload["service_id"] != service_id:
errors.append(f"{service_id}: manifest service_id does not match filename")
if (
not isinstance(payload["display_name"], str)
or not payload["display_name"].strip()
):
errors.append(f"{service_id}: display_name must be non-empty")
governed = payload["governed_paths"]
if (
not isinstance(governed, list)
or not governed
or not all(isinstance(item, str) and item for item in governed)
):
errors.append(f"{service_id}: governed_paths must be non-empty strings")
repository_governed = payload.get("governed_repository_paths", [])
if not isinstance(repository_governed, list) or not all(
isinstance(item, str) and item for item in repository_governed
):
errors.append(f"{service_id}: governed_repository_paths must be strings")
errors.extend(
_runtime_profile_reference_errors(
payload["runtime_profiles"],
scope=service_id,
require_all=False,
)
)
errors.extend(
_boundary_errors(
payload["external_boundaries"],
scope=service_id,
allowed_kinds=SERVICE_BOUNDARY_KINDS,
manifest_runtime_profiles=payload["runtime_profiles"],
require_retention=True,
require_activation=True,
)
)
errors.extend(
_security_control_errors(
payload["security_controls"],
scope=service_id,
governed_paths=[
*payload["governed_paths"],
*(
f"repository:{path}"
for path in payload.get("governed_repository_paths", [])
),
],
require_implementation=True,
)
)
review = payload["review"]
if not isinstance(review, dict):
errors.append(f"{service_id}: review must be an object")
else:
if review.get("reviewed_by") != "privacy-surface-review":
errors.append(f"{service_id}: unexpected reviewer")
if review.get("basis") != "external_boundary_review_of_shared_service_source":
errors.append(f"{service_id}: unexpected external-boundary review basis")
fingerprint = review.get("source_fingerprint")
if not isinstance(fingerprint, str) or len(fingerprint) != 64:
errors.append(f"{service_id}: invalid source fingerprint")
return errors
def _expected_role(workstream: str, roles: dict[str, dict[str, Any]]) -> str:
return str(roles.get(workstream, {}).get("kind", "workflow"))
def validate_privacy_surfaces(vera_root: Path | None = None) -> list[str]:
root = vera_root or _vera_root()
names, roles = _components(root)
manifest_dir = root / "privacy" / "workstreams"
manifests = {path.stem: path for path in manifest_dir.glob("*.json")}
errors = _runtime_profile_errors(root)
for missing in sorted(names - manifests.keys()):
errors.append(f"{missing}: registered workstream has no privacy manifest")
for extra in sorted(manifests.keys() - names):
errors.append(f"{extra}: privacy manifest is not a registered workstream")
for workstream in sorted(names & manifests.keys()):
path = manifests[workstream]
try:
payload = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
errors.append(f"{workstream}: cannot read manifest: {exc}")
continue
role = _expected_role(workstream, roles)
manifest_errors = _manifest_errors(
payload, workstream=workstream, expected_role=role
)
errors.extend(manifest_errors)
if manifest_errors:
continue
try:
component_root = _component_root(root, workstream)
wrapper = (
root
/ "skills"
/ roles.get(workstream, {}).get("skill", workstream)
/ "SKILL.md"
if role != "internal_engine"
else None
)
actual = _fingerprint(
component_root,
payload["governed_paths"],
wrapper=wrapper,
vera_root=root,
shared_paths=payload.get("governed_shared_paths", []),
repository_paths=payload.get("governed_repository_paths", []),
)
except (OSError, ValueError) as exc:
errors.append(f"{workstream}: cannot fingerprint governed source: {exc}")
continue
if actual != payload["review"]["source_fingerprint"]:
errors.append(
f"{workstream}: privacy review is stale; run the review skill, then --refresh"
)
service_names = _shared_services(root)
service_dir = root / "privacy" / "services"
service_manifests = {path.stem: path for path in service_dir.glob("*.json")}
for missing in sorted(service_names - service_manifests.keys()):
errors.append(f"{missing}: registered shared service has no privacy manifest")
for extra in sorted(service_manifests.keys() - service_names):
errors.append(f"{extra}: privacy manifest is not a registered shared service")
for service_id in sorted(service_names & service_manifests.keys()):
path = service_manifests[service_id]
try:
payload = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
errors.append(f"{service_id}: cannot read manifest: {exc}")
continue
manifest_errors = _service_manifest_errors(payload, service_id=service_id)
errors.extend(manifest_errors)
if manifest_errors:
continue
try:
actual = _fingerprint(
root,
payload["governed_paths"],
vera_root=root,
repository_paths=payload.get("governed_repository_paths", []),
)
except (OSError, ValueError) as exc:
errors.append(
f"{service_id}: cannot fingerprint governed service source: {exc}"
)
continue
if actual != payload["review"]["source_fingerprint"]:
errors.append(
f"{service_id}: privacy review is stale; run the review skill, "
"then --refresh-service"
)
return errors
def _refresh(workstream: str, vera_root: Path) -> None:
names, _ = _components(vera_root)
selected = sorted(names) if workstream == "all" else [workstream]
for name in selected:
if name not in names:
raise ValueError(f"unknown registered workstream: {name}")
manifest_path = vera_root / "privacy" / "workstreams" / f"{name}.json"
payload = json.loads(manifest_path.read_text(encoding="utf-8"))
component_root = _component_root(vera_root, name)
_, roles = _components(vera_root)
role = _expected_role(name, roles)
wrapper = (
vera_root / "skills" / roles.get(name, {}).get("skill", name) / "SKILL.md"
if role != "internal_engine"
else None
)
payload["review"]["source_fingerprint"] = _fingerprint(
component_root,
payload["governed_paths"],
wrapper=wrapper,
vera_root=vera_root,
shared_paths=payload.get("governed_shared_paths", []),
repository_paths=payload.get("governed_repository_paths", []),
)
manifest_path.write_text(
json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
)
print(f"refreshed {name}")
def _refresh_service(service_id: str, vera_root: Path) -> None:
names = _shared_services(vera_root)
selected = sorted(names) if service_id == "all" else [service_id]
for name in selected:
if name not in names:
raise ValueError(f"unknown registered shared service: {name}")
manifest_path = vera_root / "privacy" / "services" / f"{name}.json"
payload = json.loads(manifest_path.read_text(encoding="utf-8"))
payload["review"]["source_fingerprint"] = _fingerprint(
vera_root,
payload["governed_paths"],
vera_root=vera_root,
repository_paths=payload.get("governed_repository_paths", []),
)
manifest_path.write_text(
json.dumps(payload, ensure_ascii=False, indent=2) + "\n",
encoding="utf-8",
)
print(f"refreshed service {name}")
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--refresh", metavar="WORKSTREAM")
parser.add_argument("--refresh-service", metavar="SERVICE")
parser.add_argument("--refresh-all", action="store_true")
args = parser.parse_args()
root = _vera_root()
selected_refreshes = sum(
bool(value) for value in (args.refresh, args.refresh_service, args.refresh_all)
)
if selected_refreshes > 1:
parser.error("choose --refresh, --refresh-service, or --refresh-all")
if args.refresh_all:
_refresh("all", root)
_refresh_service("all", root)
elif args.refresh:
_refresh(args.refresh, root)
elif args.refresh_service:
_refresh_service(args.refresh_service, root)
errors = validate_privacy_surfaces(root)
if errors:
for error in errors:
print(f"ERROR: {error}")
return 1
print("Vera privacy surfaces are complete and current.")
return 0
if __name__ == "__main__":
raise SystemExit(main())
SHA-256: d3de93eb636c54fc0d153b5d661c4e44c47787e4a827cc4e7e8a89a52caa65aa