#!/usr/bin/env python3 """Run the bounded, cross-platform repository verification gate.""" from __future__ import annotations import json import shutil import subprocess import sys import sysconfig import tomllib from pathlib import Path ROOT = Path(__file__).resolve().parents[1] def run(label: str, command: list[str]) -> None: print(f"== {label} ==") result = subprocess.run(command, cwd=ROOT, check=False) # noqa: S603 if result.returncode: raise SystemExit(result.returncode) def uv_command() -> str | None: resolved = shutil.which("uv") if resolved: return resolved candidates = [ Path(sysconfig.get_path("scripts")) / "uv.exe", Path(sysconfig.get_path("scripts")) / "uv", Path.home() / "AppData" / "Roaming" / "Python" / f"Python{sys.version_info.major}{sys.version_info.minor}" / "Scripts" / "uv.exe", ] return next((str(path) for path in candidates if path.is_file()), None) def validate_metadata() -> None: pyproject = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8")) package = json.loads((ROOT / "package.json").read_text(encoding="utf-8")) project = pyproject["project"] assert project["requires-python"] == ">=3.13,<3.14" assert "mcp==2.0.0" in project["dependencies"] assert package["private"] is True assert package["packageManager"] == "pnpm@10.33.0" assert package["workspaces"] == ["apps/*", "packages/*"] for relative in ( "apps", "services", "connectors", "packages", "tests", "infrastructure", "evidence", "docs", ): assert (ROOT / relative).is_dir(), f"missing repository root: {relative}" for lockfile in ("uv.lock", "pnpm-lock.yaml"): assert (ROOT / lockfile).is_file(), f"missing lockfile: {lockfile}" print("Workspace metadata and lockfiles: PASS") def main() -> int: validate_metadata() python_quality_files = [ "scripts/audit_projectbrain_contracts.py", "tests/test_projectbrain_contract_audit.py", "scripts/check_boundaries.py", "scripts/check_build_reproducibility.py", "scripts/verify.py", "scripts/create_manifest.py", "scripts/validate_pack.py", "scripts/security_scan.py", "scripts/generate_sbom.py", "scripts/generate_image_sboms.py", "scripts/discover_unraid.py", "scripts/backup_state.py", "scripts/write_backup_status.py", "scripts/restore_state.py", "scripts/compose_release_check.py", "scripts/promotion_preflight.py", "scripts/publish_mcp_hub_ingestion.py", "scripts/build_mcp_hub_release_images.py", "scripts/prepare_release_security_bases.py", "scripts/package_mcp_hub_release_artifact.py", "scripts/export_release.py", "scripts/render_release_record.py", "scripts/verify_demo_token_flow.py", "scripts/draft_cve_exceptions.py", "scripts/check_cve_exceptions.py", "infrastructure/images/python-service/health_server.py", "infrastructure/images/observability/collector.py", "infrastructure/database/alembic/versions/0002_knowledge_search.py", "infrastructure/database/alembic/versions/0003_policy_trace.py", "infrastructure/database/alembic/versions/0004_audit_retention.py", "tests/test_auth.py", "tests/test_catalog.py", "tests/test_catalog_write_validation.py", "tests/test_dataplane_router.py", "tests/test_knowledge_connector.py", "tests/test_gitea_connector.py", "tests/test_appops_connector.py", "tests/test_docker_read_broker.py", "tests/test_unraid_connector.py", "tests/test_wp110_governance.py", "tests/test_contextforge.py", "tests/test_contextforge_integration.py", "tests/test_bootstrap.py", "tests/test_compose.py", "tests/test_database_candidate_provenance.py", "tests/test_mcp_hub_ingestion_publisher.py", "tests/test_mcp_hub_release_images.py", "tests/test_mcp_hub_release_artifact.py", "tests/test_release_images_workflow.py", "tests/test_domain.py", "tests/test_migrations.py", "tests/test_persistence.py", "tests/test_postgres_acceptance.py", "tests/test_wp150_operations.py", "tests/test_wp160_security.py", "tests/test_wp170_release.py", "tests/test_wp220_manifest.py", "tests/test_wp220_export.py", "tests/test_wp220_release_record.py", "tests/test_wp220_cve_exceptions.py", "tests/test_wp140_clients.py", "tests/test_wp230_authz.py", "tests/test_wp230_rbac.py", "tests/test_wp230_policy_simulate.py", "tests/test_wp230_ui_completion.py", "tests/test_wp230_session_store.py", "tests/test_wp270_functional_operations.py", "tests/test_wp280_runtime_quality.py", "tests/test_operator_workspaces.py", "tests/test_operator_search.py", "tests/test_machine_client_provisioning.py", "tests/test_client_lifecycle_audit.py", "tests/test_e2e_harness.py", "tests/e2e/harness.py", "tests/e2e/tls.py", "tests/test_promotion_preflight.py", "tests/test_production_runtime.py", "packages/hub_runtime/__init__.py", "packages/hub_runtime/secret_files.py", "packages/hub_runtime/supervisor.py", "packages/__init__.py", "packages/hub_core/__init__.py", "packages/hub_observability/__init__.py", "packages/hub_observability/telemetry.py", "packages/hub_operations/__init__.py", "packages/hub_operations/backup.py", "packages/hub_operations/recovery.py", "packages/hub_core/domain.py", "packages/hub_core/errors.py", "packages/hub_core/state_machines.py", "packages/hub_contracts/__init__.py", "packages/hub_contracts/dataplane.py", "packages/hub_policy/__init__.py", "packages/hub_policy/audit.py", "packages/hub_policy/engine.py", "packages/hub_policy/governance.py", "packages/hub_policy/rate_limit.py", "packages/connector_kit/__init__.py", "packages/connector_kit/contracts.py", "packages/connector_kit/knowledge.py", "packages/connector_kit/pagination.py", "packages/connector_kit/redaction.py", "packages/connector_kit/gitea.py", "packages/connector_kit/mobilityops.py", "services/__init__.py", "services/control_api/__init__.py", "services/control_api/authz.py", "services/control_api/clients/__init__.py", "services/control_api/clients/router.py", "services/control_api/clients/service.py", "services/observability/__init__.py", "services/observability/health.py", "services/control_api/policy/__init__.py", "services/control_api/policy/router.py", "services/control_api/policy/service.py", "services/dataplane_router/__init__.py", "services/dataplane_router/authz.py", "services/dataplane_router/errors.py", "services/dataplane_router/models.py", "services/dataplane_router/proxy.py", "services/dataplane_router/registry.py", "services/dataplane_router/router.py", "connectors/__init__.py", "connectors/knowledge/__init__.py", "connectors/knowledge/server.py", "connectors/gitea/__init__.py", "connectors/gitea/changesets.py", "connectors/gitea/fake.py", "connectors/gitea/server.py", "connectors/unraid/__init__.py", "connectors/unraid/client.py", "connectors/unraid/fake.py", "connectors/unraid/server.py", "connectors/mobilityops/__init__.py", "connectors/mobilityops/fake.py", "connectors/mobilityops/server.py", "services/control_api/persistence/__init__.py", "services/control_api/persistence/dataplane_source.py", "services/control_api/persistence/db.py", "services/control_api/persistence/models.py", "services/control_api/persistence/repositories.py", "services/control_api/persistence/seed.py", "services/control_api/knowledge/__init__.py", "services/control_api/knowledge/jobs.py", "services/control_api/knowledge/store.py", "services/control_api/gitea/__init__.py", "services/control_api/gitea/registry.py", "services/docker_read_broker/__init__.py", "services/docker_read_broker/broker.py", "services/docker_read_broker/server.py", "services/control_api/catalog/__init__.py", "services/control_api/catalog/loader.py", "services/control_api/catalog/models.py", "services/control_api/catalog/planner.py", "services/control_api/catalog/reconciler.py", "services/control_api/catalog/router.py", "services/control_api/catalog/store.py", "services/control_api/auth/__init__.py", "services/control_api/auth/bff.py", "services/control_api/auth/config.py", "services/control_api/auth/errors.py", "services/control_api/auth/fake_provider.py", "services/control_api/auth/machine.py", "services/control_api/auth/models.py", "services/control_api/auth/provider.py", "services/control_api/auth/router.py", "services/control_api/contextforge/__init__.py", "services/control_api/contextforge/client.py", "services/control_api/contextforge/errors.py", "services/control_api/contextforge/fake.py", "services/control_api/contextforge/models.py", "services/control_api/persistence/services.py", "services/runtime/__init__.py", "services/runtime/__main__.py", "services/runtime/common.py", "services/runtime/connector_gitea.py", "services/runtime/connector_appops.py", "services/runtime/gitea_operations_widget.py", "services/runtime/gitea_review_widget.py", "services/runtime/mcp_skills.py", "services/runtime/synthetic_monitor.py", "services/runtime/connector_knowledge.py", "services/runtime/connector_unraid.py", "services/runtime/connector_mobilityops.py", "services/runtime/audit.py", "services/runtime/client_service.py", "services/runtime/control_api.py", "services/runtime/dataplane.py", "services/runtime/dispatch.py", "services/runtime/mcp_server.py", "services/runtime/migrate.py", "services/runtime/state_sync.py", "services/runtime/web.py", "services/runtime/worker.py", ] # Release-manifest integrity is checked first, before any slower quality # gate: a stale or tampered PACK_MANIFEST.json means the release-integrity # invariant is already broken, and every later check downstream of it # (build, scan, package) would be validating content that doesn't match # what will actually ship. Fail loud and early rather than burying it # after several minutes of lint/type/test output. run( "Release manifest integrity (Git-tracked content only, manifest required)", [sys.executable, "scripts/validate_pack.py", "--require-manifest"], ) resolved_uv = uv_command() if resolved_uv: run("Python lockfile", [resolved_uv, "lock", "--check"]) else: print("Python lockfile: DEFERRED (uv executable is not installed)") if resolved_uv: run( "Python format", [resolved_uv, "run", "--locked", "ruff", "format", "--check", *python_quality_files], ) run("Python lint", [resolved_uv, "run", "--locked", "ruff", "check", *python_quality_files]) run( "Python types", [ resolved_uv, "run", "--locked", "mypy", "--explicit-package-bases", "scripts/audit_projectbrain_contracts.py", "scripts/check_boundaries.py", "scripts/check_build_reproducibility.py", "scripts/verify.py", "scripts/security_scan.py", "scripts/generate_sbom.py", "scripts/generate_image_sboms.py", "scripts/backup_state.py", "scripts/write_backup_status.py", "scripts/restore_state.py", "scripts/compose_release_check.py", "scripts/promotion_preflight.py", "scripts/publish_mcp_hub_ingestion.py", "scripts/build_mcp_hub_release_images.py", "scripts/prepare_release_security_bases.py", "scripts/package_mcp_hub_release_artifact.py", "scripts/discover_unraid.py", "scripts/revoke_demo_token.py", "scripts/verify_demo_token_runtime.py", "scripts/verify_demo_token_flow.py", "scripts/export_release.py", "scripts/render_release_record.py", "scripts/draft_cve_exceptions.py", "scripts/check_cve_exceptions.py", "packages/hub_core", "packages/hub_observability", "packages/hub_operations", "packages/hub_contracts", "packages/connector_kit", "connectors/knowledge", "connectors/gitea", "connectors/unraid", "connectors/mobilityops", "services/docker_read_broker", "services/control_api", "services/observability", "services/runtime", ], ) run("Import boundaries", [sys.executable, "scripts/check_boundaries.py"]) python_test_command = ( [resolved_uv, "run", "--locked", "python", "-m", "pytest", "tests", "-q"] if resolved_uv else [sys.executable, "-m", "pytest", "tests", "-q"] ) run("Python unit tests", python_test_command) run("Frontend typecheck", ["pnpm", "--filter", "@itworx-mcp-hub/web", "typecheck"]) run("Frontend lint", ["pnpm", "--filter", "@itworx-mcp-hub/web", "lint"]) run("Frontend unit tests", ["pnpm", "--filter", "@itworx-mcp-hub/web", "test"]) run("Frontend build", ["pnpm", "--filter", "@itworx-mcp-hub/web", "build"]) print("Repository verification: PASS") return 0 if __name__ == "__main__": raise SystemExit(main())