Files
buzz/migrations/0039_client_status_connection_scope.sql
Cea Stapleton Cordasco 341a08a428 feat(relay): install provider-neutral authorization runtime
Cumulative PR layer #4847. Installs the reviewed provider-neutral relay authorization runtime, crash-recoverable current-status delivery, protected-ingress production composition, canonical mutation ordering, and exact runtime-contract regressions. A configured required identity gate remains fail-closed when its retired compatibility verifier is unavailable.

Neighbor disclosure: canonical database/operator authority remains owned by the lower layers, while the core status contract is owned by #4790 and native desktop consumption remains in #4987.

Signed-off-by: Cea Stapleton Cordasco <261786559+cea@users.noreply.github.com>
2026-08-12 11:20:13 -05:00

256 lines
12 KiB
PL/PgSQL

-- Reconcile the crash-durable journal with the accepted S5 rule that status
-- revisions and withdrawals are scoped to one exact connection generation.
-- The relay producer did not exist before this migration, so any transition
-- row would be evidence of an unsupported writer and must stop rollout.
LOCK TABLE client_status_transitions, client_status_transition_heads,
client_status_delivery_outbox IN ACCESS EXCLUSIVE MODE;
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM client_status_transitions) THEN
RAISE EXCEPTION 'client status connection-scope migration requires an empty journal'
USING ERRCODE = 'object_not_in_prerequisite_state';
END IF;
END;
$$;
-- A status authorization holds FOR SHARE on the same community row until the
-- physical writer acknowledgement is durably completed. Every newer policy
-- revision therefore waits only for status flushes in its own tenant.
CREATE OR REPLACE FUNCTION client_status_policy_connection_fence_v1() RETURNS TRIGGER AS $$
BEGIN
PERFORM id FROM communities WHERE id=NEW.community_id FOR UPDATE;
IF NOT FOUND THEN
RAISE EXCEPTION 'client status policy community is unavailable'
USING ERRCODE = 'foreign_key_violation';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER client_status_policy_connection_fence
BEFORE INSERT ON identity_enrollment_policies
FOR EACH ROW EXECUTE FUNCTION client_status_policy_connection_fence_v1();
ALTER TABLE client_status_transitions
ADD COLUMN connection_fingerprint BYTEA NOT NULL CHECK (
octet_length(connection_fingerprint) = 32
AND connection_fingerprint <> decode(repeat('00', 32), 'hex')
),
ADD COLUMN evidence_author_pubkey BYTEA CHECK (
evidence_author_pubkey IS NULL OR octet_length(evidence_author_pubkey) = 32
),
ADD COLUMN evidence_binding_id UUID,
ADD COLUMN evidence_binding_version BIGINT CHECK (
evidence_binding_version IS NULL OR evidence_binding_version > 0
),
ADD COLUMN evidence_policy_revision BIGINT CHECK (
evidence_policy_revision IS NULL OR evidence_policy_revision > 0
),
ADD COLUMN evidence_invalidation_generation BIGINT CHECK (
evidence_invalidation_generation IS NULL OR evidence_invalidation_generation >= 0
),
ADD COLUMN evidence_authority_epoch BIGINT CHECK (
evidence_authority_epoch IS NULL OR evidence_authority_epoch > 0
),
ADD COLUMN evidence_fence BYTEA CHECK (
evidence_fence IS NULL
OR (octet_length(evidence_fence) = 32
AND evidence_fence <> decode(repeat('00', 32), 'hex'))
),
ADD COLUMN evidence_observed_at TIMESTAMPTZ,
ADD CONSTRAINT client_status_transition_private_evidence CHECK (
(delivery_kind = 1
AND evidence_author_pubkey IS NOT NULL
AND evidence_binding_id IS NOT NULL
AND evidence_binding_id <> '00000000-0000-0000-0000-000000000000'::uuid
AND evidence_binding_version IS NOT NULL
AND evidence_policy_revision IS NOT NULL
AND evidence_invalidation_generation IS NOT NULL
AND evidence_authority_epoch IS NOT NULL
AND evidence_fence IS NOT NULL
AND evidence_observed_at IS NOT NULL
AND evidence_observed_at < fresh_until)
OR (delivery_kind = 2
AND evidence_author_pubkey IS NULL
AND evidence_binding_id IS NULL
AND evidence_binding_version IS NULL
AND evidence_policy_revision IS NULL
AND evidence_invalidation_generation IS NULL
AND evidence_authority_epoch IS NULL
AND evidence_fence IS NULL
AND evidence_observed_at IS NULL)
);
ALTER TABLE client_status_transition_heads
ADD COLUMN connection_fingerprint BYTEA NOT NULL CHECK (
octet_length(connection_fingerprint) = 32
AND connection_fingerprint <> decode(repeat('00', 32), 'hex')
);
ALTER TABLE client_status_transition_heads
DROP CONSTRAINT client_status_transition_heads_transition,
DROP CONSTRAINT client_status_transition_heads_pkey;
DO $$
DECLARE constraint_name TEXT;
BEGIN
SELECT c.conname INTO constraint_name
FROM pg_constraint c
WHERE c.conrelid = 'client_status_transition_heads'::regclass
AND c.contype = 'u'
AND pg_get_constraintdef(c.oid)
= 'UNIQUE (community_id, transition_id)';
IF constraint_name IS NOT NULL THEN
EXECUTE format(
'ALTER TABLE client_status_transition_heads DROP CONSTRAINT %I',
constraint_name
);
END IF;
SELECT c.conname INTO constraint_name
FROM pg_constraint c
WHERE c.conrelid = 'client_status_transitions'::regclass
AND c.contype = 'u'
AND pg_get_constraintdef(c.oid)
= 'UNIQUE (community_id, subject_fingerprint, signer_fingerprint, status_revision)';
IF constraint_name IS NOT NULL THEN
EXECUTE format(
'ALTER TABLE client_status_transitions DROP CONSTRAINT %I',
constraint_name
);
END IF;
SELECT c.conname INTO constraint_name
FROM pg_constraint c
WHERE c.conrelid = 'client_status_transitions'::regclass
AND c.contype = 'u'
AND pg_get_constraintdef(c.oid)
= 'UNIQUE (community_id, transition_id, subject_fingerprint, signer_fingerprint, status_revision, delivery_kind)';
IF constraint_name IS NOT NULL THEN
EXECUTE format(
'ALTER TABLE client_status_transitions DROP CONSTRAINT %I',
constraint_name
);
END IF;
END;
$$;
ALTER TABLE client_status_transitions
ADD CONSTRAINT client_status_transition_connection_revision
UNIQUE (community_id, connection_fingerprint, status_revision),
ADD CONSTRAINT client_status_transition_connection_identity
UNIQUE (community_id, transition_id, connection_fingerprint,
subject_fingerprint, signer_fingerprint, status_revision, delivery_kind);
ALTER TABLE client_status_transition_heads
ADD PRIMARY KEY (community_id, connection_fingerprint),
ADD UNIQUE (community_id, transition_id, connection_fingerprint),
ADD CONSTRAINT client_status_transition_heads_transition
FOREIGN KEY (community_id, transition_id, connection_fingerprint,
subject_fingerprint, signer_fingerprint, status_revision, delivery_kind)
REFERENCES client_status_transitions
(community_id, transition_id, connection_fingerprint,
subject_fingerprint, signer_fingerprint, status_revision, delivery_kind)
DEFERRABLE INITIALLY DEFERRED;
CREATE OR REPLACE FUNCTION client_status_transition_head_guard_v1() RETURNS TRIGGER AS $$
BEGIN
IF TG_OP = 'INSERT' THEN
IF NEW.status_revision <> 1 THEN
RAISE EXCEPTION 'client status head must start at revision one'
USING ERRCODE = 'check_violation', CONSTRAINT = 'client_status_transition_head_revision';
END IF;
ELSIF NEW.community_id IS DISTINCT FROM OLD.community_id
OR NEW.connection_fingerprint IS DISTINCT FROM OLD.connection_fingerprint
OR NEW.subject_fingerprint IS DISTINCT FROM OLD.subject_fingerprint
OR NEW.signer_fingerprint IS DISTINCT FROM OLD.signer_fingerprint
OR NEW.status_revision <> OLD.status_revision + 1
OR NEW.transition_id IS NOT DISTINCT FROM OLD.transition_id
THEN
RAISE EXCEPTION 'client status head transition is invalid'
USING ERRCODE = 'check_violation', CONSTRAINT = 'client_status_transition_head_revision';
END IF;
NEW.updated_at := transaction_timestamp();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION client_status_delivery_state_guard_v1() RETURNS TRIGGER AS $$
DECLARE claim_advance BOOLEAN; retry_advance BOOLEAN; delivered_advance BOOLEAN; terminal_advance BOOLEAN;
DECLARE expired_transition BOOLEAN; stale_transition BOOLEAN;
BEGIN
IF NEW.community_id IS DISTINCT FROM OLD.community_id
OR NEW.delivery_id IS DISTINCT FROM OLD.delivery_id
OR NEW.transition_id IS DISTINCT FROM OLD.transition_id
OR NEW.connection_fingerprint IS DISTINCT FROM OLD.connection_fingerprint
OR NEW.created_at IS DISTINCT FROM OLD.created_at
OR NEW.retain_until IS DISTINCT FROM OLD.retain_until
OR OLD.delivery_state <> 1
THEN
RAISE EXCEPTION 'client status delivery transition is invalid'
USING ERRCODE = 'check_violation', CONSTRAINT = 'client_status_delivery_transition';
END IF;
SELECT EXISTS(SELECT 1 FROM client_status_transitions transition
WHERE transition.community_id=OLD.community_id
AND transition.transition_id=OLD.transition_id
AND transition.fresh_until <= transaction_timestamp())
INTO expired_transition;
SELECT NOT EXISTS(
SELECT 1 FROM client_status_delivery_outbox delivery
JOIN client_status_transitions transition
ON transition.community_id=delivery.community_id
AND transition.transition_id=delivery.transition_id
JOIN client_status_transition_heads head
ON head.community_id=transition.community_id
AND head.connection_fingerprint=delivery.connection_fingerprint
AND head.transition_id=transition.transition_id
WHERE delivery.community_id=OLD.community_id
AND delivery.delivery_id=OLD.delivery_id)
INTO stale_transition;
claim_advance := NEW.delivery_state = 1 AND NEW.claim_id IS NOT NULL
AND NEW.completion_claim_id IS NULL AND NEW.attempt_count = OLD.attempt_count + 1
AND NOT stale_transition AND NOT expired_transition
AND OLD.next_attempt_at <= transaction_timestamp() AND OLD.attempt_count < 16
AND (OLD.claim_id IS NULL OR OLD.claimed_until <= transaction_timestamp())
AND NEW.claim_id IS DISTINCT FROM OLD.claim_id
AND NEW.claimed_until > transaction_timestamp()
AND NEW.claimed_until <= transaction_timestamp() + INTERVAL '5 minutes'
AND NEW.attempt_started_at IS NOT NULL
AND (NEW.last_failure_reason = OLD.last_failure_reason
OR (OLD.claim_id IS NOT NULL AND OLD.claimed_until <= transaction_timestamp()
AND NEW.last_failure_reason = 7))
AND NEW.next_attempt_at = OLD.next_attempt_at;
retry_advance := NEW.delivery_state = 1 AND OLD.claim_id IS NOT NULL AND NEW.claim_id IS NULL
AND NEW.completion_claim_id IS NULL AND NEW.attempt_count = OLD.attempt_count
AND NEW.attempt_started_at = OLD.attempt_started_at AND NEW.last_failure_reason = 1
AND NEW.next_attempt_at > OLD.next_attempt_at;
delivered_advance := NEW.delivery_state = 2 AND OLD.claim_id IS NOT NULL
AND NEW.claim_id IS NULL AND NEW.completion_claim_id = OLD.claim_id
AND NEW.attempt_count = OLD.attempt_count AND NEW.delivered_at IS NOT NULL
AND NEW.terminal_at IS NULL AND NEW.last_failure_reason = 0;
terminal_advance := NEW.delivery_state = 3 AND NEW.claim_id IS NULL
AND NEW.completion_claim_id IS NOT NULL
AND NEW.attempt_count = OLD.attempt_count AND NEW.delivered_at IS NULL
AND NEW.terminal_at IS NOT NULL
AND (
(OLD.claim_id IS NOT NULL AND NEW.completion_claim_id = OLD.claim_id
AND NEW.last_failure_reason BETWEEN 2 AND 7)
OR (NEW.last_failure_reason = 2
AND (OLD.claim_id IS NULL OR NEW.completion_claim_id = OLD.claim_id))
OR (NEW.last_failure_reason = 3 AND stale_transition
AND (OLD.claim_id IS NULL OR OLD.claimed_until <= transaction_timestamp()))
OR (NEW.last_failure_reason = 5 AND expired_transition
AND (OLD.claim_id IS NULL OR OLD.claimed_until <= transaction_timestamp()))
OR (NEW.last_failure_reason = 6 AND OLD.attempt_count >= 16
AND (OLD.claim_id IS NULL OR OLD.claimed_until <= transaction_timestamp()))
);
IF NOT (claim_advance OR retry_advance OR delivered_advance OR terminal_advance) THEN
RAISE EXCEPTION 'client status delivery transition is invalid'
USING ERRCODE = 'check_violation', CONSTRAINT = 'client_status_delivery_transition';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;