teleo-infrastructure/tests/test_kb_apply_prereqs.py

1120 lines
43 KiB
Python

from __future__ import annotations
import json
import os
import shutil
import subprocess
import time
import uuid
from collections.abc import Iterator
from contextlib import contextmanager
from pathlib import Path
import pytest
from tests.docker_volume_lifecycle import (
POSTGRES_TMPFS_SPEC,
acquire_docker_volume_set_guard,
inspect_postgres_tmpfs_container,
release_docker_volume_set_guard,
remove_container_and_volumes,
)
REPO_ROOT = Path(__file__).resolve().parents[1]
MIGRATION = REPO_ROOT / "scripts" / "kb_apply_prereqs.sql"
POSTGRES_IMAGE = os.environ.get("LEOCLEAN_RUNTIME_POSTGRES_IMAGE", "postgres:16-alpine")
DATABASE = "teleo_clone"
LEGACY_APPROVED_ID = "aaaaaaaa-0000-4000-8000-000000000001"
LEGACY_APPLIED_ID = "aaaaaaaa-0000-4000-8000-000000000002"
FRESH_PROPOSAL_ID = "aaaaaaaa-0000-4000-8000-000000000003"
TIMEZONE_PROPOSAL_ID = "aaaaaaaa-0000-4000-8000-000000000004"
REVIEWER_ID = "11111111-1111-1111-1111-111111111111"
STALE_REVIEWER_ID = "22222222-2222-2222-2222-222222222222"
LEGACY_REVIEWER_HANDLE = "m3ta"
CANONICAL_REVIEWER_HANDLE = "m3taversal"
BOOTSTRAP_SQL = r"""
create role kb_gate_owner nologin inherit;
create role kb_review login inherit;
create role kb_apply login inherit;
create role broad_writer nologin;
create role rogue_owner nologin;
create role rogue_grantee nologin;
create schema kb_stage;
create table public.agents (
id uuid primary key,
handle text not null unique,
kind text not null
);
create table public.strategies (
id uuid primary key,
agent_id uuid not null,
active boolean not null default true
);
create table public.strategy_nodes (id uuid primary key);
create table public.claim_evidence (
id uuid primary key,
claim_id uuid not null,
source_id uuid not null,
role text not null
);
create table public.claim_edges (id uuid primary key);
create table public.claims (id uuid primary key);
create table public.sources (
id uuid primary key,
hash text not null
);
create table public.reasoning_tools (id uuid primary key);
insert into public.agents (id, handle, kind)
values ('11111111-1111-1111-1111-111111111111', 'm3ta', 'human');
create table kb_stage.kb_proposals (
id uuid primary key,
proposal_type text not null,
status text not null,
payload jsonb not null,
reviewed_by_handle text,
reviewed_by_agent_id uuid,
reviewed_at timestamptz,
review_note text,
applied_by_handle text,
applied_by_agent_id uuid,
applied_at timestamptz,
updated_at timestamptz not null default now()
);
create table kb_stage.kb_review_principals (
db_role name primary key,
reviewed_by_handle text not null,
reviewed_by_agent_id uuid not null references public.agents(id),
active boolean not null default true,
created_at timestamptz not null default now()
);
create table kb_stage.kb_proposal_approvals (
proposal_id uuid primary key references kb_stage.kb_proposals(id),
proposal_type text not null,
payload jsonb not null,
reviewed_by_handle text not null,
reviewed_by_agent_id uuid not null references public.agents(id),
reviewed_by_db_role name not null,
reviewed_at timestamptz not null,
review_note text not null
);
insert into kb_stage.kb_proposals (
id, proposal_type, status, payload, reviewed_by_handle, reviewed_by_agent_id,
reviewed_at, review_note, applied_by_handle, applied_by_agent_id, applied_at, updated_at
) values
(
'aaaaaaaa-0000-4000-8000-000000000001', 'add_edge', 'approved',
'{"apply_payload":{"from_claim":"aaaaaaaa-1000-4000-8000-000000000001"}}'::jsonb,
'm3ta', '11111111-1111-1111-1111-111111111111', '2026-07-18T10:00:00Z',
'Exact still-approved legacy row.', null, null, null, '2026-07-18T10:00:01Z'
),
(
'aaaaaaaa-0000-4000-8000-000000000002', 'add_edge', 'applied',
'{"apply_payload":{"from_claim":"aaaaaaaa-1000-4000-8000-000000000002"}}'::jsonb,
'm3ta', '11111111-1111-1111-1111-111111111111', '2026-07-18T09:00:00Z',
'Applied before exact approved rows were retained.', 'kb-apply',
'44444444-4444-4444-4444-444444444444', '2026-07-18T09:01:00Z',
'2026-07-18T09:01:00Z'
);
insert into kb_stage.kb_proposal_approvals (
proposal_id, proposal_type, payload, reviewed_by_handle, reviewed_by_agent_id,
reviewed_by_db_role, reviewed_at, review_note
) values
(
'aaaaaaaa-0000-4000-8000-000000000001', 'add_edge',
'{"apply_payload":{"from_claim":"aaaaaaaa-1000-4000-8000-000000000001"}}'::jsonb,
'm3ta', '11111111-1111-1111-1111-111111111111', 'kb_review',
'2026-07-18T10:00:00Z', 'Exact still-approved legacy row.'
),
(
'aaaaaaaa-0000-4000-8000-000000000002', 'add_edge',
'{"apply_payload":{"from_claim":"aaaaaaaa-1000-4000-8000-000000000002"}}'::jsonb,
'm3ta', '11111111-1111-1111-1111-111111111111', 'kb_review',
'2026-07-18T09:00:00Z', 'Applied before exact approved rows were retained.'
);
create function kb_stage.approve_strict_proposal(uuid, text, text)
returns jsonb language sql security definer
as $function$ select '{}'::jsonb $function$;
create function kb_stage.approve_strict_proposal(uuid, text, jsonb, text, text)
returns jsonb language sql security definer
as $function$ select '{}'::jsonb $function$;
create function kb_stage.assert_approved_proposal(
uuid, text, jsonb, text, uuid, timestamptz, text
) returns void language sql security definer
as $function$ select $function$;
create function kb_stage.finish_approved_proposal(
uuid, text, jsonb, text, uuid, timestamptz, text, text
) returns jsonb language sql security definer
as $function$ select '{}'::jsonb $function$;
grant all privileges on all tables in schema public
to kb_gate_owner, kb_apply, kb_review;
grant all privileges on all tables in schema kb_stage
to public, kb_gate_owner, kb_apply, kb_review;
grant all privileges on all functions in schema kb_stage
to public, kb_gate_owner, kb_apply, kb_review;
grant update (review_note) on kb_stage.kb_proposals to kb_apply;
grant select (review_note) on kb_stage.kb_proposals to public;
"""
def _psql(container: str, sql: str, *, check: bool = True) -> subprocess.CompletedProcess[str]:
completed = subprocess.run(
[
"docker",
"exec",
"-i",
container,
"psql",
"-X",
"-v",
"ON_ERROR_STOP=1",
"-U",
"postgres",
"-d",
DATABASE,
"-At",
"-F",
"|",
],
input=sql,
text=True,
capture_output=True,
check=False,
)
if check and completed.returncode != 0:
raise AssertionError(
f"psql failed with exit {completed.returncode}\nstdout:\n{completed.stdout}\nstderr:\n{completed.stderr}"
)
return completed
def _apply_migration(container: str, *, check: bool = True) -> subprocess.CompletedProcess[str]:
return _psql(container, MIGRATION.read_text(), check=check)
@contextmanager
def _postgres_clone() -> Iterator[str]:
if shutil.which("docker") is None:
pytest.skip("Docker is required for the disposable PostgreSQL migration canary")
volume_guard = acquire_docker_volume_set_guard(
context="kb_apply_prereqs PostgreSQL fixture",
)
container = f"kb-apply-prereqs-{uuid.uuid4().hex[:12]}"
try:
started = subprocess.run(
[
"docker",
"run",
"--pull=never",
"-d",
"--name",
container,
"--tmpfs",
POSTGRES_TMPFS_SPEC,
"-e",
"POSTGRES_PASSWORD=postgres",
"-e",
f"POSTGRES_DB={DATABASE}",
POSTGRES_IMAGE,
],
text=True,
capture_output=True,
check=False,
)
if started.returncode != 0:
pytest.fail(f"could not start disposable PostgreSQL: {started.stderr}")
inspect_postgres_tmpfs_container(container)
for _ in range(120):
logs = subprocess.run(
["docker", "logs", container],
text=True,
capture_output=True,
check=False,
)
query = _psql(container, "select 1;", check=False)
ready_transitions = (logs.stdout + logs.stderr).count("database system is ready to accept connections")
if ready_transitions >= 2 and query.returncode == 0:
break
time.sleep(0.25)
else:
pytest.fail("disposable PostgreSQL did not become ready")
_psql(container, BOOTSTRAP_SQL)
yield container
finally:
try:
remove_container_and_volumes(container)
finally:
release_docker_volume_set_guard(volume_guard)
@pytest.fixture(scope="module")
def migrated_postgres() -> Iterator[str]:
with _postgres_clone() as container:
_apply_migration(container)
yield container
def _lines(completed: subprocess.CompletedProcess[str]) -> set[str]:
return {line for line in completed.stdout.splitlines() if line}
def test_legacy_only_reviewer_is_canonicalized_without_rewriting_history(
migrated_postgres: str,
) -> None:
identity_rows = _psql(
migrated_postgres,
f"""
select id::text || '|' || handle || '|' || kind
from public.agents
where handle in ('{LEGACY_REVIEWER_HANDLE}', '{CANONICAL_REVIEWER_HANDLE}')
order by handle;
""",
).stdout.splitlines()
assert identity_rows == [f"{REVIEWER_ID}|{CANONICAL_REVIEWER_HANDLE}|human"]
historical_rows = _psql(
migrated_postgres,
f"""
select 'proposal|' || id::text || '|' || reviewed_by_handle || '|' || reviewed_by_agent_id::text
from kb_stage.kb_proposals
where id in ('{LEGACY_APPROVED_ID}'::uuid, '{LEGACY_APPLIED_ID}'::uuid)
order by id;
select 'approval|' || proposal_id::text || '|' || reviewed_by_handle || '|' ||
reviewed_by_agent_id::text
from kb_stage.kb_proposal_approvals
where proposal_id in ('{LEGACY_APPROVED_ID}'::uuid, '{LEGACY_APPLIED_ID}'::uuid)
order by proposal_id;
""",
).stdout.splitlines()
assert historical_rows == [
f"proposal|{LEGACY_APPROVED_ID}|{LEGACY_REVIEWER_HANDLE}|{REVIEWER_ID}",
f"proposal|{LEGACY_APPLIED_ID}|{LEGACY_REVIEWER_HANDLE}|{REVIEWER_ID}",
f"approval|{LEGACY_APPROVED_ID}|{LEGACY_REVIEWER_HANDLE}|{REVIEWER_ID}",
f"approval|{LEGACY_APPLIED_ID}|{LEGACY_REVIEWER_HANDLE}|{REVIEWER_ID}",
]
def test_already_current_reviewer_migration_is_idempotent() -> None:
with _postgres_clone() as container:
_psql(
container,
f"update public.agents set handle = '{CANONICAL_REVIEWER_HANDLE}' "
f"where handle = '{LEGACY_REVIEWER_HANDLE}';",
)
_apply_migration(container)
state_sql = f"""
select principal.reviewed_by_handle || '|' || principal.reviewed_by_agent_id::text || '|' ||
principal.active::text || '|' || principal.created_at::text || '|' ||
(select count(*) from public.agents where handle = '{LEGACY_REVIEWER_HANDLE}')::text
from kb_stage.kb_review_principals principal
where principal.db_role = 'kb_review';
"""
first_state = _psql(container, state_sql).stdout.strip()
_apply_migration(container)
second_state = _psql(container, state_sql).stdout.strip()
expected_state = f"{CANONICAL_REVIEWER_HANDLE}|{REVIEWER_ID}|true|1970-01-01 00:00:00+00|0"
assert first_state == expected_state
assert second_state == first_state
def test_stale_reviewer_principal_is_repaired_without_resetting_created_at() -> None:
with _postgres_clone() as container:
_psql(
container,
f"""
insert into public.agents (id, handle, kind)
values ('{STALE_REVIEWER_ID}', 'stale-reviewer', 'human');
insert into kb_stage.kb_review_principals
(db_role, reviewed_by_handle, reviewed_by_agent_id, active, created_at)
values (
'kb_review', 'stale-reviewer', '{STALE_REVIEWER_ID}', false,
'2001-02-03T04:05:06Z'
);
""",
)
_apply_migration(container)
principal_state = _psql(
container,
"""
select reviewed_by_handle || '|' || reviewed_by_agent_id::text || '|' || active::text || '|' ||
created_at::text
from kb_stage.kb_review_principals
where db_role = 'kb_review';
""",
).stdout.strip()
expected_state = f"{CANONICAL_REVIEWER_HANDLE}|{REVIEWER_ID}|true|2001-02-03 04:05:06+00"
assert principal_state == expected_state
def test_migration_refuses_distinct_legacy_and_canonical_reviewers() -> None:
with _postgres_clone() as container:
_psql(
container,
f"""
insert into public.agents (id, handle, kind)
values ('{STALE_REVIEWER_ID}', '{CANONICAL_REVIEWER_HANDLE}', 'human');
""",
)
refused = _apply_migration(container, check=False)
identity_rows = _psql(
container,
f"""
select handle || '|' || id::text
from public.agents
where handle in ('{LEGACY_REVIEWER_HANDLE}', '{CANONICAL_REVIEWER_HANDLE}')
order by handle;
""",
).stdout.splitlines()
assert refused.returncode != 0
assert "both reviewer handles m3ta" in refused.stderr
assert "exist with different agent UUIDs" in refused.stderr
assert identity_rows == [
f"{LEGACY_REVIEWER_HANDLE}|{REVIEWER_ID}",
f"{CANONICAL_REVIEWER_HANDLE}|{STALE_REVIEWER_ID}",
]
def test_migration_refuses_to_fabricate_missing_human_reviewer() -> None:
with _postgres_clone() as container:
_psql(
container,
f"""
delete from kb_stage.kb_proposal_approvals;
delete from public.agents where handle = '{LEGACY_REVIEWER_HANDLE}';
""",
)
refused = _apply_migration(container, check=False)
remaining_agents = _psql(container, "select count(*) from public.agents;").stdout.strip()
assert refused.returncode != 0
assert "required human reviewer agent is missing" in refused.stderr
assert "handle m3ta or m3taversal" in refused.stderr
assert remaining_agents == "0"
def test_reviewer_principal_seed_timestamp_is_deterministic(migrated_postgres: str) -> None:
created_at = _psql(
migrated_postgres,
"select created_at::text from kb_stage.kb_review_principals where db_role = 'kb_review';",
).stdout.strip()
assert created_at == "1970-01-01 00:00:00+00"
def test_upgrade_backfills_only_still_exact_approved_rows(migrated_postgres: str) -> None:
snapshot_state = _psql(
migrated_postgres,
f"""
select proposal_id::text || '|' || (approved_proposal_snapshot is not null)::text || '|' ||
coalesce(approved_proposal_snapshot->>'status', 'unavailable') || '|' ||
coalesce(approved_proposal_snapshot->>'reviewed_by_handle', 'unavailable')
from kb_stage.kb_proposal_approvals
where proposal_id in ('{LEGACY_APPROVED_ID}'::uuid, '{LEGACY_APPLIED_ID}'::uuid)
order by proposal_id;
""",
).stdout.splitlines()
assert snapshot_state == [
f"{LEGACY_APPROVED_ID}|true|approved|{LEGACY_REVIEWER_HANDLE}",
f"{LEGACY_APPLIED_ID}|false|unavailable|unavailable",
]
unavailable = _psql(
migrated_postgres,
f"""
set session authorization kb_apply;
select kb_stage.export_applied_proposal_replay_rows('{LEGACY_APPLIED_ID}'::uuid);
""",
check=False,
)
assert unavailable.returncode != 0
assert "exact applied transition unavailable" in unavailable.stderr
def test_new_approval_preserves_exact_post_approval_row_for_apply_export(migrated_postgres: str) -> None:
payload = '{"apply_payload":{"from_claim":"aaaaaaaa-1000-4000-8000-000000000003"}}'
_psql(
migrated_postgres,
f"""
insert into kb_stage.kb_proposals (id, proposal_type, status, payload, updated_at)
values ('{FRESH_PROPOSAL_ID}'::uuid, 'add_edge', 'pending_review', '{payload}'::jsonb,
'2026-07-18T11:00:00Z');
set session authorization kb_review;
select kb_stage.approve_strict_proposal(
'{FRESH_PROPOSAL_ID}'::uuid, 'add_edge', '{payload}'::jsonb, '{CANONICAL_REVIEWER_HANDLE}',
'Fresh exact approval snapshot.'
);
""",
)
approval_identity = _psql(
migrated_postgres,
f"""
select proposal.reviewed_by_handle || '|' || proposal.reviewed_by_agent_id::text || '|' ||
approval.reviewed_by_handle || '|' || approval.reviewed_by_agent_id::text || '|' ||
(approval.approved_proposal_snapshot->>'reviewed_by_handle') || '|' ||
(approval.approved_proposal_snapshot->>'reviewed_by_agent_id')
from kb_stage.kb_proposals proposal
join kb_stage.kb_proposal_approvals approval on approval.proposal_id = proposal.id
where proposal.id = '{FRESH_PROPOSAL_ID}'::uuid;
""",
).stdout.strip()
assert approval_identity == (
f"{CANONICAL_REVIEWER_HANDLE}|{REVIEWER_ID}|"
f"{CANONICAL_REVIEWER_HANDLE}|{REVIEWER_ID}|"
f"{CANONICAL_REVIEWER_HANDLE}|{REVIEWER_ID}"
)
approval_state = _psql(
migrated_postgres,
f"""
select jsonb_build_object(
'matches', approval.approved_proposal_snapshot = to_jsonb(proposal),
'status', approval.approved_proposal_snapshot->>'status',
'updated_at_matches', approval.approved_proposal_snapshot->'updated_at' = to_jsonb(proposal)->'updated_at'
)::text
from kb_stage.kb_proposal_approvals approval
join kb_stage.kb_proposals proposal on proposal.id = approval.proposal_id
where proposal.id = '{FRESH_PROPOSAL_ID}'::uuid;
""",
).stdout.strip()
assert approval_state == '{"status": "approved", "matches": true, "updated_at_matches": true}'
direct_approval_read = _psql(
migrated_postgres,
"set session authorization kb_apply; select * from kb_stage.kb_proposal_approvals;",
check=False,
)
assert direct_approval_read.returncode != 0
assert "permission denied for table kb_proposal_approvals" in direct_approval_read.stderr
premature_export = _psql(
migrated_postgres,
f"""
set session authorization kb_apply;
select kb_stage.export_applied_proposal_replay_rows('{FRESH_PROPOSAL_ID}'::uuid);
""",
check=False,
)
assert premature_export.returncode != 0
assert "exact applied transition unavailable" in premature_export.stderr
_psql(
migrated_postgres,
f"""
update kb_stage.kb_proposal_approvals
set approved_proposal_snapshot =
approved_proposal_snapshot || '{{"rationale":"tampered after approval"}}'::jsonb
where proposal_id = '{FRESH_PROPOSAL_ID}'::uuid;
""",
)
for guard_call in (
"kb_stage.assert_approved_proposal("
"proposal.id, proposal.proposal_type, proposal.payload, proposal.reviewed_by_handle, "
"proposal.reviewed_by_agent_id, proposal.reviewed_at, proposal.review_note)",
"kb_stage.finish_approved_proposal("
"proposal.id, proposal.proposal_type, proposal.payload, proposal.reviewed_by_handle, "
"proposal.reviewed_by_agent_id, proposal.reviewed_at, proposal.review_note, 'kb-apply')",
):
refused = _psql(
migrated_postgres,
f"""
set session authorization kb_apply;
select {guard_call}
from kb_stage.kb_proposals proposal where proposal.id = '{FRESH_PROPOSAL_ID}'::uuid;
""",
check=False,
)
assert refused.returncode != 0
assert "immutable approved snapshot" in refused.stderr
_psql(
migrated_postgres,
f"""
update kb_stage.kb_proposal_approvals approval
set approved_proposal_snapshot = to_jsonb(proposal)
from kb_stage.kb_proposals proposal
where approval.proposal_id = proposal.id
and proposal.id = '{FRESH_PROPOSAL_ID}'::uuid;
""",
)
exported = _psql(
migrated_postgres,
f"""
set session authorization kb_apply;
select kb_stage.assert_approved_proposal(
proposal.id, proposal.proposal_type, proposal.payload, proposal.reviewed_by_handle,
proposal.reviewed_by_agent_id, proposal.reviewed_at, proposal.review_note
)
from kb_stage.kb_proposals proposal where proposal.id = '{FRESH_PROPOSAL_ID}'::uuid;
select kb_stage.finish_approved_proposal(
proposal.id, proposal.proposal_type, proposal.payload, proposal.reviewed_by_handle,
proposal.reviewed_by_agent_id, proposal.reviewed_at, proposal.review_note, 'kb-apply'
)
from kb_stage.kb_proposals proposal where proposal.id = '{FRESH_PROPOSAL_ID}'::uuid;
select jsonb_object_keys(kb_stage.export_applied_proposal_replay_rows('{FRESH_PROPOSAL_ID}'::uuid))
order by 1;
""",
).stdout.splitlines()
assert exported[-3:] == ["applied_proposal", "approval_snapshot", "approved_proposal"]
def test_gate_functions_are_timezone_independent_across_connections(
migrated_postgres: str,
) -> None:
payload = '{"apply_payload":{"from_claim":"aaaaaaaa-1000-4000-8000-000000000004"}}'
_psql(
migrated_postgres,
f"""
insert into kb_stage.kb_proposals (id, proposal_type, status, payload, updated_at)
values ('{TIMEZONE_PROPOSAL_ID}'::uuid, 'add_edge', 'pending_review', '{payload}'::jsonb,
'2026-07-18T12:00:00Z');
set timezone = 'America/Los_Angeles';
set session authorization kb_review;
select kb_stage.approve_strict_proposal(
'{TIMEZONE_PROPOSAL_ID}'::uuid, 'add_edge', '{payload}'::jsonb, '{CANONICAL_REVIEWER_HANDLE}',
'Cross-timezone exact approval snapshot.'
);
""",
)
asserted_and_finished = _psql(
migrated_postgres,
f"""
set timezone = 'Asia/Tokyo';
set session authorization kb_apply;
select kb_stage.assert_approved_proposal(
proposal.id, proposal.proposal_type, proposal.payload, proposal.reviewed_by_handle,
proposal.reviewed_by_agent_id, proposal.reviewed_at, proposal.review_note
)
from kb_stage.kb_proposals proposal where proposal.id = '{TIMEZONE_PROPOSAL_ID}'::uuid;
select kb_stage.finish_approved_proposal(
proposal.id, proposal.proposal_type, proposal.payload, proposal.reviewed_by_handle,
proposal.reviewed_by_agent_id, proposal.reviewed_at, proposal.review_note, 'kb-apply'
)
from kb_stage.kb_proposals proposal where proposal.id = '{TIMEZONE_PROPOSAL_ID}'::uuid;
""",
)
assert '"status": "applied"' in asserted_and_finished.stdout
exported = json.loads(
_psql(
migrated_postgres,
f"""
set timezone = 'Pacific/Auckland';
set session authorization kb_apply;
select kb_stage.export_applied_proposal_replay_rows('{TIMEZONE_PROPOSAL_ID}'::uuid)::text;
""",
).stdout.splitlines()[-1]
)
approved = exported["approved_proposal"]
applied = exported["applied_proposal"]
approval = exported["approval_snapshot"]
assert approved["reviewed_at"].endswith("+00:00")
assert applied["reviewed_at"] == approved["reviewed_at"]
assert approval["reviewed_at"] == approved["reviewed_at"]
assert applied["status"] == "applied"
def test_transition_export_rollback_preserves_evidence_and_reinstalls_cleanly() -> None:
with _postgres_clone() as container:
_apply_migration(container)
before = _psql(
container,
f"""
select approved_proposal_snapshot::text
from kb_stage.kb_proposal_approvals
where proposal_id = '{LEGACY_APPROVED_ID}'::uuid;
""",
).stdout.strip()
_psql(
container,
"""
revoke all on function kb_stage.export_applied_proposal_replay_rows(uuid)
from public, kb_gate_owner, kb_apply, kb_review;
drop function kb_stage.export_applied_proposal_replay_rows(uuid);
""",
)
rolled_back = _psql(
container,
f"""
select pg_catalog.to_regprocedure(
'kb_stage.export_applied_proposal_replay_rows(uuid)'
) is null;
select approved_proposal_snapshot::text
from kb_stage.kb_proposal_approvals
where proposal_id = '{LEGACY_APPROVED_ID}'::uuid;
""",
).stdout.splitlines()
assert rolled_back == ["t", before]
_apply_migration(container)
restored = _psql(
container,
f"""
select pg_catalog.to_regprocedure(
'kb_stage.export_applied_proposal_replay_rows(uuid)'
) is not null;
select approved_proposal_snapshot::text
from kb_stage.kb_proposal_approvals
where proposal_id = '{LEGACY_APPROVED_ID}'::uuid;
""",
).stdout.splitlines()
assert restored == ["t", before]
def _catalog_snapshot(container: str) -> str:
return _psql(
container,
r"""
select 'role|' || rolname || '|' || rolcanlogin || '|' || rolinherit || '|' || rolsuper
from pg_catalog.pg_roles
where rolname in ('kb_gate_owner', 'kb_review', 'kb_apply')
order by rolname;
select 'owner|' || namespace.nspname || '|' || relation.relname || '|' || owner_role.rolname
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
join pg_catalog.pg_roles owner_role on owner_role.oid = relation.relowner
where (namespace.nspname, relation.relname) in (
('public', 'agents'), ('public', 'strategies'), ('public', 'strategy_nodes'),
('public', 'claim_evidence'), ('public', 'claim_edges'), ('public', 'claims'),
('public', 'sources'), ('public', 'reasoning_tools'),
('kb_stage', 'kb_proposals'), ('kb_stage', 'kb_review_principals'),
('kb_stage', 'kb_proposal_approvals')
)
order by namespace.nspname, relation.relname;
select 'function|' || procedure.proname || '(' || pg_catalog.oidvectortypes(procedure.proargtypes) ||
')|' || owner_role.rolname || '|' || procedure.prosecdef || '|' || procedure.proconfig::text
from pg_catalog.pg_proc procedure
join pg_catalog.pg_namespace namespace on namespace.oid = procedure.pronamespace
join pg_catalog.pg_roles owner_role on owner_role.oid = procedure.proowner
where namespace.nspname = 'kb_stage'
and procedure.proname in (
'approve_strict_proposal', 'assert_approved_proposal', 'finish_approved_proposal',
'export_applied_proposal_replay_rows'
)
order by procedure.proname, procedure.proargtypes::text;
select 'column|' || attribute.attname || '|' || attribute.atttypid::regtype::text || '|' ||
attribute.attnotnull
from pg_catalog.pg_attribute attribute
where attribute.attrelid = 'kb_stage.kb_proposal_approvals'::regclass
and attribute.attname = 'approved_proposal_snapshot'
and not attribute.attisdropped;
select 'table_acl|' || namespace.nspname || '|' || relation.relname || '|' ||
case when acl.grantee = 0 then 'PUBLIC' else grantee_role.rolname end || '|' ||
pg_catalog.upper(acl.privilege_type) || '|' || acl.is_grantable
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
cross join lateral pg_catalog.aclexplode(
coalesce(relation.relacl, pg_catalog.acldefault('r', relation.relowner))
) acl
left join pg_catalog.pg_roles grantee_role on grantee_role.oid = acl.grantee
where (namespace.nspname, relation.relname) in (
('public', 'agents'), ('public', 'strategies'), ('public', 'strategy_nodes'),
('public', 'claim_evidence'), ('public', 'claim_edges'), ('public', 'claims'),
('public', 'sources'), ('public', 'reasoning_tools'),
('kb_stage', 'kb_proposals'), ('kb_stage', 'kb_review_principals'),
('kb_stage', 'kb_proposal_approvals')
)
and acl.grantee <> relation.relowner
and (acl.grantee = 0 or grantee_role.rolname in ('kb_gate_owner', 'kb_review', 'kb_apply'))
order by namespace.nspname, relation.relname, grantee_role.rolname, acl.privilege_type;
select 'function_acl|' || procedure.proname || '(' ||
pg_catalog.oidvectortypes(procedure.proargtypes) || ')|' ||
case when acl.grantee = 0 then 'PUBLIC' else pg_catalog.pg_get_userbyid(acl.grantee) end ||
'|' || pg_catalog.upper(acl.privilege_type) || '|' || acl.is_grantable
from pg_catalog.pg_proc procedure
join pg_catalog.pg_namespace namespace on namespace.oid = procedure.pronamespace
cross join lateral pg_catalog.aclexplode(
coalesce(procedure.proacl, pg_catalog.acldefault('f', procedure.proowner))
) acl
where namespace.nspname = 'kb_stage'
and procedure.proname in (
'approve_strict_proposal', 'assert_approved_proposal', 'finish_approved_proposal',
'export_applied_proposal_replay_rows'
)
and acl.grantee <> procedure.proowner
order by procedure.proname, procedure.proargtypes::text, acl.grantee;
""",
).stdout
def test_upgrade_normalizes_exact_role_ownership_and_acl_matrix(migrated_postgres: str) -> None:
role_rows = _lines(
_psql(
migrated_postgres,
"""
select rolname || '|' || rolcanlogin || '|' || rolinherit || '|' || rolsuper || '|' ||
rolcreatedb || '|' || rolcreaterole || '|' || rolreplication || '|' || rolbypassrls
from pg_catalog.pg_roles
where rolname in ('kb_gate_owner', 'kb_review', 'kb_apply')
order by rolname;
""",
)
)
assert role_rows == {
"kb_apply|true|false|false|false|false|false|false",
"kb_gate_owner|false|false|false|false|false|false|false",
"kb_review|true|false|false|false|false|false|false",
}
assert (
_psql(
migrated_postgres,
"""
select count(*)
from pg_catalog.pg_auth_members membership
join pg_catalog.pg_roles member_role on member_role.oid = membership.member
join pg_catalog.pg_roles granted_role on granted_role.oid = membership.roleid
where member_role.rolname in ('kb_gate_owner', 'kb_review', 'kb_apply')
or granted_role.rolname in ('kb_gate_owner', 'kb_review', 'kb_apply');
""",
).stdout.strip()
== "0"
)
schema_rows = _lines(
_psql(
migrated_postgres,
"""
select protected_role.rolname || '|' || protected_schema.nspname || '|' ||
pg_catalog.has_schema_privilege(protected_role.rolname, protected_schema.nspname, 'USAGE') || '|' ||
pg_catalog.has_schema_privilege(protected_role.rolname, protected_schema.nspname, 'CREATE')
from (values ('kb_gate_owner'), ('kb_review'), ('kb_apply')) protected_role(rolname)
cross join (values ('public'), ('kb_stage')) protected_schema(nspname);
""",
)
)
assert schema_rows == {
f"{role}|{schema}|true|false"
for role in ("kb_gate_owner", "kb_review", "kb_apply")
for schema in ("public", "kb_stage")
}
function_rows = _lines(
_psql(
migrated_postgres,
"""
select procedure.proname || '(' || pg_catalog.oidvectortypes(procedure.proargtypes) || ')|' ||
owner_role.rolname || '|' || procedure.prosecdef || '|' ||
(
pg_catalog.cardinality(procedure.proconfig) = 2
and procedure.proconfig @> array[
'search_path=pg_catalog, pg_temp'::text,
'TimeZone=UTC'::text
]
)
from pg_catalog.pg_proc procedure
join pg_catalog.pg_namespace namespace on namespace.oid = procedure.pronamespace
join pg_catalog.pg_roles owner_role on owner_role.oid = procedure.proowner
where namespace.nspname = 'kb_stage'
and procedure.proname in (
'approve_strict_proposal', 'assert_approved_proposal', 'finish_approved_proposal',
'export_applied_proposal_replay_rows'
);
""",
)
)
assert function_rows == {
"approve_strict_proposal(uuid, text, jsonb, text, text)|kb_gate_owner|true|true",
"assert_approved_proposal(uuid, text, jsonb, text, uuid, timestamp with time zone, text)|"
"kb_gate_owner|true|true",
"finish_approved_proposal(uuid, text, jsonb, text, uuid, timestamp with time zone, text, text)|"
"kb_gate_owner|true|true",
"export_applied_proposal_replay_rows(uuid)|kb_gate_owner|true|true",
}
assert (
_psql(
migrated_postgres,
"select pg_catalog.to_regprocedure('kb_stage.approve_strict_proposal(uuid,text,text)') is null;",
).stdout.strip()
== "t"
)
assert (
_psql(
migrated_postgres,
"""
select count(*)
from pg_catalog.pg_attribute attribute
join pg_catalog.pg_class relation on relation.oid = attribute.attrelid
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
cross join lateral pg_catalog.aclexplode(attribute.attacl) acl
left join pg_catalog.pg_roles grantee_role on grantee_role.oid = acl.grantee
where (namespace.nspname, relation.relname) in (
('public', 'agents'), ('public', 'strategies'), ('public', 'strategy_nodes'),
('public', 'claim_evidence'), ('public', 'claim_edges'), ('public', 'claims'),
('public', 'sources'), ('public', 'reasoning_tools'),
('kb_stage', 'kb_proposals'), ('kb_stage', 'kb_review_principals'),
('kb_stage', 'kb_proposal_approvals')
)
and (acl.grantee = 0 or grantee_role.rolname in ('kb_gate_owner', 'kb_review', 'kb_apply'));
""",
).stdout.strip()
== "0"
)
for runtime_role, target_role in (
("kb_apply", "broad_writer"),
("kb_apply", "kb_gate_owner"),
("kb_review", "kb_gate_owner"),
):
denied = _psql(
migrated_postgres,
f"set session authorization {runtime_role}; set role {target_role};",
check=False,
)
assert denied.returncode != 0
assert "permission denied to set role" in denied.stderr
snapshot_lines = set(_catalog_snapshot(migrated_postgres).splitlines())
expected_table_acls = {
"table_acl|public|agents|kb_gate_owner|SELECT|false",
"table_acl|public|agents|kb_apply|SELECT|false",
"table_acl|public|agents|kb_review|SELECT|false",
"table_acl|public|strategies|kb_apply|SELECT|false",
"table_acl|public|strategies|kb_apply|INSERT|false",
"table_acl|public|strategies|kb_apply|UPDATE|false",
"table_acl|public|strategy_nodes|kb_apply|SELECT|false",
"table_acl|public|strategy_nodes|kb_apply|INSERT|false",
"table_acl|public|strategy_nodes|kb_apply|UPDATE|false",
"table_acl|public|claim_evidence|kb_apply|SELECT|false",
"table_acl|public|claim_evidence|kb_apply|INSERT|false",
"table_acl|public|claim_edges|kb_apply|SELECT|false",
"table_acl|public|claim_edges|kb_apply|INSERT|false",
"table_acl|public|claims|kb_apply|SELECT|false",
"table_acl|public|claims|kb_apply|INSERT|false",
"table_acl|public|sources|kb_apply|SELECT|false",
"table_acl|public|sources|kb_apply|INSERT|false",
"table_acl|public|reasoning_tools|kb_apply|SELECT|false",
"table_acl|public|reasoning_tools|kb_apply|INSERT|false",
"table_acl|kb_stage|kb_proposals|kb_gate_owner|SELECT|false",
"table_acl|kb_stage|kb_proposals|kb_gate_owner|UPDATE|false",
"table_acl|kb_stage|kb_proposals|kb_apply|SELECT|false",
"table_acl|kb_stage|kb_proposals|kb_review|SELECT|false",
}
assert {line for line in snapshot_lines if line.startswith("table_acl|")} == expected_table_acls
assert {line for line in snapshot_lines if line.startswith("function_acl|")} == {
"function_acl|approve_strict_proposal(uuid, text, jsonb, text, text)|kb_review|EXECUTE|false",
"function_acl|assert_approved_proposal(uuid, text, jsonb, text, uuid, timestamp with time zone, text)|"
"kb_apply|EXECUTE|false",
"function_acl|finish_approved_proposal(uuid, text, jsonb, text, uuid, timestamp with time zone, text, text)|"
"kb_apply|EXECUTE|false",
"function_acl|export_applied_proposal_replay_rows(uuid)|kb_apply|EXECUTE|false",
}
def test_migration_rerun_preserves_catalog_snapshot(migrated_postgres: str) -> None:
before = _catalog_snapshot(migrated_postgres)
_apply_migration(migrated_postgres)
assert _catalog_snapshot(migrated_postgres) == before
def _assert_migration_fails(container: str, expected_error: str) -> None:
completed = _apply_migration(container, check=False)
assert completed.returncode != 0
assert expected_error in completed.stderr
def test_migration_fails_closed_on_protected_role_membership(migrated_postgres: str) -> None:
_psql(migrated_postgres, "grant broad_writer to kb_apply;")
try:
_assert_migration_fails(migrated_postgres, "unexpected protected role membership")
finally:
_psql(migrated_postgres, "revoke broad_writer from kb_apply;")
def test_migration_fails_closed_on_ownership_drift(migrated_postgres: str) -> None:
_psql(migrated_postgres, "alter table kb_stage.kb_proposal_approvals owner to rogue_owner;")
try:
_assert_migration_fails(migrated_postgres, "unexpected protected table owner")
finally:
_psql(migrated_postgres, "alter table kb_stage.kb_proposal_approvals owner to kb_gate_owner;")
def test_migration_fails_closed_on_unexpected_table_grantee(migrated_postgres: str) -> None:
_psql(migrated_postgres, "grant select on kb_stage.kb_proposal_approvals to rogue_grantee;")
try:
_assert_migration_fails(migrated_postgres, "unexpected protected table grantee")
finally:
_psql(migrated_postgres, "revoke all on kb_stage.kb_proposal_approvals from rogue_grantee;")
def test_migration_preserves_current_and_complete_observatory_read_surfaces() -> None:
observatory_acl_sql = """
select namespace.nspname || '|' || relation.relname || '|' || acl.privilege_type || '|' ||
acl.is_grantable::text
from pg_catalog.pg_class relation
join pg_catalog.pg_namespace namespace on namespace.oid = relation.relnamespace
cross join lateral pg_catalog.aclexplode(relation.relacl) acl
join pg_catalog.pg_roles grantee on grantee.oid = acl.grantee
where grantee.rolname = 'kb_observatory_read'
order by namespace.nspname, relation.relname, acl.privilege_type;
"""
with _postgres_clone() as container:
_psql(
container,
"""
create role kb_observatory_read nologin noinherit nosuperuser nocreatedb nocreaterole
noreplication nobypassrls;
create role observatory_principal login noinherit nosuperuser nocreatedb nocreaterole
noreplication nobypassrls;
grant kb_observatory_read to observatory_principal;
grant usage on schema public, kb_stage to kb_observatory_read;
grant select on
public.claims,
public.claim_evidence,
public.claim_edges
to kb_observatory_read;
""",
)
# The current VPS manifest has this exact three-table read projection.
_apply_migration(container)
_apply_migration(container)
assert _lines(_psql(container, observatory_acl_sql)) == {
"public|claim_edges|SELECT|false",
"public|claim_evidence|SELECT|false",
"public|claims|SELECT|false",
}
# The independently managed Observatory installer extends the same
# bounded surface to source and proposal provenance reads.
_psql(
container,
"""
grant select on public.sources, kb_stage.kb_proposals to kb_observatory_read;
""",
)
_apply_migration(container)
assert _lines(_psql(container, observatory_acl_sql)) == {
"kb_stage|kb_proposals|SELECT|false",
"public|claim_edges|SELECT|false",
"public|claim_evidence|SELECT|false",
"public|claims|SELECT|false",
"public|sources|SELECT|false",
}
for grant_sql, revoke_sql, expected_error in (
(
"grant insert on public.claims to kb_observatory_read;",
"revoke insert on public.claims from kb_observatory_read;",
"unexpected protected table grantee",
),
(
"grant select on public.agents to kb_observatory_read;",
"revoke select on public.agents from kb_observatory_read;",
"unexpected protected table grantee",
),
(
"grant select on public.sources to kb_observatory_read with grant option;",
"revoke grant option for select on public.sources from kb_observatory_read;",
"unexpected protected table grantee",
),
(
"grant select (id) on public.claims to kb_observatory_read;",
"revoke select (id) on public.claims from kb_observatory_read;",
"unexpected protected table grantee",
),
(
"grant execute on function "
"kb_stage.assert_approved_proposal(uuid,text,jsonb,text,uuid,timestamptz,text) "
"to kb_observatory_read;",
"revoke execute on function "
"kb_stage.assert_approved_proposal(uuid,text,jsonb,text,uuid,timestamptz,text) "
"from kb_observatory_read;",
"unexpected protected function grantee",
),
(
"grant broad_writer to kb_observatory_read;",
"revoke broad_writer from kb_observatory_read;",
"unexpected protected role membership",
),
):
_psql(container, grant_sql)
try:
_assert_migration_fails(container, expected_error)
finally:
_psql(container, revoke_sql)
_apply_migration(container)
def test_migration_refuses_rogue_canonical_insert_before_install_and_normalizes_after_removal() -> None:
with _postgres_clone() as container:
_psql(container, "grant usage on schema public to rogue_grantee;")
for grant_sql, revoke_sql in (
(
"grant insert on public.claims to rogue_grantee;",
"revoke insert on public.claims from rogue_grantee;",
),
(
"grant insert (id) on public.claims to rogue_grantee;",
"revoke insert (id) on public.claims from rogue_grantee;",
),
):
_psql(container, grant_sql)
refused = _apply_migration(container, check=False)
assert refused.returncode != 0
assert "unexpected protected table grantee" in refused.stderr
assert _psql(container, "select count(*) from public.claims;").stdout.strip() == "0"
_psql(container, revoke_sql)
_apply_migration(container)
rogue_insert = _psql(
container,
"set session authorization rogue_grantee; "
"insert into public.claims (id) values ('99999999-9999-4999-8999-999999999999');",
check=False,
)
assert rogue_insert.returncode != 0
assert "permission denied for table claims" in rogue_insert.stderr
assert _psql(container, "select count(*) from public.claims;").stdout.strip() == "0"
def test_migration_fails_closed_on_unexpected_column_grantee(migrated_postgres: str) -> None:
_psql(
migrated_postgres,
"grant select (review_note) on kb_stage.kb_proposal_approvals to rogue_grantee;",
)
try:
_assert_migration_fails(migrated_postgres, "unexpected protected table grantee")
finally:
_psql(
migrated_postgres,
"revoke select (review_note) on kb_stage.kb_proposal_approvals from rogue_grantee;",
)
def test_migration_fails_closed_on_unexpected_function_grantee(migrated_postgres: str) -> None:
signature = "kb_stage.assert_approved_proposal(uuid,text,jsonb,text,uuid,timestamptz,text)"
_psql(migrated_postgres, f"grant execute on function {signature} to rogue_grantee;")
try:
_assert_migration_fails(migrated_postgres, "unexpected protected function grantee")
finally:
_psql(migrated_postgres, f"revoke all on function {signature} from rogue_grantee;")
def test_migration_fails_closed_on_unexpected_gate_overload(migrated_postgres: str) -> None:
_psql(
migrated_postgres,
"""
create function kb_stage.assert_approved_proposal(text)
returns void language sql security definer as $function$ select $function$;
""",
)
try:
_assert_migration_fails(migrated_postgres, "unexpected protected function overload")
finally:
_psql(migrated_postgres, "drop function kb_stage.assert_approved_proposal(text);")