Publish curated ITWorx_MCP_Hub source from 9ec6419178e8ddc76a698e84bde72d5ff4472411
This commit is contained in:
1 parent
5ff5c807d3
commit
f26354e16c
20 files changed
+1639
-84
No files matched your search
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user