mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
536 lines
17 KiB
JavaScript
536 lines
17 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const { test } = require('node:test');
|
|
|
|
const {
|
|
PluginPackageSecretBindingConflictError,
|
|
createPluginPackageSecretBinding,
|
|
} = require('@qinglong/runtime-core/plugin-package-secret-binding');
|
|
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 migrationConnectionString = process.env.QL3_TEST_POSTGRES_MIGRATION_URL;
|
|
const executorConnectionString =
|
|
process.env.QL3_TEST_POSTGRES_PACKAGE_EXECUTOR_URL;
|
|
|
|
function manifest(packageName) {
|
|
return {
|
|
apiVersion: 'qinglong.io/v1alpha1',
|
|
kind: 'Package',
|
|
metadata: {
|
|
name: packageName,
|
|
displayName: packageName,
|
|
version: '1.0.0',
|
|
description: 'PostgreSQL Secret binding transition gate',
|
|
license: 'Apache-2.0',
|
|
},
|
|
spec: {
|
|
compatibility: {
|
|
qinglong: '>=3.0.0-0 <4.0.0',
|
|
architectures: ['arm64'],
|
|
deploymentProfiles: ['cluster-control'],
|
|
},
|
|
runtimes: [],
|
|
resources: {
|
|
memory: { recommended: '16Mi' },
|
|
disk: { install: '4Mi', working: '8Mi' },
|
|
},
|
|
permissions: {
|
|
network: { allowedHosts: [] },
|
|
secrets: [{ name: 'TOKEN', required: true }],
|
|
tools: [],
|
|
},
|
|
contents: { tasks: [], workflows: [], prompts: [], tools: [] },
|
|
},
|
|
};
|
|
}
|
|
|
|
function binding({
|
|
projectId,
|
|
packageName,
|
|
installationId,
|
|
lockDigest,
|
|
generation,
|
|
previousActiveLockDigest,
|
|
digestSeed,
|
|
}) {
|
|
const packageManifest = manifest(packageName);
|
|
const resourceGeneration = createPluginPackageResourceGeneration({
|
|
installationId,
|
|
projectId,
|
|
packageName,
|
|
lockDigest,
|
|
generation,
|
|
previousActiveLockDigest,
|
|
contentDigest: digestSeed.repeat(64),
|
|
contents: packageManifest.spec.contents,
|
|
});
|
|
return createPluginPackageSecretBinding({
|
|
generation: resourceGeneration,
|
|
manifest: packageManifest,
|
|
assignments: [
|
|
{
|
|
name: 'TOKEN',
|
|
secretRef: createSecretRef({
|
|
projectId,
|
|
name: 'runtime-token',
|
|
version: generation,
|
|
}),
|
|
},
|
|
],
|
|
authority: {
|
|
kind: 'approved-action-execution',
|
|
evidenceDigest: digestSeed.repeat(64),
|
|
},
|
|
boundAtMs: 100 + generation,
|
|
});
|
|
}
|
|
|
|
async function insertProject(pool, projectId) {
|
|
await pool.query(
|
|
`INSERT INTO "ql3"."projects" (
|
|
id, name, slug, status, version, created_at_ms, updated_at_ms
|
|
) VALUES ($1, $1, $1, 'active', 1, 1, 1)`,
|
|
[projectId],
|
|
);
|
|
}
|
|
|
|
async function insertInstall(
|
|
pool,
|
|
{
|
|
projectId,
|
|
packageName,
|
|
installationId,
|
|
lockDigest,
|
|
targetGeneration,
|
|
previousActiveLockDigest,
|
|
activeLockDigest,
|
|
state,
|
|
manifestDigest,
|
|
createdAtMs,
|
|
},
|
|
) {
|
|
const recordDigest = lockDigest;
|
|
const mutationDigest = lockDigest;
|
|
const lockJson = {
|
|
lockDigest,
|
|
projectId,
|
|
packageName,
|
|
manifestDigest,
|
|
};
|
|
const recordJson = {
|
|
installationId,
|
|
projectId,
|
|
packageName,
|
|
lockDigest,
|
|
state,
|
|
version: 1,
|
|
recordDigest,
|
|
};
|
|
await pool.query(
|
|
`INSERT INTO "ql3"."plugin_package_installs" (
|
|
installation_id, project_id, package_name, package_version,
|
|
operation, lock_digest, target_generation,
|
|
previous_active_lock_digest, active_lock_digest, state, version,
|
|
last_mutation_id, last_mutation_digest, lock_json, record_json,
|
|
record_digest, created_at_ms, updated_at_ms
|
|
) VALUES (
|
|
$1, $2, $3, '1.0.0', $4, $5, $6, $7, $8, $9, 1,
|
|
$10, $11, $12::jsonb, $13::jsonb, $14, $15, $15
|
|
)`,
|
|
[
|
|
installationId,
|
|
projectId,
|
|
packageName,
|
|
targetGeneration === 1 ? 'install' : 'upgrade',
|
|
lockDigest,
|
|
targetGeneration,
|
|
previousActiveLockDigest,
|
|
activeLockDigest,
|
|
state,
|
|
`mutation-${installationId}`,
|
|
mutationDigest,
|
|
JSON.stringify(lockJson),
|
|
JSON.stringify(recordJson),
|
|
recordDigest,
|
|
createdAtMs,
|
|
],
|
|
);
|
|
}
|
|
|
|
async function insertHead(pool, value) {
|
|
await pool.query(
|
|
`INSERT INTO "ql3"."plugin_package_install_heads" (
|
|
project_id, package_name, installation_id
|
|
) VALUES ($1, $2, $3)`,
|
|
[value.projectId, value.packageName, value.installationId],
|
|
);
|
|
}
|
|
|
|
async function insertBindingDirectly(pool, value) {
|
|
return pool.query(
|
|
`INSERT INTO "ql3"."plugin_package_secret_bindings" (
|
|
generation_digest, project_id, package_name, installation_id,
|
|
lock_digest, generation, manifest_digest, authority_kind,
|
|
evidence_digest, bound_at_ms, binding_digest, binding_json
|
|
) VALUES (
|
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12::jsonb
|
|
)`,
|
|
[
|
|
value.target.generationDigest,
|
|
value.target.projectId,
|
|
value.target.packageName,
|
|
value.target.installationId,
|
|
value.target.lockDigest,
|
|
value.target.generation,
|
|
value.target.manifestDigest,
|
|
value.authority.kind,
|
|
value.authority.evidenceDigest,
|
|
value.boundAtMs,
|
|
value.bindingDigest,
|
|
JSON.stringify(value),
|
|
],
|
|
);
|
|
}
|
|
|
|
async function open(role, connectionString) {
|
|
return createPostgresDatabaseOpener({
|
|
role,
|
|
connection: {
|
|
connectionString,
|
|
tls: { mode: 'disable' },
|
|
},
|
|
pool: {
|
|
maxConnections: 1,
|
|
applicationName: `ql3-b2-secret-binding-${role}`,
|
|
},
|
|
onPoolError(error) {
|
|
throw error;
|
|
},
|
|
})();
|
|
}
|
|
|
|
if (!migrationConnectionString || !executorConnectionString) {
|
|
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(
|
|
'migration',
|
|
migrationConnectionString,
|
|
);
|
|
let executorDatabase;
|
|
try {
|
|
await runPostgresMigrations({ pool: migrationDatabase.pool });
|
|
executorDatabase = await open(
|
|
'package-executor',
|
|
executorConnectionString,
|
|
);
|
|
const readiness = await assertPostgresPackageExecutorSchemaReady(
|
|
executorDatabase.pool,
|
|
);
|
|
assert.equal(readiness.ready, true);
|
|
assert.equal(readiness.contractVersion, 62);
|
|
|
|
const repository = new PostgresPluginPackageSecretBindingRepository(
|
|
executorDatabase.pool,
|
|
);
|
|
const namespace = `b2-${process.pid}-${Date.now()}`;
|
|
|
|
const activeProjectId = `${namespace}-active`;
|
|
const activePackageName = 'active-binding';
|
|
const activeInstallationId = `${namespace}-active-install`;
|
|
const activeLockDigest = 'a'.repeat(64);
|
|
const activeBinding = binding({
|
|
projectId: activeProjectId,
|
|
packageName: activePackageName,
|
|
installationId: activeInstallationId,
|
|
lockDigest: activeLockDigest,
|
|
generation: 1,
|
|
previousActiveLockDigest: null,
|
|
digestSeed: 'b',
|
|
});
|
|
await insertProject(migrationDatabase.pool, activeProjectId);
|
|
await insertInstall(migrationDatabase.pool, {
|
|
projectId: activeProjectId,
|
|
packageName: activePackageName,
|
|
installationId: activeInstallationId,
|
|
lockDigest: activeLockDigest,
|
|
targetGeneration: 1,
|
|
previousActiveLockDigest: null,
|
|
activeLockDigest,
|
|
state: 'active',
|
|
manifestDigest: activeBinding.target.manifestDigest,
|
|
createdAtMs: 1,
|
|
});
|
|
await insertHead(migrationDatabase.pool, {
|
|
projectId: activeProjectId,
|
|
packageName: activePackageName,
|
|
installationId: activeInstallationId,
|
|
});
|
|
assert.equal((await repository.publish(activeBinding)).status, 'created');
|
|
|
|
const stagedProjectId = `${namespace}-staged`;
|
|
const stagedPackageName = 'staged-binding';
|
|
const previousInstallationId = `${namespace}-previous-install`;
|
|
const stagedInstallationId = `${namespace}-staged-install`;
|
|
const previousLockDigest = 'c'.repeat(64);
|
|
const stagedLockDigest = 'd'.repeat(64);
|
|
const stagedBinding = binding({
|
|
projectId: stagedProjectId,
|
|
packageName: stagedPackageName,
|
|
installationId: stagedInstallationId,
|
|
lockDigest: stagedLockDigest,
|
|
generation: 2,
|
|
previousActiveLockDigest: previousLockDigest,
|
|
digestSeed: 'e',
|
|
});
|
|
await insertProject(migrationDatabase.pool, stagedProjectId);
|
|
await insertInstall(migrationDatabase.pool, {
|
|
projectId: stagedProjectId,
|
|
packageName: stagedPackageName,
|
|
installationId: previousInstallationId,
|
|
lockDigest: previousLockDigest,
|
|
targetGeneration: 1,
|
|
previousActiveLockDigest: null,
|
|
activeLockDigest: previousLockDigest,
|
|
state: 'active',
|
|
manifestDigest: stagedBinding.target.manifestDigest,
|
|
createdAtMs: 1,
|
|
});
|
|
await insertInstall(migrationDatabase.pool, {
|
|
projectId: stagedProjectId,
|
|
packageName: stagedPackageName,
|
|
installationId: stagedInstallationId,
|
|
lockDigest: stagedLockDigest,
|
|
targetGeneration: 2,
|
|
previousActiveLockDigest: previousLockDigest,
|
|
activeLockDigest: previousLockDigest,
|
|
state: 'staged',
|
|
manifestDigest: stagedBinding.target.manifestDigest,
|
|
createdAtMs: 2,
|
|
});
|
|
await insertHead(migrationDatabase.pool, {
|
|
projectId: stagedProjectId,
|
|
packageName: stagedPackageName,
|
|
installationId: stagedInstallationId,
|
|
});
|
|
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';
|
|
const activatingPreviousId = `${namespace}-activating-previous`;
|
|
const activatingInstallationId = `${namespace}-activating-install`;
|
|
const activatingPreviousLock = 'f'.repeat(64);
|
|
const activatingLock = '1'.repeat(64);
|
|
const activatingBinding = binding({
|
|
projectId: activatingProjectId,
|
|
packageName: activatingPackageName,
|
|
installationId: activatingInstallationId,
|
|
lockDigest: activatingLock,
|
|
generation: 2,
|
|
previousActiveLockDigest: activatingPreviousLock,
|
|
digestSeed: '2',
|
|
});
|
|
await insertProject(migrationDatabase.pool, activatingProjectId);
|
|
await insertInstall(migrationDatabase.pool, {
|
|
projectId: activatingProjectId,
|
|
packageName: activatingPackageName,
|
|
installationId: activatingPreviousId,
|
|
lockDigest: activatingPreviousLock,
|
|
targetGeneration: 1,
|
|
previousActiveLockDigest: null,
|
|
activeLockDigest: activatingPreviousLock,
|
|
state: 'active',
|
|
manifestDigest: activatingBinding.target.manifestDigest,
|
|
createdAtMs: 1,
|
|
});
|
|
await insertInstall(migrationDatabase.pool, {
|
|
projectId: activatingProjectId,
|
|
packageName: activatingPackageName,
|
|
installationId: activatingInstallationId,
|
|
lockDigest: activatingLock,
|
|
targetGeneration: 2,
|
|
previousActiveLockDigest: activatingPreviousLock,
|
|
activeLockDigest: activatingPreviousLock,
|
|
state: 'activating',
|
|
manifestDigest: activatingBinding.target.manifestDigest,
|
|
createdAtMs: 2,
|
|
});
|
|
await insertHead(migrationDatabase.pool, {
|
|
projectId: activatingProjectId,
|
|
packageName: activatingPackageName,
|
|
installationId: activatingInstallationId,
|
|
});
|
|
await assert.rejects(
|
|
repository.publish(activatingBinding),
|
|
PluginPackageSecretBindingConflictError,
|
|
);
|
|
await assert.rejects(
|
|
insertBindingDirectly(executorDatabase.pool, activatingBinding),
|
|
(error) =>
|
|
error?.code === '23514' &&
|
|
/not current active or reviewed staged generation/.test(
|
|
error.message,
|
|
),
|
|
);
|
|
|
|
const staleProjectId = `${namespace}-stale`;
|
|
const stalePackageName = 'stale-binding';
|
|
const stalePreviousId = `${namespace}-stale-previous`;
|
|
const staleInstallationId = `${namespace}-stale-install`;
|
|
const newerInstallationId = `${namespace}-newer-install`;
|
|
const stalePreviousLock = '3'.repeat(64);
|
|
const staleLock = '4'.repeat(64);
|
|
const staleBinding = binding({
|
|
projectId: staleProjectId,
|
|
packageName: stalePackageName,
|
|
installationId: staleInstallationId,
|
|
lockDigest: staleLock,
|
|
generation: 2,
|
|
previousActiveLockDigest: stalePreviousLock,
|
|
digestSeed: '5',
|
|
});
|
|
await insertProject(migrationDatabase.pool, staleProjectId);
|
|
await insertInstall(migrationDatabase.pool, {
|
|
projectId: staleProjectId,
|
|
packageName: stalePackageName,
|
|
installationId: stalePreviousId,
|
|
lockDigest: stalePreviousLock,
|
|
targetGeneration: 1,
|
|
previousActiveLockDigest: null,
|
|
activeLockDigest: stalePreviousLock,
|
|
state: 'active',
|
|
manifestDigest: staleBinding.target.manifestDigest,
|
|
createdAtMs: 1,
|
|
});
|
|
await insertInstall(migrationDatabase.pool, {
|
|
projectId: staleProjectId,
|
|
packageName: stalePackageName,
|
|
installationId: staleInstallationId,
|
|
lockDigest: staleLock,
|
|
targetGeneration: 2,
|
|
previousActiveLockDigest: stalePreviousLock,
|
|
activeLockDigest: stalePreviousLock,
|
|
state: 'staged',
|
|
manifestDigest: staleBinding.target.manifestDigest,
|
|
createdAtMs: 2,
|
|
});
|
|
await insertInstall(migrationDatabase.pool, {
|
|
projectId: staleProjectId,
|
|
packageName: stalePackageName,
|
|
installationId: newerInstallationId,
|
|
lockDigest: '6'.repeat(64),
|
|
targetGeneration: 3,
|
|
previousActiveLockDigest: stalePreviousLock,
|
|
activeLockDigest: stalePreviousLock,
|
|
state: 'failed',
|
|
manifestDigest: staleBinding.target.manifestDigest,
|
|
createdAtMs: 3,
|
|
});
|
|
await insertHead(migrationDatabase.pool, {
|
|
projectId: staleProjectId,
|
|
packageName: stalePackageName,
|
|
installationId: staleInstallationId,
|
|
});
|
|
await assert.rejects(
|
|
repository.publish(staleBinding),
|
|
PluginPackageSecretBindingConflictError,
|
|
);
|
|
await assert.rejects(
|
|
insertBindingDirectly(executorDatabase.pool, staleBinding),
|
|
(error) => error?.code === '23514',
|
|
);
|
|
} finally {
|
|
if (executorDatabase) await executorDatabase.close();
|
|
await migrationDatabase.close();
|
|
}
|
|
});
|
|
}
|