feat(v2): 完善配置中心与可替换轨迹质检并联动预审依据

This commit is contained in:
2026-10-01 17:13:02 +08:00
parent 1adbe16cb3
commit e604d177cb
42 changed files with 1285 additions and 83 deletions
+14 -12
View File
@@ -35,7 +35,8 @@ from services.project_assistant import ProjectAssistantService
PROJECT = "DEMO-B"
PRESCREEN = prescreen_api.router.prefix
MANAGER = {"X-Xingbang-Demo-Role": "manager"}
REVIEWER = {"X-Xingbang-Demo-Role": "reviewer"}
ADMIN = {"X-Xingbang-Demo-Role": "admin"}
PUBLISHER = {"Authorization": "Bearer fixture-publisher"}
CARD_ID = "skill.history.fixture"
@@ -65,7 +66,7 @@ class GovernanceTestCase(unittest.TestCase):
patch.object(api, "service", lambda: self.service),
patch.object(prescreen_api, "_service", lambda: self.service),
patch.object(catalog, "DB_PATH", self.path / "catalog.sqlite3"),
patch.dict(os.environ, {"XINGBANG_AUTH_USERS": "", "XINGBANG_REQUIRE_AUTH": "0",
patch.dict(os.environ, {"XINGBANG_AUTH_USERS": '[{"id":"config-admin-b","role":"admin","projects":["DEMO-B"],"token":"fixture-publisher"}]', "XINGBANG_REQUIRE_AUTH": "0",
"XINGBANG_LOCAL_MODEL_URL": "", "XINGBANG_DEMO_ROLE_LOGIN": "1"}),
]
for item in self.patches:
@@ -98,7 +99,7 @@ class GovernanceTestCase(unittest.TestCase):
"operator": "eq", "threshold": True}],
}, actor, PROJECT, origin="history_derived", source_event_ids=["event-1"])
def add_test_cases(self, card_id: str = CARD_ID, headers=MANAGER):
def add_test_cases(self, card_id: str = CARD_ID, headers=ADMIN):
"""补独立测试样本——14 §4 的"专家修改 → 测试"步骤,也是发布门禁的前置条件。"""
return self.request("PATCH", f"/knowledge-candidates/{card_id}", {
"changes": {"test_cases": [
@@ -115,7 +116,7 @@ class GovernanceTestCase(unittest.TestCase):
draft = knowledge_cards.current_draft(db, card_id)
return knowledge_cards.draft_card(db, draft["id"])
def request(self, method, path, body=None, headers=MANAGER):
def request(self, method, path, body=None, headers=ADMIN):
return self.client.request(method, PRESCREEN + path, json=body, headers=headers)
def with_fake_model(self, payload):
@@ -194,7 +195,7 @@ class PublicationTests(GovernanceTestCase):
super().setUp()
self.propose_history_card()
def publish(self, headers=REVIEWER):
def publish(self, headers=PUBLISHER):
return self.request("POST", f"/knowledge-candidates/{CARD_ID}/transitions",
{"action": "publish"}, headers)
@@ -206,30 +207,31 @@ class PublicationTests(GovernanceTestCase):
def test_manager_cannot_evaluate_or_publish(self):
"""角色门禁与既有 /components 入口一致:客户经理不得自评自批。"""
evaluate = self.request("POST", f"/knowledge-candidates/{CARD_ID}/transitions",
{"action": "evaluate"})
{"action": "evaluate"}, MANAGER)
self.assertEqual(evaluate.status_code, 403)
self.assertEqual(self.publish(MANAGER).status_code, 403)
def test_self_approval_is_rejected(self):
"""AC-03/AC-43:提议人不能给自己的候选发布版本。"""
drafted = self.propose_history_card("skill.history.selfmade", actor="demo-reviewer")
drafted = self.propose_history_card("skill.history.selfmade", actor="config-admin-b")
evaluated = self.request("POST", f"/knowledge-candidates/{drafted['component_id']}/transitions",
{"action": "evaluate"}, REVIEWER)
{"action": "evaluate"}, PUBLISHER)
self.assertEqual(evaluated.status_code, 200, evaluated.text)
published = self.request("POST", f"/knowledge-candidates/{drafted['component_id']}/transitions",
{"action": "publish"}, REVIEWER)
{"action": "publish"}, PUBLISHER)
self.assertEqual(published.status_code, 403, "同一人不得既提议又发布")
def test_revision_after_publication_bumps_version_and_keeps_lineage(self):
self.assertEqual(self.add_test_cases().status_code, 200)
self.request("POST", f"/knowledge-candidates/{CARD_ID}/transitions", {"action": "evaluate"},
REVIEWER)
PUBLISHER)
published = self.publish()
self.assertEqual(published.status_code, 200, published.text)
self.assertEqual(published.json()["version"], "1.0.0")
revised = self.request("PATCH", f"/knowledge-candidates/{CARD_ID}",
{"changes": {"exception_note": "补充例外"}, "note": "上会前修订"},
REVIEWER)
PUBLISHER)
self.assertEqual(revised.status_code, 200, revised.text)
card = self.card()
self.assertEqual(card["version"], "1.0.1", "已发布版本不可覆盖,必须升版本")
@@ -251,7 +253,7 @@ class UnknownObjectTests(GovernanceTestCase):
def test_transitioning_an_unknown_candidate_is_404(self):
response = self.request("POST", "/knowledge-candidates/skill.not.exists/transitions",
{"action": "evaluate"}, REVIEWER)
{"action": "evaluate"}, PUBLISHER)
self.assertEqual(response.status_code, 404)