"""B2.6:显示组和 PRIMARY 证据必须由独立人审,且审核通过不等于执行授权。""" from __future__ import annotations import copy import importlib.util from pathlib import Path import unittest ROOT = Path(__file__).resolve().parents[1] SCRIPT = ROOT / "tools/provider-pipeline/standard_display_review_gate.py" spec = importlib.util.spec_from_file_location("review_gate_module", SCRIPT) gate = importlib.util.module_from_spec(spec) assert spec and spec.loader spec.loader.exec_module(gate) HASHARGS = dict(queue_sha256="a" * 64, groups_sha256="b" * 64, style_sha256="c" * 64) def fixtures(): queue = { "schemaVersion": "navsea-feature-identity-scope-audit/v1", "providerId": "unknown-provider", "datasetId": "test-v1", "reviewQueue": [ { "visualObjectTypeId": "VO-1", "assignmentStatus": "LAYER_ONLY", "standardLayer": "reviewed_category", "primaryReviewStatus": "PENDING_REVIEW", "componentCandidates": [ {"componentIndex": 0, "drawingRole": "line", "styleLayerId": "layer-A"}, {"componentIndex": 1, "drawingRole": "text", "styleLayerId": "layer-B"}, ], }, { "visualObjectTypeId": "VO-2", "assignmentStatus": "UNKNOWN", "standardLayer": None, "primaryReviewStatus": "PENDING_REVIEW", "componentCandidates": [{"componentIndex": 0, "drawingRole": "icon", "styleLayerId": "layer-C"}], }, ], } groups = { "schemaVersion": gate.GROUP_SCHEMA, "approvalStatus": "OBSERVED_NOT_APPROVED", "groupIds": ["display-A", "display-B"], } draft = gate.generate_review_draft(queue, groups, **HASHARGS) return queue, groups, draft def review_both(draft): std = draft["standardLayerDecisions"][0] std.update(status="REVIEWED", displayGroupId="display-A", reviewer="real-reviewer", evidenceRefs=["audit/signed-standard-review"]) obj = draft["visualObjectDecisions"][0] obj.update(status="REVIEWED", reviewedStandardLayer="reviewed_category", primaryComponentIndex=0, componentParentLinks=[ {"componentIndex": 1, "parentComponentIndex": 0} ], reviewer="real-reviewer", evidenceRefs=["audit/signed-primary-review"]) class StandardDisplayReviewGateTests(unittest.TestCase): def test_pending_draft_is_not_executable_and_keeps_unknown(self): queue, groups, draft = fixtures() self.assertEqual(len(draft["standardLayerDecisions"]), 1) self.assertEqual(len(draft["visualObjectDecisions"]), 2) result = gate.validate_review_draft(draft, queue, groups, **HASHARGS) self.assertEqual(result["status"], "PASS_PENDING_REVIEW") self.assertEqual(result["runtimeExecutionAuthorizedCount"], 0) self.assertEqual(result["visualObjectStatusCounts"], {"PENDING": 2}) def test_unapproved_host_groups_rejects_review(self): queue, groups, draft = fixtures() review_both(draft) out = gate.validate_review_draft(draft, queue, groups, **HASHARGS) self.assertEqual(out["status"], "FAIL_CLOSED") self.assertTrue(any("未正式批准" in error for error in out["validationErrors"])) def test_explicit_reviewed_records_structurally_valid_but_never_runtime_authorized(self): queue, groups, draft = fixtures() groups["approvalStatus"] = "APPROVED" review_both(draft) result = gate.validate_review_draft(draft, queue, groups, **HASHARGS) self.assertEqual(result["status"], "PASS_PENDING_REVIEW") self.assertEqual(result["reviewedObjectCount"], 1) self.assertEqual(result["runtimeExecutionAuthorizedCount"], 0) self.assertEqual(result["globalIdentityAuthorizedCount"], 0) def test_incomplete_or_double_parent_component_links_fail_closed(self): queue, groups, draft = fixtures() groups["approvalStatus"] = "APPROVED" review_both(draft) first = draft["visualObjectDecisions"][0] first["componentParentLinks"] = [] self.assertEqual(gate.validate_review_draft(draft, queue, groups, **HASHARGS)["status"], "FAIL_CLOSED") first["componentParentLinks"] = [ {"componentIndex": 1, "parentComponentIndex": 0}, {"componentIndex": 1, "parentComponentIndex": 0}, ] self.assertEqual(gate.validate_review_draft(draft, queue, groups, **HASHARGS)["status"], "FAIL_CLOSED") def test_unknown_classification_cannot_be_promoted_through_review(self): queue, groups, draft = fixtures() groups["approvalStatus"] = "APPROVED" review_both(draft) second = draft["visualObjectDecisions"][1] second.update(status="REVIEWED", reviewedStandardLayer="reviewed_category", primaryComponentIndex=0, componentParentLinks=[], reviewer="not-authorized", evidenceRefs=["ticket/123"]) out = gate.validate_review_draft(draft, queue, groups, **HASHARGS) self.assertEqual(out["status"], "FAIL_CLOSED") self.assertTrue(any("UNKNOWN/AMBIGUOUS" in err for err in out["validationErrors"])) def test_binding_digest_and_extra_or_missing_review_ids_fail_closed(self): queue, groups, draft = fixtures() with self.assertRaisesRegex(ValueError, "指纹"): gate.validate_review_draft(draft, queue, groups, **{**HASHARGS, "style_sha256": "wrong"}) draft["visualObjectDecisions"].pop() with self.assertRaisesRegex(ValueError, "缺少"): gate.validate_review_draft(draft, queue, groups, **HASHARGS) draft = gate.generate_review_draft(queue, groups, **HASHARGS) draft["standardLayerDecisions"].append(copy.deepcopy(draft["standardLayerDecisions"][0])) with self.assertRaisesRegex(ValueError, "重复"): gate.validate_review_draft(draft, queue, groups, **HASHARGS) def test_pending_row_cannot_smuggle_parent_or_group(self): queue, groups, draft = fixtures() draft["visualObjectDecisions"][0]["primaryComponentIndex"] = 0 result = gate.validate_review_draft(draft, queue, groups, **HASHARGS) self.assertEqual(result["status"], "FAIL_CLOSED") draft = gate.generate_review_draft(queue, groups, **HASHARGS) draft["standardLayerDecisions"][0]["displayGroupId"] = "display-A" result = gate.validate_review_draft(draft, queue, groups, **HASHARGS) self.assertEqual(result["status"], "FAIL_CLOSED") def test_cross_provider_visual_types_have_no_implied_same_semantics(self): queue_a, groups, draft_a = fixtures() queue_b = copy.deepcopy(queue_a) queue_b["providerId"] = "independent-provider" draft_b = gate.generate_review_draft(queue_b, groups, **HASHARGS) self.assertEqual(draft_a["visualObjectDecisions"], draft_b["visualObjectDecisions"]) self.assertNotEqual(draft_a["binding"]["providerId"], draft_b["binding"]["providerId"]) with self.assertRaisesRegex(ValueError, "来源身份"): gate.validate_review_draft(draft_a, queue_b, groups, **HASHARGS) result = gate.validate_review_draft(draft_b, queue_b, groups, **HASHARGS) self.assertEqual(result["runtimeExecutionAuthorizedCount"], 0) if __name__ == "__main__": unittest.main()