Files
qinglong/packages/ql3-cluster-postgres/src/migrations/pg-0004-project-policy.ts
T

120 lines
4.4 KiB
TypeScript

import { definePostgresSqlMigration } from './sqlMigration';
export const POSTGRESQL_PROJECT_TABLE = 'projects';
export const POSTGRESQL_PROJECT_ROLE_BINDING_TABLE = 'project_role_bindings';
export const pg0004ProjectPolicyMigration = definePostgresSqlMigration({
id: 'pg-0004-project-policy',
statements: [
`
CREATE TABLE "ql3"."${POSTGRESQL_PROJECT_TABLE}" (
id varchar(128) PRIMARY KEY
CONSTRAINT ql3_projects_id_check CHECK (char_length(id) >= 1),
name varchar(255) NOT NULL
CONSTRAINT ql3_projects_name_check CHECK (char_length(name) >= 1),
slug varchar(128) NOT NULL
CONSTRAINT ql3_projects_slug_check
CHECK (slug ~ '^[a-z0-9](?:[a-z0-9-]{0,126}[a-z0-9])?$'),
status varchar(16) NOT NULL
CONSTRAINT ql3_projects_status_check
CHECK (status IN ('active', 'archived')),
version integer NOT NULL
CONSTRAINT ql3_projects_version_check
CHECK (version BETWEEN 1 AND 2147483647),
created_at_ms bigint NOT NULL
CONSTRAINT ql3_projects_created_at_check CHECK (created_at_ms >= 0),
updated_at_ms bigint NOT NULL
CONSTRAINT ql3_projects_updated_at_check
CHECK (updated_at_ms >= created_at_ms)
)
`.trim(),
`
CREATE UNIQUE INDEX ql3_projects_slug_uidx
ON "ql3"."${POSTGRESQL_PROJECT_TABLE}" (slug)
`.trim(),
`
INSERT INTO "ql3"."${POSTGRESQL_PROJECT_TABLE}" (
id, name, slug, status, version, created_at_ms, updated_at_ms
)
VALUES ('default', 'Default', 'default', 'active', 1, 0, 0)
`.trim(),
`
CREATE TABLE "ql3"."${POSTGRESQL_PROJECT_ROLE_BINDING_TABLE}" (
project_id varchar(128) NOT NULL,
subject_type varchar(32) NOT NULL
CONSTRAINT ql3_project_role_bindings_subject_type_check
CHECK (subject_type IN ('user', 'api_app', 'mcp_client', 'agent', 'system', 'worker')),
subject_id varchar(255) NOT NULL
CONSTRAINT ql3_project_role_bindings_subject_id_check
CHECK (char_length(subject_id) >= 1),
version integer NOT NULL
CONSTRAINT ql3_project_role_bindings_version_check
CHECK (version BETWEEN 1 AND 2147483647),
state varchar(16) NOT NULL
CONSTRAINT ql3_project_role_bindings_state_check
CHECK (state IN ('active', 'revoked')),
role varchar(16),
mutation_id varchar(64) NOT NULL
CONSTRAINT ql3_project_role_bindings_mutation_id_check
CHECK (mutation_id ~ '^[A-Za-z0-9._:-]{1,64}$'),
changed_by_type varchar(32) NOT NULL
CONSTRAINT ql3_project_role_bindings_changed_by_type_check
CHECK (changed_by_type IN ('user', 'api_app', 'mcp_client', 'agent', 'system', 'worker')),
changed_by_id varchar(255) NOT NULL
CONSTRAINT ql3_project_role_bindings_changed_by_id_check
CHECK (char_length(changed_by_id) >= 1),
created_at_ms bigint NOT NULL
CONSTRAINT ql3_project_role_bindings_created_at_check
CHECK (created_at_ms >= 0),
CONSTRAINT project_role_bindings_pkey
PRIMARY KEY (project_id, subject_type, subject_id, version),
CONSTRAINT ql3_project_role_bindings_role_state_check
CHECK (
(state = 'active' AND role IN ('owner', 'admin', 'operator', 'viewer'))
OR (state = 'revoked' AND role IS NULL)
),
CONSTRAINT ql3_project_role_bindings_project_fk
FOREIGN KEY (project_id) REFERENCES "ql3"."${POSTGRESQL_PROJECT_TABLE}" (id)
ON DELETE CASCADE
)
`.trim(),
`
CREATE INDEX ql3_project_role_bindings_current_idx
ON "ql3"."${POSTGRESQL_PROJECT_ROLE_BINDING_TABLE}"
(project_id, subject_type, subject_id, version DESC)
`.trim(),
`
CREATE UNIQUE INDEX ql3_project_role_bindings_mutation_uidx
ON "ql3"."${POSTGRESQL_PROJECT_ROLE_BINDING_TABLE}"
(project_id, mutation_id)
`.trim(),
`
CREATE INDEX ql3_project_role_bindings_subject_idx
ON "ql3"."${POSTGRESQL_PROJECT_ROLE_BINDING_TABLE}"
(subject_type, subject_id, project_id, version DESC)
`.trim(),
`
DO $ql3$
BEGIN
UPDATE "ql3"."schema_capabilities"
SET contract_version = 3,
migration_id = 'pg-0004-project-policy',
capabilities = '{"project_policy":1,"run_core":1,"run_retry_policy":1}'::jsonb,
updated_at_ms = floor(
extract(epoch FROM transaction_timestamp()) * 1000
)::bigint
WHERE contract_name = 'control-core'
AND contract_version = 2
AND migration_id = 'pg-0003-run-retry-policy'
AND capabilities = '{"run_core":1,"run_retry_policy":1}'::jsonb;
IF NOT FOUND THEN
RAISE EXCEPTION 'control-core capability is not at version 2'
USING ERRCODE = 'check_violation';
END IF;
END
$ql3$
`.trim(),
],
});