QRun-IO/ci-policy: ci / fork-guard (pull_request) Skipped
QRun-IO/ci-policy: native / fork-deny (pull_request) Skipped
QRun-IO/ci-policy: native / dotnet-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / Scoped workflow [workflow f1d46718955078331817c6206b822a94bc7d769f] (pull_request) Successful in 9s
QRun-IO/ci-policy: ci / head-profile (pull_request) Skipped
QRun-IO/ci-policy: native / native-result (pull_request) Successful in 9s
QRun-IO/ci-policy: ci / repository-policy (pull_request) Skipped
QRun-IO/ci-policy: ci / application-template-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / gradle-1 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (pull_request) Skipped
QRun-IO/ci-policy: ci / node-8 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-9 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-10 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-13 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-14 (pull_request) Skipped
QRun-IO/ci-policy: ci / android-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / original-business (pull_request) Skipped
QRun-IO/ci-policy: ci / original-mcp (pull_request) Skipped
QRun-IO/ci-policy: ci / original-voyage (pull_request) Skipped
QRun-IO/ci-policy: ci / original-cli (pull_request) Skipped
QRun-IO/ci-policy: ci / not-enrolled (pull_request) Skipped
QRun-IO/ci-policy: ci / shared-pipeline (pull_request) Skipped
Shared Java Maven CI with Docker / secrets (push) Successful in 38s
QRun-IO/ci-policy: Shared Java Maven CI with Docker / secrets (pull_request) Successful in 38s
qbit release candidate / cut-rc (pull_request) Failing after 18s
Release candidate / release-rc (pull_request) Failing after 18s
qbit release candidate / tag-and-release (pull_request) Skipped
QRun-IO/ci-policy: Shared Java Maven CI with Docker / verify (pull_request) Failing after 15m39s
QRun-IO/ci-policy: Shared Java Maven CI with Docker / gate (pull_request) Failing after 24s
QRun-IO/ci-policy: ci / java-docker-3 (pull_request) Failing after 1h14m34s
QRun-IO/ci-policy: ci / ci-result (pull_request) Failing after 10s
Shared Java Maven CI with Docker / verify (push) Failing after 17m19s
Shared Java Maven CI with Docker / gate (push) Failing after 24s
qrun-release / release (push) Failing after 1h16m30s
qrun-release / postpublish (push) Skipped
Add user and group QQQ application-role access editing, bounded catalogs, webhook inbox and SQL mirrors, refreshed session permissions, and deferred invitation assignments. Include the isolated local review host, browser acceptance scripts, documentation and the token-widget column mapping fix. User approved this RC checkpoint. Full 1.0 gates remain documented, including the schema-drift matcher and PostgreSQL integration errors from the full gate. Companion UI: QRun-IO/qqq-frontend-next#205. Co-Authored-By: GPT-6 <noreply@openai.com>
118 lines
4.2 KiB
SQL
118 lines
4.2 KiB
SQL
-- Additive PostgreSQL migration for DESIGN sections 6.2 and 7.
|
|
-- Apply to the host's local database, NEVER Authentik's database.
|
|
-- Replace authentik_ with the configured table prefix when applicable.
|
|
-- Storage foundation only: MIRROR and WEBHOOK remain disabled until the
|
|
-- reconciler, durable processing, and session invalidation gates are complete.
|
|
|
|
CREATE TABLE authentik_user_mirror
|
|
(
|
|
id SERIAL PRIMARY KEY,
|
|
pk INTEGER NOT NULL UNIQUE,
|
|
uuid VARCHAR(64),
|
|
username VARCHAR(255) NOT NULL UNIQUE,
|
|
email VARCHAR(255) UNIQUE,
|
|
name VARCHAR(255),
|
|
type VARCHAR(40),
|
|
path VARCHAR(1024),
|
|
source_is_superuser BOOLEAN,
|
|
source_is_protected BOOLEAN,
|
|
is_active BOOLEAN,
|
|
last_login TIMESTAMP,
|
|
is_superuser BOOLEAN,
|
|
is_protected BOOLEAN,
|
|
group_names TEXT,
|
|
effective_permissions TEXT,
|
|
mfa_device_count INTEGER,
|
|
failed_logins24h INTEGER,
|
|
refreshed_at TIMESTAMP NOT NULL
|
|
);
|
|
-- Blank email must be normalized to NULL. Ambiguous nonblank emails must
|
|
-- stop synchronization and cannot be used for permission fallback.
|
|
-- QQQ DATE_TIME binds UTC LocalDateTime values. Mirror DATE_TIME columns use
|
|
-- timezone-free TIMESTAMP containing UTC, so a non-UTC database session cannot
|
|
-- reinterpret them. JDBC-owned inbox/state clocks below use zoned instants.
|
|
|
|
CREATE TABLE authentik_group_mirror
|
|
(
|
|
id SERIAL PRIMARY KEY,
|
|
pk VARCHAR(64) NOT NULL UNIQUE,
|
|
name VARCHAR(255),
|
|
parent_pks TEXT,
|
|
attributes TEXT,
|
|
member_count INTEGER,
|
|
is_superuser BOOLEAN,
|
|
refreshed_at TIMESTAMP NOT NULL
|
|
);
|
|
|
|
CREATE TABLE authentik_membership_mirror
|
|
(
|
|
id SERIAL PRIMARY KEY,
|
|
user_pk INTEGER NOT NULL,
|
|
group_pk VARCHAR(64) NOT NULL,
|
|
group_name VARCHAR(255),
|
|
refreshed_at TIMESTAMP NOT NULL,
|
|
UNIQUE (user_pk, group_pk)
|
|
);
|
|
CREATE INDEX idx_authentik_membership_mirror_group ON authentik_membership_mirror (group_pk);
|
|
|
|
CREATE TABLE authentik_webhook_inbox
|
|
(
|
|
id SERIAL PRIMARY KEY,
|
|
event_pk VARCHAR(64) NOT NULL UNIQUE,
|
|
payload_json TEXT NOT NULL,
|
|
status VARCHAR(30) NOT NULL,
|
|
attempts INTEGER NOT NULL DEFAULT 0,
|
|
received_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
next_attempt_at TIMESTAMP WITH TIME ZONE,
|
|
processed_at TIMESTAMP WITH TIME ZONE,
|
|
lease_owner VARCHAR(64),
|
|
lease_until TIMESTAMP WITH TIME ZONE,
|
|
error_code VARCHAR(100)
|
|
);
|
|
CREATE INDEX idx_authentik_webhook_inbox_pending ON authentik_webhook_inbox (status, next_attempt_at);
|
|
CREATE INDEX idx_authentik_webhook_inbox_retention ON authentik_webhook_inbox (received_at);
|
|
|
|
CREATE TABLE authentik_sync_state
|
|
(
|
|
id SERIAL PRIMARY KEY,
|
|
sync_key VARCHAR(64) NOT NULL UNIQUE,
|
|
watermark TIMESTAMP WITH TIME ZONE,
|
|
last_full_sync TIMESTAMP WITH TIME ZONE,
|
|
scope_fingerprint VARCHAR(64),
|
|
lease_owner VARCHAR(64),
|
|
lease_until TIMESTAMP WITH TIME ZONE
|
|
);
|
|
|
|
-- Authentication adapter-owned immutable identity binding. Store only the hash
|
|
-- of the QQQ session UUID, never its bearer credential or access/refresh tokens.
|
|
CREATE TABLE authentik_session_binding
|
|
(
|
|
id SERIAL PRIMARY KEY,
|
|
session_hash VARCHAR(64) NOT NULL UNIQUE,
|
|
issuer_fingerprint VARCHAR(64) NOT NULL,
|
|
user_pk INTEGER,
|
|
user_uuid VARCHAR(64),
|
|
user_reference VARCHAR(1024),
|
|
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
revoked BOOLEAN NOT NULL DEFAULT FALSE,
|
|
CHECK (revoked OR (user_pk IS NOT NULL AND user_pk > 0 AND user_uuid IS NOT NULL AND user_reference IS NOT NULL))
|
|
);
|
|
CREATE INDEX idx_authentik_session_binding_expiry ON authentik_session_binding (expires_at);
|
|
|
|
-- Internal, immutable invitation intent plus one-time binding/assignment progress.
|
|
-- Payload contains operator identity, reason and group IDs, never invitation URLs,
|
|
-- passwords, API tokens or email delivery credentials.
|
|
CREATE TABLE authentik_invitation_assignment
|
|
(
|
|
id SERIAL PRIMARY KEY,
|
|
reference VARCHAR(36) NOT NULL UNIQUE,
|
|
scope_fingerprint VARCHAR(64) NOT NULL,
|
|
invitation_id VARCHAR(36) UNIQUE,
|
|
status VARCHAR(20) NOT NULL,
|
|
payload_json TEXT NOT NULL,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
CHECK (status IN ('WAITING', 'READY', 'COMPLETE', 'REVIEW', 'CANCELLED'))
|
|
);
|
|
CREATE INDEX idx_authentik_invitation_assignment_expiry ON authentik_invitation_assignment (expires_at);
|