| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162 |
- """Add encrypted, versioned external data-source credentials."""
- from alembic import op
- revision = "20260718_50"
- down_revision = "20260716_40"
- branch_labels = None
- depends_on = None
- def upgrade() -> None:
- op.execute(
- """
- CREATE TABLE IF NOT EXISTS public.datasource_credentials (
- id UUID PRIMARY KEY,
- data_source_uid UUID NOT NULL,
- credential_version INTEGER NOT NULL
- CHECK (credential_version > 0),
- encrypted_payload BYTEA NOT NULL,
- nonce BYTEA NOT NULL CHECK (octet_length(nonce) = 12),
- key_version VARCHAR(40) NOT NULL,
- status VARCHAR(20) NOT NULL DEFAULT 'active'
- CHECK (status IN ('active', 'retired', 'revoked')),
- created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
- retired_at TIMESTAMPTZ,
- UNIQUE (data_source_uid, credential_version)
- );
- CREATE UNIQUE INDEX IF NOT EXISTS uq_datasource_credential_active
- ON public.datasource_credentials(data_source_uid)
- WHERE status = 'active';
- CREATE INDEX IF NOT EXISTS idx_datasource_credential_lookup
- ON public.datasource_credentials(
- data_source_uid, credential_version, status
- );
- CREATE TABLE IF NOT EXISTS public.datasource_credential_audit_events (
- id BIGSERIAL PRIMARY KEY,
- data_source_uid UUID NOT NULL,
- credential_version INTEGER,
- actor_uid UUID REFERENCES public.users(id) ON DELETE SET NULL,
- event_type VARCHAR(60) NOT NULL,
- success BOOLEAN NOT NULL,
- safe_detail VARCHAR(500),
- created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
- );
- CREATE INDEX IF NOT EXISTS idx_datasource_credential_audit_source
- ON public.datasource_credential_audit_events(
- data_source_uid, created_at DESC
- );
- CREATE INDEX IF NOT EXISTS idx_datasource_credential_audit_actor
- ON public.datasource_credential_audit_events(
- actor_uid, created_at DESC
- );
- """
- )
- def downgrade() -> None:
- # Credential and audit history remain available during application rollback.
- pass
|