Publish curated ITWorx_MCP_Hub source from 9ec6419178e8ddc76a698e84bde72d5ff4472411

This commit is contained in:
Public Source Publisher committed 2026-10-01 09:39:30 +00:00
1 parent 5ff5c807d3
commit f26354e16c
20 files changed
+1639 -84

No files matched your search

+210
View File
@@ -0,0 +1,210 @@
name: Managed validation
run-name: "Managed validation / ${{ inputs.profile || 'full' }}"
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
inputs:
profile:
description: Allowlisted validation profile
required: true
default: full
type: choice
options: [test, lint, typecheck, build, security, full]
permissions:
contents: read
concurrency:
group: managed-validation-${{ gitea.repository }}-${{ gitea.ref }}
cancel-in-progress: true
jobs:
full:
name: full
runs-on: linux-validation
timeout-minutes: 30
env:
CI: "true"
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: projectbrain_integration
POSTGRES_USER: projectbrain
POSTGRES_PASSWORD: projectbrain-test-password
options: >-
--health-cmd "pg_isready -U projectbrain -d projectbrain_integration"
--health-interval 5s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Validate repository with a bounded profile
shell: bash
env:
REQUESTED_PROFILE: ${{ inputs.profile }}
run: |
set -euo pipefail
profile="${REQUESTED_PROFILE:-full}"
case "${profile}" in
test|lint|typecheck|build|security|full) ;;
*) echo "Profile is not allowlisted" >&2; exit 2 ;;
esac
if [[ "${profile}" == security && ( ! -f package.json || ! -f pnpm-lock.yaml ) ]]; then
echo "Security profile requires the repository's pinned pnpm audit:security command" >&2
exit 2
fi
git diff --check
if git grep -nE '^(<<<<<<< |=======$|>>>>>>> )' -- . ':!*.lock' ':!*.patch'; then
echo "Unresolved merge markers detected" >&2
exit 1
fi
# MANAGED_FAST_PATH: only documentation may skip product tests.
# Include deletions and renames; workflow and runner changes must
# always execute validation.
if [[ -n "${GITHUB_BASE_REF:-}" ]]; then
git fetch --no-tags origin "+refs/heads/${GITHUB_BASE_REF}:refs/remotes/origin/${GITHUB_BASE_REF}"
managed_base="origin/${GITHUB_BASE_REF}"
git diff --check "${managed_base}..HEAD"
mapfile -t managed_changed_files < <(
git diff --name-only --no-renames "${managed_base}..HEAD"
)
managed_runtime_change=0
for managed_path in "${managed_changed_files[@]}"; do
case "${managed_path}" in
*.md|*.mdx)
;;
*)
managed_runtime_change=1
break
;;
esac
done
if [[ "${#managed_changed_files[@]}" -gt 0 && "${managed_runtime_change}" -eq 0 ]]; then
printf 'Managed validation fast path: %s non-runtime file(s); full product suite skipped.\n' \
"${#managed_changed_files[@]}"
if [[ "${profile}" == full ]]; then
node scripts/check-doc-links.mjs
node scripts/check-unraid-template-readiness.mjs
fi
exit 0
fi
fi
if [[ -f pyproject.toml || -f requirements.txt ]]; then
# Compile only tracked Python sources. Running compileall after a
# Node install would otherwise traverse node_modules and turn a
# lightweight baseline into a large runner workload.
git ls-files -z '*.py' | xargs -0 -r python -m py_compile
if [[ -f uv.lock ]]; then
python -m venv "${RUNNER_TEMP}/managed-uv"
uv_python="${RUNNER_TEMP}/managed-uv/bin/python"
"${uv_python}" -m pip install --disable-pip-version-check uv==0.10.0
managed_uv="${RUNNER_TEMP}/managed-uv/bin/uv"
export UV_PROJECT_ENVIRONMENT="${RUNNER_TEMP}/managed-project-venv"
"${managed_uv}" sync --locked
export PATH="${UV_PROJECT_ENVIRONMENT}/bin:${PATH}"
if [[ "${profile}" == test || "${profile}" == full ]]; then
if "${managed_uv}" run python -c 'import pytest' 2>/dev/null; then
"${managed_uv}" run python -m pytest
fi
fi
if [[ "${profile}" == lint || "${profile}" == full ]]; then
if "${managed_uv}" run python -c 'import ruff' 2>/dev/null; then
"${managed_uv}" run python -m ruff check .
fi
fi
elif [[ -f requirements.txt ]]; then
python -m venv "${RUNNER_TEMP}/managed-python"
managed_python="${RUNNER_TEMP}/managed-python/bin/python"
"${managed_python}" -m pip install --disable-pip-version-check -r requirements.txt
export PATH="${RUNNER_TEMP}/managed-python/bin:${PATH}"
if [[ "${profile}" == test || "${profile}" == full ]]; then
if "${managed_python}" -c 'import pytest' 2>/dev/null; then
"${managed_python}" -m pytest
fi
fi
fi
fi
# Keep ordinary unit/contract validation database-independent. The
# real PostgreSQL suite is enabled only after migrations are applied
# in the deployment-authoritative full profile below.
if [[ -f package.json ]]; then
corepack enable
if [[ -f pnpm-lock.yaml ]]; then
pnpm install --frozen-lockfile
if [[ "${profile}" == test ]]; then
pnpm --if-present test
[[ -f backend/package.json ]] && pnpm --filter projectbrain-api run test
elif [[ "${profile}" == full ]]; then
pnpm run test:coverage
[[ -f backend/package.json ]] && pnpm --filter projectbrain-api run test:coverage
fi
if [[ "${profile}" == security ]]; then
pnpm run audit:security
fi
if [[ "${profile}" == lint || "${profile}" == full ]]; then
pnpm --if-present lint
[[ -f backend/package.json ]] && pnpm --filter projectbrain-api run lint
fi
if [[ "${profile}" == typecheck || "${profile}" == full ]]; then
pnpm --if-present typecheck
[[ -f backend/package.json ]] && pnpm --filter projectbrain-api run typecheck
fi
if [[ "${profile}" == build || "${profile}" == full ]]; then
pnpm --if-present build
[[ -f backend/package.json ]] && pnpm --filter projectbrain-api run build
fi
if [[ "${profile}" == full ]]; then
pnpm run audit:openapi
pnpm run audit:architecture
pnpm run audit:docs
pnpm run audit:v1-freeze
pnpm run audit:unraid-template
fi
if [[ "${profile}" == full && -f backend/package.json ]]; then
export DATABASE_URL="postgresql://projectbrain:projectbrain-test-password@postgres:5432/projectbrain_integration?schema=public"
export TEST_DATABASE_URL="${DATABASE_URL}"
pnpm --dir backend prisma:generate
pnpm --dir backend db:deploy
pnpm --dir backend db:seed
pnpm --dir backend test:database
pnpm --dir backend exec prisma migrate reset --schema prisma/schema.prisma --force --skip-seed
pnpm --dir backend db:seed
fi
if [[ "${profile}" == full && -f playwright.config.ts ]]; then
pnpm exec playwright install --with-deps --force chromium chromium-headless-shell
pnpm test:e2e
pnpm test:e2e:real
fi
elif [[ -f package-lock.json ]]; then
npm ci
[[ "${profile}" == test || "${profile}" == full ]] && npm run --if-present test
[[ "${profile}" == lint || "${profile}" == full ]] && npm run --if-present lint
if [[ "${profile}" == typecheck || "${profile}" == full ]]; then
npm run --if-present typecheck
fi
[[ "${profile}" == build || "${profile}" == full ]] && npm run --if-present build
fi
fi
if [[ -f go.mod ]]; then
if [[ "${profile}" == test || "${profile}" == build || "${profile}" == full ]]; then
go test ./...
fi
fi
if [[ -f Cargo.toml ]]; then
if [[ "${profile}" == test || "${profile}" == build || "${profile}" == full ]]; then
cargo test --locked
fi
fi
if compgen -G '*.sln' >/dev/null; then
if [[ "${profile}" == test || "${profile}" == build || "${profile}" == full ]]; then
dotnet test --configuration Release
fi
fi
+95 -1
View File
@@ -18,7 +18,7 @@ ROOT = Path(__file__).resolve().parents[1]
def test_appops_tool_catalog_is_bijective_and_server_namespaced() -> None:
assert len(UPSTREAM_TO_PUBLIC) == len(PUBLIC_TO_UPSTREAM) == 25
assert len(UPSTREAM_TO_PUBLIC) == len(PUBLIC_TO_UPSTREAM) == 29
assert all(name.startswith("server.") for name in PUBLIC_TO_UPSTREAM)
assert PUBLIC_TO_UPSTREAM["server.summary.get"] == "get_system_summary"
assert PUBLIC_TO_UPSTREAM["server.operation.execute"] == "server.operation.execute"
@@ -28,6 +28,19 @@ def test_appops_tool_catalog_is_bijective_and_server_namespaced() -> None:
assert PUBLIC_TO_UPSTREAM["server.deployment.rollback"] == "deployment.rollback"
assert PUBLIC_TO_UPSTREAM["server.deployment.target.enroll"] == "target.enroll"
assert PUBLIC_TO_UPSTREAM["server.ci.runners.status"] == "gitea.actions.runners.status"
assert PUBLIC_TO_UPSTREAM["server.appops.deployment.status"] == "appops.deployment.status"
assert (
PUBLIC_TO_UPSTREAM["server.appops.self_upgrade.preflight"]
== "appops.self_upgrade.preflight"
)
assert (
PUBLIC_TO_UPSTREAM["server.appops.self_upgrade.apply"]
== "appops.self_upgrade.apply"
)
assert (
PUBLIC_TO_UPSTREAM["server.appops.self_upgrade.status"]
== "appops.self_upgrade.status"
)
def test_every_public_appops_tool_has_governance_metadata() -> None:
@@ -42,6 +55,50 @@ def test_every_public_appops_tool_has_governance_metadata() -> None:
assert set(PUBLIC_TO_UPSTREAM) <= canonical_names
def test_appops_self_upgrade_manifests_are_fixed_target_and_fingerprint_bound() -> None:
specs = {}
for path in (ROOT / "catalog" / "tools").glob("*.yaml"):
document = yaml.safe_load(path.read_text(encoding="utf-8"))
spec = document.get("spec") if isinstance(document, dict) else None
if isinstance(spec, dict) and spec.get("canonicalName", "").startswith(
"server.appops."
):
specs[spec["canonicalName"]] = spec
assert set(specs) == {
"server.appops.deployment.status",
"server.appops.self_upgrade.preflight",
"server.appops.self_upgrade.apply",
"server.appops.self_upgrade.status",
}
for name in (
"server.appops.self_upgrade.preflight",
"server.appops.self_upgrade.apply",
):
schema = specs[name]["inputSchema"]
assert schema["properties"]["repository"]["const"] == "jens/unraid-appops-gateway"
assert schema["properties"]["revision"]["pattern"] == "^[0-9a-f]{40}$"
assert schema["properties"]["reason"]["minLength"] == 8
assert schema["properties"]["reason"]["maxLength"] == 500
assert schema["properties"]["expected_current_revision"]["pattern"] == "^[0-9a-f]{40}$"
apply = specs["server.appops.self_upgrade.apply"]
assert apply["riskClass"] == "R3"
assert apply["readOnly"] is False
assert apply["inputSchema"]["properties"]["expected_preflight_fingerprint"][
"pattern"
] == "^[0-9a-f]{64}$"
assert {
"expected_preflight_fingerprint",
"idempotency_key",
} <= set(apply["inputSchema"]["required"])
policy = yaml.safe_load(
(ROOT / "catalog" / "policies" / "041-appops-governed-operations.yaml").read_text(
encoding="utf-8"
)
)
assert "server.appops.self_upgrade.apply" in policy["spec"]["match"]["toolPatterns"]
def test_appops_proxy_rewrites_only_registered_tool_calls() -> None:
request = {
"jsonrpc": "2.0",
@@ -73,6 +130,35 @@ def test_appops_proxy_rewrites_only_registered_tool_calls() -> None:
with pytest.raises(ValueError, match="not registered"):
rewrite_request({"method": "tools/call", "params": {"name": "shell.execute"}})
upgrade_request = {
"jsonrpc": "2.0",
"id": 10,
"method": "tools/call",
"params": {
"name": "server.appops.self_upgrade.apply",
"arguments": {
"repository": "jens/unraid-appops-gateway",
"revision": "a" * 40,
"reason": "approved release",
"expected_preflight_fingerprint": "b" * 64,
"idempotency_key": "upgrade-2026-09-30",
"expected_current_revision": "c" * 40,
},
},
}
upgrade_rewritten = rewrite_request(upgrade_request)
assert upgrade_rewritten["params"]["name"] == "appops.self_upgrade.apply"
assert upgrade_rewritten["params"]["arguments"] == upgrade_request["params"]["arguments"]
for upstream_name in (
"appops.deployment.status",
"appops.self_upgrade.preflight",
"appops.self_upgrade.apply",
"appops.self_upgrade.status",
):
with pytest.raises(ValueError, match="not registered"):
rewrite_request({"method": "tools/call", "params": {"name": upstream_name}})
def test_appops_proxy_rewrites_discovery_and_drops_unknown_tools() -> None:
response = {
@@ -84,6 +170,10 @@ def test_appops_proxy_rewrites_discovery_and_drops_unknown_tools() -> None:
{"name": "gitea.projects.catalog", "description": "projects"},
{"name": "deployment.preflight", "description": "deployment preflight"},
{"name": "deployment.apply", "description": "typed deployment"},
{"name": "appops.deployment.status", "description": "AppOps revision"},
{"name": "appops.self_upgrade.preflight", "description": "upgrade preflight"},
{"name": "appops.self_upgrade.apply", "description": "upgrade apply"},
{"name": "appops.self_upgrade.status", "description": "upgrade status"},
{"name": "future_unsafe_tool", "description": "unknown"},
]
},
@@ -93,6 +183,10 @@ def test_appops_proxy_rewrites_discovery_and_drops_unknown_tools() -> None:
{"name": "server.project.list", "description": "projects"},
{"name": "server.deployment.preflight", "description": "deployment preflight"},
{"name": "server.deployment.apply", "description": "typed deployment"},
{"name": "server.appops.deployment.status", "description": "AppOps revision"},
{"name": "server.appops.self_upgrade.preflight", "description": "upgrade preflight"},
{"name": "server.appops.self_upgrade.apply", "description": "upgrade apply"},
{"name": "server.appops.self_upgrade.status", "description": "upgrade status"},
]
+1 -1
View File
@@ -33,7 +33,7 @@ class CatalogLoaderTests(unittest.TestCase):
def test_committed_catalog_validates_without_network_or_secret_values(self) -> None:
report = CatalogLoader(ROOT / "catalog").load()
self.assertTrue(report.valid, report.issues)
self.assertEqual(len(report.documents), 277)
self.assertEqual(len(report.documents), 281)
self.assertEqual(len(report.issues), 0)
self.assertIsNotNone(report.desired_hash)
+713 -1
View File
@@ -24,7 +24,7 @@ from connectors.gitea.changesets import (
validate_operations,
)
from connectors.gitea.managed_validation import MANAGED_VALIDATION_WORKFLOW
from connectors.gitea.server import _select_validation_workflow
from connectors.gitea.server import _managed_validation_profile, _select_validation_workflow
from connectors.knowledge import KnowledgeConnector
from packages.connector_kit import (
ConnectorContext,
@@ -43,6 +43,49 @@ from services.control_api.gitea.registry import registration_from_project
PROJECT_ID = UUID("11111111-1111-1111-1111-111111111111")
OTHER_PROJECT_ID = UUID("22222222-2222-2222-2222-222222222222")
ROOT = Path(__file__).resolve().parents[1]
PROJECTBRAIN_VALIDATION_WORKFLOW = (
ROOT / "tests" / "fixtures" / "projectbrain-managed-validation.yml"
).read_text(encoding="utf-8")
def projectbrain_connector(
server: FakeGiteaServer | None = None,
) -> tuple[GiteaConnector, FakeGiteaServer]:
fixture = server or FakeGiteaServer()
fixture._repos["Jens/projectbrain"] = {
"owner": {"login": "Jens"},
"name": "projectbrain",
"full_name": "Jens/projectbrain",
"description": "ProjectBrain",
"private": True,
"default_branch": "main",
}
fixture._managed_workflows["Jens/projectbrain"] = PROJECTBRAIN_VALIDATION_WORKFLOW
protection = copy.deepcopy(fixture._branch_protections["acme/hub"][0])
protection["status_check_contexts"] = ["Pull request / quality (pull_request)"]
protection["required_approvals"] = 2
fixture._branch_protections["Jens/projectbrain"] = [protection]
settings = GiteaSettings(
base_url="http://gitea.test",
token_reference="docker-secret://gitea_mcp_token", # noqa: S106
allow_insecure_http_for_tests=True,
)
client = GiteaClient(
settings, StaticTokenProvider("fixture-token-must-not-leak"), transport=fixture.transport()
)
registry = GiteaRepositoryRegistry(
(
RegisteredRepository(
repository_ref="projectbrain-repository",
project_id=PROJECT_ID,
owner="Jens",
name="projectbrain",
source_uri="itworx-git://projectbrain/projectbrain-repository",
private=True,
),
)
)
return GiteaConnector(client, registry, write_client=client), fixture
def context(project_id: UUID = PROJECT_ID, slug: str = "hub") -> ConnectorContext:
@@ -114,6 +157,262 @@ class GiteaConnectorTests(unittest.TestCase):
self.assertIs(_select_validation_workflow([legacy, managed]), managed)
self.assertIs(_select_validation_workflow([managed, legacy]), managed)
def test_projectbrain_managed_validation_profile_is_pinned_and_repository_scoped(self) -> None:
self.assertEqual(
_managed_validation_profile("Jens/projectbrain", PROJECTBRAIN_VALIDATION_WORKFLOW),
"projectbrain",
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace("pnpm test:e2e:real", ""),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
"pnpm test:e2e:real", "# pnpm test:e2e:real"
),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
"pnpm test:e2e:real", 'echo "pnpm test:e2e:real"'
),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
'export TEST_DATABASE_URL="${DATABASE_URL}"',
'# export TEST_DATABASE_URL="${DATABASE_URL}"',
),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" image: postgres:16", " image: postgres:15"
),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(" pull_request:\n", ""),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" pull_request:\n", ' pull_request:\n paths: ["backend/**"]\n'
),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" pull_request:\n", " pull_request:\n types: [edited]\n"
),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace("branches: [main]", "branches: [master]"),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
"branches: [main]", "branches: [main, '!main']"
),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" pull_request:\n",
" pull_request:\n branches: [main, '!main']\n",
),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" name: full\n", " name: full\n if: false\n"
),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" name: full\n", " name: full\n needs: [conditional-setup]\n"
),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" - name: Validate repository with a bounded profile\n",
" - name: Validate repository with a bounded profile\n"
" if: false\n",
),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" name: full\n", " name: full\n continue-on-error: true\n"
),
)
)
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain",
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" - name: Validate repository with a bounded profile\n",
" - name: Validate repository with a bounded profile\n"
" continue-on-error: true\n",
),
)
)
bypass_mutations = (
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" pnpm test:e2e:real\n",
" cat <<'EOF'\n"
" pnpm test:e2e:real\n"
" EOF\n",
),
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" pnpm --dir backend test:database\n",
" exit 0\n"
" pnpm --dir backend test:database\n",
),
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" pnpm test:e2e:real\n",
" if false; then\n"
" pnpm test:e2e:real\n"
" fi\n",
),
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" pnpm test:e2e:real\n",
" export PATH=/tmp/untrusted:$PATH\n"
" pnpm test:e2e:real\n",
),
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 "
"# v4.2.2\n",
" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 "
"# v4.2.2\n"
" - run: echo injected-action\n",
),
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
"run-name: \"Managed validation / ${{ inputs.profile || 'full' }}\"",
'run-name: "Managed validation / full"',
),
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" default: full\n", " default: test\n"
),
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
"permissions:\n", "env:\n PATH: /tmp/untrusted\n\npermissions:\n"
),
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
"permissions:\n", "defaults:\n run:\n shell: sh\n\npermissions:\n"
),
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
"jobs:\n", "jobs:\n extra:\n runs-on: linux-validation\n steps: []\n"
),
)
for modified_workflow in bypass_mutations:
with self.subTest(modified_workflow=modified_workflow[-160:]):
self.assertIsNone(
_managed_validation_profile("Jens/projectbrain", modified_workflow)
)
alias_chain = ["level0: &level0 [marker]"]
for level in range(1, 23):
alias_chain.append(
f"level{level}: &level{level} [*level{level - 1}, *level{level - 1}]"
)
alias_bomb = PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
"jobs:\n", "\n".join(alias_chain) + "\njobs:\n"
)
self.assertIsNone(_managed_validation_profile("Jens/projectbrain", alias_bomb))
self.assertIsNone(
_managed_validation_profile(
"Jens/projectbrain", PROJECTBRAIN_VALIDATION_WORKFLOW + "\njobs: {}\n"
)
)
self.assertIsNone(
_managed_validation_profile("Acme/hub", PROJECTBRAIN_VALIDATION_WORKFLOW)
)
self.assertEqual(
_managed_validation_profile("Acme/hub", MANAGED_VALIDATION_WORKFLOW),
"canonical",
)
self.assertIsNone(
_managed_validation_profile(
"Acme/hub", MANAGED_VALIDATION_WORKFLOW + "\n# custom project workflow\n"
)
)
def test_projectbrain_profile_pins_coverage_audits_security_and_doc_checks(self) -> None:
required_commands = (
("root coverage gate", "pnpm run test:coverage", "pnpm --if-present test"),
(
"backend coverage gate",
"pnpm --filter projectbrain-api run test:coverage",
"pnpm --filter projectbrain-api run test",
),
("security audit", "pnpm run audit:security", "pnpm --if-present audit:security"),
("OpenAPI audit", "pnpm run audit:openapi", "echo skipped-openapi-audit"),
(
"architecture audit",
"pnpm run audit:architecture",
"echo skipped-architecture-audit",
),
("documentation audit", "pnpm run audit:docs", "echo skipped-docs-audit"),
("v1 freeze audit", "pnpm run audit:v1-freeze", "echo skipped-v1-freeze-audit"),
(
"Unraid template audit",
"pnpm run audit:unraid-template",
"echo skipped-unraid-template-audit",
),
(
"documentation fast-path check",
"node scripts/check-doc-links.mjs",
"echo skipped-doc-link-check",
),
(
"Unraid documentation fast-path check",
"node scripts/check-unraid-template-readiness.mjs",
"echo skipped-unraid-readiness-check",
),
)
for label, command, replacement in required_commands:
with self.subTest(gate=label):
self.assertIn(command, PROJECTBRAIN_VALIDATION_WORKFLOW)
modified_workflow = PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
command, replacement, 1
)
self.assertIsNone(
_managed_validation_profile("Jens/projectbrain", modified_workflow)
)
def test_native_skills_are_complete_digest_verified_and_bounded(self) -> None:
from services.runtime.mcp_skills import SkillGetParams, SkillListParams, StaticSkills
@@ -653,6 +952,16 @@ class GiteaConnectorTests(unittest.TestCase):
"main",
)
self.assertIn("expectedPlanHash", schemas["gitea.branchprotection.ensure"]["required"])
self.assertEqual(
schemas["gitea.branchprotection.ensure"]["properties"]["applyScope"]["enum"],
["all", "protection_only"],
)
portfolio_plan_properties = schemas["gitea.portfolio.governance.apply"]["properties"][
"plans"
]["items"]["properties"]
self.assertEqual(
portfolio_plan_properties["applyScope"]["enum"], ["all", "protection_only"]
)
self.assertEqual(
schemas["gitea.portfolio.governance.apply"]["properties"]["plans"]["maxItems"],
5,
@@ -755,6 +1064,24 @@ class GiteaConnectorTests(unittest.TestCase):
self.assertEqual(server.version, "1.14.0")
self.assertIn("plan-locked governance tools", server.instructions)
names = {tool.name for tool in tools}
ensure_tool = next(
tool for tool in tools if tool.name == "gitea.branchprotection.ensure"
)
portfolio_apply_tool = next(
tool for tool in tools if tool.name == "gitea.portfolio.governance.apply"
)
self.assertEqual(
ensure_tool.input_schema["properties"]["applyScope"]["enum"],
["all", "protection_only"],
)
portfolio_schema = portfolio_apply_tool.input_schema
plan_ref = portfolio_schema["properties"]["plans"]["items"]["$ref"]
plan_schema_name = plan_ref.rsplit("/", maxsplit=1)[-1]
plan_schema = portfolio_schema["$defs"][plan_schema_name]
self.assertEqual(
plan_schema["properties"]["applyScope"]["enum"], ["all", "protection_only"]
)
self.assertEqual(portfolio_schema["properties"]["plans"]["maxItems"], 5)
self.assertTrue(
{
"gitea.repository.create",
@@ -1065,6 +1392,391 @@ class GiteaConnectorTests(unittest.TestCase):
finally:
connector_instance.client.close()
def test_projectbrain_custom_workflow_is_preserved_while_full_and_quality_are_added(
self,
) -> None:
connector_instance, fixture = projectbrain_connector()
original_workflow = fixture._managed_workflows["Jens/projectbrain"]
fixture._branch_protections["Jens/projectbrain"][0]["status_check_contexts"] = [
"Pull request / quality (pull_request)"
]
original_protection = copy.deepcopy(
fixture._branch_protections["Jens/projectbrain"][0]
)
try:
current = context()
preview = connector_instance.branch_protection_preview(
current, "projectbrain-repository"
)["data"]
self.assertEqual(preview["workflow"]["profile"], "projectbrain")
self.assertEqual(preview["workflow"]["action"], "none")
self.assertNotEqual(
preview["workflow"]["currentDigest"],
hashlib.sha256(MANAGED_VALIDATION_WORKFLOW.encode()).hexdigest(),
)
self.assertEqual(
preview["branchProtection"]["desired"]["status_check_contexts"],
[
"Managed validation / full (pull_request)",
"Pull request / quality (pull_request)",
],
)
self.assertEqual(preview["branchProtection"]["action"], "update")
applied = connector_instance.branch_protection_ensure(
current, "projectbrain-repository", preview["planHash"]
)["data"]
self.assertTrue(applied["changed"])
self.assertTrue(applied["verified"])
self.assertTrue(applied["compliant"])
self.assertEqual(fixture._managed_workflows["Jens/projectbrain"], original_workflow)
self.assertEqual(
fixture._branch_protections["Jens/projectbrain"][0]["status_check_contexts"],
[
"Managed validation / full (pull_request)",
"Pull request / quality (pull_request)",
],
)
self.assertEqual(
fixture._branch_protections["Jens/projectbrain"][0]["required_approvals"],
original_protection["required_approvals"],
)
workflow_writes = [
(method, path)
for method, path in zip(
fixture.recorded_methods, fixture.recorded_paths, strict=True
)
if path.endswith("/.gitea/workflows/managed-validation.yml")
and method in {"POST", "PUT", "DELETE"}
]
self.assertEqual(workflow_writes, [])
finally:
connector_instance.client.close()
def test_projectbrain_all_scope_fails_if_gitea_drops_an_extra_required_context(self) -> None:
connector_instance, fixture = projectbrain_connector()
fixture._branch_protections["Jens/projectbrain"][0]["status_check_contexts"] = [
"Pull request / quality (pull_request)",
"Additional required check",
]
original_read = connector_instance.client.branch_protections
read_count = 0
def drop_extra_context(repository: RegisteredRepository) -> list[dict[str, object]]:
nonlocal read_count
read_count += 1
if read_count == 3:
fixture._branch_protections["Jens/projectbrain"][0][
"status_check_contexts"
].remove("Additional required check")
return original_read(repository)
try:
current = context()
with patch.object(
connector_instance.client,
"branch_protections",
side_effect=drop_extra_context,
):
preview = connector_instance.branch_protection_preview(
current, "projectbrain-repository"
)["data"]
self.assertIn(
"Additional required check",
preview["branchProtection"]["desired"]["status_check_contexts"],
)
with self.assertRaisesRegex(GiteaError, "did not retain"):
connector_instance.branch_protection_ensure(
current, "projectbrain-repository", preview["planHash"]
)
self.assertNotIn(
"Additional required check",
fixture._branch_protections["Jens/projectbrain"][0]["status_check_contexts"],
)
finally:
connector_instance.client.close()
def test_projectbrain_all_scope_rejects_an_accepted_workflow_digest_change(self) -> None:
connector_instance, fixture = projectbrain_connector()
fixture._branch_protections["Jens/projectbrain"][0]["status_check_contexts"] = [
"Pull request / quality (pull_request)"
]
modified_workflow = PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" pull_request:\n", " pull_request:\n branches: [main]\n"
)
original_update = connector_instance.client.update_branch_protection
def update_protection_then_change_workflow(
repository: RegisteredRepository,
branch: str,
payload: dict[str, object],
) -> object:
response = original_update(repository, branch, payload)
fixture._managed_workflows["Jens/projectbrain"] = modified_workflow
return response
try:
current = context()
preview = connector_instance.branch_protection_preview(
current, "projectbrain-repository"
)["data"]
self.assertEqual(preview["workflow"]["profile"], "projectbrain")
with patch.object(
connector_instance.client,
"update_branch_protection",
side_effect=update_protection_then_change_workflow,
):
with self.assertRaisesRegex(GiteaError, "did not retain"):
connector_instance.branch_protection_ensure(
current, "projectbrain-repository", preview["planHash"]
)
self.assertEqual(
_managed_validation_profile("Jens/projectbrain", modified_workflow),
"projectbrain",
)
self.assertEqual(fixture._managed_workflows["Jens/projectbrain"], modified_workflow)
finally:
connector_instance.client.close()
def test_projectbrain_custom_profile_blocks_unsafe_existing_protection(self) -> None:
connector_instance, fixture = projectbrain_connector()
protection = fixture._branch_protections["Jens/projectbrain"][0]
protection["enable_push"] = True
protection["block_admin_merge_override"] = False
original_protection = copy.deepcopy(protection)
try:
current = context()
preview = connector_instance.branch_protection_preview(
current, "projectbrain-repository"
)["data"]
self.assertEqual(preview["workflow"]["profile"], "projectbrain")
self.assertIn(
"managed-validation-projectbrain-protection-safety-locks-invalid",
preview["blockers"],
)
with self.assertRaisesRegex(GiteaError, "unresolved blockers"):
connector_instance.branch_protection_ensure(
current, "projectbrain-repository", preview["planHash"]
)
self.assertEqual(
fixture._branch_protections["Jens/projectbrain"][0], original_protection
)
finally:
connector_instance.client.close()
def test_projectbrain_all_scope_creates_safe_protection_without_rewriting_profile(self) -> None:
connector_instance, fixture = projectbrain_connector()
original_workflow = fixture._managed_workflows["Jens/projectbrain"]
fixture._branch_protections["Jens/projectbrain"] = []
try:
current = context()
preview = connector_instance.branch_protection_preview(
current, "projectbrain-repository"
)["data"]
self.assertEqual(preview["workflow"]["profile"], "projectbrain")
self.assertEqual(preview["branchProtection"]["action"], "create")
applied = connector_instance.branch_protection_ensure(
current, "projectbrain-repository", preview["planHash"]
)["data"]
self.assertTrue(applied["compliant"])
self.assertTrue(applied["verified"])
self.assertEqual(fixture._managed_workflows["Jens/projectbrain"], original_workflow)
created_protection = fixture._branch_protections["Jens/projectbrain"][0]
self.assertEqual(
created_protection["status_check_contexts"],
[
"Managed validation / full (pull_request)",
"Pull request / quality (pull_request)",
],
)
self.assertTrue(created_protection["block_admin_merge_override"])
finally:
connector_instance.client.close()
def test_projectbrain_protection_only_is_hash_bound_and_preserves_workflow(
self,
) -> None:
connector_instance, fixture = projectbrain_connector()
invalid_workflow = PROJECTBRAIN_VALIDATION_WORKFLOW.replace(" pull_request:\n", "")
fixture._managed_workflows["Jens/projectbrain"] = invalid_workflow
protection = fixture._branch_protections["Jens/projectbrain"][0]
protection["status_check_contexts"] = [
"Pull request / quality (pull_request)",
"Additional required check",
]
protection["required_approvals"] = 2
protection["require_signed_commits"] = True
original_protection = copy.deepcopy(protection)
try:
current = context()
preview = connector_instance.branch_protection_preview(
current, "projectbrain-repository"
)["data"]
self.assertEqual(preview["workflow"]["profile"], "projectbrain-required")
self.assertEqual(preview["workflow"]["action"], "none")
self.assertIn("managed-validation-projectbrain-profile-invalid", preview["blockers"])
self.assertFalse(preview["compliant"])
self.assertTrue(preview["protectionOnlyAvailable"])
self.assertNotEqual(preview["planHash"], preview["protectionOnlyPlanHash"])
with self.assertRaisesRegex(GiteaError, "unresolved blockers"):
connector_instance.branch_protection_ensure(
current, "projectbrain-repository", preview["planHash"]
)
with self.assertRaisesRegex(GiteaError, "preview the repository again"):
connector_instance.branch_protection_ensure(
current,
"projectbrain-repository",
preview["planHash"],
apply_scope="protection_only",
)
self.assertEqual(fixture._managed_workflows["Jens/projectbrain"], invalid_workflow)
self.assertEqual(
fixture._branch_protections["Jens/projectbrain"][0], original_protection
)
portfolio_result = connector_instance.portfolio_governance_apply(
current,
[
{
"repositoryRef": "projectbrain-repository",
"planHash": preview["protectionOnlyPlanHash"],
"applyScope": "protection_only",
}
],
)["data"]
self.assertEqual(portfolio_result["summary"], {"total": 1, "applied": 1, "failed": 0})
self.assertEqual(portfolio_result["items"][0]["applyScope"], "protection_only")
updated_protection = fixture._branch_protections["Jens/projectbrain"][0]
self.assertEqual(
updated_protection["status_check_contexts"],
[
"Additional required check",
"Managed validation / full (pull_request)",
"Pull request / quality (pull_request)",
],
)
self.assertEqual(updated_protection["required_approvals"], 2)
self.assertTrue(updated_protection["require_signed_commits"])
self.assertEqual(fixture._managed_workflows["Jens/projectbrain"], invalid_workflow)
self.assertEqual(
fixture.recorded_bodies[-1],
{
"status_check_contexts": [
"Additional required check",
"Managed validation / full (pull_request)",
"Pull request / quality (pull_request)",
]
},
)
finally:
connector_instance.client.close()
def test_projectbrain_protection_only_requires_an_existing_enabled_rule(self) -> None:
connector_instance, fixture = projectbrain_connector()
fixture._managed_workflows["Jens/projectbrain"] = PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" pull_request:\n", ""
)
fixture._branch_protections["Jens/projectbrain"] = []
try:
preview = connector_instance.branch_protection_preview(
context(), "projectbrain-repository"
)["data"]
self.assertFalse(preview["protectionOnlyAvailable"])
self.assertIsNone(preview["protectionOnlyPlanHash"])
self.assertEqual(preview["branchProtection"]["action"], "create")
finally:
connector_instance.client.close()
def test_projectbrain_protection_only_fails_if_gitea_drops_an_extra_context(self) -> None:
connector_instance, fixture = projectbrain_connector()
fixture._managed_workflows["Jens/projectbrain"] = PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" pull_request:\n", ""
)
fixture._branch_protections["Jens/projectbrain"][0]["status_check_contexts"] = [
"Pull request / quality (pull_request)",
"Additional required check",
]
original_read = connector_instance.client.branch_protections
read_count = 0
def drop_extra_context(repository: RegisteredRepository) -> list[dict[str, object]]:
nonlocal read_count
read_count += 1
if read_count == 3:
fixture._branch_protections["Jens/projectbrain"][0][
"status_check_contexts"
].remove("Additional required check")
return original_read(repository)
try:
current = context()
with patch.object(
connector_instance.client,
"branch_protections",
side_effect=drop_extra_context,
):
preview = connector_instance.branch_protection_preview(
current, "projectbrain-repository"
)["data"]
self.assertTrue(preview["protectionOnlyAvailable"])
with self.assertRaisesRegex(GiteaError, "did not retain"):
connector_instance.branch_protection_ensure(
current,
"projectbrain-repository",
preview["protectionOnlyPlanHash"],
apply_scope="protection_only",
)
self.assertNotIn(
"Additional required check",
fixture._branch_protections["Jens/projectbrain"][0]["status_check_contexts"],
)
finally:
connector_instance.client.close()
def test_projectbrain_protection_only_rejects_other_protection_changes(self) -> None:
connector_instance, fixture = projectbrain_connector()
fixture._managed_workflows["Jens/projectbrain"] = PROJECTBRAIN_VALIDATION_WORKFLOW.replace(
" pull_request:\n", ""
)
original_read = connector_instance.client.branch_protections
read_count = 0
def changed_protection_response(
repository: RegisteredRepository,
) -> list[dict[str, object]]:
nonlocal read_count
protections = original_read(repository)
read_count += 1
if read_count == 3:
protections[0]["required_approvals"] = 0
protections[0]["block_admin_merge_override"] = False
return protections
try:
current = context()
with patch.object(
connector_instance.client,
"branch_protections",
side_effect=changed_protection_response,
):
preview = connector_instance.branch_protection_preview(
current, "projectbrain-repository"
)["data"]
with self.assertRaisesRegex(GiteaError, "did not retain"):
connector_instance.branch_protection_ensure(
current,
"projectbrain-repository",
preview["protectionOnlyPlanHash"],
apply_scope="protection_only",
)
self.assertEqual(
fixture._managed_workflows["Jens/projectbrain"],
PROJECTBRAIN_VALIDATION_WORKFLOW.replace(" pull_request:\n", ""),
)
finally:
connector_instance.client.close()
def test_governance_update_never_relaxes_protected_main_push(
self,
) -> None: