mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
235 lines
6.6 KiB
JavaScript
235 lines
6.6 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const { test } = require('node:test');
|
|
|
|
const {
|
|
createTaskDefinitionRecord,
|
|
} = require('@qinglong/runtime-core/task-definition');
|
|
const { createTriggerRecord } = require('@qinglong/runtime-core/trigger');
|
|
const {
|
|
ClusterAutomationManagementTransportAuthenticationError,
|
|
ClusterAutomationManagementTransportRequestError,
|
|
createClusterAutomationManagementTransport,
|
|
} = require('@qinglong/cluster-admin/automation-management-transport');
|
|
|
|
const principal = Object.freeze({
|
|
subject: Object.freeze({ type: 'user', id: 'operator-a' }),
|
|
authenticationId: 'session-operator-a',
|
|
authenticatedAtMs: 900,
|
|
expiresAtMs: 10_000,
|
|
assurance: 'hardware',
|
|
});
|
|
const taskCommand = Object.freeze({
|
|
projectId: 'project-a',
|
|
taskId: 'task-a',
|
|
expectedRevision: null,
|
|
mutationId: '123e4567-e89b-42d3-a456-426614174000',
|
|
name: 'Sensitive task name',
|
|
kind: 'script',
|
|
spec: {
|
|
schema: 'qinglong/script@v1',
|
|
config: { source: 'sensitive script body' },
|
|
},
|
|
labels: {},
|
|
enabled: true,
|
|
occurredAtMs: 1_000,
|
|
});
|
|
const triggerCommand = Object.freeze({
|
|
projectId: 'project-a',
|
|
triggerId: 'trigger-a',
|
|
expectedRevision: null,
|
|
mutationId: '123e4567-e89b-42d3-a456-426614174002',
|
|
taskId: 'task-a',
|
|
taskRevision: 1,
|
|
taskContentDigest: 'a'.repeat(64),
|
|
spec: {
|
|
schema: 'qinglong/cron@v1',
|
|
config: {
|
|
expression: '*/5 * * * *',
|
|
timezone: 'UTC',
|
|
misfirePolicy: 'fire_once',
|
|
},
|
|
},
|
|
enabled: true,
|
|
occurredAtMs: 1_000,
|
|
});
|
|
|
|
test('routes strong User Task/Trigger publications and returns only low-sensitive summaries', async () => {
|
|
const calls = [];
|
|
const transport = createClusterAutomationManagementTransport({
|
|
service: {
|
|
async publishTask(request) {
|
|
calls.push(['task', request]);
|
|
return {
|
|
status: 'created',
|
|
definition: createTaskDefinitionRecord(request.command, 900),
|
|
};
|
|
},
|
|
async publishTrigger(request) {
|
|
calls.push(['trigger', request]);
|
|
return {
|
|
status: 'created',
|
|
trigger: createTriggerRecord(request.command, 900),
|
|
};
|
|
},
|
|
async inspectTask(request) {
|
|
calls.push(['task-inspect', request]);
|
|
return createTaskDefinitionRecord(taskCommand, 900);
|
|
},
|
|
async listTasks(request) {
|
|
calls.push(['task-list', request]);
|
|
return {
|
|
definitions: [createTaskDefinitionRecord(taskCommand, 900)],
|
|
truncated: true,
|
|
next: { taskId: 'task-a' },
|
|
};
|
|
},
|
|
async inspectTrigger(request) {
|
|
calls.push(['trigger-inspect', request]);
|
|
return null;
|
|
},
|
|
async listTriggers(request) {
|
|
calls.push(['trigger-list', request]);
|
|
return {
|
|
triggers: [createTriggerRecord(triggerCommand, 900)],
|
|
truncated: false,
|
|
};
|
|
},
|
|
},
|
|
now: () => 1_100,
|
|
});
|
|
const authentication = { async authenticate() { return principal; } };
|
|
const task = await transport.execute(
|
|
{
|
|
schemaVersion: 1,
|
|
operation: 'task.publish',
|
|
request: { requestId: 'request-task', command: taskCommand },
|
|
},
|
|
authentication,
|
|
);
|
|
const trigger = await transport.execute(
|
|
{
|
|
schemaVersion: 1,
|
|
operation: 'trigger.publish',
|
|
request: { requestId: 'request-trigger', command: triggerCommand },
|
|
},
|
|
authentication,
|
|
);
|
|
const taskInspection = await transport.execute(
|
|
{
|
|
schemaVersion: 1,
|
|
operation: 'task.inspect',
|
|
request: {
|
|
requestId: 'request-task-inspect',
|
|
auditEventId: '123e4567-e89b-42d3-a456-426614174010',
|
|
projectId: 'project-a',
|
|
taskId: 'task-a',
|
|
},
|
|
},
|
|
authentication,
|
|
);
|
|
const taskList = await transport.execute(
|
|
{
|
|
schemaVersion: 1,
|
|
operation: 'task.list',
|
|
request: {
|
|
requestId: 'request-task-list',
|
|
auditEventId: '123e4567-e89b-42d3-a456-426614174011',
|
|
projectId: 'project-a',
|
|
limit: 1,
|
|
},
|
|
},
|
|
authentication,
|
|
);
|
|
const triggerInspection = await transport.execute(
|
|
{
|
|
schemaVersion: 1,
|
|
operation: 'trigger.inspect',
|
|
request: {
|
|
requestId: 'request-trigger-inspect',
|
|
auditEventId: '123e4567-e89b-42d3-a456-426614174012',
|
|
projectId: 'project-a',
|
|
triggerId: 'trigger-a',
|
|
},
|
|
},
|
|
authentication,
|
|
);
|
|
const triggerList = await transport.execute(
|
|
{
|
|
schemaVersion: 1,
|
|
operation: 'trigger.list',
|
|
request: {
|
|
requestId: 'request-trigger-list',
|
|
auditEventId: '123e4567-e89b-42d3-a456-426614174013',
|
|
projectId: 'project-a',
|
|
limit: 1,
|
|
},
|
|
},
|
|
authentication,
|
|
);
|
|
assert.deepEqual(calls.map(([kind]) => kind), [
|
|
'task',
|
|
'trigger',
|
|
'task-inspect',
|
|
'task-list',
|
|
'trigger-inspect',
|
|
'trigger-list',
|
|
]);
|
|
assert.deepEqual(calls.map(([, request]) => request.principal), [
|
|
principal,
|
|
principal,
|
|
principal,
|
|
principal,
|
|
principal,
|
|
principal,
|
|
]);
|
|
assert.equal(task.task.contentDigest.length, 64);
|
|
assert.equal(trigger.trigger.taskContentDigest, 'a'.repeat(64));
|
|
assert.equal(taskInspection.status, 'found');
|
|
assert.equal(taskList.next.taskId, 'task-a');
|
|
assert.equal(triggerInspection.status, 'absent');
|
|
assert.equal(triggerList.next, null);
|
|
const serialized = JSON.stringify([
|
|
task,
|
|
trigger,
|
|
taskInspection,
|
|
taskList,
|
|
triggerInspection,
|
|
triggerList,
|
|
]);
|
|
assert.doesNotMatch(serialized, /Sensitive|script body|expression|authenticationId|mutationId/);
|
|
});
|
|
|
|
test('rejects malformed envelopes and weak identities before service authority', async () => {
|
|
let calls = 0;
|
|
const transport = createClusterAutomationManagementTransport({
|
|
service: {
|
|
async publishTask() { calls += 1; },
|
|
async publishTrigger() { calls += 1; },
|
|
async inspectTask() { calls += 1; },
|
|
async listTasks() { calls += 1; },
|
|
async inspectTrigger() { calls += 1; },
|
|
async listTriggers() { calls += 1; },
|
|
},
|
|
now: () => 1_100,
|
|
});
|
|
await assert.rejects(
|
|
transport.execute(
|
|
{ schemaVersion: 1, operation: 'task.publish', request: {}, extra: true },
|
|
{ async authenticate() { return principal; } },
|
|
),
|
|
ClusterAutomationManagementTransportRequestError,
|
|
);
|
|
await assert.rejects(
|
|
transport.execute(
|
|
{
|
|
schemaVersion: 1,
|
|
operation: 'task.publish',
|
|
request: { requestId: 'request-task', command: taskCommand },
|
|
},
|
|
{ async authenticate() { return { ...principal, assurance: 'single_factor' }; } },
|
|
),
|
|
ClusterAutomationManagementTransportAuthenticationError,
|
|
);
|
|
assert.equal(calls, 0);
|
|
});
|