feat(ql3): expose bounded worker session observation

This commit is contained in:
whyour
2026-08-20 12:55:44 +08:00
parent 6265e31dce
commit 4a4fa85f51
24 changed files with 1437 additions and 28 deletions
@@ -4,6 +4,9 @@ const { test } = require('node:test');
const {
createClusterWorkerCredentialManagementService,
} = require('@qinglong/cluster-admin/worker-credential-management');
const {
canonicalRemoteWorkerCapabilities,
} = require('@qinglong/runtime-core/remote-dispatch');
const REQUESTER = Object.freeze({
subject: Object.freeze({ type: 'user', id: 'operator-a' }),
@@ -20,6 +23,32 @@ const REVIEWER = Object.freeze({
assurance: 'hardware',
});
function sessionRow() {
const capabilities = canonicalRemoteWorkerCapabilities({
architecture: 'arm64',
executors: ['remote-worker'],
protocolVersion: '1.0.0',
supportTier: 'tier1',
runtimes: [{ name: 'node', version: '24.18.0' }],
});
return {
observedAtMs: 2_000,
workerId: 'worker-a',
sessionId: '018f0f5d-7b6a-7a11-8f4d-2f7b4f477001',
generation: 2,
status: 'online',
version: 5,
capabilitiesJson: capabilities.json,
capabilitiesHash: capabilities.hash,
maxConcurrentRuns: 2,
availableSlots: 1,
registeredAtMs: 1_000,
lastHeartbeatAtMs: 1_900,
leaseExpiresAtMs: 3_000,
updatedAtMs: 1_900,
};
}
function approvalFixture() {
const plans = new Map();
const approvals = new Map();
@@ -76,6 +105,9 @@ function approvalFixture() {
const stored = audits.get(values[0]);
return { rows: stored ? [stored] : [], rowCount: stored ? 1 : 0 };
}
if (text.includes('FROM "ql3"."worker_sessions"')) {
return { rows: [sessionRow()], rowCount: 1 };
}
if (text.includes('"ql3"."lock_approval_policy_fence"')) {
return { rows: [{ matches: true }], rowCount: 1 };
}
@@ -277,3 +309,50 @@ test('authorizes and consumes durable quota before reading management state', as
assert.equal(quotaCalls[1].operation, 'worker-credential.propose');
assert.equal(quotaCalls[1].planReads, readsBefore);
});
test('observes one Session and one bounded page only after worker.manage quota', async () => {
const state = approvalFixture();
const quotaCalls = [];
const service = createClusterWorkerCredentialManagementService({
pool: state.pool,
now: () => 2_000,
quota: {
async consume(command) {
quotaCalls.push(command);
return { admitted: true, retryAfterMs: null };
},
},
});
const inspection = await service.inspectSession({
authorityProjectId: 'cluster-authority',
workerId: 'worker-a',
inspectionId: 'worker-session-inspection-a',
principal: REQUESTER,
});
const page = await service.listSessions({
authorityProjectId: 'cluster-authority',
afterWorkerId: null,
inspectionId: 'worker-session-list-a',
principal: REQUESTER,
});
assert.equal(inspection.worker.workerId, 'worker-a');
assert.equal(inspection.worker.compatibility, 'default_placement');
assert.equal(page.workers.length, 1);
assert.equal(page.workers[0].workerId, 'worker-a');
assert.deepEqual(
quotaCalls.map(({ operation, idempotencyKey }) => ({
operation,
idempotencyKey,
})),
[
{
operation: 'worker-session.observe',
idempotencyKey: 'session-inspect:worker-session-inspection-a',
},
{
operation: 'worker-session.observe',
idempotencyKey: 'session-list:worker-session-list-a',
},
],
);
});
@@ -82,6 +82,39 @@ const approval = Object.freeze({
actionDigest: 'd'.repeat(64),
previewDigest: plan.previewDigest,
});
const session = Object.freeze({
workerId: 'worker-1',
sessionId: '018f0f5d-7b6a-7a11-8f4d-2f7b4f477001',
generation: 2,
sessionVersion: 5,
lifecycle: 'online',
compatibility: 'default_placement',
architecture: 'arm64',
supportTier: 'tier1',
protocolVersion: '1.0.0',
operatingSystem: 'linux',
maxConcurrentRuns: 2,
availableSlots: 1,
registeredAtMs: 900,
lastHeartbeatAtMs: 1_050,
leaseExpiresAtMs: 2_000,
updatedAtMs: 1_050,
observedAtMs: 1_100,
runtimes: Object.freeze([{ name: 'node', version: '24.18.0' }]),
declaredCapacity: Object.freeze({
cpuCores: 1,
memoryBytes: 268_435_456,
diskBytes: 1_073_741_824,
gpuCount: 0,
}),
});
const sessionSummary = Object.freeze(
Object.fromEntries(
Object.entries(session).filter(
([key]) => key !== 'runtimes' && key !== 'declaredCapacity',
),
),
);
function command(operation) {
return {
@@ -152,7 +185,7 @@ afterEach(() => {
}
});
test('validates all four low-sensitive Worker management results', () => {
test('validates all six low-sensitive Worker management results', () => {
const fixtures = [
[
'worker-credential.plan',
@@ -187,6 +220,25 @@ test('validates all four low-sensitive Worker management results', () => {
stale: false,
},
],
[
'worker-session.inspect',
{
schemaVersion: 1,
operation: 'worker-session.inspect',
observedAtMs: 1_100,
worker: session,
},
],
[
'worker-session.list',
{
schemaVersion: 1,
operation: 'worker-session.list',
observedAtMs: 1_100,
workers: [sessionSummary],
nextCursor: null,
},
],
];
for (const [operation, result] of fixtures) {
assert.equal(
@@ -223,6 +275,51 @@ test('rejects widened and secret-bearing response shapes', () => {
command('worker-credential.inspect'),
),
);
assert.throws(() =>
validateClusterWorkerCredentialManagementClientResult(
{
schemaVersion: 1,
operation: 'worker-session.inspect',
observedAtMs: 1_100,
worker: { ...session, labels: { secret: 'value' } },
},
command('worker-session.inspect'),
),
);
assert.throws(() =>
validateClusterWorkerCredentialManagementClientResult(
{
schemaVersion: 1,
operation: 'worker-session.list',
observedAtMs: 1_100,
workers: [
{ ...sessionSummary, workerId: 'worker-b' },
{ ...sessionSummary, workerId: 'worker-a' },
],
nextCursor: null,
},
command('worker-session.list'),
),
);
for (const worker of [
{ ...session, workerId: null },
{ ...session, generation: -1 },
{ ...session, availableSlots: 3 },
{ ...session, observedAtMs: 1_000 },
{ ...session, declaredCapacity: { ...session.declaredCapacity, gpuCount: -1 } },
]) {
assert.throws(() =>
validateClusterWorkerCredentialManagementClientResult(
{
schemaVersion: 1,
operation: 'worker-session.inspect',
observedAtMs: worker.observedAtMs,
worker,
},
command('worker-session.inspect'),
),
);
}
});
test('requires one matching private client certificate identity before connect', async () => {
@@ -69,6 +69,41 @@ function approval(planValue) {
});
}
const SESSION_OBSERVATION = Object.freeze({
workerId: 'worker-a',
sessionId: '018f0f5d-7b6a-7a11-8f4d-2f7b4f477001',
generation: 2,
sessionVersion: 5,
lifecycle: 'online',
compatibility: 'default_placement',
architecture: 'arm64',
supportTier: 'tier1',
protocolVersion: '1.0.0',
operatingSystem: 'linux',
maxConcurrentRuns: 2,
availableSlots: 1,
registeredAtMs: 900,
lastHeartbeatAtMs: 1_050,
leaseExpiresAtMs: 2_000,
updatedAtMs: 1_050,
observedAtMs: 1_100,
runtimes: Object.freeze([{ name: 'node', version: '24.18.0' }]),
declaredCapacity: Object.freeze({
cpuCores: 1,
memoryBytes: 268_435_456,
diskBytes: 1_073_741_824,
gpuCount: 0,
}),
});
const SESSION_SUMMARY = Object.freeze(
Object.fromEntries(
Object.entries(SESSION_OBSERVATION).filter(
([key]) => key !== 'runtimes' && key !== 'declaredCapacity',
),
),
);
function commands() {
return [
{
@@ -122,10 +157,28 @@ function commands() {
inspectionId: 'inspection-worker-a-generation-2',
},
},
{
schemaVersion: 1,
operation: 'worker-session.inspect',
request: {
authorityProjectId: 'cluster-authority',
workerId: 'worker-a',
inspectionId: 'inspection-worker-session-a',
},
},
{
schemaVersion: 1,
operation: 'worker-session.list',
request: {
authorityProjectId: 'cluster-authority',
afterWorkerId: null,
inspectionId: 'inspection-worker-session-list-a',
},
},
];
}
test('routes the four public commands with strong User authority and low-sensitive results', async () => {
test('routes six public commands with strong User authority and low-sensitive results', async () => {
const planValue = plan();
const approvalValue = approval(planValue);
const calls = [];
@@ -154,6 +207,18 @@ test('routes the four public commands with strong User authority and low-sensiti
stale: false,
};
},
async inspectSession(request) {
calls.push(['inspectSession', request]);
return { observedAtMs: 1_100, worker: SESSION_OBSERVATION };
},
async listSessions(request) {
calls.push(['listSessions', request]);
return {
observedAtMs: 1_100,
workers: [SESSION_SUMMARY],
nextCursor: null,
};
},
};
const transport = createClusterWorkerCredentialManagementTransport({
service,
@@ -170,7 +235,7 @@ test('routes the four public commands with strong User authority and low-sensiti
}
assert.deepEqual(
calls.map(([kind]) => kind),
['plan', 'propose', 'decide', 'inspect'],
['plan', 'propose', 'decide', 'inspect', 'inspectSession', 'listSessions'],
);
for (const [, request] of calls) {
assert.deepEqual(request.principal, principal());
@@ -182,11 +247,15 @@ test('routes the four public commands with strong User authority and low-sensiti
'worker-credential.propose',
'worker-credential.decide',
'worker-credential.inspect',
'worker-session.inspect',
'worker-session.list',
],
);
assert.equal(results[0].plan.planDigest, planValue.planDigest);
assert.equal(results[1].approval.actionDigest, planValue.planDigest);
assert.equal(results[3].stale, false);
assert.equal(results[4].worker.compatibility, 'default_placement');
assert.equal(results[5].workers[0].workerId, 'worker-a');
const serialized = JSON.stringify(results);
assert.doesNotMatch(serialized, /authenticationId|credential-token|secret/i);
});
@@ -194,7 +263,14 @@ test('routes the four public commands with strong User authority and low-sensiti
test('rejects weak or unavailable identity before management authority', async () => {
let calls = 0;
const service = Object.fromEntries(
['plan', 'propose', 'decide', 'inspectAuthorized'].map((name) => [
[
'plan',
'propose',
'decide',
'inspectAuthorized',
'inspectSession',
'listSessions',
].map((name) => [
name,
async () => {
calls += 1;
@@ -232,6 +308,8 @@ test('rejects widened and internal commands before authentication', async () =>
async propose() {},
async decide() {},
async inspectAuthorized() {},
async inspectSession() {},
async listSessions() {},
},
});
let authentications = 0;