mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
feat(ql3): admit plugin secret action jobs
This commit is contained in:
@@ -27,6 +27,27 @@ function environment(overrides = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
function actionControllerEnvironment(overrides = {}) {
|
||||
return environment({
|
||||
QL3_PLUGIN_PACKAGE_EXECUTOR_SECRET_ROOT: undefined,
|
||||
QL3_PLUGIN_PACKAGE_SECRET_ACTION_CONTROLLER_ENABLED: 'true',
|
||||
QL3_PLUGIN_PACKAGE_SECRET_ACTION_CONTROLLER_LIMIT: '6',
|
||||
QL3_PLUGIN_PACKAGE_SECRET_ACTION_IMAGE:
|
||||
'registry.example.com/qinglong/qinglong3-cluster-admin@sha256:' +
|
||||
'c'.repeat(64),
|
||||
QL3_PLUGIN_PACKAGE_SECRET_ACTION_POSTGRES_CA_SECRET:
|
||||
'ql3-cluster-plugin-package-executor',
|
||||
QL3_PLUGIN_PACKAGE_SECRET_ACTION_POSTGRES_CA_KEY: 'postgres-ca.crt',
|
||||
QL3_PLUGIN_PACKAGE_SECRET_ACTION_POSTGRES_SERVERNAME:
|
||||
'postgres.qinglong3-system.svc',
|
||||
QL3_PLUGIN_PACKAGE_SECRET_ACTION_POSTGRES_URL_SECRET:
|
||||
'ql3-cluster-plugin-package-executor',
|
||||
QL3_PLUGIN_PACKAGE_SECRET_ACTION_POSTGRES_URL_KEY:
|
||||
'postgres-package-executor-url',
|
||||
...overrides,
|
||||
});
|
||||
}
|
||||
|
||||
test('disabled executor opens no PostgreSQL authority', async () => {
|
||||
let opened = 0;
|
||||
const result = await runClusterPluginPackageExecutorProcess({
|
||||
@@ -74,6 +95,27 @@ test('loads one bounded action-scoped dispatch without widening batch limits', (
|
||||
assert.equal(config.maxBatches, 4);
|
||||
});
|
||||
|
||||
test('loads a bounded digest-pinned Kubernetes Secret action controller', () => {
|
||||
const config = loadClusterPluginPackageExecutorProcessConfig(
|
||||
actionControllerEnvironment(),
|
||||
);
|
||||
assert.equal(config.enabled, true);
|
||||
assert.equal(config.secretProjectionRoot, null);
|
||||
assert.equal(config.kubernetesSecretActions.limit, 6);
|
||||
assert.equal(
|
||||
config.kubernetesSecretActions.job.serviceAccountName,
|
||||
'ql3-plugin-package-secret-action',
|
||||
);
|
||||
assert.equal(
|
||||
config.kubernetesSecretActions.job.postgres.connection.mode,
|
||||
'url',
|
||||
);
|
||||
assert.equal(
|
||||
config.kubernetesSecretActions.job.postgres.connection.secretName,
|
||||
'ql3-cluster-plugin-package-executor',
|
||||
);
|
||||
});
|
||||
|
||||
test('action-scoped mode skips every Approval consumer and shared queue scan', async () => {
|
||||
const calls = [];
|
||||
const pool = {};
|
||||
@@ -151,6 +193,129 @@ test('action-scoped mode skips every Approval consumer and shared queue scan', a
|
||||
assert.equal(result.batches[0].dispatch.succeeded, 1);
|
||||
});
|
||||
|
||||
test('batch mode consumes approvals before reconciling exact Secret action Jobs', async () => {
|
||||
const calls = [];
|
||||
const pool = {
|
||||
async query() {
|
||||
throw new Error('repositories are injected behind the controller factory');
|
||||
},
|
||||
async connect() {
|
||||
throw new Error('repositories are injected behind the controller factory');
|
||||
},
|
||||
};
|
||||
const approvalSummary = {
|
||||
scanned: 0,
|
||||
consumed: 0,
|
||||
existing: 0,
|
||||
expired: 0,
|
||||
blocked: 0,
|
||||
};
|
||||
const readiness = {
|
||||
ready: true,
|
||||
writablePrimary: true,
|
||||
serverVersionNum: 180004,
|
||||
serverMajor: 18,
|
||||
currentUser: 'ql3_package_executor',
|
||||
contractName: 'control-core',
|
||||
contractVersion: 62,
|
||||
migrationIds: ['pg-0063-plugin-package-secret-binding-transition-receipts'],
|
||||
};
|
||||
const result = await runClusterPluginPackageExecutorProcess({
|
||||
environment: actionControllerEnvironment(),
|
||||
async openDatabase() {
|
||||
calls.push('open');
|
||||
return {
|
||||
pool,
|
||||
async close() {
|
||||
calls.push('close');
|
||||
},
|
||||
};
|
||||
},
|
||||
async assertReady() {
|
||||
calls.push('ready');
|
||||
return readiness;
|
||||
},
|
||||
async consumeApprovals() {
|
||||
calls.push('publisher-approvals');
|
||||
return approvalSummary;
|
||||
},
|
||||
async consumeTrustTransitionApprovals() {
|
||||
calls.push('trust-approvals');
|
||||
return approvalSummary;
|
||||
},
|
||||
async consumeSecretBindingApprovals() {
|
||||
calls.push('binding-approvals');
|
||||
return { ...approvalSummary, scanned: 1, consumed: 1 };
|
||||
},
|
||||
async consumeSecretBindingTransitionApprovals() {
|
||||
calls.push('transition-approvals');
|
||||
return approvalSummary;
|
||||
},
|
||||
async createSecretActionController(options) {
|
||||
assert.equal(options.job.image.endsWith('c'.repeat(64)), true);
|
||||
calls.push('controller-open');
|
||||
return {
|
||||
controller: {
|
||||
async reconcile({ limit }) {
|
||||
calls.push(`reconcile:${limit}`);
|
||||
return {
|
||||
scanned: 1,
|
||||
created: 1,
|
||||
existing: 0,
|
||||
active: 0,
|
||||
recoveryRequired: 0,
|
||||
unavailable: 0,
|
||||
truncated: false,
|
||||
};
|
||||
},
|
||||
},
|
||||
dispose() {
|
||||
calls.push('controller-close');
|
||||
},
|
||||
};
|
||||
},
|
||||
createDispatcher() {
|
||||
return {
|
||||
async dispatchById() {
|
||||
throw new Error('batch mode must not exact dispatch');
|
||||
},
|
||||
async dispatchBatch() {
|
||||
calls.push('dispatch-batch');
|
||||
return {
|
||||
scanned: 0,
|
||||
claimed: 0,
|
||||
started: 0,
|
||||
succeeded: 0,
|
||||
failed: 0,
|
||||
blocked: 0,
|
||||
retrying: 0,
|
||||
deferred: 0,
|
||||
recoveryRequired: 0,
|
||||
alreadyTerminal: 0,
|
||||
unavailable: 0,
|
||||
truncated: false,
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
assert.equal(result.batches.length, 1);
|
||||
assert.equal(result.batches[0].secretActionJobs.created, 1);
|
||||
assert.deepEqual(calls, [
|
||||
'open',
|
||||
'ready',
|
||||
'publisher-approvals',
|
||||
'trust-approvals',
|
||||
'binding-approvals',
|
||||
'transition-approvals',
|
||||
'controller-open',
|
||||
'reconcile:6',
|
||||
'dispatch-batch',
|
||||
'controller-close',
|
||||
'close',
|
||||
]);
|
||||
});
|
||||
|
||||
test('rejects implicit insecure PostgreSQL and unbounded work', () => {
|
||||
for (const invalid of [
|
||||
environment({ QL3_POSTGRES_ALLOW_INSECURE: undefined }),
|
||||
@@ -161,6 +326,12 @@ test('rejects implicit insecure PostgreSQL and unbounded work', () => {
|
||||
environment({
|
||||
QL3_PLUGIN_PACKAGE_EXECUTOR_DISPATCH_ID: 'dispatch id with spaces',
|
||||
}),
|
||||
actionControllerEnvironment({
|
||||
QL3_PLUGIN_PACKAGE_SECRET_ACTION_IMAGE: 'tag-only:latest',
|
||||
}),
|
||||
actionControllerEnvironment({
|
||||
QL3_PLUGIN_PACKAGE_SECRET_ACTION_POSTGRES_URL_SECRET: undefined,
|
||||
}),
|
||||
]) {
|
||||
assert.throws(
|
||||
() => loadClusterPluginPackageExecutorProcessConfig(invalid),
|
||||
|
||||
Reference in New Issue
Block a user