mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-22 19:29:13 +08:00
308 lines
15 KiB
TypeScript
308 lines
15 KiB
TypeScript
import { CAPABILITIES_V62 } from './pg-0063-plugin-package-secret-binding-transition-receipts';
|
|
import { definePostgresSqlMigration } from './sqlMigration';
|
|
|
|
export const CAPABILITIES_V63 = CAPABILITIES_V62.replace(
|
|
'"plugin_package_secret_binding_transition_receipt":1,',
|
|
'"plugin_package_secret_binding_transition_approval_plan":1,"plugin_package_secret_binding_transition_receipt":1,',
|
|
);
|
|
|
|
export const pg0064PluginPackageSecretBindingTransitionApprovalPlansMigration =
|
|
definePostgresSqlMigration({
|
|
id: 'pg-0064-plugin-package-secret-binding-transition-approval-plans',
|
|
statements: [
|
|
`
|
|
CREATE TABLE "ql3"."plugin_package_secret_binding_transition_approval_plans" (
|
|
action_ref varchar(255) PRIMARY KEY,
|
|
approval_plan_digest char(64) NOT NULL,
|
|
transition_digest char(64) NOT NULL,
|
|
generation_digest char(64) NOT NULL,
|
|
project_id varchar(128) NOT NULL,
|
|
package_name varchar(63) NOT NULL,
|
|
installation_id varchar(128) NOT NULL,
|
|
lock_digest char(64) NOT NULL,
|
|
generation integer NOT NULL,
|
|
manifest_digest char(64) NOT NULL,
|
|
previous_active_lock_digest char(64) NOT NULL,
|
|
requested_by_type varchar(16) NOT NULL,
|
|
requested_by_id varchar(255) NOT NULL,
|
|
planned_at_ms bigint NOT NULL,
|
|
expires_at_ms bigint NOT NULL,
|
|
plan_json jsonb NOT NULL,
|
|
CONSTRAINT ql3_pp_secret_transition_plan_project_fk
|
|
FOREIGN KEY (project_id) REFERENCES "ql3"."projects" (id)
|
|
ON DELETE RESTRICT ON UPDATE RESTRICT,
|
|
CONSTRAINT ql3_pp_secret_transition_plan_install_fk
|
|
FOREIGN KEY (installation_id)
|
|
REFERENCES "ql3"."plugin_package_installs" (installation_id)
|
|
ON DELETE RESTRICT ON UPDATE RESTRICT,
|
|
CONSTRAINT ql3_pp_secret_transition_plan_identity_check CHECK (
|
|
action_ref ~ '^[A-Za-z0-9][A-Za-z0-9._:/-]{0,254}$' AND
|
|
project_id ~ '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' AND
|
|
package_name ~ '^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$' AND
|
|
installation_id ~ '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' AND
|
|
generation BETWEEN 2 AND 2147483647 AND
|
|
requested_by_type = 'user' AND
|
|
octet_length(requested_by_id) BETWEEN 1 AND 255 AND
|
|
requested_by_id !~ '[[:cntrl:]]'
|
|
),
|
|
CONSTRAINT ql3_pp_secret_transition_plan_digest_check CHECK (
|
|
approval_plan_digest ~ '^[0-9a-f]{64}$' AND
|
|
transition_digest ~ '^[0-9a-f]{64}$' AND
|
|
generation_digest ~ '^[0-9a-f]{64}$' AND
|
|
lock_digest ~ '^[0-9a-f]{64}$' AND
|
|
manifest_digest ~ '^[0-9a-f]{64}$' AND
|
|
previous_active_lock_digest ~ '^[0-9a-f]{64}$'
|
|
),
|
|
CONSTRAINT ql3_pp_secret_transition_plan_time_check CHECK (
|
|
planned_at_ms >= 0 AND expires_at_ms > planned_at_ms AND
|
|
expires_at_ms - planned_at_ms <= 900000
|
|
),
|
|
CONSTRAINT ql3_pp_secret_transition_plan_json_check CHECK (
|
|
jsonb_typeof(plan_json) = 'object' AND
|
|
octet_length(plan_json::text) BETWEEN 2 AND 229376 AND
|
|
plan_json @> jsonb_build_object(
|
|
'schema', 'qinglong/plugin-package-secret-binding-transition-approval-plan@v1',
|
|
'actionRef', action_ref,
|
|
'approvalPlanDigest', approval_plan_digest,
|
|
'requestedBy', jsonb_build_object(
|
|
'type', requested_by_type,
|
|
'id', requested_by_id
|
|
),
|
|
'plannedAtMs', planned_at_ms,
|
|
'expiresAtMs', expires_at_ms,
|
|
'transitionPlan', jsonb_build_object(
|
|
'schema', 'qinglong/plugin-package-secret-binding-transition-plan@v1',
|
|
'transitionDigest', transition_digest,
|
|
'previousActiveLockDigest', previous_active_lock_digest,
|
|
'nextTarget', jsonb_build_object(
|
|
'generationDigest', generation_digest,
|
|
'projectId', project_id,
|
|
'packageName', package_name,
|
|
'installationId', installation_id,
|
|
'lockDigest', lock_digest,
|
|
'generation', generation,
|
|
'manifestDigest', manifest_digest
|
|
)
|
|
)
|
|
) AND
|
|
jsonb_typeof(plan_json #> '{transitionPlan,changes}') = 'array' AND
|
|
jsonb_array_length(plan_json #> '{transitionPlan,changes}') BETWEEN 1 AND 64
|
|
)
|
|
)
|
|
`.trim(),
|
|
`CREATE UNIQUE INDEX ql3_pp_secret_transition_plan_digest_uidx ON "ql3"."plugin_package_secret_binding_transition_approval_plans" (approval_plan_digest)`,
|
|
`CREATE UNIQUE INDEX ql3_pp_secret_transition_plan_target_uidx ON "ql3"."plugin_package_secret_binding_transition_approval_plans" (generation_digest)`,
|
|
`CREATE INDEX ql3_pp_secret_transition_plan_expiry_idx ON "ql3"."plugin_package_secret_binding_transition_approval_plans" (expires_at_ms, action_ref)`,
|
|
`
|
|
CREATE FUNCTION "ql3"."plugin_package_secret_binding_transition_snapshot"(
|
|
p_project_id varchar,
|
|
p_package_name varchar
|
|
)
|
|
RETURNS TABLE (
|
|
next_record_json jsonb,
|
|
next_lock_json jsonb,
|
|
next_proposal_json jsonb,
|
|
previous_record_json jsonb,
|
|
previous_lock_json jsonb,
|
|
previous_proposal_json jsonb,
|
|
previous_binding_json jsonb,
|
|
previous_attempt_generation integer,
|
|
observed_at_ms bigint
|
|
)
|
|
LANGUAGE plpgsql
|
|
VOLATILE
|
|
SECURITY DEFINER
|
|
SET search_path = pg_catalog, ql3
|
|
AS $ql3$
|
|
BEGIN
|
|
IF NOT pg_has_role(session_user, 'ql3_package_manager', 'member') THEN
|
|
RAISE EXCEPTION 'Package manager authority is required'
|
|
USING ERRCODE = 'insufficient_privilege';
|
|
END IF;
|
|
RETURN QUERY
|
|
SELECT current.record_json,
|
|
current.lock_json,
|
|
current_proposal.proposal_json,
|
|
previous.record_json,
|
|
previous.lock_json,
|
|
previous_proposal.proposal_json,
|
|
previous_binding.binding_json,
|
|
(
|
|
SELECT MAX(history.target_generation)
|
|
FROM "ql3"."plugin_package_installs" AS history
|
|
WHERE history.project_id = current.project_id
|
|
AND history.package_name = current.package_name
|
|
AND history.target_generation < current.target_generation
|
|
),
|
|
floor(extract(epoch FROM transaction_timestamp()) * 1000)::bigint
|
|
FROM "ql3"."plugin_package_install_heads" AS head
|
|
JOIN "ql3"."plugin_package_installs" AS current
|
|
ON current.installation_id = head.installation_id
|
|
AND current.project_id = head.project_id
|
|
AND current.package_name = head.package_name
|
|
JOIN "ql3"."plugin_package_admission_receipts" AS current_admission
|
|
ON current_admission.installation_id = current.installation_id
|
|
JOIN "ql3"."plugin_package_install_proposals" AS current_proposal
|
|
ON current_proposal.action_ref = current_admission.action_ref
|
|
JOIN "ql3"."plugin_package_installs" AS previous
|
|
ON previous.project_id = current.project_id
|
|
AND previous.package_name = current.package_name
|
|
AND previous.lock_digest = current.previous_active_lock_digest
|
|
JOIN "ql3"."plugin_package_admission_receipts" AS previous_admission
|
|
ON previous_admission.installation_id = previous.installation_id
|
|
JOIN "ql3"."plugin_package_install_proposals" AS previous_proposal
|
|
ON previous_proposal.action_ref = previous_admission.action_ref
|
|
LEFT JOIN "ql3"."plugin_package_secret_bindings" AS previous_binding
|
|
ON previous_binding.installation_id = previous.installation_id
|
|
AND previous_binding.project_id = previous.project_id
|
|
AND previous_binding.package_name = previous.package_name
|
|
AND previous_binding.lock_digest = previous.lock_digest
|
|
AND previous_binding.generation = previous.target_generation
|
|
WHERE head.project_id = p_project_id
|
|
AND head.package_name = p_package_name
|
|
AND current.state = 'staged'
|
|
AND current.previous_active_lock_digest IS NOT NULL
|
|
AND current.active_lock_digest = current.previous_active_lock_digest
|
|
AND current.target_generation = (
|
|
SELECT MAX(latest.target_generation)
|
|
FROM "ql3"."plugin_package_installs" AS latest
|
|
WHERE latest.project_id = current.project_id
|
|
AND latest.package_name = current.package_name
|
|
)
|
|
AND previous.state = 'active'
|
|
AND previous.active_lock_digest = previous.lock_digest
|
|
AND NOT EXISTS (
|
|
SELECT 1
|
|
FROM "ql3"."plugin_package_secret_binding_transition_receipts" receipt
|
|
WHERE receipt.project_id = current.project_id
|
|
AND receipt.package_name = current.package_name
|
|
AND receipt.generation = current.target_generation
|
|
)
|
|
FOR SHARE OF head, current, previous;
|
|
END
|
|
$ql3$
|
|
`.trim(),
|
|
`
|
|
CREATE FUNCTION "ql3"."create_plugin_package_secret_transition_plan"(
|
|
p_plan_json jsonb
|
|
)
|
|
RETURNS varchar
|
|
LANGUAGE plpgsql
|
|
VOLATILE
|
|
SECURITY DEFINER
|
|
SET search_path = pg_catalog, ql3
|
|
AS $ql3$
|
|
DECLARE
|
|
existing_plan jsonb;
|
|
inserted_action_ref varchar(255);
|
|
BEGIN
|
|
IF NOT pg_has_role(session_user, 'ql3_package_manager', 'member') THEN
|
|
RAISE EXCEPTION 'Package manager authority is required'
|
|
USING ERRCODE = 'insufficient_privilege';
|
|
END IF;
|
|
PERFORM pg_advisory_xact_lock(
|
|
hashtextextended(p_plan_json ->> 'actionRef', 70513064)
|
|
);
|
|
SELECT plan_json INTO existing_plan
|
|
FROM "ql3"."plugin_package_secret_binding_transition_approval_plans"
|
|
WHERE action_ref = p_plan_json ->> 'actionRef'
|
|
FOR SHARE;
|
|
IF existing_plan IS NOT NULL THEN
|
|
IF existing_plan = p_plan_json THEN RETURN 'existing'; END IF;
|
|
RAISE EXCEPTION 'Secret transition actionRef is already bound'
|
|
USING ERRCODE = 'unique_violation';
|
|
END IF;
|
|
|
|
INSERT INTO "ql3"."plugin_package_secret_binding_transition_approval_plans" (
|
|
action_ref, approval_plan_digest, transition_digest, generation_digest,
|
|
project_id, package_name, installation_id, lock_digest, generation,
|
|
manifest_digest, previous_active_lock_digest, requested_by_type,
|
|
requested_by_id, planned_at_ms, expires_at_ms, plan_json
|
|
)
|
|
SELECT p_plan_json ->> 'actionRef',
|
|
p_plan_json ->> 'approvalPlanDigest',
|
|
p_plan_json #>> '{transitionPlan,transitionDigest}',
|
|
p_plan_json #>> '{transitionPlan,nextTarget,generationDigest}',
|
|
p_plan_json #>> '{transitionPlan,nextTarget,projectId}',
|
|
p_plan_json #>> '{transitionPlan,nextTarget,packageName}',
|
|
p_plan_json #>> '{transitionPlan,nextTarget,installationId}',
|
|
p_plan_json #>> '{transitionPlan,nextTarget,lockDigest}',
|
|
(p_plan_json #>> '{transitionPlan,nextTarget,generation}')::integer,
|
|
p_plan_json #>> '{transitionPlan,nextTarget,manifestDigest}',
|
|
p_plan_json #>> '{transitionPlan,previousActiveLockDigest}',
|
|
p_plan_json #>> '{requestedBy,type}',
|
|
p_plan_json #>> '{requestedBy,id}',
|
|
(p_plan_json ->> 'plannedAtMs')::bigint,
|
|
(p_plan_json ->> 'expiresAtMs')::bigint,
|
|
p_plan_json
|
|
FROM "ql3"."plugin_package_install_heads" head
|
|
JOIN "ql3"."plugin_package_installs" install
|
|
ON install.installation_id = head.installation_id
|
|
AND install.project_id = head.project_id
|
|
AND install.package_name = head.package_name
|
|
JOIN "ql3"."plugin_package_installs" previous
|
|
ON previous.project_id = install.project_id
|
|
AND previous.package_name = install.package_name
|
|
AND previous.lock_digest = install.previous_active_lock_digest
|
|
LEFT JOIN "ql3"."plugin_package_secret_bindings" previous_binding
|
|
ON previous_binding.installation_id = previous.installation_id
|
|
AND previous_binding.project_id = previous.project_id
|
|
AND previous_binding.package_name = previous.package_name
|
|
AND previous_binding.lock_digest = previous.lock_digest
|
|
AND previous_binding.generation = previous.target_generation
|
|
WHERE head.project_id = p_plan_json #>> '{transitionPlan,nextTarget,projectId}'
|
|
AND head.package_name = p_plan_json #>> '{transitionPlan,nextTarget,packageName}'
|
|
AND install.installation_id = p_plan_json #>> '{transitionPlan,nextTarget,installationId}'
|
|
AND install.lock_digest = p_plan_json #>> '{transitionPlan,nextTarget,lockDigest}'
|
|
AND install.target_generation = (p_plan_json #>> '{transitionPlan,nextTarget,generation}')::integer
|
|
AND install.lock_json ->> 'manifestDigest' = p_plan_json #>> '{transitionPlan,nextTarget,manifestDigest}'
|
|
AND install.state = 'staged'
|
|
AND install.previous_active_lock_digest = p_plan_json #>> '{transitionPlan,previousActiveLockDigest}'
|
|
AND install.active_lock_digest = install.previous_active_lock_digest
|
|
AND previous.installation_id = p_plan_json #>> '{transitionPlan,previousTarget,installationId}'
|
|
AND previous.lock_digest = p_plan_json #>> '{transitionPlan,previousTarget,lockDigest}'
|
|
AND previous.target_generation = (p_plan_json #>> '{transitionPlan,previousTarget,generation}')::integer
|
|
AND previous.lock_json ->> 'manifestDigest' = p_plan_json #>> '{transitionPlan,previousTarget,manifestDigest}'
|
|
AND previous.state = 'active'
|
|
AND previous.active_lock_digest = previous.lock_digest
|
|
AND (
|
|
SELECT MAX(attempt.target_generation)
|
|
FROM "ql3"."plugin_package_installs" attempt
|
|
WHERE attempt.project_id = install.project_id
|
|
AND attempt.package_name = install.package_name
|
|
AND attempt.target_generation < install.target_generation
|
|
) = (p_plan_json #>> '{transitionPlan,previousAttemptGeneration}')::integer
|
|
AND (
|
|
(previous_binding.binding_json IS NULL AND
|
|
p_plan_json #> '{transitionPlan,previousBinding}' = 'null'::jsonb) OR
|
|
previous_binding.binding_json = p_plan_json #> '{transitionPlan,previousBinding}'
|
|
)
|
|
AND install.target_generation = (
|
|
SELECT MAX(history.target_generation)
|
|
FROM "ql3"."plugin_package_installs" history
|
|
WHERE history.project_id = install.project_id
|
|
AND history.package_name = install.package_name
|
|
)
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM "ql3"."plugin_package_secret_binding_transition_receipts" receipt
|
|
WHERE receipt.generation_digest = p_plan_json #>> '{transitionPlan,nextTarget,generationDigest}'
|
|
)
|
|
RETURNING action_ref INTO inserted_action_ref;
|
|
IF inserted_action_ref IS NULL THEN
|
|
RAISE EXCEPTION 'Secret transition target is not current staged generation'
|
|
USING ERRCODE = 'check_violation';
|
|
END IF;
|
|
RETURN 'created';
|
|
END
|
|
$ql3$
|
|
`.trim(),
|
|
`REVOKE ALL ON "ql3"."plugin_package_secret_binding_transition_approval_plans" FROM PUBLIC, ql3_runtime, ql3_admin, ql3_package_manager, ql3_package_executor, ql3_worker_ingress`,
|
|
`GRANT SELECT ON "ql3"."plugin_package_secret_binding_transition_approval_plans" TO ql3_package_manager, ql3_package_executor`,
|
|
`REVOKE ALL ON FUNCTION "ql3"."plugin_package_secret_binding_transition_snapshot"(varchar, varchar) FROM PUBLIC, ql3_runtime, ql3_admin, ql3_package_manager, ql3_package_executor, ql3_worker_ingress`,
|
|
`GRANT EXECUTE ON FUNCTION "ql3"."plugin_package_secret_binding_transition_snapshot"(varchar, varchar) TO ql3_package_manager`,
|
|
`REVOKE ALL ON FUNCTION "ql3"."create_plugin_package_secret_transition_plan"(jsonb) FROM PUBLIC, ql3_runtime, ql3_admin, ql3_package_manager, ql3_package_executor, ql3_worker_ingress`,
|
|
`GRANT EXECUTE ON FUNCTION "ql3"."create_plugin_package_secret_transition_plan"(jsonb) TO ql3_package_manager`,
|
|
`DO $ql3$ BEGIN UPDATE "ql3"."schema_capabilities" SET contract_version = 63, migration_id = 'pg-0064-plugin-package-secret-binding-transition-approval-plans', capabilities = '${CAPABILITIES_V63}'::jsonb, updated_at_ms = floor(extract(epoch FROM transaction_timestamp()) * 1000)::bigint WHERE contract_name = 'control-core' AND contract_version = 62 AND migration_id = 'pg-0063-plugin-package-secret-binding-transition-receipts' AND capabilities = '${CAPABILITIES_V62}'::jsonb; IF NOT FOUND THEN RAISE EXCEPTION 'control-core capability is not at version 62' USING ERRCODE = 'check_violation'; END IF; END $ql3$`,
|
|
],
|
|
});
|