feat(ql3): materialize package secret bindings

This commit is contained in:
whyour
2026-08-13 10:31:06 +08:00
parent 55ef085a6e
commit d72631a2b0
34 changed files with 839 additions and 115 deletions
@@ -303,5 +303,10 @@ export const postgresqlMainMigrationManifest: MigrationStreamManifest =
checksum:
'87582d256c868bd7f5af352c4b052fdab9f3714e1e7179e35d33bfa5d62957be',
}),
Object.freeze({
id: 'pg-0060-plugin-package-secret-materialization-guard',
checksum:
'28284ca860b39ff9de5b2aa1a2a60ef2c463fd6a72798d237040174272b64b1e',
}),
]),
});
@@ -62,6 +62,7 @@ import { pg0056RunManagementBoundaryMigration } from '../run-management/pg-0056-
import { pg0057RunManagementStopBoundaryMigration } from '../run-management/pg-0057-run-management-stop-boundary';
import { pg0058PluginPackageAutomationDispositionEventsMigration } from './pg-0058-plugin-package-automation-disposition-events';
import { pg0059PluginPackageSecretBindingsMigration } from './pg-0059-plugin-package-secret-bindings';
import { pg0060PluginPackageSecretMaterializationGuardMigration } from './pg-0060-plugin-package-secret-materialization-guard';
export const postgresqlMainMigrationStream: MigrationStreamDefinition<PostgresMigrationContext> =
Object.freeze({
@@ -129,5 +130,6 @@ export const postgresqlMainMigrationStream: MigrationStreamDefinition<PostgresMi
pg0057RunManagementStopBoundaryMigration,
pg0058PluginPackageAutomationDispositionEventsMigration,
pg0059PluginPackageSecretBindingsMigration,
pg0060PluginPackageSecretMaterializationGuardMigration,
]),
});
@@ -0,0 +1,101 @@
import { CAPABILITIES_V58 } from './pg-0059-plugin-package-secret-bindings';
import { definePostgresSqlMigration } from './sqlMigration';
export const CAPABILITIES_V59 = CAPABILITIES_V58.replace(
'"plugin_package_secret_binding":1,',
'"plugin_package_secret_binding":1,"plugin_package_secret_materialization":1,',
);
export const pg0060PluginPackageSecretMaterializationGuardMigration =
definePostgresSqlMigration({
id: 'pg-0060-plugin-package-secret-materialization-guard',
statements: [
`
CREATE FUNCTION "ql3"."enforce_plugin_package_secret_materialization"()
RETURNS trigger
LANGUAGE plpgsql
VOLATILE
SET search_path = pg_catalog, ql3
AS $ql3$
DECLARE
secret_count integer;
embedded_binding jsonb;
stored_binding jsonb;
BEGIN
IF jsonb_typeof(
NEW.revision_json #> '{manifest,spec,permissions,secrets}'
) IS DISTINCT FROM 'array' THEN
RAISE EXCEPTION 'Package Secret permission declarations are malformed'
USING ERRCODE = 'check_violation';
END IF;
secret_count := jsonb_array_length(
NEW.revision_json #> '{manifest,spec,permissions,secrets}'
);
embedded_binding := NEW.revision_json -> 'secretBinding';
IF secret_count = 0 THEN
IF embedded_binding IS NOT NULL THEN
RAISE EXCEPTION 'unexpected Package Secret binding'
USING ERRCODE = 'check_violation';
END IF;
ELSE
SELECT binding.binding_json
INTO stored_binding
FROM "ql3"."plugin_package_secret_bindings" AS binding
WHERE binding.generation_digest = NEW.generation_digest;
IF stored_binding IS NULL OR stored_binding <> embedded_binding THEN
RAISE EXCEPTION 'Package Secret binding is absent or mismatched'
USING ERRCODE = 'check_violation';
END IF;
END IF;
IF EXISTS (
SELECT 1
FROM jsonb_array_elements(NEW.revision_json -> 'resources') AS resource
CROSS JOIN LATERAL jsonb_array_elements(
COALESCE(
resource #> '{value,spec,config,environment}',
'[]'::jsonb
)
) AS environment
WHERE resource ->> 'kind' = 'task'
AND environment ->> 'kind' = 'package-secret'
) THEN
RAISE EXCEPTION 'unresolved Package Secret placeholder'
USING ERRCODE = 'check_violation';
END IF;
IF EXISTS (
SELECT 1
FROM jsonb_array_elements(NEW.revision_json -> 'resources') AS resource
CROSS JOIN LATERAL jsonb_array_elements(
COALESCE(
resource #> '{value,spec,config,environment}',
'[]'::jsonb
)
) AS environment
WHERE resource ->> 'kind' = 'task'
AND environment ->> 'kind' = 'secret'
AND NOT EXISTS (
SELECT 1
FROM jsonb_array_elements(
COALESCE(embedded_binding -> 'entries', '[]'::jsonb)
) AS binding_entry
WHERE binding_entry ->> 'secretRef' =
environment ->> 'secretRef'
)
) THEN
RAISE EXCEPTION 'Task SecretRef is outside Package binding'
USING ERRCODE = 'check_violation';
END IF;
RETURN NEW;
END
$ql3$
`.trim(),
`REVOKE ALL ON FUNCTION "ql3"."enforce_plugin_package_secret_materialization"() FROM PUBLIC, ql3_runtime, ql3_admin, ql3_package_manager, ql3_package_executor, ql3_worker_ingress`,
`CREATE TRIGGER ql3_plugin_package_secret_materialization_guard BEFORE INSERT ON "ql3"."plugin_package_materialized_revisions" FOR EACH ROW EXECUTE FUNCTION "ql3"."enforce_plugin_package_secret_materialization"()`,
`DO $ql3$ BEGIN UPDATE "ql3"."schema_capabilities" SET contract_version = 59, migration_id = 'pg-0060-plugin-package-secret-materialization-guard', capabilities = '${CAPABILITIES_V59}'::jsonb, updated_at_ms = floor(extract(epoch FROM transaction_timestamp()) * 1000)::bigint WHERE contract_name = 'control-core' AND contract_version = 58 AND migration_id = 'pg-0059-plugin-package-secret-bindings' AND capabilities = '${CAPABILITIES_V58}'::jsonb; IF NOT FOUND THEN RAISE EXCEPTION 'control-core capability is not at version 58' USING ERRCODE = 'check_violation'; END IF; END $ql3$`,
],
});
@@ -15,8 +15,8 @@ export interface PostgresSchemaContractFunction {
export interface PostgresSchemaContract {
readonly schema: 'ql3';
readonly contractName: 'control-core';
readonly contractVersion: 58;
readonly migrationId: 'pg-0059-plugin-package-secret-bindings';
readonly contractVersion: 59;
readonly migrationId: 'pg-0060-plugin-package-secret-materialization-guard';
readonly minimumServerMajor: 16;
readonly maximumServerMajor: 18;
readonly capabilities: Readonly<{
@@ -56,6 +56,7 @@ export interface PostgresSchemaContract {
plugin_package_management_quota: 1;
plugin_package_materialized_revision: 1;
plugin_package_secret_binding: 1;
plugin_package_secret_materialization: 1;
plugin_package_proposal: 1;
plugin_package_publisher_provenance: 1;
plugin_package_publisher_trust_authority: 1;
@@ -105,8 +106,8 @@ export const postgresqlControlSchemaContract: PostgresSchemaContract =
Object.freeze({
schema: 'ql3',
contractName: 'control-core',
contractVersion: 58,
migrationId: 'pg-0059-plugin-package-secret-bindings',
contractVersion: 59,
migrationId: 'pg-0060-plugin-package-secret-materialization-guard',
minimumServerMajor: 16,
maximumServerMajor: 18,
capabilities: Object.freeze({
@@ -139,6 +140,7 @@ export const postgresqlControlSchemaContract: PostgresSchemaContract =
plugin_package_management_quota: 1,
plugin_package_materialized_revision: 1,
plugin_package_secret_binding: 1,
plugin_package_secret_materialization: 1,
plugin_package_proposal: 1,
plugin_package_publisher_provenance: 1,
plugin_package_publisher_trust_authority: 1,
@@ -2336,6 +2338,14 @@ export const postgresqlControlSchemaContract: PostgresSchemaContract =
'ql3_run_retry_policies_run_fk',
]),
functions: Object.freeze([
Object.freeze({
name: 'enforce_plugin_package_secret_materialization',
identityArguments: '',
owner: 'ql3_migration',
securityDefiner: false,
volatility: 'volatile',
configuration: Object.freeze(['search_path=pg_catalog, ql3']),
}),
Object.freeze({
name: 'register_plugin_package_automation_disposition_event',
identityArguments: '',
@@ -1507,6 +1507,7 @@ const REQUIRED_RUNTIME_FUNCTION_PRIVILEGES: RequiredFunctionPrivileges =
commit_plugin_package_lifecycle: false,
commit_plugin_package_quarantine: false,
commit_plugin_package_task_reconciliation: false,
enforce_plugin_package_secret_materialization: false,
enforce_plugin_package_stage_provenance: false,
lock_active_plugin_package_project: false,
lock_approval_policy_fence: false,
@@ -1525,6 +1526,7 @@ const REQUIRED_PACKAGE_MANAGER_FUNCTION_PRIVILEGES: RequiredFunctionPrivileges =
commit_plugin_package_lifecycle: false,
commit_plugin_package_quarantine: false,
commit_plugin_package_task_reconciliation: false,
enforce_plugin_package_secret_materialization: false,
enforce_plugin_package_stage_provenance: false,
lock_active_plugin_package_project: false,
lock_approval_policy_fence: true,
@@ -1543,6 +1545,7 @@ const REQUIRED_PACKAGE_EXECUTOR_FUNCTION_PRIVILEGES: RequiredFunctionPrivileges
commit_plugin_package_lifecycle: true,
commit_plugin_package_quarantine: true,
commit_plugin_package_task_reconciliation: true,
enforce_plugin_package_secret_materialization: false,
enforce_plugin_package_stage_provenance: false,
lock_active_plugin_package_project: true,
lock_approval_policy_fence: true,