test_phase3_wp06_http_commit_postgres.py 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. """Real Flask/SQLAlchemy commit boundary checks for trusted-delivery HTTP."""
  2. from __future__ import annotations
  3. import os
  4. import uuid
  5. from datetime import UTC, datetime, timedelta
  6. import pytest
  7. from sqlalchemy import create_engine, text
  8. pytestmark = pytest.mark.integration
  9. def _url():
  10. value = os.environ.get("TEST_DATABASE_URL")
  11. if not value:
  12. pytest.skip("TEST_DATABASE_URL is required")
  13. return value
  14. def _policy(actor, code):
  15. return {
  16. "code": code,
  17. "version": "1.0.0",
  18. "selector": {
  19. "subjects": [actor], "roles": ["editor"],
  20. "business_domains": [str(uuid.uuid4())], "assets": [str(uuid.uuid4())],
  21. "purposes": ["quality_review"], "environments": ["test"],
  22. "actions": ["read"], "classifications": ["sensitive"],
  23. "expires_at": (datetime.now(UTC) + timedelta(days=1)).isoformat(),
  24. },
  25. "resource_rules": {
  26. "row_filter": {"op": "eq", "field": "region", "value": "CN-31"},
  27. "field_rules": [{"field": "code", "effect": "allow", "mask_ref": None}],
  28. },
  29. }
  30. def test_trusted_delivery_http_success_is_committed_and_commit_failure_rolls_back(monkeypatch):
  31. """A 201 is observable by another connection; a failed commit leaves no row."""
  32. database_url = _url()
  33. actor = str(uuid.uuid4())
  34. prefix = f"WP06_HTTP_{actor[:8].upper()}"
  35. engine = create_engine(database_url, pool_pre_ping=True)
  36. try:
  37. with engine.begin() as connection:
  38. connection.execute(text("""INSERT INTO public.users(id,username,display_name,password_hash,status)
  39. VALUES(CAST(:id AS uuid),:name,:name,'test','active')"""), {"id": actor, "name": f"wp06-test-http-{actor[:8]}"})
  40. monkeypatch.setenv("DATABASE_URL", database_url)
  41. monkeypatch.setattr(
  42. "app.core.system.permissions.authenticate_request",
  43. lambda: {"id": actor, "sub": actor, "roles": ["editor"]},
  44. )
  45. from app import create_app, db
  46. app = create_app()
  47. app.config.update(TESTING=True)
  48. client = app.test_client()
  49. response = client.post("/api/system/trusted-delivery/policy-versions", json=_policy(actor, f"{prefix}_OK"))
  50. assert response.status_code == 201
  51. assert response.headers["Cache-Control"] == "no-store"
  52. with engine.connect() as observer:
  53. assert observer.execute(text("SELECT count(*) FROM public.trusted_delivery_policy_versions WHERE code=:code"), {"code": f"{prefix}_OK"}).scalar_one() == 1
  54. def fail_commit():
  55. raise RuntimeError("synthetic commit failure")
  56. monkeypatch.setattr(db.session, "commit", fail_commit)
  57. rejected = client.post("/api/system/trusted-delivery/policy-versions", json=_policy(actor, f"{prefix}_ROLLBACK"))
  58. assert rejected.status_code == 400
  59. with engine.connect() as observer:
  60. assert observer.execute(text("SELECT count(*) FROM public.trusted_delivery_policy_versions WHERE code=:code"), {"code": f"{prefix}_ROLLBACK"}).scalar_one() == 0
  61. finally:
  62. with engine.begin() as connection:
  63. connection.execute(text("DELETE FROM public.trusted_delivery_policy_transitions WHERE policy_uid IN (SELECT uid FROM public.trusted_delivery_policy_versions WHERE code LIKE :prefix)"), {"prefix": f"{prefix}%"})
  64. connection.execute(text("DELETE FROM public.trusted_delivery_policy_versions WHERE code LIKE :prefix"), {"prefix": f"{prefix}%"})
  65. connection.execute(text("ALTER TABLE public.trusted_delivery_evidence DISABLE TRIGGER USER"))
  66. connection.execute(text("DELETE FROM public.trusted_delivery_evidence WHERE actor_uid=CAST(:id AS uuid)"), {"id": actor})
  67. connection.execute(text("ALTER TABLE public.trusted_delivery_evidence ENABLE TRIGGER USER"))
  68. connection.execute(text("DELETE FROM public.users WHERE id=CAST(:id AS uuid)"), {"id": actor})
  69. engine.dispose()