test_wp13_plugin_platform_postgres.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. """Real PostgreSQL migration and ACL probes for the WP13 fixture baseline."""
  2. # ruff: noqa: B017
  3. from __future__ import annotations
  4. import hashlib
  5. import json
  6. import os
  7. import subprocess
  8. import uuid
  9. from concurrent.futures import ThreadPoolExecutor
  10. from pathlib import Path
  11. from threading import Barrier
  12. import pytest
  13. from sqlalchemy import create_engine, text
  14. from sqlalchemy.engine import make_url
  15. ROOT = Path(__file__).resolve().parents[2]
  16. def _alembic(url: str, command: str, revision: str) -> subprocess.CompletedProcess[str]:
  17. return subprocess.run(
  18. [str(ROOT / ".venv/bin/alembic"), "-c", str(ROOT / "alembic.ini"), command, revision],
  19. cwd=ROOT, env={**os.environ, "MIGRATION_DATABASE_URL": url}, text=True, capture_output=True,
  20. )
  21. @pytest.mark.integration
  22. def test_wp13_restricted_migrator_creates_closed_facts_and_empty_round_trip(monkeypatch):
  23. base_url = os.getenv("TEST_DATABASE_URL")
  24. if not base_url:
  25. pytest.skip("TEST_DATABASE_URL is required")
  26. base = make_url(base_url)
  27. database = f"wp13_{uuid.uuid4().hex}"
  28. migrator = f"wp13_migrator_{uuid.uuid4().hex[:10]}"
  29. runtime_login = f"wp13_runtime_{uuid.uuid4().hex[:10]}"
  30. control_login = f"wp13_control_{uuid.uuid4().hex[:10]}"
  31. password = f"m-{uuid.uuid4().hex}"
  32. runtime_password = f"r-{uuid.uuid4().hex}"
  33. control_password = f"c-{uuid.uuid4().hex}"
  34. admin = create_engine(base.set(database="postgres").render_as_string(hide_password=False), isolation_level="AUTOCOMMIT")
  35. quoted_database = admin.dialect.identifier_preparer.quote(database)
  36. quoted_migrator = admin.dialect.identifier_preparer.quote(migrator)
  37. created_owner = False
  38. created_control = False
  39. try:
  40. with admin.connect() as connection:
  41. connection.execute(text(f"CREATE DATABASE {quoted_database}"))
  42. connection.execute(text(f"CREATE ROLE {admin.dialect.identifier_preparer.quote(runtime_login)} LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION PASSWORD :password"), {"password": runtime_password})
  43. connection.execute(text(f"CREATE ROLE {admin.dialect.identifier_preparer.quote(control_login)} LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION INHERIT PASSWORD :password"), {"password": control_password})
  44. url = base.set(database=database).render_as_string(hide_password=False)
  45. engine = create_engine(url)
  46. with engine.begin() as connection:
  47. connection.execute(text("CREATE EXTENSION IF NOT EXISTS pgcrypto"))
  48. created_owner = not connection.execute(text("SELECT EXISTS(SELECT 1 FROM pg_roles WHERE rolname='dataops_plugin_platform_owner')")).scalar_one()
  49. created_control = not connection.execute(text("SELECT EXISTS(SELECT 1 FROM pg_roles WHERE rolname='dataops_plugin_platform_control')")).scalar_one()
  50. if created_owner:
  51. connection.execute(text("CREATE ROLE dataops_plugin_platform_owner NOLOGIN NOSUPERUSER NOCREATEROLE"))
  52. if created_control:
  53. connection.execute(text("CREATE ROLE dataops_plugin_platform_control NOLOGIN NOSUPERUSER NOCREATEROLE"))
  54. connection.execute(text("GRANT USAGE,CREATE ON SCHEMA public TO dataops_plugin_platform_owner"))
  55. assert _alembic(url, "stamp", "20260818_552").returncode == 0
  56. with engine.begin() as connection:
  57. connection.execute(text(f"CREATE ROLE {quoted_migrator} LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION PASSWORD :password"), {"password": password})
  58. connection.execute(text(f"GRANT dataops_plugin_platform_owner TO {quoted_migrator}"))
  59. connection.execute(text(f"GRANT USAGE,CREATE ON SCHEMA public TO {quoted_migrator}"))
  60. connection.execute(text(f"GRANT SELECT,UPDATE ON public.alembic_version TO {quoted_migrator}"))
  61. restricted_url = base.set(database=database, username=migrator, password=password).render_as_string(hide_password=False)
  62. upgraded = _alembic(restricted_url, "upgrade", "20260818_559")
  63. assert upgraded.returncode == 0, upgraded.stdout + upgraded.stderr
  64. with engine.begin() as connection:
  65. connection.execute(text(f"GRANT dataops_app_runtime TO {engine.dialect.identifier_preparer.quote(runtime_login)}"))
  66. connection.execute(text(f"GRANT dataops_plugin_platform_control TO {engine.dialect.identifier_preparer.quote(control_login)}"))
  67. with engine.connect() as connection:
  68. assert connection.execute(text("SELECT count(*) FROM public.plugin_registry_versions")).scalar_one() == 0
  69. assert not connection.execute(text("SELECT has_table_privilege('dataops_app_runtime','public.plugin_runs','SELECT')")).scalar_one()
  70. assert connection.execute(text("SELECT to_regprocedure('public.plugin_platform_runtime_execute(jsonb)') IS NULL")).scalar_one()
  71. with engine.begin() as connection:
  72. connection.execute(text("""INSERT INTO public.plugin_registry_versions(plugin_uid,version,plugin_type,manifest_digest,artifact_digest,trust_store_key_id,signature_digest,sbom_digest,license_digest,vulnerability_digest,provenance_digest,fixture_id,permissions,capabilities,resource)
  73. VALUES('fixture-fence-db','1.0.0','quality',:manifest_digest,:artifact_digest,'local-fixture-key-v1',:signature_digest,:sbom_digest,:license_digest,:vulnerability_digest,:provenance_digest,'ENGINEERING_EVIDENCE_ONLY',CAST(:permissions AS jsonb),CAST(:capabilities AS jsonb),CAST(:resource AS jsonb))"""), {"manifest_digest": "a" * 64, "artifact_digest": "b" * 64, "signature_digest": "c" * 64, "sbom_digest": "d" * 64, "license_digest": "e" * 64, "vulnerability_digest": "f" * 64, "provenance_digest": "0" * 64, "permissions": json.dumps({"file": False, "network": False, "secret": False, "child_process": False}), "capabilities": json.dumps(["evaluate"]), "resource": json.dumps({"timeout_ms": 100, "max_output_bytes": 4096, "max_concurrency": 1, "max_retries": 1})})
  74. refused_fence = _alembic(restricted_url, "downgrade", "20260818_556")
  75. assert refused_fence.returncode != 0
  76. refused_legacy_fence = _alembic(restricted_url, "downgrade", "20260818_555")
  77. assert refused_legacy_fence.returncode != 0
  78. with engine.connect() as connection:
  79. assert connection.execute(text("SELECT version_num FROM alembic_version")).scalar_one() == "20260818_559"
  80. assert connection.execute(text("SELECT count(*) FROM public.plugin_registry_versions WHERE plugin_uid='fixture-fence-db'")).scalar_one() == 1
  81. with engine.begin() as connection:
  82. connection.execute(text("DELETE FROM public.plugin_registry_versions WHERE plugin_uid='fixture-fence-db'"))
  83. assert _alembic(restricted_url, "downgrade", "20260818_556").returncode == 0
  84. assert _alembic(restricted_url, "upgrade", "20260818_559").returncode == 0
  85. from app import create_app
  86. from app.core.plugins.governance import (
  87. fixture_signature_digest,
  88. )
  89. runtime_url = base.set(database=database, username=runtime_login, password=runtime_password).render_as_string(hide_password=False)
  90. control_url = base.set(database=database, username=control_login, password=control_password).render_as_string(hide_password=False)
  91. monkeypatch.setenv("DB_ROLE_INIT_DATABASE_URL", url)
  92. monkeypatch.setenv("MIGRATION_DATABASE_URL", restricted_url)
  93. monkeypatch.setenv("DATABASE_URL", runtime_url)
  94. monkeypatch.setenv("DATAOPS_RUNTIME_USER", runtime_login)
  95. monkeypatch.setenv("DATAOPS_RUNTIME_PASSWORD", runtime_password)
  96. monkeypatch.setenv("DATAOPS_MIGRATOR_USER", migrator)
  97. monkeypatch.setenv("BI_AI_CATALOG_CONTROL_DATABASE_URL", control_url)
  98. monkeypatch.setenv("DATAOPS_BI_AI_CATALOG_CONTROL_USER", control_login)
  99. monkeypatch.setenv("DATAOPS_BI_AI_CATALOG_CONTROL_PASSWORD", control_password)
  100. from app.core.edge_gateway.runtime_roles import provision_runtime_login
  101. provision_runtime_login()
  102. control_attack = create_engine(control_url)
  103. try:
  104. with control_attack.connect() as connection:
  105. assert connection.execute(text("SELECT has_function_privilege(current_user,'public.plugin_platform_control_v2(jsonb)','EXECUTE')")).scalar_one() is False
  106. assert connection.execute(text("SELECT has_function_privilege(current_user,'public.plugin_platform_control_v3(jsonb)','EXECUTE')")).scalar_one() is False
  107. assert connection.execute(text("SELECT has_function_privilege(current_user,'public.plugin_platform_control_v4(jsonb)','EXECUTE')")).scalar_one() is False
  108. assert connection.execute(text("SELECT has_function_privilege(current_user,'public.plugin_platform_control_v5(jsonb)','EXECUTE')")).scalar_one() is True
  109. with pytest.raises(Exception):
  110. connection.execute(text("SELECT public.plugin_platform_control_v2('{}'::jsonb)"))
  111. finally:
  112. control_attack.dispose()
  113. runtime_attack = create_engine(runtime_url)
  114. try:
  115. with runtime_attack.connect() as connection:
  116. with pytest.raises(Exception):
  117. connection.execute(text("SET ROLE dataops_plugin_platform_control"))
  118. connection.rollback()
  119. with runtime_attack.connect() as connection:
  120. with pytest.raises(Exception):
  121. connection.execute(text("SELECT public.plugin_platform_runtime_execute('{}'::jsonb)"))
  122. with pytest.raises(Exception):
  123. connection.execute(text("SELECT public.plugin_platform_runtime_v2('{}'::jsonb)"))
  124. finally:
  125. runtime_attack.dispose()
  126. monkeypatch.setenv("PLUGIN_PLATFORM_CONTROL_DATABASE_URL", control_url)
  127. monkeypatch.setenv("TRUSTED_PLUGIN_TENANT", "tenant-a")
  128. monkeypatch.setenv("TRUSTED_PLUGIN_DOMAIN", "default")
  129. api_identities = {
  130. "submitter": {"id": "01900000-0000-7000-8000-000000000012", "roles": ["admin"]},
  131. "reviewer": {"id": "01900000-0000-7000-8000-000000000013", "roles": ["admin"]},
  132. "operator": {"id": "01900000-0000-7000-8000-000000000014", "roles": ["admin"]},
  133. }
  134. monkeypatch.setattr("app.core.system.auth.load_identity_from_token", lambda token, secret: api_identities.get(token))
  135. api_manifest = {"schema_version": 1, "plugin_uid": "fixture-api-db", "name": "fixture-api-db", "version": "1.0.0", "api_version": "1", "type": "quality", "capabilities": ["evaluate"], "permissions": {"network": False, "file": False, "secret": False, "child_process": False}, "resource": {"timeout_ms": 100, "max_output_bytes": 4096, "max_concurrency": 1, "max_retries": 1}, "compatibility": {"platform_api": "1"}, "distribution": {"kind": "builtin_fixture", "fixture_id": "ENGINEERING_EVIDENCE_ONLY", "artifact_digest": "c" * 64}}
  136. api_record = {"artifact_digest": "c" * 64, "signature": {"trust_store_key_id": "local-fixture-key-v1", "signature_digest": fixture_signature_digest("c" * 64)}, "sbom_digest": "d" * 64, "license_digest": "e" * 64, "vulnerability_digest": "f" * 64, "provenance_digest": "0" * 64}
  137. app = create_app()
  138. app.config.update(TESTING=True)
  139. client = app.test_client()
  140. api_created = client.post("/api/system/plugins/registry", json={"manifest": api_manifest, "registry_record": api_record}, headers={"Authorization": "Bearer submitter"})
  141. assert api_created.status_code == 201 and api_created.headers["Cache-Control"] == "no-store"
  142. pre_review_api_approval = client.post("/api/system/plugins/fixture-api-db/1.0.0/approvals", json={"approval_action": "approve"}, headers={"Authorization": "Bearer operator"})
  143. assert pre_review_api_approval.status_code == 400 and pre_review_api_approval.headers["Cache-Control"] == "no-store"
  144. api_reviewed = client.post("/api/system/plugins/fixture-api-db/1.0.0/review", json={}, headers={"Authorization": "Bearer reviewer"})
  145. assert api_reviewed.status_code == 200 and api_reviewed.headers["Cache-Control"] == "no-store"
  146. self_approval = client.post("/api/system/plugins/fixture-api-db/1.0.0/approvals", json={"approval_action": "approve"}, headers={"Authorization": "Bearer reviewer"})
  147. assert self_approval.status_code == 400 and self_approval.headers["Cache-Control"] == "no-store"
  148. submitter_approval = client.post("/api/system/plugins/fixture-api-db/1.0.0/approvals", json={"approval_action": "approve"}, headers={"Authorization": "Bearer submitter"})
  149. assert submitter_approval.status_code == 400 and submitter_approval.headers["Cache-Control"] == "no-store"
  150. api_approval = create_app().test_client().post("/api/system/plugins/fixture-api-db/1.0.0/approvals", json={"approval_action": "approve"}, headers={"Authorization": "Bearer operator"})
  151. assert api_approval.status_code == 201 and api_approval.headers["Cache-Control"] == "no-store"
  152. forged_reviewer = client.post("/api/system/plugins/fixture-api-db/1.0.0/approvals", json={"approval_action": "approve", "reviewer_ref": "forged"}, headers={"Authorization": "Bearer operator"})
  153. assert forged_reviewer.status_code == 400 and forged_reviewer.headers["Cache-Control"] == "no-store"
  154. duplicate = create_app().test_client().post("/api/system/plugins/registry", json={"manifest": api_manifest, "registry_record": api_record}, headers={"Authorization": "Bearer submitter"})
  155. assert duplicate.status_code == 400 and duplicate.headers["Cache-Control"] == "no-store"
  156. with engine.connect() as connection:
  157. assert connection.execute(text("SELECT state FROM public.plugin_registry_versions WHERE plugin_uid='fixture-api-db'")).scalar_one() == "reviewed"
  158. assert connection.execute(text("SELECT count(*) FROM public.plugin_registry_versions WHERE plugin_uid='fixture-api-db'")).scalar_one() == 1
  159. def control(payload: dict) -> dict:
  160. with engine.begin() as connection:
  161. connection.execute(text("SET LOCAL SESSION AUTHORIZATION dataops_plugin_platform_control"))
  162. return dict(connection.execute(text("SELECT public.plugin_platform_control_v5(CAST(:payload AS jsonb))"), {"payload": json.dumps(payload)}).scalar_one())
  163. artifact_digest = "b" * 64
  164. registered = control({"action": "register", "plugin_uid": "fixture-quality-db", "version": "1.0.0", "actor_ref": "author-a", "plugin_type": "quality", "manifest_digest": "a" * 64, "artifact_digest": artifact_digest, "signature_digest": hashlib.sha256(f"local-fixture-key-v1|{artifact_digest}".encode("ascii")).hexdigest(), "sbom_digest": "d" * 64, "license_digest": "e" * 64, "vulnerability_digest": "f" * 64, "provenance_digest": "0" * 64, "capabilities": ["evaluate"], "resource": {"timeout_ms": 100, "max_output_bytes": 4096, "max_concurrency": 1, "max_retries": 1}})
  165. assert registered["state"] == "draft"
  166. with pytest.raises(Exception):
  167. control({"action": "issue_approval", "plugin_uid": "fixture-quality-db", "version": "1.0.0", "actor_ref": "operator-a", "approval_action": "approve", "tenant_ref": "tenant-a", "domain_ref": "default", "expires_in_seconds": 300})
  168. with pytest.raises(Exception):
  169. control({"action": "review", "plugin_uid": "fixture-quality-db", "version": "1.0.0", "actor_ref": "author-a"})
  170. reviewed = control({"action": "review", "plugin_uid": "fixture-quality-db", "version": "1.0.0", "actor_ref": "reviewer-a"})
  171. with engine.connect() as connection:
  172. review_fact = connection.execute(text("SELECT state,review_actor,review_generation,reviewed_at,review_manifest_digest,manifest_digest FROM public.plugin_registry_versions WHERE plugin_uid='fixture-quality-db' AND version='1.0.0'")).mappings().one()
  173. assert review_fact["state"] == "reviewed" and review_fact["review_actor"] == "reviewer-a"
  174. assert review_fact["review_generation"] == 1 and review_fact["reviewed_at"] is not None
  175. assert review_fact["review_manifest_digest"] == review_fact["manifest_digest"]
  176. with pytest.raises(Exception):
  177. control({"action": "issue_approval", "plugin_uid": "fixture-quality-db", "version": "1.0.0", "actor_ref": "author-a", "approval_action": "approve", "tenant_ref": "tenant-a", "domain_ref": "default", "expires_in_seconds": 300})
  178. def approve(action: str) -> str:
  179. return control({"action": "issue_approval", "plugin_uid": "fixture-quality-db", "version": "1.0.0", "actor_ref": "operator-a", "approval_action": action, "tenant_ref": "tenant-a", "domain_ref": "default", "expires_in_seconds": 300})["approval_uid"]
  180. approval_ids = {action: approve(action) for action in ("approve", "canary", "activate", "recover")}
  181. with pytest.raises(Exception):
  182. control({"action": "issue_approval", "plugin_uid": "fixture-quality-db", "version": "1.0.0", "actor_ref": "reviewer-a", "approval_action": "pause", "tenant_ref": "tenant-a", "domain_ref": "default", "expires_in_seconds": 300})
  183. def transition(target: str, fence: int) -> dict:
  184. action = {"approved": "approve", "canary": "canary", "active": "activate", "paused": "pause", "rolled_back": "rollback", "revoked": "revoke", "recovery": "recover"}[target]
  185. return control({"action": "transition", "plugin_uid": "fixture-quality-db", "version": "1.0.0", "actor_ref": "operator-a", "tenant_ref": "tenant-a", "domain_ref": "default", "approval_uid": approval_ids[action], "target_state": target, "expected_fence": fence, "incident_uid": ""})
  186. approved = transition("approved", reviewed["fence"])
  187. with pytest.raises(Exception):
  188. control({"action": "transition", "plugin_uid": "fixture-quality-db", "version": "1.0.0", "actor_ref": "operator-a", "tenant_ref": "tenant-b", "domain_ref": "default", "approval_uid": approval_ids["canary"], "target_state": "canary", "expected_fence": approved["fence"], "incident_uid": ""})
  189. transition_barrier = Barrier(2)
  190. def canary_worker() -> tuple[str, dict | str]:
  191. try:
  192. transition_barrier.wait(timeout=3)
  193. return "ok", transition("canary", approved["fence"])
  194. except Exception as exc:
  195. return "denied", str(exc)
  196. with ThreadPoolExecutor(max_workers=2) as pool:
  197. transition_outcomes = list(pool.map(lambda _: canary_worker(), range(2)))
  198. assert sorted(item[0] for item in transition_outcomes) == ["denied", "ok"]
  199. canary = next(item[1] for item in transition_outcomes if item[0] == "ok")
  200. assert isinstance(canary, dict)
  201. active = transition("active", canary["fence"])
  202. assert active["state"] == "active"
  203. with pytest.raises(Exception):
  204. transition("active", active["fence"])
  205. with engine.connect() as connection:
  206. connection.execute(text("SET LOCAL SESSION AUTHORIZATION dataops_plugin_platform_control"))
  207. with pytest.raises(Exception):
  208. connection.execute(text("SELECT public.plugin_platform_issue_claim_v3(CAST(:payload AS jsonb))"), {"payload": json.dumps({"plugin_uid": "fixture-quality-db", "version": "1.0.0", "tenant_ref": "tenant-a", "domain_ref": "default", "principal_ref": "operator-a", "operation_name": "escalate", "input_digest": "1" * 64, "idempotency_key": "operation-escalation"})})
  209. connection.rollback()
  210. with engine.begin() as connection:
  211. connection.execute(text("SET LOCAL SESSION AUTHORIZATION dataops_plugin_platform_control"))
  212. claim = dict(connection.execute(text("SELECT public.plugin_platform_issue_claim_v3(CAST(:payload AS jsonb))"), {"payload": json.dumps({"plugin_uid": "fixture-quality-db", "version": "1.0.0", "tenant_ref": "tenant-a", "domain_ref": "default", "principal_ref": "operator-a", "operation_name": "evaluate", "input_digest": "2" * 64, "idempotency_key": "run-001"})}).scalar_one())
  213. with engine.begin() as connection:
  214. connection.execute(text("SET LOCAL SESSION AUTHORIZATION dataops_app_runtime"))
  215. queued = dict(connection.execute(text("SELECT public.plugin_platform_runtime_v3(CAST(:payload AS jsonb))"), {"payload": json.dumps({"action": "enqueue", "claim_uid": claim["claim_uid"], "idempotency_key": "run-001", "input_digest": "2" * 64, "operation_name": "evaluate"})}).scalar_one())
  216. barrier = Barrier(2)
  217. def claim_worker(worker: str):
  218. try:
  219. barrier.wait(timeout=3)
  220. with engine.begin() as connection:
  221. connection.execute(text("SET LOCAL SESSION AUTHORIZATION dataops_app_runtime"))
  222. return "ok", dict(connection.execute(text("SELECT public.plugin_platform_runtime_v3(CAST(:payload AS jsonb))"), {"payload": json.dumps({"action": "claim", "run_uid": queued["run_uid"], "worker": worker})}).scalar_one())
  223. except Exception as exc:
  224. return "denied", str(exc)
  225. with ThreadPoolExecutor(max_workers=2) as pool:
  226. outcomes = list(pool.map(claim_worker, ("worker-a", "worker-b")))
  227. assert sorted(item[0] for item in outcomes) == ["denied", "ok"]
  228. winning = next(item[1] for item in outcomes if item[0] == "ok")
  229. with engine.begin() as connection:
  230. connection.execute(text("SET LOCAL SESSION AUTHORIZATION dataops_app_runtime"))
  231. settled = dict(connection.execute(text("SELECT public.plugin_platform_runtime_v3(CAST(:payload AS jsonb))"), {"payload": json.dumps({"action": "settle", "run_uid": queued["run_uid"], "worker": winning["lease_owner"], "fence": winning["fence"], "success": True, "output_digest": "3" * 64, "failure_digest": "4" * 64})}).scalar_one())
  232. assert settled["state"] == "succeeded"
  233. def issue(input_digest: str, idempotency_key: str) -> dict:
  234. with engine.begin() as connection:
  235. connection.execute(text("SET LOCAL SESSION AUTHORIZATION dataops_plugin_platform_control"))
  236. return dict(connection.execute(text("SELECT public.plugin_platform_issue_claim_v3(CAST(:payload AS jsonb))"), {"payload": json.dumps({"plugin_uid": "fixture-quality-db", "version": "1.0.0", "tenant_ref": "tenant-a", "domain_ref": "default", "principal_ref": "operator-a", "operation_name": "evaluate", "input_digest": input_digest, "idempotency_key": idempotency_key})}).scalar_one())
  237. def runtime(payload: dict) -> dict:
  238. with engine.begin() as connection:
  239. connection.execute(text("SET LOCAL SESSION AUTHORIZATION dataops_app_runtime"))
  240. return dict(connection.execute(text("SELECT public.plugin_platform_runtime_v3(CAST(:payload AS jsonb))"), {"payload": json.dumps(payload)}).scalar_one())
  241. replay_claim = issue("2" * 64, "run-001")
  242. replay = runtime({"action": "enqueue", "claim_uid": replay_claim["claim_uid"], "idempotency_key": "run-001", "input_digest": "2" * 64, "operation_name": "evaluate"})
  243. assert replay["run_uid"] == queued["run_uid"] and replay["replay"] is True
  244. changed_claim = issue("5" * 64, "run-001")
  245. with pytest.raises(Exception):
  246. runtime({"action": "enqueue", "claim_uid": changed_claim["claim_uid"], "idempotency_key": "run-001", "input_digest": "5" * 64, "operation_name": "evaluate"})
  247. failed_claim = issue("8" * 64, "run-fail")
  248. failed = runtime({"action": "enqueue", "claim_uid": failed_claim["claim_uid"], "idempotency_key": "run-fail", "input_digest": "8" * 64, "operation_name": "evaluate"})
  249. late = runtime({"action": "claim", "run_uid": failed["run_uid"], "worker": "worker-late"})
  250. with engine.begin() as connection:
  251. connection.execute(text("UPDATE public.plugin_runs SET lease_expires_at=clock_timestamp()-interval '1 second' WHERE run_uid=:run_uid"), {"run_uid": failed["run_uid"]})
  252. replacement = runtime({"action": "claim", "run_uid": failed["run_uid"], "worker": "worker-replacement"})
  253. with pytest.raises(Exception):
  254. runtime({"action": "settle", "run_uid": failed["run_uid"], "worker": late["lease_owner"], "fence": late["fence"], "success": False, "output_digest": "0" * 64, "failure_digest": "9" * 64})
  255. first_failed = runtime({"action": "settle", "run_uid": failed["run_uid"], "worker": replacement["lease_owner"], "fence": replacement["fence"], "success": False, "output_digest": "0" * 64, "failure_digest": "9" * 64})
  256. assert first_failed["state"] == "pending"
  257. for retry in range(2):
  258. with engine.begin() as connection:
  259. connection.execute(text("UPDATE public.plugin_runs SET next_attempt_at=clock_timestamp() WHERE run_uid=:run_uid"), {"run_uid": failed["run_uid"]})
  260. lease = runtime({"action": "claim", "run_uid": failed["run_uid"], "worker": f"retry-{retry}"})
  261. dead = runtime({"action": "settle", "run_uid": failed["run_uid"], "worker": lease["lease_owner"], "fence": lease["fence"], "success": False, "output_digest": "0" * 64, "failure_digest": "9" * 64})
  262. assert dead["state"] == "dead_letter"
  263. with pytest.raises(Exception):
  264. runtime({"action": "recover", "run_uid": failed["run_uid"], "worker": "runtime-attacker"})
  265. recovery_incident = str(uuid.uuid4())
  266. recovery_approval = approval_ids["recover"]
  267. with engine.connect() as connection:
  268. connection.execute(text("SET LOCAL SESSION AUTHORIZATION dataops_plugin_platform_control"))
  269. with pytest.raises(Exception):
  270. connection.execute(text("SELECT public.plugin_platform_issue_recovery_claim(CAST(:payload AS jsonb))"), {"payload": json.dumps({"plugin_uid": "fixture-quality-db", "version": "1.0.0", "actor_ref": "operator-a", "tenant_ref": "tenant-b", "domain_ref": "default", "run_uid": failed["run_uid"], "approval_uid": recovery_approval, "incident_uid": recovery_incident, "expected_fence": dead["fence"]})})
  271. connection.rollback()
  272. with engine.connect() as connection:
  273. connection.execute(text("SET LOCAL SESSION AUTHORIZATION dataops_plugin_platform_control"))
  274. with pytest.raises(Exception):
  275. connection.execute(text("SELECT public.plugin_platform_issue_recovery_claim(CAST(:payload AS jsonb))"), {"payload": json.dumps({"plugin_uid": "fixture-quality-db", "version": "1.0.0", "actor_ref": "operator-a", "tenant_ref": "tenant-a", "domain_ref": "default", "run_uid": failed["run_uid"], "approval_uid": recovery_approval, "incident_uid": recovery_incident, "expected_fence": dead["fence"] + 1})})
  276. connection.rollback()
  277. with engine.begin() as connection:
  278. connection.execute(text("SET LOCAL SESSION AUTHORIZATION dataops_plugin_platform_control"))
  279. recovery_claim = dict(connection.execute(text("SELECT public.plugin_platform_issue_recovery_claim(CAST(:payload AS jsonb))"), {"payload": json.dumps({"plugin_uid": "fixture-quality-db", "version": "1.0.0", "actor_ref": "operator-a", "tenant_ref": "tenant-a", "domain_ref": "default", "run_uid": failed["run_uid"], "approval_uid": recovery_approval, "incident_uid": recovery_incident, "expected_fence": dead["fence"]})}).scalar_one())
  280. recovered = runtime({"action": "recover", "claim_uid": recovery_claim["claim_uid"], "worker": "recovery-worker"})
  281. assert recovered["state"] == "pending"
  282. with pytest.raises(Exception):
  283. runtime({"action": "recover", "claim_uid": recovery_claim["claim_uid"], "worker": "recovery-replay"})
  284. with engine.connect() as connection:
  285. assert connection.execute(text("SELECT count(*) FROM public.plugin_dead_letters WHERE run_uid=:run_uid"), {"run_uid": failed["run_uid"]}).scalar_one() == 0
  286. assert connection.execute(text("SELECT count(*) FROM public.plugin_audit_outbox WHERE event_type IN ('active','invoked','dead_letter')")).scalar_one() >= 3
  287. assert _alembic(restricted_url, "downgrade", "20260818_554").returncode != 0
  288. with engine.begin() as connection:
  289. for table in ("plugin_recovery_claims", "plugin_dead_letters", "plugin_runs", "plugin_request_claims", "plugin_runtime_breakers", "plugin_approvals", "plugin_audit_outbox", "plugin_registry_versions"):
  290. connection.execute(text(f"DELETE FROM public.{table}"))
  291. assert _alembic(restricted_url, "downgrade", "20260818_554").returncode == 0
  292. assert _alembic(restricted_url, "upgrade", "20260818_555").returncode == 0
  293. assert _alembic(restricted_url, "upgrade", "20260818_556").returncode == 0
  294. assert _alembic(restricted_url, "upgrade", "20260818_557").returncode == 0
  295. assert _alembic(restricted_url, "upgrade", "20260818_559").returncode == 0
  296. finally:
  297. engine.dispose() if "engine" in locals() else None
  298. with admin.connect() as connection:
  299. connection.execute(text("SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname=:name"), {"name": database})
  300. connection.execute(text(f"DROP DATABASE IF EXISTS {quoted_database}"))
  301. connection.execute(text(f"DROP ROLE IF EXISTS {quoted_migrator}"))
  302. connection.execute(text(f"DROP ROLE IF EXISTS {admin.dialect.identifier_preparer.quote(runtime_login)}"))
  303. connection.execute(text(f"DROP ROLE IF EXISTS {admin.dialect.identifier_preparer.quote(control_login)}"))
  304. if created_control:
  305. connection.execute(text("DROP ROLE IF EXISTS dataops_plugin_platform_control"))
  306. if created_owner:
  307. connection.execute(text("DROP ROLE IF EXISTS dataops_plugin_platform_owner"))
  308. admin.dispose()