mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const {
|
||||
chmodSync,
|
||||
mkdtempSync,
|
||||
readFileSync,
|
||||
realpathSync,
|
||||
rmSync,
|
||||
writeFileSync,
|
||||
} = require('node:fs');
|
||||
const { tmpdir } = require('node:os');
|
||||
const { join, resolve } = require('node:path');
|
||||
const { afterEach, test } = require('node:test');
|
||||
|
||||
const {
|
||||
ClusterPluginPackageManagementClientRequestError,
|
||||
} = require('@qinglong/cluster-admin/plugin-package-management-client');
|
||||
const {
|
||||
executeClusterApprovalManagementClient,
|
||||
validateClusterApprovalManagementClientResult,
|
||||
} = require('@qinglong/cluster-admin/approval-management-client');
|
||||
|
||||
const FIXTURES = resolve(
|
||||
__dirname,
|
||||
'../../ql3-cluster-control/test/fixtures/mtls',
|
||||
);
|
||||
const temporaryDirectories = [];
|
||||
|
||||
const ACTION = Object.freeze({
|
||||
permission: 'run.start',
|
||||
actionType: 'tool.invoke',
|
||||
actionRef: 'tool:task-1',
|
||||
actionDigest: 'a'.repeat(64),
|
||||
previewDigest: 'b'.repeat(64),
|
||||
});
|
||||
const BASE_REQUEST = Object.freeze({
|
||||
projectId: 'default',
|
||||
approvalRequestId: 'approval-1',
|
||||
requestId: 'approval-command-1',
|
||||
auditEventId: '60000000-0000-4000-8000-000000000001',
|
||||
failureAuditEventId: '60000000-0000-4000-8000-000000000002',
|
||||
});
|
||||
|
||||
function privateWrite(filePath, value) {
|
||||
writeFileSync(filePath, value, { mode: 0o600 });
|
||||
chmodSync(filePath, 0o600);
|
||||
}
|
||||
|
||||
function clientFiles() {
|
||||
const directory = realpathSync(
|
||||
mkdtempSync(join(tmpdir(), 'ql3-approval-client-')),
|
||||
);
|
||||
temporaryDirectories.push(directory);
|
||||
const paths = {
|
||||
configFile: join(directory, 'client.json'),
|
||||
commandFile: join(directory, 'command.json'),
|
||||
assertionFile: join(directory, 'assertion.jwt'),
|
||||
};
|
||||
const caFile = join(directory, 'ca.crt');
|
||||
const clientCertificateFile = join(directory, 'client.crt');
|
||||
const clientPrivateKeyFile = join(directory, 'client.key');
|
||||
privateWrite(caFile, readFileSync(join(FIXTURES, 'ca-cert.pem')));
|
||||
privateWrite(
|
||||
clientCertificateFile,
|
||||
readFileSync(join(FIXTURES, 'client-cert.pem')),
|
||||
);
|
||||
privateWrite(
|
||||
clientPrivateKeyFile,
|
||||
readFileSync(join(FIXTURES, 'client-key.pem')),
|
||||
);
|
||||
privateWrite(
|
||||
paths.configFile,
|
||||
`${JSON.stringify({
|
||||
schemaVersion: 1,
|
||||
endpoint:
|
||||
'https://approval.example.test:8447/api/v3/approvals/management',
|
||||
servername: 'approval.example.test',
|
||||
caFile,
|
||||
clientCertificateFile,
|
||||
clientPrivateKeyFile,
|
||||
requestTimeoutMs: 1_000,
|
||||
})}\n`,
|
||||
);
|
||||
privateWrite(
|
||||
paths.commandFile,
|
||||
`${JSON.stringify({
|
||||
schemaVersion: 1,
|
||||
operation: 'approval.inspect',
|
||||
request: BASE_REQUEST,
|
||||
})}\n`,
|
||||
);
|
||||
privateWrite(
|
||||
paths.assertionFile,
|
||||
'eyJhbGciOiJFZERTQSJ9.eyJzdWIiOiJ1In0.c2lnbmF0dXJl',
|
||||
);
|
||||
return paths;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
for (const directory of temporaryDirectories.splice(0)) {
|
||||
rmSync(directory, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('validates exact inspect results and binds them to the requested Approval', () => {
|
||||
const command = {
|
||||
schemaVersion: 1,
|
||||
operation: 'approval.inspect',
|
||||
request: BASE_REQUEST,
|
||||
};
|
||||
const found = {
|
||||
schemaVersion: 1,
|
||||
operation: 'approval.inspect',
|
||||
status: 'found',
|
||||
approval: {
|
||||
projectId: 'default',
|
||||
approvalRequestId: 'approval-1',
|
||||
version: 1,
|
||||
state: 'pending',
|
||||
risk: 'high',
|
||||
decisionMode: 'human_confirmation',
|
||||
expectedAction: ACTION,
|
||||
requestedBy: { type: 'agent', id: 'agent-1' },
|
||||
requestedAtMs: 1_000,
|
||||
expiresAtMs: 10_000,
|
||||
preview: {
|
||||
title: 'Run task',
|
||||
summary: 'Runs one reviewed task.',
|
||||
fields: [{ kind: 'identifier', label: 'Task', value: 'task-1' }],
|
||||
warnings: ['external_effect'],
|
||||
},
|
||||
},
|
||||
};
|
||||
assert.deepEqual(
|
||||
validateClusterApprovalManagementClientResult(found, command),
|
||||
found,
|
||||
);
|
||||
assert.deepEqual(
|
||||
validateClusterApprovalManagementClientResult(
|
||||
{ ...found, status: 'absent', approval: null },
|
||||
command,
|
||||
),
|
||||
{ ...found, status: 'absent', approval: null },
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
validateClusterApprovalManagementClientResult(
|
||||
{
|
||||
...found,
|
||||
approval: { ...found.approval, projectId: 'other' },
|
||||
},
|
||||
command,
|
||||
),
|
||||
ClusterPluginPackageManagementClientRequestError,
|
||||
);
|
||||
});
|
||||
|
||||
test('validates the durable decision tuple and rejects server-side drift', () => {
|
||||
const command = {
|
||||
schemaVersion: 1,
|
||||
operation: 'approval.decide',
|
||||
request: {
|
||||
...BASE_REQUEST,
|
||||
expectedVersion: 1,
|
||||
expectedAction: ACTION,
|
||||
decisionId: 'decision-1',
|
||||
decision: 'approved',
|
||||
reasonCode: 'reviewed',
|
||||
},
|
||||
};
|
||||
const result = {
|
||||
schemaVersion: 1,
|
||||
operation: 'approval.decide',
|
||||
status: 'decided',
|
||||
approval: {
|
||||
projectId: 'default',
|
||||
approvalRequestId: 'approval-1',
|
||||
version: 2,
|
||||
state: 'approved',
|
||||
expectedAction: ACTION,
|
||||
decisionId: 'decision-1',
|
||||
decision: 'approved',
|
||||
reasonCode: 'reviewed',
|
||||
decidedBy: { type: 'user', id: 'owner-1' },
|
||||
decidedAtMs: 2_000,
|
||||
},
|
||||
};
|
||||
assert.deepEqual(
|
||||
validateClusterApprovalManagementClientResult(result, command),
|
||||
result,
|
||||
);
|
||||
for (const approval of [
|
||||
{ ...result.approval, version: 1 },
|
||||
{ ...result.approval, state: 'rejected' },
|
||||
{ ...result.approval, decisionId: 'decision-2' },
|
||||
]) {
|
||||
assert.throws(
|
||||
() =>
|
||||
validateClusterApprovalManagementClientResult(
|
||||
{ ...result, approval },
|
||||
command,
|
||||
),
|
||||
ClusterPluginPackageManagementClientRequestError,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('accepts only the exact Approval route before opening one mTLS connection', async () => {
|
||||
let connects = 0;
|
||||
await assert.rejects(
|
||||
executeClusterApprovalManagementClient(clientFiles(), {
|
||||
async connect(target) {
|
||||
connects += 1;
|
||||
assert.deepEqual(target, {
|
||||
hostname: 'approval.example.test',
|
||||
port: 8447,
|
||||
});
|
||||
throw new Error('expected-connect-stop');
|
||||
},
|
||||
}),
|
||||
{ code: 'QL3_PLUGIN_PACKAGE_MANAGEMENT_CLIENT_REQUEST_FAILED' },
|
||||
);
|
||||
assert.equal(connects, 1);
|
||||
});
|
||||
Reference in New Issue
Block a user