| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549 |
- from __future__ import annotations
- import os
- import subprocess
- import threading
- import uuid
- from concurrent.futures import ThreadPoolExecutor
- from pathlib import Path
- import pytest
- from sqlalchemy import create_engine, text
- from sqlalchemy.engine import make_url
- from sqlalchemy.exc import SQLAlchemyError
- from app.core.system.tenant_repository import SqlAlchemyTenantFoundationRepository
- pytestmark = pytest.mark.integration
- ROOT = Path(__file__).resolve().parents[2]
- def test_wp10_real_postgres_runtime_is_rls_scoped_and_two_connections_cannot_overreserve():
- # Superseded by claim-bound tests below: direct runtime repository access
- # must now fail before any payload or tenant GUC can reach PostgreSQL.
- with pytest.raises(RuntimeError, match="tenant_legacy_gateway_sealed"):
- SqlAlchemyTenantFoundationRepository(object())
- return
- database_url = os.getenv("TEST_DATABASE_URL")
- if not database_url:
- pytest.skip("TEST_DATABASE_URL is required")
- tenant_id = f"wp10-{uuid.uuid4().hex[:16]}"
- engine = create_engine(database_url, pool_pre_ping=True)
- try:
- with engine.begin() as connection:
- repository = SqlAlchemyTenantFoundationRepository(connection)
- repository.provision(tenant_id, "private_single_tenant", "provision-1")
- first = engine.connect()
- second = engine.connect()
- first_transaction = first.begin()
- second_transaction = second.begin()
- try:
- first_repo = SqlAlchemyTenantFoundationRepository(first)
- second_repo = SqlAlchemyTenantFoundationRepository(second)
- fence = first_repo.reserve_quota(tenant_id, "records", 1, "reserve-1")
- first_transaction.commit()
- with pytest.raises(ValueError, match="tenant_quota_exhausted"):
- second_repo.reserve_quota(tenant_id, "records", 1, "reserve-2")
- second_transaction.rollback()
- with engine.begin() as check:
- runtime = SqlAlchemyTenantFoundationRepository(check)
- assert runtime.list_audit(tenant_id)[0]["tenant_id"] == tenant_id
- with pytest.raises(ValueError, match="tenant_scope_denied"):
- runtime.list_audit("wrong-tenant")
- assert fence == 1
- finally:
- if first_transaction.is_active:
- first_transaction.rollback()
- if second_transaction.is_active:
- second_transaction.rollback()
- first.close()
- second.close()
- finally:
- with engine.begin() as cleanup:
- cleanup.execute(text("DELETE FROM public.tenant_quota_reservations WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_audit_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_quotas WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenants WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- engine.dispose()
- def test_wp10_runtime_role_cannot_directly_mutate_tenant_audit_after_role_init():
- with pytest.raises(RuntimeError, match="tenant_legacy_gateway_sealed"):
- SqlAlchemyTenantFoundationRepository(object())
- return
- database_url = os.getenv("TEST_DATABASE_URL")
- runtime_url = os.getenv("TEST_RUNTIME_DATABASE_URL")
- if not database_url or not runtime_url:
- pytest.skip("TEST_DATABASE_URL and TEST_RUNTIME_DATABASE_URL are required")
- tenant_id = f"wp10-{uuid.uuid4().hex[:16]}"
- admin = create_engine(database_url, pool_pre_ping=True)
- runtime = create_engine(runtime_url, pool_pre_ping=True)
- try:
- with admin.begin() as connection:
- SqlAlchemyTenantFoundationRepository(connection).provision(
- tenant_id, "private_single_tenant", "provision-1"
- )
- with runtime.begin() as connection:
- connection.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- with pytest.raises(SQLAlchemyError):
- connection.execute(text("DELETE FROM public.tenant_audit_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- finally:
- with admin.begin() as cleanup:
- cleanup.execute(text("DELETE FROM public.tenant_quota_reservations WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_audit_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_quotas WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenants WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- runtime.dispose()
- admin.dispose()
- def test_wp10_lifecycle_fence_replay_and_frozen_task_rejection_persist_in_postgres():
- with pytest.raises(RuntimeError, match="tenant_legacy_gateway_sealed"):
- SqlAlchemyTenantFoundationRepository(object())
- return
- database_url = os.getenv("TEST_DATABASE_URL")
- if not database_url:
- pytest.skip("TEST_DATABASE_URL is required")
- tenant_id = f"wp10-{uuid.uuid4().hex[:16]}"
- engine = create_engine(database_url, pool_pre_ping=True)
- try:
- with engine.begin() as connection:
- repository = SqlAlchemyTenantFoundationRepository(connection)
- repository.provision(tenant_id, "private_single_tenant", "provision-1")
- frozen = repository.transition_lifecycle(tenant_id, "freeze", 0, "freeze-1")
- replay = repository.transition_lifecycle(tenant_id, "freeze", 0, "freeze-1")
- assert replay == frozen
- with pytest.raises(ValueError, match="tenant_fence_conflict"):
- repository.transition_lifecycle(tenant_id, "begin_recovery", 0, "recover-1", approval_ref="approval-1")
- with pytest.raises(ValueError, match="tenant_not_active"):
- repository.reserve_quota(tenant_id, "background_tasks", 1, "task-while-frozen")
- recovered = repository.transition_lifecycle(tenant_id, "begin_recovery", frozen, "recover-1", approval_ref="approval-1")
- active = repository.transition_lifecycle(tenant_id, "activate", recovered, "activate-1", approval_ref="approval-1")
- assert active > recovered > frozen
- finally:
- with engine.begin() as cleanup:
- cleanup.execute(text("DELETE FROM public.tenant_quota_reservations WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_lifecycle_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_audit_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_quotas WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenants WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- engine.dispose()
- def test_wp10_postgres_quota_accepts_bounded_decimal_without_overreserve():
- with pytest.raises(RuntimeError, match="tenant_legacy_gateway_sealed"):
- SqlAlchemyTenantFoundationRepository(object())
- return
- database_url = os.getenv("TEST_DATABASE_URL")
- if not database_url:
- pytest.skip("TEST_DATABASE_URL is required")
- tenant_id = f"wp10-{uuid.uuid4().hex[:16]}"
- engine = create_engine(database_url, pool_pre_ping=True)
- try:
- with engine.begin() as connection:
- repository = SqlAlchemyTenantFoundationRepository(connection)
- repository.provision(tenant_id, "private_single_tenant", "provision-1")
- assert repository.reserve_quota(tenant_id, "records", 0.5, "decimal-1") == 1
- with pytest.raises(ValueError, match="tenant_quota_exhausted"):
- repository.reserve_quota(tenant_id, "records", 0.75, "decimal-2")
- finally:
- with engine.begin() as cleanup:
- cleanup.execute(text("DELETE FROM public.tenant_quota_reservations WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_audit_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_quotas WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenants WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- engine.dispose()
- def test_wp10_runtime_cannot_claim_another_tenant_by_payload_or_guc():
- database_url = os.getenv("TEST_DATABASE_URL")
- if not database_url:
- pytest.skip("TEST_DATABASE_URL is required")
- alpha = f"wp10-alpha-{uuid.uuid4().hex[:12]}"
- beta = f"wp10-beta-{uuid.uuid4().hex[:12]}"
- runtime_name = f"wp10_runtime_{uuid.uuid4().hex[:12]}"
- runtime_password = f"wp10_{uuid.uuid4().hex}"
- admin = create_engine(database_url, pool_pre_ping=True)
- runtime = None
- try:
- with admin.begin() as connection:
- quoted_runtime = connection.dialect.identifier_preparer.quote(runtime_name)
- connection.execute(text(f"CREATE ROLE {quoted_runtime} LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION PASSWORD :password"), {"password": runtime_password})
- connection.execute(text(f"GRANT dataops_app_runtime TO {quoted_runtime}"))
- connection.execute(text("INSERT INTO public.tenants(tenant_id,delivery_mode,state) VALUES(:tenant_id,'private_single_tenant','active')"), {"tenant_id": alpha})
- runtime = create_engine(make_url(database_url).set(username=runtime_name, password=runtime_password).render_as_string(hide_password=False), pool_pre_ping=True)
- with runtime.begin() as connection:
- connection.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": alpha})
- with pytest.raises(SQLAlchemyError, match="permission denied"):
- connection.execute(text("SELECT public.tenant_foundation_write('provision', CAST(:payload AS jsonb))"), {"payload": f'{{"tenant_id":"{beta}","delivery_mode":"private_single_tenant","idempotency_key":"beta-provision"}}'})
- with admin.connect() as connection:
- assert connection.execute(text("SELECT count(*) FROM public.tenants WHERE tenant_id=:tenant_id"), {"tenant_id": beta}).scalar_one() == 0
- finally:
- with admin.begin() as cleanup:
- for tenant_id in (alpha, beta):
- cleanup.execute(text("DELETE FROM public.tenant_quota_reservations WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_audit_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_quotas WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenants WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- if runtime is not None:
- runtime.dispose()
- with admin.begin() as connection:
- connection.execute(text(f"DROP ROLE IF EXISTS {connection.dialect.identifier_preparer.quote(runtime_name)}"))
- admin.dispose()
- def test_wp10_control_claim_is_membership_derived_one_shot_and_runtime_cannot_issue():
- database_url = os.getenv("TEST_DATABASE_URL")
- if not database_url:
- pytest.skip("TEST_DATABASE_URL is required")
- tenant_id = f"wp10-claim-{uuid.uuid4().hex[:12]}"
- principal = str(uuid.uuid4())
- claim_uid, nonce = str(uuid.uuid4()), str(uuid.uuid4())
- control_name = f"wp10_control_{uuid.uuid4().hex[:12]}"
- control_password = f"wp10_{uuid.uuid4().hex}"
- runtime_name = f"wp10_runtime_{uuid.uuid4().hex[:12]}"
- runtime_password = f"wp10_{uuid.uuid4().hex}"
- admin = create_engine(database_url, pool_pre_ping=True)
- runtime = None
- control = None
- try:
- with admin.begin() as connection:
- quoted_control = connection.dialect.identifier_preparer.quote(control_name)
- connection.execute(text(
- f"CREATE ROLE {quoted_control} LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION PASSWORD :password"
- ), {"password": control_password})
- connection.execute(text(f"GRANT dataops_tenant_control TO {quoted_control}"))
- quoted_runtime = connection.dialect.identifier_preparer.quote(runtime_name)
- connection.execute(text(
- f"CREATE ROLE {quoted_runtime} LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION PASSWORD :password"
- ), {"password": runtime_password})
- connection.execute(text(f"GRANT dataops_app_runtime TO {quoted_runtime}"))
- connection.execute(text("INSERT INTO public.tenants(tenant_id,delivery_mode,state) VALUES(:tenant_id,'private_single_tenant','active')"), {"tenant_id": tenant_id})
- connection.execute(text("INSERT INTO public.tenant_control_memberships(tenant_id,principal_id,host) VALUES(:tenant_id,:principal,'private.example')"), {"tenant_id": tenant_id, "principal": principal})
- control_url = make_url(database_url).set(username=control_name, password=control_password).render_as_string(hide_password=False)
- control = create_engine(control_url, pool_pre_ping=True)
- runtime = create_engine(make_url(database_url).set(username=runtime_name, password=runtime_password).render_as_string(hide_password=False), pool_pre_ping=True)
- with control.begin() as connection:
- assert connection.execute(text("SELECT current_user")).scalar_one() == control_name
- issued = connection.execute(text("SELECT public.tenant_control_issue_claim(CAST(:payload AS jsonb))"), {"payload": f'{{"claim_uid":"{claim_uid}","nonce":"{nonce}","principal_id":"{principal}","host":"private.example","action":"quota_reserve","request":{{"quota_name":"records","amount":"1","idempotency_key":"claim-reserve-1"}}}}'}).scalar_one()
- assert dict(issued)["tenant_id"] == tenant_id
- with runtime.begin() as connection, pytest.raises(SQLAlchemyError):
- connection.execute(text("SELECT public.tenant_control_issue_claim(CAST(:payload AS jsonb))"), {"payload": "{}"})
- with control.begin() as connection:
- assert dict(connection.execute(text("SELECT public.tenant_control_consume_claim(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),:action,CAST(:request AS jsonb))"), {"claim_uid": claim_uid, "nonce": nonce, "action": "quota_reserve", "request": '{"quota_name":"records","amount":"1","idempotency_key":"claim-reserve-1"}'}).scalar_one())["tenant_id"] == tenant_id
- with pytest.raises(SQLAlchemyError):
- connection.execute(text("SELECT public.tenant_control_consume_claim(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),:action,CAST(:request AS jsonb))"), {"claim_uid": claim_uid, "nonce": nonce, "action": "quota_reserve", "request": '{"quota_name":"records","amount":"1","idempotency_key":"claim-reserve-1"}'})
- finally:
- with admin.begin() as cleanup:
- cleanup.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_outbox_scope_lookup WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_outbox WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_claims WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_memberships WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- # The append-only tenant audit table is RLS-scoped even for the
- # owner role. Test cleanup must declare the exact generated
- # tenant scope; it must not weaken RLS or use a broad delete.
- cleanup.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_audit_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenants WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- if control is not None:
- control.dispose()
- if runtime is not None:
- runtime.dispose()
- with admin.begin() as connection:
- connection.execute(text(f"DROP ROLE IF EXISTS {connection.dialect.identifier_preparer.quote(control_name)}"))
- connection.execute(text(f"DROP ROLE IF EXISTS {connection.dialect.identifier_preparer.quote(runtime_name)}"))
- admin.dispose()
- def test_wp10_control_claim_two_connections_allow_one_consumer_and_reject_after_restart():
- database_url = os.getenv("TEST_DATABASE_URL")
- if not database_url:
- pytest.skip("TEST_DATABASE_URL is required")
- tenant_id = f"wp10-claim-race-{uuid.uuid4().hex[:10]}"
- principal = str(uuid.uuid4())
- claim_uid, nonce = str(uuid.uuid4()), str(uuid.uuid4())
- request_json = '{"quota_name":"records","amount":"1","idempotency_key":"claim-race-1"}'
- control_name = f"wp10_control_{uuid.uuid4().hex[:12]}"
- control_password = f"wp10_{uuid.uuid4().hex}"
- admin = create_engine(database_url, pool_pre_ping=True)
- control = None
- try:
- with admin.begin() as connection:
- quoted_control = connection.dialect.identifier_preparer.quote(control_name)
- connection.execute(text(
- f"CREATE ROLE {quoted_control} LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION PASSWORD :password"
- ), {"password": control_password})
- connection.execute(text(f"GRANT dataops_tenant_control TO {quoted_control}"))
- connection.execute(text("INSERT INTO public.tenants(tenant_id,delivery_mode,state) VALUES(:tenant_id,'private_single_tenant','active')"), {"tenant_id": tenant_id})
- connection.execute(text("INSERT INTO public.tenant_control_memberships(tenant_id,principal_id,host) VALUES(:tenant_id,:principal,'private.example')"), {"tenant_id": tenant_id, "principal": principal})
- control_url = make_url(database_url).set(username=control_name, password=control_password).render_as_string(hide_password=False)
- control = create_engine(control_url, pool_pre_ping=True)
- with control.begin() as connection:
- connection.execute(text("SELECT public.tenant_control_issue_claim(CAST(:payload AS jsonb))"), {"payload": f'{{"claim_uid":"{claim_uid}","nonce":"{nonce}","principal_id":"{principal}","host":"private.example","action":"quota_reserve","request":{request_json}}}'})
- barrier = threading.Barrier(2)
- def consume_once() -> bool:
- with control.begin() as connection:
- barrier.wait(timeout=10)
- try:
- connection.execute(text("SELECT public.tenant_control_consume_claim(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),:action,CAST(:request AS jsonb))"), {"claim_uid": claim_uid, "nonce": nonce, "action": "quota_reserve", "request": request_json}).scalar_one()
- return True
- except SQLAlchemyError:
- return False
- with ThreadPoolExecutor(max_workers=2) as workers:
- outcomes = list(workers.map(lambda _: consume_once(), range(2)))
- assert outcomes.count(True) == 1
- assert outcomes.count(False) == 1
- control.dispose()
- control = create_engine(control_url, pool_pre_ping=True)
- with control.begin() as restarted, pytest.raises(SQLAlchemyError, match="tenant_claim_replayed_or_expired"):
- restarted.execute(text("SELECT public.tenant_control_consume_claim(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),:action,CAST(:request AS jsonb))"), {"claim_uid": claim_uid, "nonce": nonce, "action": "quota_reserve", "request": request_json})
- finally:
- if control is not None:
- control.dispose()
- with admin.begin() as cleanup:
- cleanup.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_outbox_scope_lookup WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_outbox WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_claims WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_memberships WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_audit_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenants WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text(f"DROP ROLE IF EXISTS {cleanup.dialect.identifier_preparer.quote(control_name)}"))
- admin.dispose()
- def test_wp10_control_claim_binds_decimal_quota_reserve_and_release_atomically():
- database_url = os.getenv("TEST_DATABASE_URL")
- if not database_url:
- pytest.skip("TEST_DATABASE_URL is required")
- tenant_id = f"wp10-quota-{uuid.uuid4().hex[:14]}"
- principal = str(uuid.uuid4())
- control_name = f"wp10_control_{uuid.uuid4().hex[:12]}"
- control_password = f"wp10_{uuid.uuid4().hex}"
- request_json = '{"quota_name":"records","amount":"0.5","idempotency_key":"quota-1"}'
- admin = create_engine(database_url, pool_pre_ping=True)
- control = None
- try:
- with admin.begin() as connection:
- quoted_control = connection.dialect.identifier_preparer.quote(control_name)
- connection.execute(text(f"CREATE ROLE {quoted_control} LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION PASSWORD :password"), {"password": control_password})
- connection.execute(text(f"GRANT dataops_tenant_control TO {quoted_control}"))
- connection.execute(text("INSERT INTO public.tenants(tenant_id,delivery_mode,state) VALUES(:tenant_id,'private_single_tenant','active')"), {"tenant_id": tenant_id})
- connection.execute(text("INSERT INTO public.tenant_quotas(tenant_id,quota_name,limit_units) VALUES(:tenant_id,'records',1)"), {"tenant_id": tenant_id})
- connection.execute(text("INSERT INTO public.tenant_control_memberships(tenant_id,principal_id,host) VALUES(:tenant_id,:principal,'private.example')"), {"tenant_id": tenant_id, "principal": principal})
- control_url = make_url(database_url).set(username=control_name, password=control_password).render_as_string(hide_password=False)
- control = create_engine(control_url, pool_pre_ping=True)
- def claim(action: str, request: str) -> tuple[str, str]:
- claim_uid, nonce = str(uuid.uuid4()), str(uuid.uuid4())
- with control.begin() as connection:
- connection.execute(text("SELECT public.tenant_control_issue_claim(CAST(:payload AS jsonb))"), {"payload": f'{{"claim_uid":"{claim_uid}","nonce":"{nonce}","principal_id":"{principal}","host":"private.example","action":"{action}","request":{request}}}'})
- return claim_uid, nonce
- reserve_claim, reserve_nonce = claim("quota_reserve", request_json)
- with control.begin() as connection:
- reserved = connection.execute(text("SELECT public.tenant_control_quota_mutate(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),:action,CAST(:request AS jsonb))"), {"claim_uid": reserve_claim, "nonce": reserve_nonce, "action": "quota_reserve", "request": request_json}).scalar_one()
- assert dict(reserved)["status"] == "reserved"
- with control.begin() as connection, pytest.raises(SQLAlchemyError):
- connection.execute(text("SELECT public.tenant_control_quota_mutate(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),:action,CAST(:request AS jsonb))"), {"claim_uid": reserve_claim, "nonce": reserve_nonce, "action": "quota_reserve", "request": request_json})
- release_request = '{"quota_name":"records","idempotency_key":"quota-1","lease_fence":"1"}'
- release_claim, release_nonce = claim("quota_release", release_request)
- with control.begin() as connection:
- released = connection.execute(text("SELECT public.tenant_control_quota_mutate(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),:action,CAST(:request AS jsonb))"), {"claim_uid": release_claim, "nonce": release_nonce, "action": "quota_release", "request": release_request}).scalar_one()
- assert dict(released)["status"] == "released"
- with admin.connect() as check:
- assert check.execute(text("SELECT reserved_units FROM public.tenant_quotas WHERE tenant_id=:tenant_id AND quota_name='records'"), {"tenant_id": tenant_id}).scalar_one() == 0
- settle_request = '{"quota_name":"records","amount":"0.25","idempotency_key":"settle-1"}'
- settle_reserve_claim, settle_reserve_nonce = claim("quota_reserve", settle_request)
- with control.begin() as connection:
- assert dict(connection.execute(text("SELECT public.tenant_control_quota_mutate(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),:action,CAST(:request AS jsonb))"), {"claim_uid": settle_reserve_claim, "nonce": settle_reserve_nonce, "action": "quota_reserve", "request": settle_request}).scalar_one())["status"] == "reserved"
- settle_request = '{"quota_name":"records","idempotency_key":"settle-1","lease_fence":"3"}'
- settle_claim, settle_nonce = claim("quota_settle", settle_request)
- with control.begin() as connection:
- assert dict(connection.execute(text("SELECT public.tenant_control_quota_mutate(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),:action,CAST(:request AS jsonb))"), {"claim_uid": settle_claim, "nonce": settle_nonce, "action": "quota_settle", "request": settle_request}).scalar_one())["status"] == "settled"
- late_claim, late_nonce = claim("quota_release", settle_request)
- with control.begin() as connection, pytest.raises(SQLAlchemyError, match="tenant_quota_terminal"):
- connection.execute(text("SELECT public.tenant_control_quota_mutate(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),:action,CAST(:request AS jsonb))"), {"claim_uid": late_claim, "nonce": late_nonce, "action": "quota_release", "request": settle_request})
- invalid_request = '{"quota_name":"records","amount":1.0,"idempotency_key":"float-1"}'
- invalid_claim, invalid_nonce = claim("quota_reserve", invalid_request)
- with control.begin() as connection, pytest.raises(SQLAlchemyError, match="tenant_payload_closed"):
- connection.execute(text("SELECT public.tenant_control_quota_mutate(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),:action,CAST(:request AS jsonb))"), {"claim_uid": invalid_claim, "nonce": invalid_nonce, "action": "quota_reserve", "request": invalid_request})
- overflow_request = '{"quota_name":"records","amount":"1000000000000000000000001","idempotency_key":"overflow-1"}'
- overflow_claim, overflow_nonce = claim("quota_reserve", overflow_request)
- with control.begin() as connection, pytest.raises(SQLAlchemyError, match="tenant_payload_invalid"):
- connection.execute(text("SELECT public.tenant_control_quota_mutate(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),:action,CAST(:request AS jsonb))"), {"claim_uid": overflow_claim, "nonce": overflow_nonce, "action": "quota_reserve", "request": overflow_request})
- finally:
- if control is not None:
- control.dispose()
- with admin.begin() as cleanup:
- cleanup.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_outbox_scope_lookup WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_outbox WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_claims WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_memberships WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_quota_reservations WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_audit_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_quotas WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenants WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text(f"DROP ROLE IF EXISTS {cleanup.dialect.identifier_preparer.quote(control_name)}"))
- admin.dispose()
- def test_wp10_unapproved_shared_delivery_mode_cannot_issue_control_claim():
- database_url = os.getenv("TEST_DATABASE_URL")
- if not database_url:
- pytest.skip("TEST_DATABASE_URL is required")
- tenant_id, principal = f"wp10-shared-{uuid.uuid4().hex[:12]}", str(uuid.uuid4())
- control_name, control_password = f"wp10_control_{uuid.uuid4().hex[:12]}", f"wp10_{uuid.uuid4().hex}"
- claim_uid, nonce = str(uuid.uuid4()), str(uuid.uuid4())
- admin = create_engine(database_url, pool_pre_ping=True)
- control = None
- try:
- with admin.begin() as connection:
- quoted_control = connection.dialect.identifier_preparer.quote(control_name)
- connection.execute(text(f"CREATE ROLE {quoted_control} LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION PASSWORD :password"), {"password": control_password})
- connection.execute(text(f"GRANT dataops_tenant_control TO {quoted_control}"))
- connection.execute(text("INSERT INTO public.tenants(tenant_id,delivery_mode,state) VALUES(:tenant_id,'shared_control_plane','active')"), {"tenant_id": tenant_id})
- connection.execute(text("INSERT INTO public.tenant_control_memberships(tenant_id,principal_id,host) VALUES(:tenant_id,:principal,'shared.example')"), {"tenant_id": tenant_id, "principal": principal})
- control = create_engine(make_url(database_url).set(username=control_name, password=control_password).render_as_string(hide_password=False), pool_pre_ping=True)
- with control.begin() as connection, pytest.raises(SQLAlchemyError, match="tenant_membership_denied"):
- connection.execute(text("SELECT public.tenant_control_issue_claim(CAST(:payload AS jsonb))"), {"payload": f'{{"claim_uid":"{claim_uid}","nonce":"{nonce}","principal_id":"{principal}","host":"shared.example","action":"quota_reserve","request":{{"quota_name":"records","amount":"1","idempotency_key":"shared-1"}}}}'})
- finally:
- if control is not None:
- control.dispose()
- with admin.begin() as cleanup:
- cleanup.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_outbox_scope_lookup WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_outbox WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_claims WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_memberships WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_audit_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenants WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text(f"DROP ROLE IF EXISTS {cleanup.dialect.identifier_preparer.quote(control_name)}"))
- admin.dispose()
- def test_wp10_claim_bound_lifecycle_fence_hold_backup_rollback_and_delete():
- database_url = os.getenv("TEST_DATABASE_URL")
- if not database_url:
- pytest.skip("TEST_DATABASE_URL is required")
- control_name, control_password = f"wp10_legacy_control_{uuid.uuid4().hex[:12]}", f"wp10_{uuid.uuid4().hex}"
- admin = create_engine(database_url, pool_pre_ping=True)
- try:
- with admin.begin() as connection:
- quoted_control = connection.dialect.identifier_preparer.quote(control_name)
- connection.execute(text(f"CREATE ROLE {quoted_control} LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION PASSWORD :password"), {"password": control_password})
- connection.execute(text(f"GRANT dataops_tenant_control TO {quoted_control}"))
- control_url = make_url(database_url).set(username=control_name, password=control_password).render_as_string(hide_password=False)
- with create_engine(control_url).connect() as connection, pytest.raises(SQLAlchemyError):
- connection.execute(text("SELECT public.tenant_control_lifecycle_mutate(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),'{}'::jsonb)"), {"claim_uid": str(uuid.uuid4()), "nonce": str(uuid.uuid4())})
- finally:
- with admin.begin() as connection:
- connection.execute(text(f"DROP ROLE IF EXISTS {connection.dialect.identifier_preparer.quote(control_name)}"))
- admin.dispose()
- return
- tenant_id, principal = f"wp10-life-{uuid.uuid4().hex[:12]}", str(uuid.uuid4())
- control_name, control_password = f"wp10_control_{uuid.uuid4().hex[:12]}", f"wp10_{uuid.uuid4().hex}"
- admin = create_engine(database_url, pool_pre_ping=True)
- control = None
- try:
- with admin.begin() as connection:
- quoted_control = connection.dialect.identifier_preparer.quote(control_name)
- connection.execute(text(f"CREATE ROLE {quoted_control} LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION PASSWORD :password"), {"password": control_password})
- connection.execute(text(f"GRANT dataops_tenant_control TO {quoted_control}"))
- connection.execute(text("INSERT INTO public.tenants(tenant_id,delivery_mode,state) VALUES(:tenant_id,'private_single_tenant','active')"), {"tenant_id": tenant_id})
- connection.execute(text("INSERT INTO public.tenant_control_memberships(tenant_id,principal_id,host) VALUES(:tenant_id,:principal,'private.example')"), {"tenant_id": tenant_id, "principal": principal})
- control = create_engine(make_url(database_url).set(username=control_name, password=control_password).render_as_string(hide_password=False), pool_pre_ping=True)
- def transition(operation: str, fence: int, key: str, *, approval: str | None = None, backup: str | None = None, retention: str | None = None):
- request = {"operation": operation, "expected_fence": str(fence), "idempotency_key": key, "approval_ref": approval, "backup_digest": backup, "retention_seconds": retention}
- claim_uid, nonce = str(uuid.uuid4()), str(uuid.uuid4())
- with control.begin() as connection:
- connection.execute(text("SELECT public.tenant_control_issue_claim(CAST(:payload AS jsonb))"), {"payload": __import__('json').dumps({"claim_uid": claim_uid, "nonce": nonce, "principal_id": principal, "host": "private.example", "action": "lifecycle_transition", "request": request})})
- return dict(connection.execute(text("SELECT public.tenant_control_lifecycle_mutate(CAST(:claim_uid AS uuid),CAST(:nonce AS uuid),CAST(:request AS jsonb))"), {"claim_uid": claim_uid, "nonce": nonce, "request": __import__('json').dumps(request)}).scalar_one())
- assert transition("freeze", 0, "freeze-1")["state"] == "frozen"
- assert transition("begin_recovery", 1, "recover-1", approval="approval-1")["state"] == "recovering"
- assert transition("activate", 2, "activate-1", approval="approval-2")["state"] == "active"
- with admin.begin() as connection:
- connection.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- connection.execute(text("INSERT INTO public.tenant_legal_holds(hold_ref,tenant_id,state,evidence_digest) VALUES('hold-1',:tenant_id,'active',:digest)"), {"tenant_id": tenant_id, "digest": "a" * 64})
- with pytest.raises(SQLAlchemyError, match="tenant_hold_active"):
- transition("mark_deletion_candidate", 3, "delete-candidate-1", approval="approval-3", backup="b" * 64, retention="60")
- with admin.begin() as connection:
- connection.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- connection.execute(text("UPDATE public.tenant_legal_holds SET state='released',released_at=clock_timestamp() WHERE hold_ref='hold-1'"))
- candidate = transition("mark_deletion_candidate", 3, "delete-candidate-1", approval="approval-3", backup="b" * 64, retention="60")
- assert candidate["state"] == "deletion_candidate"
- assert transition("rollback", 4, "rollback-1")["state"] == "frozen"
- candidate_again = transition("mark_deletion_candidate", 5, "delete-candidate-2", approval="approval-4", backup="c" * 64, retention="120")
- assert candidate_again["state"] == "deletion_candidate"
- assert transition("delete", 6, "delete-1", approval="approval-5", backup="d" * 64, retention="120")["state"] == "deleted"
- # Deleted tenants cannot even receive a lifecycle claim, so rollback
- # is intentionally impossible after the destructive transition.
- with pytest.raises(SQLAlchemyError, match="tenant_membership_denied"):
- transition("rollback", 7, "rollback-after-delete")
- finally:
- if control is not None:
- control.dispose()
- with admin.begin() as cleanup:
- cleanup.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_outbox_scope_lookup WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_outbox WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_claims WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_legal_holds WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_lifecycle_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_audit_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_control_memberships WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenants WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text(f"DROP ROLE IF EXISTS {cleanup.dialect.identifier_preparer.quote(control_name)}"))
- admin.dispose()
- def test_wp10_live_tenant_data_blocks_downgrade_before_503_gateway_can_return():
- database_url = os.getenv("TEST_DATABASE_URL")
- if not database_url:
- pytest.skip("TEST_DATABASE_URL is required")
- tenant_id = f"wp10-downgrade-{uuid.uuid4().hex[:12]}"
- engine = create_engine(database_url, pool_pre_ping=True)
- try:
- with engine.begin() as connection:
- connection.execute(text("INSERT INTO public.tenants(tenant_id,delivery_mode,state) VALUES(:tenant_id,'private_single_tenant','active')"), {"tenant_id": tenant_id})
- result = subprocess.run(
- [str(ROOT / ".venv/bin/alembic"), "-c", str(ROOT / "alembic.ini"), "downgrade", "20260817_520"],
- cwd=ROOT,
- env={**os.environ, "MIGRATION_DATABASE_URL": database_url},
- capture_output=True,
- text=True,
- )
- assert result.returncode != 0
- assert "downgrade refused" in result.stderr and "tenant" in result.stderr
- with engine.connect() as connection:
- assert connection.execute(text("SELECT version_num FROM public.alembic_version")).scalar_one() == "20260817_525"
- finally:
- with engine.begin() as cleanup:
- cleanup.execute(text("SELECT set_config('dataops.tenant_id', :tenant_id, true)"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenant_audit_events WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- cleanup.execute(text("DELETE FROM public.tenants WHERE tenant_id=:tenant_id"), {"tenant_id": tenant_id})
- engine.dispose()
- def test_wp10_low_privilege_migrator_reaches_the_tenant_foundation_head(wp06_head):
- engine = create_engine(wp06_head.migration_url, pool_pre_ping=True)
- try:
- with engine.connect() as connection:
- head = connection.execute(text("SELECT version_num FROM public.alembic_version")).scalar_one()
- privileges = connection.execute(text("SELECT rolsuper,rolcreaterole FROM pg_roles WHERE rolname=current_user")).one()
- assert head == "20260817_525"
- assert tuple(privileges) == (False, False)
- finally:
- engine.dispose()
|