Files
Gitea-Tools/tests/test_reconciler_profile.py
T
sysadminandClaude Opus 4.8 8cac50b2e7 feat(profiles): make gitea.branch.delete a documented reconciler-owned capability
Merged-PR source-branch cleanup is reconciler work (task_capability_map maps
cleanup_merged_pr_branch -> reconciler / gitea.branch.delete), but the
reconciler profile schema, execution-profile docs, and tests never covered
the permission, so no configured profile could run the guarded
gitea_cleanup_merged_pr_branch path.

- reconciler_profile.py: add gitea.branch.delete to
  RECONCILER_RECOMMENDED_OPERATIONS (not required; not forbidden)
- docs/gitea-execution-profiles.md: document merged-branch cleanup
  ownership, least-privilege constraints, and the no-alias caveat
- tests/test_reconciler_profile.py: reconciler profile with branch.delete
  stays valid and classified reconciler; missing grant is reported as
  missing-recommended
- tests/test_branch_cleanup_guard.py: author- and merger-shaped profiles
  without gitea.branch.delete fail closed on gitea_cleanup_merged_pr_branch

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-12 21:31:00 -04:00

123 lines
3.7 KiB
Python

"""Tests for reconciler profile model (#304)."""
import os
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import gitea_mcp_server as mcp_server
import migrate_profiles
import reconciler_profile
PRGS_RECONCILER_ALLOWED = [
"gitea.read",
"gitea.pr.comment",
"gitea.issue.comment",
"gitea.issue.close",
"gitea.pr.close",
]
PRGS_RECONCILER_FORBIDDEN = [
"gitea.pr.approve",
"gitea.pr.merge",
"gitea.pr.create",
"gitea.branch.push",
]
class TestReconcilerProfileModel(unittest.TestCase):
def test_prgs_reconciler_shape_valid(self):
result = reconciler_profile.assess_reconciler_profile(
PRGS_RECONCILER_ALLOWED,
PRGS_RECONCILER_FORBIDDEN,
)
self.assertTrue(result["is_reconciler_profile"])
self.assertTrue(result["valid"])
self.assertEqual(result["reasons"], [])
def test_author_profile_not_reconciler(self):
allowed = [
"gitea.read",
"gitea.pr.create",
"gitea.branch.push",
"gitea.issue.comment",
]
forbidden = ["gitea.pr.approve", "gitea.pr.merge"]
self.assertFalse(
reconciler_profile.is_reconciler_profile(allowed, forbidden)
)
def test_reviewer_profile_not_reconciler(self):
allowed = [
"gitea.read",
"gitea.pr.review",
"gitea.pr.approve",
"gitea.pr.merge",
]
forbidden = ["gitea.pr.create", "gitea.branch.push"]
self.assertFalse(
reconciler_profile.is_reconciler_profile(allowed, forbidden)
)
def test_broad_close_on_author_invalid(self):
allowed = PRGS_RECONCILER_ALLOWED + ["gitea.pr.create"]
result = reconciler_profile.assess_reconciler_profile(
allowed,
PRGS_RECONCILER_FORBIDDEN,
)
self.assertFalse(result["valid"])
self.assertFalse(result["is_reconciler_profile"])
def test_role_kind_detects_reconciler(self):
role = mcp_server._role_kind(
PRGS_RECONCILER_ALLOWED,
PRGS_RECONCILER_FORBIDDEN,
)
self.assertEqual(role, "reconciler")
def test_migrate_infer_role_reconciler(self):
self.assertEqual(
migrate_profiles.infer_role("prgs-reconciler", "prgs-reconciler"),
"reconciler",
)
def test_branch_delete_is_recommended_for_reconciler(self):
self.assertIn(
"gitea.branch.delete",
reconciler_profile.RECONCILER_RECOMMENDED_OPERATIONS,
)
self.assertNotIn(
"gitea.branch.delete",
reconciler_profile.RECONCILER_REQUIRED_OPERATIONS,
)
def test_reconciler_with_branch_delete_stays_valid(self):
allowed = PRGS_RECONCILER_ALLOWED + ["gitea.branch.delete"]
result = reconciler_profile.assess_reconciler_profile(
allowed,
PRGS_RECONCILER_FORBIDDEN,
)
self.assertTrue(result["is_reconciler_profile"])
self.assertTrue(result["valid"])
self.assertNotIn(
"gitea.branch.delete", result["missing_recommended_operations"]
)
self.assertEqual(
mcp_server._role_kind(allowed, PRGS_RECONCILER_FORBIDDEN),
"reconciler",
)
def test_reconciler_without_branch_delete_reports_missing_recommended(self):
result = reconciler_profile.assess_reconciler_profile(
PRGS_RECONCILER_ALLOWED,
PRGS_RECONCILER_FORBIDDEN,
)
self.assertTrue(result["valid"])
self.assertIn(
"gitea.branch.delete", result["missing_recommended_operations"]
)
if __name__ == "__main__":
unittest.main()