feat(ql3): persist cluster secret transition receipts

This commit is contained in:
whyour
2026-08-13 21:48:57 +08:00
parent c877147d0f
commit 5f93e0b5d2
26 changed files with 1127 additions and 66 deletions
@@ -8,18 +8,22 @@ const {
const {
createPluginPackageResourceGeneration,
} = require('@qinglong/runtime-core/plugin-package-resource-generation');
const {
createPluginPackageSecretBindingTarget,
} = require('@qinglong/runtime-core/plugin-package-secret-binding');
const {
createPluginPackageSecretBindingTransitionPlan,
} = require('@qinglong/runtime-core/plugin-package-secret-binding-transition-plan');
const { createSecretRef } = require('@qinglong/runtime-core/secret-reference');
const {
assertPostgresPackageExecutorSchemaReady,
createPostgresDatabaseOpener,
PostgresPluginPackageSecretBindingRepository,
PostgresPluginPackageSecretBindingTransitionRepository,
} = require('../dist/entrypoints/packageExecutor');
const {
runPostgresMigrations,
} = require('../dist/migration/migration');
const { runPostgresMigrations } = require('../dist/migration/migration');
const migrationConnectionString =
process.env.QL3_TEST_POSTGRES_MIGRATION_URL;
const migrationConnectionString = process.env.QL3_TEST_POSTGRES_MIGRATION_URL;
const executorConnectionString =
process.env.QL3_TEST_POSTGRES_PACKAGE_EXECUTOR_URL;
@@ -221,9 +225,12 @@ async function open(role, connectionString) {
}
if (!migrationConnectionString || !executorConnectionString) {
test('PostgreSQL Secret binding transition gate requires migration and executor URLs', {
skip: true,
});
test(
'PostgreSQL Secret binding transition gate requires migration and executor URLs',
{
skip: true,
},
);
} else {
test('PostgreSQL enforces active and reviewed staged Secret binding targets', async () => {
const migrationDatabase = await open(
@@ -241,7 +248,7 @@ if (!migrationConnectionString || !executorConnectionString) {
executorDatabase.pool,
);
assert.equal(readiness.ready, true);
assert.equal(readiness.contractVersion, 61);
assert.equal(readiness.contractVersion, 62);
const repository = new PostgresPluginPackageSecretBindingRepository(
executorDatabase.pool,
@@ -326,8 +333,75 @@ if (!migrationConnectionString || !executorConnectionString) {
packageName: stagedPackageName,
installationId: stagedInstallationId,
});
assert.equal((await repository.publish(stagedBinding)).status, 'created');
assert.equal((await repository.publish(stagedBinding)).status, 'existing');
const previousGeneration = createPluginPackageResourceGeneration({
installationId: previousInstallationId,
projectId: stagedProjectId,
packageName: stagedPackageName,
lockDigest: previousLockDigest,
generation: 1,
previousActiveLockDigest: null,
contentDigest: '7'.repeat(64),
contents: manifest(stagedPackageName).spec.contents,
});
const nextGeneration = createPluginPackageResourceGeneration({
installationId: stagedInstallationId,
projectId: stagedProjectId,
packageName: stagedPackageName,
lockDigest: stagedLockDigest,
generation: 2,
previousActiveLockDigest: previousLockDigest,
contentDigest: 'e'.repeat(64),
contents: manifest(stagedPackageName).spec.contents,
});
const transitionPlan = createPluginPackageSecretBindingTransitionPlan({
previousTarget: createPluginPackageSecretBindingTarget(
previousGeneration,
manifest(stagedPackageName),
),
previousBinding: null,
previousAttemptGeneration: 1,
nextGeneration,
nextManifest: manifest(stagedPackageName),
assignments: [
{
name: 'TOKEN',
secretRef: createSecretRef({
projectId: stagedProjectId,
name: 'runtime-token',
version: 2,
}),
},
],
plannedAtMs: 100,
});
const transitions =
new PostgresPluginPackageSecretBindingTransitionRepository(
executorDatabase.pool,
);
const committed = await transitions.apply({
transitionPlan,
evidenceDigest: transitionPlan.transitionDigest,
committedAtMs: 102,
});
assert.equal(committed.status, 'created');
assert.equal(
committed.receipt.bindingDigest,
committed.binding.bindingDigest,
);
assert.equal(
(
await transitions.apply({
transitionPlan,
evidenceDigest: transitionPlan.transitionDigest,
committedAtMs: 102,
})
).status,
'existing',
);
assert.deepEqual(
await transitions.find(transitionPlan.nextTarget.generationDigest),
committed.receipt,
);
const activatingProjectId = `${namespace}-activating`;
const activatingPackageName = 'activating-binding';
@@ -113,6 +113,7 @@ test('defines the immutable PostgreSQL capability and Run core stream', async ()
'pg-0060-plugin-package-secret-materialization-guard',
'pg-0061-plugin-package-secret-binding-approval-plans',
'pg-0062-plugin-package-secret-binding-target-guard',
'pg-0063-plugin-package-secret-binding-transition-receipts',
],
);
for (const migration of postgresqlMainMigrationStream.migrations) {
@@ -166,6 +167,7 @@ test('keeps local-only and legacy tables out of the cluster baseline', async ()
'plugin_package_materialized_revisions',
'plugin_package_secret_bindings',
'plugin_package_secret_binding_approval_plans',
'plugin_package_secret_binding_transition_receipts',
'plugin_package_lifecycle_events',
'plugin_package_lifecycle_heads',
'plugin_package_lifecycle_receipts',
@@ -560,6 +562,11 @@ test('freezes every published PostgreSQL migration checksum', () => {
checksum:
'cd4f92d8702da6b92dd9ae5153b5180400b94442f56393692b6ec038f998596b',
},
{
id: 'pg-0063-plugin-package-secret-binding-transition-receipts',
checksum:
'20c4d6e640b7fb05fc2f44dd9bec6d2d081697b83acf4e7dd5deb9a07afe54df',
},
];
assert.deepEqual(
postgresqlMainMigrationStream.migrations.map(({ id, checksum }) => ({
@@ -2127,3 +2134,41 @@ test('advances capability v61 with a staged-target Secret binding database guard
/migration_id = 'pg-0061-plugin-package-secret-binding-approval-plans'/,
);
});
test('advances capability v62 with immutable Secret binding transition receipts', async () => {
const migration = migrationById(
'pg-0063-plugin-package-secret-binding-transition-receipts',
);
const statements = [];
await migration.up({
async query(statement) {
statements.push(statement);
return { rows: [] };
},
});
const sql = statements.join('\n');
assert.match(
sql,
/CREATE TABLE "ql3"\."plugin_package_secret_binding_transition_receipts"/,
);
assert.match(
sql,
/CREATE FUNCTION "ql3"\."enforce_plugin_package_secret_binding_transition_receipt_target"\(\)/,
);
assert.match(sql, /install\.state = 'staged'/);
assert.match(sql, /previous\.state = 'active'/);
assert.match(sql, /MAX\(history\.target_generation\)/);
assert.match(sql, /binding\.binding_digest = NEW\.binding_digest/);
assert.doesNotMatch(sql, /SECURITY DEFINER/);
assert.match(
sql,
/GRANT SELECT, INSERT ON "ql3"\."plugin_package_secret_binding_transition_receipts" TO ql3_package_executor/,
);
assert.match(sql, /contract_version = 62/);
assert.match(sql, /"plugin_package_secret_binding_transition_receipt":1/);
assert.match(sql, /contract_version = 61/);
assert.match(
sql,
/migration_id = 'pg-0062-plugin-package-secret-binding-target-guard'/,
);
});
@@ -76,6 +76,12 @@ function validPrivileges() {
plugin_package_materialized_revisions: [false, false, false, false],
plugin_package_secret_bindings: [false, false, false, false],
plugin_package_secret_binding_approval_plans: [false, false, false, false],
plugin_package_secret_binding_transition_receipts: [
false,
false,
false,
false,
],
project_tool_definition_snapshots: [false, false, false, false],
project_tool_definition_snapshot_sources: [false, false, false, false],
plugin_package_quarantine_events: [false, false, false, false],
@@ -196,6 +202,12 @@ function validAdminPrivileges() {
plugin_package_materialized_revisions: [false, false, false, false],
plugin_package_secret_bindings: [false, false, false, false],
plugin_package_secret_binding_approval_plans: [false, false, false, false],
plugin_package_secret_binding_transition_receipts: [
false,
false,
false,
false,
],
project_tool_definition_snapshots: [false, false, false, false],
project_tool_definition_snapshot_sources: [false, false, false, false],
plugin_package_quarantine_events: [false, false, false, false],
@@ -308,6 +320,7 @@ function packagePrivileges(kind) {
'plugin_package_install_mutations',
'plugin_package_materialized_revisions',
'plugin_package_secret_bindings',
'plugin_package_secret_binding_transition_receipts',
'project_tool_definition_snapshots',
'project_tool_definition_snapshot_sources',
'plugin_package_admission_receipts',
@@ -351,6 +364,7 @@ function packagePrivileges(kind) {
'plugin_package_install_mutations',
'plugin_package_materialized_revisions',
'plugin_package_secret_bindings',
'plugin_package_secret_binding_transition_receipts',
'plugin_package_automation_publications',
'plugin_package_automation_publication_heads',
'project_tool_definition_snapshots',
@@ -776,7 +790,7 @@ test('accepts the exact PostgreSQL control schema and least-privilege runtime ro
serverMajor: 16,
currentUser: 'ql3_runtime',
contractName: 'control-core',
contractVersion: 61,
contractVersion: 62,
migrationIds: [
'pg-0001-schema-capability',
'pg-0002-run-core',
@@ -840,6 +854,7 @@ test('accepts the exact PostgreSQL control schema and least-privilege runtime ro
'pg-0060-plugin-package-secret-materialization-guard',
'pg-0061-plugin-package-secret-binding-approval-plans',
'pg-0062-plugin-package-secret-binding-target-guard',
'pg-0063-plugin-package-secret-binding-transition-receipts',
],
});
});
@@ -870,10 +885,10 @@ test('accepts the exact schema and isolated least-privilege admin role', async (
}),
);
assert.equal(report.currentUser, 'ql3_admin');
assert.equal(report.contractVersion, 61);
assert.equal(report.contractVersion, 62);
assert.equal(
report.migrationIds.at(-1),
'pg-0062-plugin-package-secret-binding-target-guard',
'pg-0063-plugin-package-secret-binding-transition-receipts',
);
});
@@ -886,10 +901,10 @@ test('accepts the isolated least-privilege automation manager role', async () =>
}),
);
assert.equal(report.currentUser, 'ql3_automation_manager');
assert.equal(report.contractVersion, 61);
assert.equal(report.contractVersion, 62);
assert.equal(
report.migrationIds.at(-1),
'pg-0062-plugin-package-secret-binding-target-guard',
'pg-0063-plugin-package-secret-binding-transition-receipts',
);
const widened = automationManagerPrivileges();
@@ -918,10 +933,10 @@ test('accepts the isolated least-privilege human Approval manager role', async (
}),
);
assert.equal(report.currentUser, 'ql3_approval_manager');
assert.equal(report.contractVersion, 61);
assert.equal(report.contractVersion, 62);
assert.equal(
report.migrationIds.at(-1),
'pg-0062-plugin-package-secret-binding-target-guard',
'pg-0063-plugin-package-secret-binding-transition-receipts',
);
const widened = approvalManagerPrivileges();
@@ -952,10 +967,10 @@ test('accepts the isolated least-privilege Run manager role', async () => {
}),
);
assert.equal(report.currentUser, 'ql3_run_manager');
assert.equal(report.contractVersion, 61);
assert.equal(report.contractVersion, 62);
assert.equal(
report.migrationIds.at(-1),
'pg-0062-plugin-package-secret-binding-target-guard',
'pg-0063-plugin-package-secret-binding-transition-receipts',
);
const widened = runManagerPrivileges();
@@ -1087,10 +1102,10 @@ test('accepts the exact schema and isolated Worker ingress role', async () => {
}),
);
assert.equal(report.currentUser, 'ql3_worker_ingress');
assert.equal(report.contractVersion, 61);
assert.equal(report.contractVersion, 62);
assert.equal(
report.migrationIds.at(-1),
'pg-0062-plugin-package-secret-binding-target-guard',
'pg-0063-plugin-package-secret-binding-transition-receipts',
);
});