chore(merge): 整合最新 main 与统一认证变更
ci / verify (pull_request) Successful in 12m18s
ci / verify (pull_request) Successful in 12m18s
合并远端生产 CI、依赖与 API 文档改动,保留统一认证和 SSF 能力。由于远端生产基线已占用 0062,将尚未发布的身份迁移整理为 0063 至 0068 的最终增量 Schema,移除仅用于开发期草稿升级的破坏性迁移步骤。 验证:go test ./...。其余生产门禁在合并提交后继续执行。
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
UPDATE model_catalog_providers
|
||||
SET default_auth_type = 'APIKey',
|
||||
updated_at = now()
|
||||
WHERE provider_key = 'keling'
|
||||
OR provider_code = 'keling';
|
||||
|
||||
UPDATE integration_platforms
|
||||
SET auth_type = CASE
|
||||
WHEN COALESCE(NULLIF(trim(credentials->>'accessKey'), ''), NULLIF(trim(credentials->>'secretKey'), '')) IS NULL
|
||||
THEN 'APIKey'
|
||||
ELSE auth_type
|
||||
END,
|
||||
credentials = CASE
|
||||
WHEN credentials ? 'apiKey' THEN credentials
|
||||
ELSE credentials || '{"apiKey": ""}'::jsonb
|
||||
END,
|
||||
updated_at = now()
|
||||
WHERE provider = 'keling'
|
||||
AND deleted_at IS NULL;
|
||||
|
||||
WITH keling_30_turbo AS (
|
||||
SELECT
|
||||
'keling:kling-3.0-turbo' AS canonical_model_key,
|
||||
'kling-3.0-turbo' AS provider_model_name,
|
||||
'可灵3.0 Turbo' AS display_name,
|
||||
'["video_generate","image_to_video"]'::jsonb AS model_type,
|
||||
'{
|
||||
"video_generate": {
|
||||
"aspect_ratio_allowed": ["16:9", "1:1", "9:16"],
|
||||
"output_resolutions": ["720p", "1080p"],
|
||||
"duration_range": [3, 15],
|
||||
"output_audio": true,
|
||||
"prompt_length_limit": {
|
||||
"max": 3072,
|
||||
"label": "可灵3.0 Turbo"
|
||||
}
|
||||
},
|
||||
"image_to_video": {
|
||||
"output_resolutions": ["720p", "1080p"],
|
||||
"duration_range": [3, 15],
|
||||
"input_first_frame": true,
|
||||
"input_last_frame": false,
|
||||
"input_first_last_frame": false,
|
||||
"aspect_ratio_allowed": [],
|
||||
"output_audio": true,
|
||||
"input_reference_generate_single": false,
|
||||
"input_reference_generate_multiple": false,
|
||||
"support_video_effect_template": false,
|
||||
"prompt_length_limit": {
|
||||
"max": 2500,
|
||||
"label": "可灵3.0 Turbo"
|
||||
}
|
||||
},
|
||||
"originalTypes": ["video_generate", "image_to_video"]
|
||||
}'::jsonb AS capabilities,
|
||||
COALESCE(
|
||||
(
|
||||
SELECT base_billing_config
|
||||
FROM base_model_catalog
|
||||
WHERE canonical_model_key = 'keling:kling-v3'
|
||||
LIMIT 1
|
||||
),
|
||||
'{
|
||||
"video": {
|
||||
"basePrice": 100,
|
||||
"baseWeight": 1,
|
||||
"dynamicWeight": {
|
||||
"720p": 1,
|
||||
"1080p": 1.5,
|
||||
"audio-true": 2,
|
||||
"audio-false": 1
|
||||
}
|
||||
},
|
||||
"currency": "resource"
|
||||
}'::jsonb
|
||||
) AS base_billing_config,
|
||||
COALESCE(
|
||||
(
|
||||
SELECT default_rate_limit_policy
|
||||
FROM base_model_catalog
|
||||
WHERE canonical_model_key = 'keling:kling-v3'
|
||||
LIMIT 1
|
||||
),
|
||||
'{"platformLimits":{"max_concurrent_requests":5}}'::jsonb
|
||||
) AS default_rate_limit_policy,
|
||||
'{
|
||||
"source": "server-main.integration-platform",
|
||||
"sourceProviderCode": "keling",
|
||||
"sourceProviderName": "可灵AI",
|
||||
"sourceSpecType": "keling",
|
||||
"originalTypes": ["video_generate", "image_to_video"],
|
||||
"alias": "可灵3.0 Turbo",
|
||||
"description": "可灵新任务 API 的 3.0 Turbo 文生视频与首帧图生视频模型",
|
||||
"iconPath": "https://static.51easyai.com/kling-color.webp",
|
||||
"billingType": "external-api",
|
||||
"billingMode": "",
|
||||
"referenceModel": "",
|
||||
"modelWeight": null,
|
||||
"selectable": true,
|
||||
"rawModel": {
|
||||
"name": "kling-3.0-turbo",
|
||||
"types": ["video_generate", "image_to_video"],
|
||||
"alias": "可灵3.0 Turbo",
|
||||
"icon_path": "https://static.51easyai.com/kling-color.webp"
|
||||
}
|
||||
}'::jsonb AS metadata
|
||||
)
|
||||
INSERT INTO base_model_catalog (
|
||||
provider_id,
|
||||
provider_key,
|
||||
canonical_model_key,
|
||||
provider_model_name,
|
||||
model_type,
|
||||
display_name,
|
||||
capabilities,
|
||||
base_billing_config,
|
||||
default_rate_limit_policy,
|
||||
metadata,
|
||||
catalog_type,
|
||||
default_snapshot,
|
||||
status
|
||||
)
|
||||
SELECT
|
||||
(
|
||||
SELECT id
|
||||
FROM model_catalog_providers
|
||||
WHERE provider_key = 'keling' OR provider_code = 'keling'
|
||||
LIMIT 1
|
||||
),
|
||||
'keling',
|
||||
model.canonical_model_key,
|
||||
model.provider_model_name,
|
||||
model.model_type,
|
||||
model.display_name,
|
||||
model.capabilities,
|
||||
model.base_billing_config,
|
||||
model.default_rate_limit_policy,
|
||||
jsonb_set(model.metadata, '{rawModel,capabilities}', model.capabilities, true),
|
||||
'system',
|
||||
jsonb_build_object(
|
||||
'providerKey', 'keling',
|
||||
'canonicalModelKey', model.canonical_model_key,
|
||||
'providerModelName', model.provider_model_name,
|
||||
'modelType', model.model_type,
|
||||
'modelAlias', model.display_name,
|
||||
'displayName', model.display_name,
|
||||
'capabilities', model.capabilities,
|
||||
'baseBillingConfig', model.base_billing_config,
|
||||
'defaultRateLimitPolicy', model.default_rate_limit_policy,
|
||||
'metadata', jsonb_set(model.metadata, '{rawModel,capabilities}', model.capabilities, true),
|
||||
'status', 'active'
|
||||
),
|
||||
'active'
|
||||
FROM keling_30_turbo model
|
||||
ON CONFLICT (canonical_model_key) DO UPDATE
|
||||
SET provider_id = EXCLUDED.provider_id,
|
||||
provider_key = EXCLUDED.provider_key,
|
||||
provider_model_name = CASE WHEN base_model_catalog.customized_at IS NULL THEN EXCLUDED.provider_model_name ELSE base_model_catalog.provider_model_name END,
|
||||
model_type = CASE WHEN base_model_catalog.customized_at IS NULL THEN EXCLUDED.model_type ELSE base_model_catalog.model_type END,
|
||||
display_name = CASE WHEN base_model_catalog.customized_at IS NULL THEN EXCLUDED.display_name ELSE base_model_catalog.display_name END,
|
||||
capabilities = CASE WHEN base_model_catalog.customized_at IS NULL THEN EXCLUDED.capabilities ELSE base_model_catalog.capabilities END,
|
||||
base_billing_config = CASE WHEN base_model_catalog.customized_at IS NULL THEN EXCLUDED.base_billing_config ELSE base_model_catalog.base_billing_config END,
|
||||
default_rate_limit_policy = CASE WHEN base_model_catalog.customized_at IS NULL THEN EXCLUDED.default_rate_limit_policy ELSE base_model_catalog.default_rate_limit_policy END,
|
||||
metadata = CASE WHEN base_model_catalog.customized_at IS NULL THEN EXCLUDED.metadata ELSE base_model_catalog.metadata END,
|
||||
catalog_type = CASE WHEN base_model_catalog.customized_at IS NULL THEN 'system' ELSE base_model_catalog.catalog_type END,
|
||||
default_snapshot = CASE WHEN base_model_catalog.customized_at IS NULL THEN EXCLUDED.default_snapshot ELSE base_model_catalog.default_snapshot END,
|
||||
status = CASE WHEN base_model_catalog.customized_at IS NULL THEN 'active' ELSE base_model_catalog.status END,
|
||||
updated_at = now();
|
||||
|
||||
INSERT INTO platform_models (
|
||||
platform_id,
|
||||
base_model_id,
|
||||
model_name,
|
||||
provider_model_name,
|
||||
model_alias,
|
||||
model_type,
|
||||
display_name,
|
||||
capabilities,
|
||||
pricing_mode,
|
||||
billing_config,
|
||||
retry_policy,
|
||||
rate_limit_policy,
|
||||
enabled
|
||||
)
|
||||
SELECT
|
||||
platform.id,
|
||||
base_model.id,
|
||||
base_model.provider_model_name,
|
||||
base_model.provider_model_name,
|
||||
base_model.display_name,
|
||||
base_model.model_type,
|
||||
base_model.display_name,
|
||||
base_model.capabilities,
|
||||
'inherit_discount',
|
||||
base_model.base_billing_config,
|
||||
'{"enabled":true,"maxAttempts":1}'::jsonb,
|
||||
base_model.default_rate_limit_policy,
|
||||
true
|
||||
FROM integration_platforms platform
|
||||
JOIN base_model_catalog base_model
|
||||
ON base_model.canonical_model_key = 'keling:kling-3.0-turbo'
|
||||
WHERE platform.provider = 'keling'
|
||||
AND platform.deleted_at IS NULL
|
||||
ON CONFLICT (platform_id, model_name) DO UPDATE
|
||||
SET base_model_id = EXCLUDED.base_model_id,
|
||||
provider_model_name = EXCLUDED.provider_model_name,
|
||||
model_alias = EXCLUDED.model_alias,
|
||||
display_name = EXCLUDED.display_name,
|
||||
model_type = EXCLUDED.model_type,
|
||||
capabilities = EXCLUDED.capabilities,
|
||||
pricing_mode = EXCLUDED.pricing_mode,
|
||||
billing_config = EXCLUDED.billing_config,
|
||||
retry_policy = EXCLUDED.retry_policy,
|
||||
rate_limit_policy = EXCLUDED.rate_limit_policy,
|
||||
enabled = EXCLUDED.enabled,
|
||||
updated_at = now();
|
||||
@@ -1,15 +0,0 @@
|
||||
-- 0063 was released before its idempotency table was added. Installations that
|
||||
-- already recorded 0063 need a new immutable migration to repair that drift.
|
||||
CREATE TABLE IF NOT EXISTS gateway_security_event_connection_idempotency (
|
||||
operation text NOT NULL,
|
||||
idempotency_key text NOT NULL,
|
||||
request_hash text NOT NULL,
|
||||
response jsonb NOT NULL,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (operation, idempotency_key),
|
||||
CONSTRAINT gateway_security_event_connection_idempotency_operation
|
||||
CHECK (operation IN ('connect','verify','rotate','disconnect'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gateway_security_event_connection_idempotency_created
|
||||
ON gateway_security_event_connection_idempotency(created_at);
|
||||
+6
@@ -7,6 +7,8 @@ CREATE TABLE IF NOT EXISTS gateway_security_event_connections (
|
||||
stream_id uuid,
|
||||
credential_ref text NOT NULL,
|
||||
next_credential_ref text,
|
||||
management_client_id text,
|
||||
management_credential_ref text,
|
||||
lifecycle_status text NOT NULL,
|
||||
version bigint NOT NULL DEFAULT 1,
|
||||
last_error_category text,
|
||||
@@ -19,6 +21,10 @@ CREATE TABLE IF NOT EXISTS gateway_security_event_connections (
|
||||
)),
|
||||
CONSTRAINT gateway_security_event_connection_stream_pair CHECK (
|
||||
(audience IS NULL AND stream_id IS NULL) OR (audience IS NOT NULL AND stream_id IS NOT NULL)
|
||||
),
|
||||
CONSTRAINT gateway_security_event_management_credential_pair CHECK (
|
||||
(management_client_id IS NULL AND management_credential_ref IS NULL) OR
|
||||
(management_client_id IS NOT NULL AND management_credential_ref IS NOT NULL)
|
||||
)
|
||||
);
|
||||
|
||||
+3
@@ -19,6 +19,9 @@ CREATE TABLE IF NOT EXISTS gateway_identity_configuration_revisions (
|
||||
legacy_jwt_enabled boolean NOT NULL DEFAULT false,
|
||||
token_introspection boolean NOT NULL DEFAULT false,
|
||||
session_revocation boolean NOT NULL DEFAULT false,
|
||||
security_event_issuer text,
|
||||
security_event_configuration_url text,
|
||||
security_event_audience text,
|
||||
machine_credential_ref text,
|
||||
session_encryption_key_ref text,
|
||||
session_idle_seconds integer NOT NULL DEFAULT 1800 CHECK (session_idle_seconds > 0),
|
||||
@@ -1,37 +0,0 @@
|
||||
-- 0062 was released before the verification challenge table and the complete
|
||||
-- stream-state columns were added. Installations that already recorded 0062
|
||||
-- need a new immutable migration to repair that drift.
|
||||
ALTER TABLE gateway_security_event_stream_state
|
||||
ADD COLUMN IF NOT EXISTS stream_status text NOT NULL DEFAULT 'unknown',
|
||||
ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_constraint
|
||||
WHERE conrelid = 'gateway_security_event_stream_state'::regclass
|
||||
AND conname = 'gateway_security_event_stream_state_status'
|
||||
) THEN
|
||||
ALTER TABLE gateway_security_event_stream_state
|
||||
ADD CONSTRAINT gateway_security_event_stream_state_status
|
||||
CHECK (stream_status IN ('unknown','enabled','paused','disabled'));
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gateway_security_event_verification_challenges (
|
||||
issuer text NOT NULL,
|
||||
audience text NOT NULL,
|
||||
state_hash bytea NOT NULL,
|
||||
created_at timestamptz NOT NULL,
|
||||
expires_at timestamptz NOT NULL,
|
||||
PRIMARY KEY (issuer, audience, state_hash),
|
||||
FOREIGN KEY (issuer, audience)
|
||||
REFERENCES gateway_security_event_stream_state(issuer, audience) ON DELETE CASCADE,
|
||||
CONSTRAINT gateway_security_event_verification_challenge_hash
|
||||
CHECK (octet_length(state_hash) = 32)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gateway_security_event_challenges_expiry
|
||||
ON gateway_security_event_verification_challenges(expires_at);
|
||||
@@ -0,0 +1,55 @@
|
||||
CREATE TABLE IF NOT EXISTS gateway_identity_onboarding_exchanges (
|
||||
id uuid PRIMARY KEY,
|
||||
revision_id uuid NOT NULL UNIQUE REFERENCES gateway_identity_configuration_revisions(id) ON DELETE CASCADE,
|
||||
remote_exchange_id uuid NOT NULL UNIQUE,
|
||||
exchange_token_ref text NOT NULL CHECK (exchange_token_ref ~ '^[a-z0-9][a-z0-9-]{0,127}$'),
|
||||
status text NOT NULL CHECK (status IN (
|
||||
'metadata_pending','preparing','ready','credentials_saved','completed','failed','expired','cancelled'
|
||||
)),
|
||||
cleanup_status text NOT NULL DEFAULT 'none' CHECK (cleanup_status IN ('none','pending','completed')),
|
||||
remote_version bigint NOT NULL CHECK (remote_version > 0),
|
||||
expires_at timestamptz NOT NULL,
|
||||
version bigint NOT NULL DEFAULT 1 CHECK (version > 0),
|
||||
last_error_category text,
|
||||
auth_center_audit_id text,
|
||||
last_trace_id text,
|
||||
cancelled_at timestamptz,
|
||||
cleanup_completed_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT gateway_identity_onboarding_cleanup_lifecycle_check CHECK (
|
||||
(status <> 'cancelled' AND cleanup_status = 'none' AND cancelled_at IS NULL AND cleanup_completed_at IS NULL) OR
|
||||
(status = 'cancelled' AND cancelled_at IS NOT NULL AND (
|
||||
(cleanup_status = 'pending' AND cleanup_completed_at IS NULL) OR
|
||||
(cleanup_status = 'completed' AND cleanup_completed_at IS NOT NULL)
|
||||
))
|
||||
),
|
||||
CONSTRAINT gateway_identity_onboarding_error_category_check CHECK (
|
||||
last_error_category IS NULL OR last_error_category IN (
|
||||
'metadata_submission_failed','exchange_status_unavailable','credential_delivery_failed',
|
||||
'exchange_completion_failed','exchange_expired','remote_exchange_failed','remote_state_invalid',
|
||||
'security_event_configuration_invalid','security_event_connection_conflict',
|
||||
'security_event_discovery_failed','security_event_management_token_failed',
|
||||
'security_event_stream_create_failed','security_event_stream_response_invalid',
|
||||
'security_event_receiver_activation_failed','security_event_preparation_failed',
|
||||
'security_event_retirement_pending','security_event_credential_handoff_unsafe',
|
||||
'security_event_connection_binding_missing','security_event_connection_binding_unavailable',
|
||||
'security_event_connection_binding_invalid','security_event_connection_binding_mismatch',
|
||||
'pairing_step_failed','cleanup_revision_unavailable','cleanup_security_event_unavailable',
|
||||
'cleanup_security_event_configuration_invalid','cleanup_security_event_connection_conflict',
|
||||
'cleanup_security_event_discovery_failed','cleanup_security_event_management_token_failed',
|
||||
'cleanup_security_event_stream_create_failed','cleanup_security_event_stream_response_invalid',
|
||||
'cleanup_security_event_receiver_activation_failed','cleanup_security_event_preparation_failed',
|
||||
'cleanup_security_event_retirement_pending','cleanup_security_event_connection_cleanup_failed',
|
||||
'cleanup_security_event_secret_cleanup_failed','cleanup_security_event_credential_handoff_unsafe',
|
||||
'cleanup_security_event_failed','cleanup_secret_store_failed','cleanup_finalize_failed'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gateway_identity_onboarding_status
|
||||
ON gateway_identity_onboarding_exchanges(status, updated_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gateway_identity_onboarding_cleanup
|
||||
ON gateway_identity_onboarding_exchanges(cleanup_status, updated_at)
|
||||
WHERE cleanup_status = 'pending';
|
||||
@@ -1,9 +0,0 @@
|
||||
ALTER TABLE gateway_security_event_connections
|
||||
ADD COLUMN IF NOT EXISTS management_client_id text,
|
||||
ADD COLUMN IF NOT EXISTS management_credential_ref text;
|
||||
|
||||
ALTER TABLE gateway_security_event_connections
|
||||
ADD CONSTRAINT gateway_security_event_management_credential_pair CHECK (
|
||||
(management_client_id IS NULL AND management_credential_ref IS NULL) OR
|
||||
(management_client_id IS NOT NULL AND management_credential_ref IS NOT NULL)
|
||||
);
|
||||
+5
-8
@@ -1,18 +1,15 @@
|
||||
CREATE TABLE IF NOT EXISTS gateway_identity_secret_cleanup_queue (
|
||||
secret_ref text PRIMARY KEY CHECK (secret_ref ~ '^[a-z0-9][a-z0-9-]{0,127}$'),
|
||||
not_before timestamptz NOT NULL,
|
||||
status text NOT NULL DEFAULT 'pending',
|
||||
status text NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','claimed')),
|
||||
claim_token uuid,
|
||||
lease_expires_at timestamptz,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT gateway_identity_secret_cleanup_status_check
|
||||
CHECK (status IN ('pending','claimed')),
|
||||
CONSTRAINT gateway_identity_secret_cleanup_claim_check
|
||||
CHECK (
|
||||
(status = 'pending' AND claim_token IS NULL AND lease_expires_at IS NULL) OR
|
||||
(status = 'claimed' AND claim_token IS NOT NULL AND lease_expires_at IS NOT NULL)
|
||||
)
|
||||
CONSTRAINT gateway_identity_secret_cleanup_claim_check CHECK (
|
||||
(status = 'pending' AND claim_token IS NULL AND lease_expires_at IS NULL) OR
|
||||
(status = 'claimed' AND claim_token IS NOT NULL AND lease_expires_at IS NOT NULL)
|
||||
)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gateway_identity_secret_cleanup_due
|
||||
@@ -1,23 +0,0 @@
|
||||
ALTER TABLE gateway_identity_configuration_revisions
|
||||
ADD COLUMN IF NOT EXISTS security_event_issuer text,
|
||||
ADD COLUMN IF NOT EXISTS security_event_configuration_url text,
|
||||
ADD COLUMN IF NOT EXISTS security_event_audience text;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gateway_identity_onboarding_exchanges (
|
||||
id uuid PRIMARY KEY,
|
||||
revision_id uuid NOT NULL UNIQUE REFERENCES gateway_identity_configuration_revisions(id) ON DELETE CASCADE,
|
||||
remote_exchange_id uuid NOT NULL UNIQUE,
|
||||
exchange_token_ref text NOT NULL CHECK (exchange_token_ref ~ '^[a-z0-9][a-z0-9-]{0,127}$'),
|
||||
status text NOT NULL CHECK (status IN ('metadata_pending','preparing','ready','credentials_saved','completed','failed','expired')),
|
||||
remote_version bigint NOT NULL CHECK (remote_version > 0),
|
||||
expires_at timestamptz NOT NULL,
|
||||
version bigint NOT NULL DEFAULT 1 CHECK (version > 0),
|
||||
last_error_category text,
|
||||
auth_center_audit_id text,
|
||||
last_trace_id text,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gateway_identity_onboarding_status
|
||||
ON gateway_identity_onboarding_exchanges(status, updated_at DESC);
|
||||
+1
-4
@@ -1,6 +1,3 @@
|
||||
SET LOCAL lock_timeout = '10s';
|
||||
SET LOCAL statement_timeout = '60s';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gateway_identity_pairing_start_reservation (
|
||||
singleton boolean PRIMARY KEY DEFAULT true CHECK (singleton),
|
||||
attempt_id uuid NOT NULL UNIQUE,
|
||||
@@ -16,7 +13,7 @@ CREATE TABLE IF NOT EXISTS gateway_identity_pairing_start_reservation (
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gateway_identity_pairing_start_expiry
|
||||
ON gateway_identity_pairing_start_reservation(state,expires_at);
|
||||
ON gateway_identity_pairing_start_reservation(state, expires_at);
|
||||
|
||||
INSERT INTO gateway_identity_pairing_start_reservation(singleton,attempt_id,state,revision_id,expires_at)
|
||||
SELECT true,exchange.id,'paired',revision.id,exchange.expires_at
|
||||
@@ -1,69 +0,0 @@
|
||||
SET LOCAL lock_timeout = '10s';
|
||||
SET LOCAL statement_timeout = '60s';
|
||||
|
||||
ALTER TABLE gateway_identity_onboarding_exchanges
|
||||
DROP CONSTRAINT gateway_identity_onboarding_exchanges_status_check;
|
||||
|
||||
ALTER TABLE gateway_identity_onboarding_exchanges
|
||||
ADD CONSTRAINT gateway_identity_onboarding_exchanges_status_check
|
||||
CHECK (status IN ('metadata_pending','preparing','ready','credentials_saved','completed','failed','expired','cancelled')),
|
||||
ADD COLUMN cleanup_status text NOT NULL DEFAULT 'none',
|
||||
ADD COLUMN cancelled_at timestamptz,
|
||||
ADD COLUMN cleanup_completed_at timestamptz;
|
||||
|
||||
ALTER TABLE gateway_identity_onboarding_exchanges
|
||||
ADD CONSTRAINT gateway_identity_onboarding_cleanup_status_check
|
||||
CHECK (cleanup_status IN ('none','pending','completed')),
|
||||
ADD CONSTRAINT gateway_identity_onboarding_cleanup_lifecycle_check
|
||||
CHECK (
|
||||
(status <> 'cancelled' AND cleanup_status = 'none' AND cancelled_at IS NULL AND cleanup_completed_at IS NULL) OR
|
||||
(status = 'cancelled' AND cancelled_at IS NOT NULL AND (
|
||||
(cleanup_status = 'pending' AND cleanup_completed_at IS NULL) OR
|
||||
(cleanup_status = 'completed' AND cleanup_completed_at IS NOT NULL)
|
||||
))
|
||||
);
|
||||
|
||||
UPDATE gateway_identity_onboarding_exchanges
|
||||
SET last_error_category = 'pairing_step_failed'
|
||||
WHERE last_error_category IS NOT NULL
|
||||
AND last_error_category NOT IN (
|
||||
'metadata_submission_failed','exchange_status_unavailable','credential_delivery_failed',
|
||||
'exchange_completion_failed','exchange_expired','remote_exchange_failed','remote_state_invalid',
|
||||
'security_event_configuration_invalid','security_event_connection_conflict',
|
||||
'security_event_discovery_failed','security_event_management_token_failed',
|
||||
'security_event_stream_create_failed','security_event_stream_response_invalid',
|
||||
'security_event_receiver_activation_failed','security_event_preparation_failed',
|
||||
'security_event_retirement_pending','pairing_step_failed',
|
||||
'cleanup_revision_unavailable','cleanup_security_event_unavailable',
|
||||
'cleanup_security_event_configuration_invalid','cleanup_security_event_connection_conflict',
|
||||
'cleanup_security_event_discovery_failed','cleanup_security_event_management_token_failed',
|
||||
'cleanup_security_event_stream_create_failed','cleanup_security_event_stream_response_invalid',
|
||||
'cleanup_security_event_receiver_activation_failed','cleanup_security_event_preparation_failed',
|
||||
'cleanup_security_event_retirement_pending','cleanup_security_event_connection_cleanup_failed',
|
||||
'cleanup_security_event_secret_cleanup_failed','cleanup_security_event_failed',
|
||||
'cleanup_secret_store_failed','cleanup_finalize_failed'
|
||||
);
|
||||
|
||||
ALTER TABLE gateway_identity_onboarding_exchanges
|
||||
ADD CONSTRAINT gateway_identity_onboarding_error_category_check
|
||||
CHECK (last_error_category IS NULL OR last_error_category IN (
|
||||
'metadata_submission_failed','exchange_status_unavailable','credential_delivery_failed',
|
||||
'exchange_completion_failed','exchange_expired','remote_exchange_failed','remote_state_invalid',
|
||||
'security_event_configuration_invalid','security_event_connection_conflict',
|
||||
'security_event_discovery_failed','security_event_management_token_failed',
|
||||
'security_event_stream_create_failed','security_event_stream_response_invalid',
|
||||
'security_event_receiver_activation_failed','security_event_preparation_failed',
|
||||
'security_event_retirement_pending','pairing_step_failed',
|
||||
'cleanup_revision_unavailable','cleanup_security_event_unavailable',
|
||||
'cleanup_security_event_configuration_invalid','cleanup_security_event_connection_conflict',
|
||||
'cleanup_security_event_discovery_failed','cleanup_security_event_management_token_failed',
|
||||
'cleanup_security_event_stream_create_failed','cleanup_security_event_stream_response_invalid',
|
||||
'cleanup_security_event_receiver_activation_failed','cleanup_security_event_preparation_failed',
|
||||
'cleanup_security_event_retirement_pending','cleanup_security_event_connection_cleanup_failed',
|
||||
'cleanup_security_event_secret_cleanup_failed','cleanup_security_event_failed',
|
||||
'cleanup_secret_store_failed','cleanup_finalize_failed'
|
||||
));
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gateway_identity_onboarding_cleanup
|
||||
ON gateway_identity_onboarding_exchanges(cleanup_status, updated_at)
|
||||
WHERE cleanup_status = 'pending';
|
||||
@@ -1,34 +0,0 @@
|
||||
SET LOCAL lock_timeout = '10s';
|
||||
SET LOCAL statement_timeout = '60s';
|
||||
|
||||
ALTER TABLE gateway_identity_secret_cleanup_queue
|
||||
ADD COLUMN IF NOT EXISTS status text,
|
||||
ADD COLUMN IF NOT EXISTS claim_token uuid,
|
||||
ADD COLUMN IF NOT EXISTS lease_expires_at timestamptz;
|
||||
|
||||
ALTER TABLE gateway_identity_secret_cleanup_queue
|
||||
DROP CONSTRAINT IF EXISTS gateway_identity_secret_cleanup_status_check,
|
||||
DROP CONSTRAINT IF EXISTS gateway_identity_secret_cleanup_claim_check;
|
||||
|
||||
UPDATE gateway_identity_secret_cleanup_queue
|
||||
SET status='pending',claim_token=NULL,lease_expires_at=NULL,updated_at=now()
|
||||
WHERE status IS NULL
|
||||
OR status NOT IN ('pending','claimed')
|
||||
OR (status='pending' AND (claim_token IS NOT NULL OR lease_expires_at IS NOT NULL))
|
||||
OR (status='claimed' AND (claim_token IS NULL OR lease_expires_at IS NULL));
|
||||
|
||||
ALTER TABLE gateway_identity_secret_cleanup_queue
|
||||
ALTER COLUMN status SET DEFAULT 'pending',
|
||||
ALTER COLUMN status SET NOT NULL,
|
||||
ADD CONSTRAINT gateway_identity_secret_cleanup_status_check
|
||||
CHECK (status IN ('pending','claimed')),
|
||||
ADD CONSTRAINT gateway_identity_secret_cleanup_claim_check
|
||||
CHECK (
|
||||
(status='pending' AND claim_token IS NULL AND lease_expires_at IS NULL) OR
|
||||
(status='claimed' AND claim_token IS NOT NULL AND lease_expires_at IS NOT NULL)
|
||||
);
|
||||
|
||||
DROP INDEX IF EXISTS idx_gateway_identity_secret_cleanup_due;
|
||||
|
||||
CREATE INDEX idx_gateway_identity_secret_cleanup_due
|
||||
ON gateway_identity_secret_cleanup_queue(status,not_before,lease_expires_at,updated_at);
|
||||
@@ -1,89 +0,0 @@
|
||||
SET LOCAL lock_timeout = '10s';
|
||||
SET LOCAL statement_timeout = '60s';
|
||||
|
||||
-- 0071 was briefly released with only the singleton reservation lease fields.
|
||||
-- Add the durable lifecycle columns without rewriting that already-applied
|
||||
-- migration, then reconcile the singleton with the canonical outstanding
|
||||
-- pairing (when one exists).
|
||||
ALTER TABLE gateway_identity_pairing_start_reservation
|
||||
ADD COLUMN IF NOT EXISTS state text,
|
||||
ADD COLUMN IF NOT EXISTS revision_id uuid,
|
||||
ADD COLUMN IF NOT EXISTS updated_at timestamptz;
|
||||
|
||||
UPDATE gateway_identity_pairing_start_reservation
|
||||
SET state=CASE WHEN revision_id IS NULL THEN 'starting' ELSE 'paired' END,
|
||||
updated_at=COALESCE(updated_at,created_at,now())
|
||||
WHERE state IS NULL
|
||||
OR state NOT IN ('starting','paired')
|
||||
OR (state='starting' AND revision_id IS NOT NULL)
|
||||
OR (state='paired' AND revision_id IS NULL)
|
||||
OR updated_at IS NULL;
|
||||
|
||||
WITH canonical_pairing AS (
|
||||
SELECT exchange.id AS attempt_id,
|
||||
revision.id AS revision_id,
|
||||
exchange.expires_at
|
||||
FROM gateway_identity_configuration_revisions revision
|
||||
JOIN gateway_identity_onboarding_exchanges exchange
|
||||
ON exchange.revision_id=revision.id
|
||||
WHERE revision.state IN ('draft','validated','failed')
|
||||
AND NOT (exchange.status='cancelled' AND exchange.cleanup_status='completed')
|
||||
ORDER BY revision.created_at DESC,exchange.created_at DESC
|
||||
LIMIT 1
|
||||
)
|
||||
INSERT INTO gateway_identity_pairing_start_reservation(
|
||||
singleton,attempt_id,state,revision_id,expires_at,updated_at
|
||||
)
|
||||
SELECT true,attempt_id,'paired',revision_id,expires_at,now()
|
||||
FROM canonical_pairing
|
||||
ON CONFLICT (singleton) DO UPDATE
|
||||
SET attempt_id=EXCLUDED.attempt_id,
|
||||
state=EXCLUDED.state,
|
||||
revision_id=EXCLUDED.revision_id,
|
||||
expires_at=EXCLUDED.expires_at,
|
||||
updated_at=now();
|
||||
|
||||
ALTER TABLE gateway_identity_pairing_start_reservation
|
||||
ALTER COLUMN state SET DEFAULT 'starting',
|
||||
ALTER COLUMN state SET NOT NULL,
|
||||
ALTER COLUMN updated_at SET DEFAULT now(),
|
||||
ALTER COLUMN updated_at SET NOT NULL;
|
||||
|
||||
ALTER TABLE gateway_identity_pairing_start_reservation
|
||||
DROP CONSTRAINT IF EXISTS gateway_identity_pairing_start_state_value_check,
|
||||
DROP CONSTRAINT IF EXISTS gateway_identity_pairing_start_state_check;
|
||||
|
||||
ALTER TABLE gateway_identity_pairing_start_reservation
|
||||
ADD CONSTRAINT gateway_identity_pairing_start_state_value_check
|
||||
CHECK (state IN ('starting','paired')),
|
||||
ADD CONSTRAINT gateway_identity_pairing_start_state_check CHECK (
|
||||
(state='starting' AND revision_id IS NULL) OR
|
||||
(state='paired' AND revision_id IS NOT NULL)
|
||||
);
|
||||
|
||||
DO $migration$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_constraint
|
||||
WHERE conrelid='gateway_identity_pairing_start_reservation'::regclass
|
||||
AND contype='f'
|
||||
AND pg_get_constraintdef(oid) LIKE 'FOREIGN KEY (revision_id)%'
|
||||
) THEN
|
||||
ALTER TABLE gateway_identity_pairing_start_reservation
|
||||
ADD CONSTRAINT gateway_identity_pairing_start_revision_fk
|
||||
FOREIGN KEY (revision_id)
|
||||
REFERENCES gateway_identity_configuration_revisions(id)
|
||||
ON DELETE RESTRICT;
|
||||
END IF;
|
||||
END
|
||||
$migration$;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_gateway_identity_pairing_start_revision_unique
|
||||
ON gateway_identity_pairing_start_reservation(revision_id)
|
||||
WHERE revision_id IS NOT NULL;
|
||||
|
||||
DROP INDEX IF EXISTS idx_gateway_identity_pairing_start_expiry;
|
||||
|
||||
CREATE INDEX idx_gateway_identity_pairing_start_expiry
|
||||
ON gateway_identity_pairing_start_reservation(state,expires_at);
|
||||
@@ -1,32 +0,0 @@
|
||||
SET LOCAL lock_timeout = '10s';
|
||||
SET LOCAL statement_timeout = '60s';
|
||||
|
||||
-- Pairing recovery added explicit, redacted error categories after 0069 was
|
||||
-- released. Keep the database allow-list in lockstep so PostgreSQL can persist
|
||||
-- the reason an administrator must resolve instead of hiding it behind a CHECK
|
||||
-- violation.
|
||||
ALTER TABLE gateway_identity_onboarding_exchanges
|
||||
DROP CONSTRAINT IF EXISTS gateway_identity_onboarding_error_category_check;
|
||||
|
||||
ALTER TABLE gateway_identity_onboarding_exchanges
|
||||
ADD CONSTRAINT gateway_identity_onboarding_error_category_check
|
||||
CHECK (last_error_category IS NULL OR last_error_category IN (
|
||||
'metadata_submission_failed','exchange_status_unavailable','credential_delivery_failed',
|
||||
'exchange_completion_failed','exchange_expired','remote_exchange_failed','remote_state_invalid',
|
||||
'security_event_configuration_invalid','security_event_connection_conflict',
|
||||
'security_event_discovery_failed','security_event_management_token_failed',
|
||||
'security_event_stream_create_failed','security_event_stream_response_invalid',
|
||||
'security_event_receiver_activation_failed','security_event_preparation_failed',
|
||||
'security_event_retirement_pending','security_event_credential_handoff_unsafe',
|
||||
'security_event_connection_binding_missing','security_event_connection_binding_unavailable',
|
||||
'security_event_connection_binding_invalid','security_event_connection_binding_mismatch',
|
||||
'pairing_step_failed',
|
||||
'cleanup_revision_unavailable','cleanup_security_event_unavailable',
|
||||
'cleanup_security_event_configuration_invalid','cleanup_security_event_connection_conflict',
|
||||
'cleanup_security_event_discovery_failed','cleanup_security_event_management_token_failed',
|
||||
'cleanup_security_event_stream_create_failed','cleanup_security_event_stream_response_invalid',
|
||||
'cleanup_security_event_receiver_activation_failed','cleanup_security_event_preparation_failed',
|
||||
'cleanup_security_event_retirement_pending','cleanup_security_event_connection_cleanup_failed',
|
||||
'cleanup_security_event_secret_cleanup_failed','cleanup_security_event_credential_handoff_unsafe',
|
||||
'cleanup_security_event_failed','cleanup_secret_store_failed','cleanup_finalize_failed'
|
||||
));
|
||||
Reference in New Issue
Block a user