feat(ql3): establish 3.0 incubation baseline

This commit is contained in:
whyour
2026-08-12 00:25:26 +08:00
parent 4bf92dcfeb
commit c699c32461
2817 changed files with 779642 additions and 653 deletions
@@ -0,0 +1,66 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
API_CREDENTIAL_SUBJECT_TYPES,
InvalidApiCredentialValueError,
assertApiCredentialId,
normalizeApiCredentialRecord,
} = require('@qinglong/runtime-core/api-credential');
function record(overrides = {}) {
return {
credentialId: 'app_primary',
version: 2,
pepperKeyId: 'legacy-v1',
state: 'active',
subject: { type: 'api_app', id: 'app_primary' },
subjectStatus: 'active',
secretDigest: 'a'.repeat(64),
createdAtMs: 100,
notBeforeAtMs: 100,
expiresAtMs: 1_000,
...overrides,
};
}
test('normalizes one immutable API credential without secret material', () => {
const source = record();
const normalized = normalizeApiCredentialRecord(source);
source.subject.id = 'mutated';
assert.deepEqual(normalized, record());
assert.equal(Object.isFrozen(normalized), true);
assert.equal(Object.isFrozen(normalized.subject), true);
assert.deepEqual(API_CREDENTIAL_SUBJECT_TYPES, [
'user',
'api_app',
'mcp_client',
'agent',
]);
assert.equal(JSON.stringify(normalized).includes('token'), false);
});
test('rejects widened, malformed, disabled-lifetime and privileged subjects', () => {
const invalid = [
{ ...record(), extra: true },
record({ credentialId: '../escape' }),
record({ version: 0 }),
record({ pepperKeyId: '../escape' }),
record({ state: 'unknown' }),
record({ subject: { type: 'system', id: 'system' } }),
record({ subject: { type: 'worker', id: 'worker-1' } }),
record({ subjectStatus: 'unknown' }),
record({ secretDigest: 'A'.repeat(64) }),
record({ notBeforeAtMs: 99 }),
record({ expiresAtMs: 100 }),
];
for (const value of invalid) {
assert.throws(
() => normalizeApiCredentialRecord(value),
InvalidApiCredentialValueError,
);
}
assert.throws(
() => assertApiCredentialId(''),
InvalidApiCredentialValueError,
);
});
@@ -0,0 +1,99 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidApiCredentialAdministrationValueError,
REVOKED_API_CREDENTIAL_DIGEST,
normalizeAppendApiCredentialCommand,
} = require('@qinglong/runtime-core/api-credential-administration');
function command(overrides = {}) {
const mutation = {
mutationId: '123e4567-e89b-42d3-a456-426614174211',
operation: 'issue',
credentialId: 'credential_primary',
credentialVersion: 1,
expectedPreviousVersion: 0,
changedBy: { type: 'user', id: 'usr_admin' },
createdAtMs: 100,
...overrides.mutation,
};
const credential = {
credentialId: mutation.credentialId,
version: mutation.credentialVersion,
pepperKeyId: 'legacy-v1',
state: 'active',
subject: { type: 'api_app', id: 'app_primary' },
subjectStatus: 'active',
secretDigest: 'a'.repeat(64),
createdAtMs: mutation.createdAtMs,
notBeforeAtMs: 100,
expiresAtMs: 1000,
...overrides.credential,
};
return {
expectedCurrentVersion: 0,
credential,
mutation,
audit: {
eventId: mutation.mutationId,
requestId: 'request-credential-issue',
operationId: `credential.${mutation.operation}`,
projectId: null,
subject: mutation.changedBy,
authenticationId: 'admin:usr_admin:1',
outcome: 'allowed',
reasons: ['credential_admin'],
fence: null,
occurredAtMs: mutation.createdAtMs,
...overrides.audit,
},
...overrides.command,
};
}
test('normalizes one atomic credential issue and audit command', () => {
const normalized = normalizeAppendApiCredentialCommand(command());
assert.equal(normalized.credential.version, 1);
assert.equal(normalized.mutation.operation, 'issue');
assert.equal(Object.isFrozen(normalized.credential), true);
});
test('normalizes a revoke without retaining the previous digest', () => {
const input = command({
mutation: {
mutationId: '123e4567-e89b-42d3-a456-426614174212',
operation: 'revoke',
credentialVersion: 3,
expectedPreviousVersion: 2,
createdAtMs: 500,
},
credential: {
version: 3,
state: 'revoked',
secretDigest: REVOKED_API_CREDENTIAL_DIGEST,
createdAtMs: 500,
notBeforeAtMs: 500,
expiresAtMs: 501,
},
command: { expectedCurrentVersion: 2 },
});
assert.equal(
normalizeAppendApiCredentialCommand(input).credential.secretDigest,
REVOKED_API_CREDENTIAL_DIGEST,
);
});
test('rejects unfenced, secret-retaining and audit-drifted mutations', () => {
for (const input of [
command({ mutation: { credentialVersion: 2 } }),
command({ mutation: { changedBy: { type: 'agent', id: 'agent-1' } } }),
command({ credential: { state: 'revoked' } }),
command({ audit: { operationId: 'credential.rotate' } }),
command({ command: { unexpected: true } }),
]) {
assert.throws(
() => normalizeAppendApiCredentialCommand(input),
InvalidApiCredentialAdministrationValueError,
);
}
});
@@ -0,0 +1,34 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidApiCredentialTokenValueError,
apiCredentialSecretDigest,
assertApiCredentialPepper,
formatApiCredentialToken,
} = require('@qinglong/runtime-core/api-credential-token');
test('derives one domain-separated digest and formats the canonical token', () => {
const pepper = Buffer.alloc(32, 1).toString('base64url');
const secret = Buffer.alloc(32, 2).toString('base64url');
assert.doesNotThrow(() => assertApiCredentialPepper(pepper));
assert.equal(
apiCredentialSecretDigest(pepper, 'app_primary', secret),
'e15b6ff4b2ab5037c149974e6bd788eca4777e4d698f649373d39244555d4991',
);
assert.equal(
formatApiCredentialToken('app_primary', secret),
`ql3c_app_primary_${secret}`,
);
});
test('rejects weak, non-canonical and widened token material', () => {
const canonical = Buffer.alloc(32, 1).toString('base64url');
for (const action of [
() => assertApiCredentialPepper('weak'),
() => apiCredentialSecretDigest(canonical, '../escape', canonical),
() => apiCredentialSecretDigest(canonical, 'valid', `${canonical}=`),
() => formatApiCredentialToken('valid', 'weak'),
]) {
assert.throws(action, InvalidApiCredentialTokenValueError);
}
});
@@ -0,0 +1,163 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
ApprovalDecisionAuthorizationError,
ApprovalDecisionBindingConflictError,
ApprovalDecisionTargetUnavailableError,
createApprovalDecisionService,
} = require('@qinglong/runtime-core/approval-decision');
const {
createApprovalRequest,
decideApprovalRequest,
} = require('@qinglong/runtime-core/approved-action');
const FENCE = Object.freeze({ projectVersion: 1, bindingVersion: 2 });
const ACTION = Object.freeze({
permission: 'run.start',
actionType: 'tool.invoke',
actionRef: 'tool:run-task-1',
actionDigest: 'a'.repeat(64),
previewDigest: 'b'.repeat(64),
});
const PRINCIPAL = Object.freeze({
subject: Object.freeze({ type: 'user', id: 'owner-1' }),
authenticationId: 'local-approval:auth-1',
authenticatedAtMs: 1_500,
expiresAtMs: 20_000,
assurance: 'local_console',
});
function pending(overrides = {}) {
return createApprovalRequest({
id: 'approval-1',
projectId: 'default',
action: ACTION,
risk: 'high',
decisionMode: 'human_confirmation',
requestedBy: { type: 'agent', id: 'agent-1' },
requestedAtMs: 1_000,
expiresAtMs: 10_000,
requestFence: FENCE,
...overrides,
});
}
function command(overrides = {}) {
return {
projectId: 'default',
approvalRequestId: 'approval-1',
expectedVersion: 1,
expectedAction: ACTION,
decisionId: 'decision-1',
decision: 'approved',
reasonCode: 'reviewed',
auditEventId: '10000000-0000-4000-8000-000000000001',
requestId: 'owner-command-1',
principal: PRINCIPAL,
...overrides,
};
}
function fixture(current = pending()) {
let stored = current;
let decideCalls = 0;
let confirmCalls = 0;
let captured;
const service = createApprovalDecisionService({
approvals: {
async findById(id) {
return id === stored.id ? stored : null;
},
async decide(value) {
decideCalls += 1;
captured = value;
const { requestId: _requestId, audit: _audit, ...decision } = value;
stored = decideApprovalRequest(stored, decision);
return { status: 'decided', request: stored };
},
},
policy: {
async authorize(principal, projectId, permission) {
assert.deepEqual(principal, PRINCIPAL);
assert.ok(projectId === 'default' || projectId === 'other');
assert.equal(permission, 'approval.decide');
return { effect: 'allow', reasons: ['role_grant'], fence: FENCE };
},
},
async confirmAuthorization() {
confirmCalls += 1;
},
now: () => 2_000,
});
return {
service,
state: () => ({ stored, decideCalls, confirmCalls, captured }),
};
}
test('binds a human decision to the exact reviewed action and durable audit', async () => {
const { service, state } = fixture();
const result = await service.decide(command());
assert.equal(result.status, 'decided');
assert.equal(result.request.state, 'approved');
assert.equal(state().decideCalls, 1);
assert.equal(state().confirmCalls, 1);
assert.deepEqual(state().captured.audit, {
eventId: '10000000-0000-4000-8000-000000000001',
requestId: 'owner-command-1',
operationId: 'approval.decide',
projectId: 'default',
subject: PRINCIPAL.subject,
authenticationId: PRINCIPAL.authenticationId,
outcome: 'allowed',
reasons: ['human_approval_decision'],
fence: FENCE,
occurredAtMs: 2_000,
});
});
test('returns an idempotent receipt without a second mutation', async () => {
const first = fixture();
await first.service.decide(command());
const replay = fixture(first.state().stored);
const result = await replay.service.decide(command({
auditEventId: '10000000-0000-4000-8000-000000000002',
requestId: 'owner-command-retry',
}));
assert.equal(result.status, 'existing');
assert.equal(replay.state().decideCalls, 0);
assert.equal(replay.state().confirmCalls, 1);
});
test('rejects binding drift and masks absent or cross-project targets', async () => {
const { service, state } = fixture();
await assert.rejects(
service.decide(command({
expectedAction: { ...ACTION, previewDigest: 'c'.repeat(64) },
})),
ApprovalDecisionBindingConflictError,
);
assert.equal(state().decideCalls, 0);
await assert.rejects(
service.decide(command({ projectId: 'other' })),
ApprovalDecisionTargetUnavailableError,
);
});
test('requires a strongly authenticated User even when policy allows', async () => {
const { service } = fixture();
for (const principal of [
{ ...PRINCIPAL, assurance: 'single_factor' },
{
...PRINCIPAL,
subject: { type: 'agent', id: 'agent-1' },
assurance: 'hardware',
},
]) {
await assert.rejects(
service.decide(command({ principal })),
ApprovalDecisionAuthorizationError,
);
}
});
@@ -0,0 +1,135 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
createApprovalRequest,
decideApprovalRequest,
} = require('@qinglong/runtime-core/approved-action');
const {
MAX_APPROVAL_REQUEST_PAGE_SIZE,
MAX_APPROVAL_DETAIL_PREVIEW_BYTES,
InvalidApprovalDiscoveryValueError,
approvalRequestUpdatedAtMs,
assertApprovalDiscoveryProjectId,
assertApprovalDiscoveryRequestId,
assertApprovalRequestPageSize,
normalizeApprovalRequestCursor,
normalizeApprovalDetailPreview,
} = require('@qinglong/runtime-core/approval-discovery');
function pending() {
return createApprovalRequest({
id: 'approval-1',
projectId: 'default',
action: {
permission: 'run.start',
actionType: 'tool.invoke',
actionRef: 'tool:run.start',
actionDigest: 'a'.repeat(64),
previewDigest: 'b'.repeat(64),
},
risk: 'medium',
decisionMode: 'human_confirmation',
requestedBy: { type: 'agent', id: 'agent-1' },
requestedAtMs: 10,
expiresAtMs: 1_000,
requestFence: { projectVersion: 1, bindingVersion: 1 },
});
}
test('bounds Approval discovery pages and exact keyset cursors', () => {
assert.equal(MAX_APPROVAL_REQUEST_PAGE_SIZE, 64);
assert.doesNotThrow(() => assertApprovalRequestPageSize(1));
assert.doesNotThrow(() => assertApprovalRequestPageSize(64));
for (const value of [0, 65, 1.5, Number.NaN]) {
assert.throws(
() => assertApprovalRequestPageSize(value),
InvalidApprovalDiscoveryValueError,
);
}
assert.deepEqual(
normalizeApprovalRequestCursor({ updatedAtMs: 20, requestId: 'approval-2' }),
{ updatedAtMs: 20, requestId: 'approval-2' },
);
for (const value of [
null,
{ updatedAtMs: -1, requestId: 'approval-2' },
{ updatedAtMs: 20, requestId: '' },
{ updatedAtMs: 20, requestId: 'approval-2', extra: true },
]) {
assert.throws(
() => normalizeApprovalRequestCursor(value),
InvalidApprovalDiscoveryValueError,
);
}
});
test('accepts bounded Project identifiers and rejects control data', () => {
assert.doesNotThrow(() => assertApprovalDiscoveryProjectId('default'));
assert.doesNotThrow(() => assertApprovalDiscoveryRequestId('approval-1'));
for (const value of ['', 'x'.repeat(129), 'project\nother']) {
assert.throws(
() => assertApprovalDiscoveryProjectId(value),
InvalidApprovalDiscoveryValueError,
);
}
for (const value of ['', 'x'.repeat(129), 'approval/other']) {
assert.throws(
() => assertApprovalDiscoveryRequestId(value),
InvalidApprovalDiscoveryValueError,
);
}
});
test('derives the sortable timestamp from the latest durable transition', () => {
const request = pending();
assert.equal(approvalRequestUpdatedAtMs(request), 10);
const approved = decideApprovalRequest(request, {
expectedVersion: 1,
decisionId: 'decision-1',
decision: 'approved',
reasonCode: 'reviewed',
principal: {
subject: { type: 'user', id: 'owner-1' },
authenticationId: 'auth-owner-1',
authenticatedAtMs: 15,
expiresAtMs: 100,
assurance: 'local_console',
},
decidedAtMs: 20,
authorizationFence: { projectVersion: 1, bindingVersion: 1 },
});
assert.equal(approvalRequestUpdatedAtMs(approved), 20);
});
test('normalizes only a bounded document-only Approval preview', () => {
assert.equal(MAX_APPROVAL_DETAIL_PREVIEW_BYTES, 8 * 1024);
assert.deepEqual(
normalizeApprovalDetailPreview({
title: 'Run task',
summary: 'Runs one task.',
fields: [{ kind: 'redacted', label: 'Token', value: null }],
warnings: ['external_effect'],
}),
{
title: 'Run task',
summary: 'Runs one task.',
fields: [{ kind: 'redacted', label: 'Token', value: null }],
warnings: ['external_effect'],
},
);
assert.throws(
() =>
normalizeApprovalDetailPreview({
title: 'x'.repeat(256),
summary: 'x'.repeat(2_048),
fields: Array.from({ length: 16 }, (_, index) => ({
kind: 'text',
label: `field-${index}-${'x'.repeat(110)}`,
value: 'x'.repeat(512),
})),
warnings: [],
}),
InvalidApprovalDiscoveryValueError,
);
});
@@ -0,0 +1,159 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
ApprovalInspectionAuthorizationError,
ApprovalInspectionUnavailableError,
createApprovalInspectionService,
} = require('@qinglong/runtime-core/approval-inspection');
const {
createApprovalRequest,
} = require('@qinglong/runtime-core/approved-action');
const FENCE = Object.freeze({ projectVersion: 3, bindingVersion: 7 });
const PRINCIPAL = Object.freeze({
subject: Object.freeze({ type: 'user', id: 'owner-1' }),
authenticationId: 'oidc:session-1',
authenticatedAtMs: 1_500,
expiresAtMs: 20_000,
assurance: 'hardware',
});
const REQUEST = Object.freeze({
projectId: 'default',
approvalRequestId: 'approval-1',
requestId: 'approval-inspect-1',
auditEventId: '30000000-0000-4000-8000-000000000001',
principal: PRINCIPAL,
});
function approval(overrides = {}) {
return createApprovalRequest({
id: 'approval-1',
projectId: 'default',
action: {
permission: 'run.start',
actionType: 'tool.invoke',
actionRef: 'tool:task-1',
actionDigest: 'a'.repeat(64),
previewDigest: 'b'.repeat(64),
},
risk: 'high',
decisionMode: 'human_confirmation',
requestedBy: { type: 'agent', id: 'agent-1' },
requestedAtMs: 1_000,
expiresAtMs: 10_000,
requestFence: FENCE,
...overrides,
});
}
function detail(request = approval()) {
return {
request,
preview: {
title: 'Run task',
summary: 'Runs one reviewed task.',
fields: [{ kind: 'identifier', label: 'Task', value: 'task-1' }],
warnings: ['external_effect'],
},
};
}
function fixture(overrides = {}) {
const audits = [];
const permissions = [];
let reads = 0;
let confirms = 0;
const service = createApprovalInspectionService({
source: {
async getApprovalRequestDetail(query) {
reads += 1;
assert.deepEqual(query, {
projectId: 'default',
requestId: 'approval-1',
});
return overrides.found === undefined ? detail() : overrides.found;
},
},
policy: {
async authorize(principal, projectId, permission) {
assert.deepEqual(principal, PRINCIPAL);
assert.equal(projectId, 'default');
permissions.push(permission);
const fence =
permission === 'artifact.read' && overrides.artifactFence
? overrides.artifactFence
: FENCE;
return { effect: 'allow', reasons: ['role_grant'], fence };
},
},
audit: {
async record(record) {
audits.push(record);
},
},
async confirmAuthorization() {
confirms += 1;
},
now: () => 2_000,
});
return {
service,
state: () => ({ audits, confirms, permissions: permissions.sort(), reads }),
};
}
test('requires dual current authority and audits one exact human inspection', async () => {
const value = fixture();
const result = await value.service.inspect(REQUEST);
assert.equal(result.request.id, 'approval-1');
assert.equal(result.preview.title, 'Run task');
assert.deepEqual(value.state().permissions, ['approval.read', 'artifact.read']);
assert.equal(value.state().confirms, 1);
assert.equal(value.state().reads, 1);
assert.deepEqual(value.state().audits, [
{
eventId: REQUEST.auditEventId,
requestId: REQUEST.requestId,
operationId: 'approval.inspect',
projectId: 'default',
subject: PRINCIPAL.subject,
authenticationId: PRINCIPAL.authenticationId,
outcome: 'allowed',
reasons: ['human_approval_inspection'],
fence: FENCE,
occurredAtMs: 2_000,
},
]);
});
test('audits an absent target without revealing cross-Project existence', async () => {
const value = fixture({ found: null });
assert.equal(await value.service.inspect(REQUEST), null);
assert.equal(value.state().audits.length, 1);
assert.equal(value.state().audits[0].outcome, 'allowed');
});
test('rejects authorization fence drift before reading Approval content', async () => {
const value = fixture({
artifactFence: { projectVersion: 4, bindingVersion: 7 },
});
await assert.rejects(
value.service.inspect(REQUEST),
ApprovalInspectionAuthorizationError,
);
assert.equal(value.state().confirms, 0);
assert.equal(value.state().reads, 0);
assert.equal(value.state().audits.length, 0);
});
test('fails closed when storage returns an Approval outside the exact binding', async () => {
const value = fixture({
found: detail(approval({ id: 'approval-2' })),
});
await assert.rejects(
value.service.inspect(REQUEST),
ApprovalInspectionUnavailableError,
);
assert.equal(value.state().audits.length, 0);
});
@@ -0,0 +1,210 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
APPROVAL_REQUEST_SCHEMA,
APPROVED_ACTION_DISPATCH_SCHEMA,
ApprovalHumanDecisionRequiredError,
ApprovalMutationConflictError,
ApprovalRequestExpiredError,
ApprovalRequestVersionConflictError,
ApprovalSeparationOfDutyError,
InvalidApprovedActionValueError,
approvalRequestEffectiveStatus,
consumeApprovalRequest,
createApprovalRequest,
decideApprovalRequest,
normalizeApprovalRequestRecord,
normalizeApprovedActionDispatchRecord,
} = require('@qinglong/runtime-core/approved-action');
const DIGEST_A = 'a'.repeat(64);
const DIGEST_B = 'b'.repeat(64);
const REQUESTER = Object.freeze({ type: 'user', id: 'usr_owner' });
const REVIEWER = Object.freeze({ type: 'user', id: 'usr_reviewer' });
const SYSTEM = Object.freeze({ type: 'system', id: 'approved-dispatcher' });
const FENCE = Object.freeze({ projectVersion: 2, bindingVersion: 3 });
function action(overrides = {}) {
return {
permission: 'package.manage',
actionType: 'plugin_package.install',
actionRef: 'proposal:pkg-demo-v1',
actionDigest: DIGEST_A,
previewDigest: DIGEST_B,
...overrides,
};
}
function request(overrides = {}) {
return createApprovalRequest({
id: 'approval-1',
projectId: 'default',
action: action(),
risk: 'high',
decisionMode: 'human_confirmation',
requestedBy: REQUESTER,
requestedAtMs: 1_000,
expiresAtMs: 61_000,
requestFence: FENCE,
...overrides,
});
}
function principal(subject = REQUESTER, overrides = {}) {
return {
subject,
authenticationId: 'auth-step-up-1',
authenticatedAtMs: 1_500,
expiresAtMs: 10_000,
assurance: 'local_console',
...overrides,
};
}
function approve(current, overrides = {}) {
return decideApprovalRequest(current, {
expectedVersion: 1,
decisionId: 'decision-1',
decision: 'approved',
reasonCode: 'reviewed',
principal: principal(),
decidedAtMs: 2_000,
authorizationFence: FENCE,
...overrides,
});
}
function consume(current, overrides = {}) {
return consumeApprovalRequest(current, {
expectedVersion: 2,
consumptionId: 'consume-1',
dispatchId: 'dispatch-1',
action: action(),
requestedBy: REQUESTER,
consumedBy: SYSTEM,
consumedAtMs: 3_000,
authorizationFence: FENCE,
...overrides,
});
}
test('builds a digest-bound request and reports pending expiry without mutation', () => {
const created = request();
assert.equal(created.schema, APPROVAL_REQUEST_SCHEMA);
assert.equal(created.version, 1);
assert.equal(created.state, 'pending');
assert.equal(created.action.permission, 'package.manage');
assert.equal(approvalRequestEffectiveStatus(created, 60_999), 'pending');
assert.equal(approvalRequestEffectiveStatus(created, 61_000), 'expired');
assert.equal(created.state, 'pending');
assert.throws(
() => request({ expiresAtMs: 1_000 + 24 * 60 * 60 * 1_000 + 1 }),
InvalidApprovedActionValueError,
);
});
test('allows strong same-user confirmation for owner-only edge deployments', () => {
const decided = approve(request());
assert.equal(decided.version, 2);
assert.equal(decided.state, 'approved');
assert.deepEqual(decided.decidedBy, REQUESTER);
assert.equal(decided.decisionAssurance, 'local_console');
const result = consume(decided);
assert.equal(result.request.version, 3);
assert.equal(result.request.state, 'consumed');
assert.equal(result.dispatch.schema, APPROVED_ACTION_DISPATCH_SCHEMA);
assert.equal(result.dispatch.approvalRequestVersion, 3);
assert.equal(result.dispatch.action.actionDigest, DIGEST_A);
assert.equal(result.dispatch.approvedBy.id, REQUESTER.id);
assert.deepEqual(result.dispatch.approvalFence, FENCE);
assert.deepEqual(
normalizeApprovedActionDispatchRecord(result.dispatch),
result.dispatch,
);
});
test('enforces separation of duty when the project ceremony requests it', () => {
const separated = request({ decisionMode: 'separation_of_duty' });
assert.throws(() => approve(separated), ApprovalSeparationOfDutyError);
const decided = approve(separated, {
principal: principal(REVIEWER, {
authenticationId: 'auth-reviewer-1',
assurance: 'multi_factor',
}),
});
assert.equal(decided.decidedBy.id, REVIEWER.id);
assert.equal(decided.decisionAssurance, 'multi_factor');
});
test('rejects weak, service and expired human decision principals', () => {
for (const candidate of [
principal(REQUESTER, { assurance: 'single_factor' }),
principal(
{ type: 'system', id: 'not-human' },
{ assurance: 'service' },
),
principal(REQUESTER, { expiresAtMs: 2_000 }),
]) {
assert.throws(
() => approve(request(), { principal: candidate }),
ApprovalHumanDecisionRequiredError,
);
}
});
test('provides exact decision and consumption replay while rejecting drift', () => {
const decided = approve(request());
assert.deepEqual(approve(decided), decided);
assert.throws(
() => approve(decided, { reasonCode: 'changed' }),
ApprovalMutationConflictError,
);
const consumed = consume(decided);
const replay = consume(consumed.request);
assert.deepEqual(replay, consumed);
assert.throws(
() =>
consume(consumed.request, {
action: action({ previewDigest: 'c'.repeat(64) }),
}),
ApprovalMutationConflictError,
);
});
test('fails closed on expiry, stale versions and corrupt persisted tuples', () => {
assert.throws(
() =>
approve(request(), {
decidedAtMs: 61_000,
principal: principal(REQUESTER, { expiresAtMs: 70_000 }),
}),
ApprovalRequestExpiredError,
);
assert.throws(
() => approve(request(), { expectedVersion: 2 }),
ApprovalRequestVersionConflictError,
);
const decided = approve(request());
assert.throws(
() => consume(decided, { consumedAtMs: 61_000 }),
ApprovalRequestExpiredError,
);
assert.throws(
() =>
normalizeApprovalRequestRecord({
...decided,
decisionAuthenticationId: null,
}),
InvalidApprovedActionValueError,
);
assert.throws(
() =>
normalizeApprovedActionDispatchRecord({
...consume(decided).dispatch,
unexpected: true,
}),
InvalidApprovedActionValueError,
);
});
@@ -0,0 +1,304 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
consumeApprovalRequest,
createApprovalRequest,
decideApprovalRequest,
} = require('@qinglong/runtime-core/approved-action');
const {
approvedActionExecutionEffectiveStatus,
claimApprovedActionExecution,
completeApprovedActionExecution,
createApprovedActionExecution,
releaseApprovedActionExecutionBeforeStart,
startApprovedActionExecution,
} = require('@qinglong/runtime-core/approved-action-execution');
const {
ApprovedActionDispatcher,
} = require('@qinglong/runtime-core/approved-action-dispatcher');
const REQUESTER = Object.freeze({ type: 'user', id: 'usr_owner' });
const DISPATCHER = Object.freeze({ type: 'system', id: 'dispatcher' });
const FENCE = Object.freeze({ projectVersion: 1, bindingVersion: 1 });
const ACTION_DIGEST = 'a'.repeat(64);
const RESULT_DIGEST = 'c'.repeat(64);
function dispatch() {
const pending = createApprovalRequest({
id: 'approval-dispatcher-v1',
projectId: 'default',
action: {
permission: 'package.manage',
actionType: 'plugin_package.install',
actionRef: 'proposal:dispatcher-v1',
actionDigest: ACTION_DIGEST,
previewDigest: 'b'.repeat(64),
},
risk: 'high',
decisionMode: 'human_confirmation',
requestedBy: REQUESTER,
requestedAtMs: 10,
expiresAtMs: 10_000,
requestFence: FENCE,
});
const approved = decideApprovalRequest(pending, {
expectedVersion: 1,
decisionId: 'decision-dispatcher-v1',
decision: 'approved',
reasonCode: 'reviewed',
principal: {
subject: REQUESTER,
authenticationId: 'auth-owner',
authenticatedAtMs: 15,
expiresAtMs: 5_000,
assurance: 'local_console',
},
decidedAtMs: 20,
authorizationFence: FENCE,
});
return consumeApprovalRequest(approved, {
expectedVersion: 2,
consumptionId: 'consume-dispatcher-v1',
dispatchId: 'dispatch-dispatcher-v1',
action: pending.action,
requestedBy: REQUESTER,
consumedBy: DISPATCHER,
consumedAtMs: 30,
authorizationFence: FENCE,
}).dispatch;
}
class InMemoryExecutionRepository {
constructor(value, options = {}) {
this.dispatch = value;
this.execution = createApprovedActionExecution(value);
this.loseStartResponse = options.loseStartResponse === true;
this.loseCompletionResponse = options.loseCompletionResponse === true;
this.startCalls = 0;
this.completeCalls = 0;
}
snapshot() {
return Object.freeze({
dispatch: this.dispatch,
execution: this.execution,
});
}
async findExecutionByDispatchId(dispatchId) {
return dispatchId === this.dispatch.id ? this.snapshot() : null;
}
async listDueExecutions({ nowMs, limit, actionTypes }) {
const effective = approvedActionExecutionEffectiveStatus(
this.execution,
nowMs,
);
const due =
(effective === 'pending' || effective === 'retry_wait') &&
this.execution.eligibleAtMs <= nowMs &&
actionTypes.includes(this.dispatch.action.actionType);
return {
executions: due && limit > 0 ? [this.snapshot()] : [],
truncated: false,
};
}
async claimExecution(command) {
if (command.dispatchId !== this.dispatch.id) return { status: 'not_found' };
const effective = approvedActionExecutionEffectiveStatus(
this.execution,
command.nowMs,
);
if (effective !== 'pending' && effective !== 'retry_wait') {
return { status: effective, snapshot: this.snapshot() };
}
this.execution = claimApprovedActionExecution(this.execution, {
owner: command.owner,
leaseToken: command.leaseToken,
nowMs: command.nowMs,
leaseDurationMs: command.leaseDurationMs,
});
return { status: 'claimed', snapshot: this.snapshot() };
}
async startExecution(command) {
this.startCalls += 1;
this.execution = startApprovedActionExecution(this.snapshot(), command);
if (this.loseStartResponse) throw new Error('start response lost');
return this.snapshot();
}
async renewExecution() {
throw new Error('dispatcher must not renew after start');
}
async releaseExecutionBeforeStart(command) {
this.execution = releaseApprovedActionExecutionBeforeStart(
this.execution,
{
owner: command.owner,
leaseToken: command.leaseToken,
expectedVersion: command.expectedVersion,
resultMutationId: command.resultMutationId,
resultCode: command.resultCode,
atMs: command.atMs,
...(command.retryAtMs === undefined
? {}
: { retryAtMs: command.retryAtMs }),
},
);
return this.snapshot();
}
async completeExecution(command) {
this.completeCalls += 1;
this.execution = completeApprovedActionExecution(this.execution, {
owner: command.owner,
leaseToken: command.leaseToken,
expectedVersion: command.expectedVersion,
resultMutationId: command.resultMutationId,
outcome: command.outcome,
resultCode: command.resultCode,
...(command.resultDigest === undefined
? {}
: { resultDigest: command.resultDigest }),
completedAtMs: command.completedAtMs,
});
if (this.loseCompletionResponse) {
throw new Error('completion response lost');
}
return this.snapshot();
}
}
function createDispatcher(repository, handler) {
let id = 0;
return new ApprovedActionDispatcher(repository, [handler], {
owner: 'dispatcher_instance_1',
leaseDurationMs: 1_000,
retryBaseMs: 100,
retryMaxMs: 1_000,
defaultBatchSize: 1,
clock: () => 100,
createId: () => `dispatcher-id-${++id}`,
});
}
test('commits the start barrier before executing and completes one success', async () => {
const repository = new InMemoryExecutionRepository(dispatch());
let observed;
const dispatcher = createDispatcher(repository, {
actionType: 'plugin_package.install',
async inspect(value) {
return { status: 'ready', actionDigest: value.action.actionDigest };
},
async execute(context) {
observed = context;
return {
outcome: 'succeeded',
resultCode: 'package_admitted',
resultDigest: RESULT_DIGEST,
};
},
});
const summary = await dispatcher.dispatchBatch();
assert.deepEqual(summary, {
scanned: 1,
claimed: 1,
started: 1,
succeeded: 1,
failed: 0,
blocked: 0,
retrying: 0,
deferred: 0,
recoveryRequired: 0,
alreadyTerminal: 0,
unavailable: 0,
truncated: false,
});
assert.equal(observed.execution.status, 'executing');
assert.equal(observed.execution.version, observed.fence.version);
assert.equal(repository.execution.status, 'succeeded');
assert.equal(repository.execution.resultDigest, RESULT_DIGEST);
});
test('retries inspection only before start and blocks an exception after start', async () => {
const retryRepository = new InMemoryExecutionRepository(dispatch());
const retrying = await createDispatcher(retryRepository, {
actionType: 'plugin_package.install',
async inspect() {
return { status: 'retry', resultCode: 'proposal_unavailable' };
},
async execute() {
throw new Error('must not execute');
},
}).dispatchBatch();
assert.equal(retrying.retrying, 1);
assert.equal(retrying.started, 0);
assert.equal(retryRepository.execution.status, 'retry_wait');
const blockedRepository = new InMemoryExecutionRepository(dispatch());
const blocked = await createDispatcher(blockedRepository, {
actionType: 'plugin_package.install',
async inspect() {
return { status: 'ready', actionDigest: ACTION_DIGEST };
},
async execute() {
throw new Error('outcome is indeterminate');
},
}).dispatchBatch();
assert.equal(blocked.started, 1);
assert.equal(blocked.blocked, 1);
assert.equal(blocked.retrying, 0);
assert.equal(blockedRepository.execution.status, 'blocked');
assert.equal(
blockedRepository.execution.resultCode,
'handler_failed_after_start',
);
});
test('converges lost start and completion responses without repeating effects', async () => {
const repository = new InMemoryExecutionRepository(dispatch(), {
loseStartResponse: true,
loseCompletionResponse: true,
});
let effects = 0;
const summary = await createDispatcher(repository, {
actionType: 'plugin_package.install',
async inspect() {
return { status: 'ready', actionDigest: ACTION_DIGEST };
},
async execute() {
effects += 1;
return {
outcome: 'succeeded',
resultCode: 'package_admitted',
resultDigest: RESULT_DIGEST,
};
},
}).dispatchBatch();
assert.equal(summary.succeeded, 1);
assert.equal(summary.unavailable, 0);
assert.equal(repository.startCalls, 1);
assert.equal(repository.completeCalls, 1);
assert.equal(effects, 1);
});
test('does not claim an action without a matching handler', async () => {
const repository = new InMemoryExecutionRepository(dispatch());
let id = 0;
const dispatcher = new ApprovedActionDispatcher(repository, [], {
owner: 'dispatcher_instance_1',
clock: () => 100,
createId: () => `dispatcher-id-${++id}`,
});
const summary = await dispatcher.dispatchBatch({ limit: 1 });
assert.equal(summary.scanned, 0);
assert.equal(summary.claimed, 0);
assert.equal(summary.blocked, 0);
assert.equal(summary.started, 0);
assert.equal(repository.execution.status, 'pending');
assert.equal(repository.startCalls, 0);
});
@@ -0,0 +1,232 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
consumeApprovalRequest,
createApprovalRequest,
decideApprovalRequest,
} = require('@qinglong/runtime-core/approved-action');
const {
ApprovedActionExecutionFenceConflictError,
InvalidApprovedActionExecutionError,
approvedActionExecutionEffectiveStatus,
claimApprovedActionExecution,
completeApprovedActionExecution,
createApprovedActionExecution,
normalizeApprovedActionExecutionRecord,
normalizeApprovedActionExecutionSnapshot,
releaseApprovedActionExecutionBeforeStart,
startApprovedActionExecution,
} = require('@qinglong/runtime-core/approved-action-execution');
const REQUESTER = Object.freeze({ type: 'user', id: 'usr_owner' });
const SYSTEM = Object.freeze({ type: 'system', id: 'package_dispatcher' });
const FENCE = Object.freeze({ projectVersion: 1, bindingVersion: 1 });
function dispatch() {
const action = {
permission: 'package.manage',
actionType: 'plugin_package.install',
actionRef: 'proposal:monitor-v1',
actionDigest: 'a'.repeat(64),
previewDigest: 'b'.repeat(64),
};
const pending = createApprovalRequest({
id: 'approval-monitor-v1',
projectId: 'default',
action,
risk: 'high',
decisionMode: 'human_confirmation',
requestedBy: REQUESTER,
requestedAtMs: 10,
expiresAtMs: 10_000,
requestFence: FENCE,
});
const approved = decideApprovalRequest(pending, {
expectedVersion: 1,
decisionId: 'decision-monitor-v1',
decision: 'approved',
reasonCode: 'reviewed',
principal: {
subject: REQUESTER,
authenticationId: 'auth-owner-step-up',
authenticatedAtMs: 15,
expiresAtMs: 5_000,
assurance: 'local_console',
},
decidedAtMs: 20,
authorizationFence: FENCE,
});
return consumeApprovalRequest(approved, {
expectedVersion: 2,
consumptionId: 'consume-monitor-v1',
dispatchId: 'dispatch-monitor-v1',
action,
requestedBy: REQUESTER,
consumedBy: SYSTEM,
consumedAtMs: 30,
authorizationFence: FENCE,
}).dispatch;
}
test('persists a pending baseline before claim and a durable start barrier before success', () => {
const approvedDispatch = dispatch();
const pending = createApprovedActionExecution(approvedDispatch);
assert.equal(pending.status, 'pending');
assert.equal(pending.version, 0);
assert.equal(pending.eligibleAtMs, approvedDispatch.createdAtMs);
assert.deepEqual(
normalizeApprovedActionExecutionSnapshot({
dispatch: approvedDispatch,
execution: pending,
}).execution,
pending,
);
const leased = claimApprovedActionExecution(pending, {
owner: 'admin-1',
leaseToken: 'lease-1',
nowMs: 40,
leaseDurationMs: 1_000,
});
assert.equal(leased.status, 'leased');
assert.equal(leased.attemptCount, 1);
const executing = startApprovedActionExecution(
{ dispatch: approvedDispatch, execution: leased },
{
dispatchId: approvedDispatch.id,
approvalRequestId: approvedDispatch.approvalRequestId,
actionDigest: approvedDispatch.action.actionDigest,
owner: 'admin-1',
leaseToken: 'lease-1',
expectedVersion: leased.version,
startedAtMs: 50,
},
);
assert.equal(executing.status, 'executing');
assert.equal(executing.startedAtMs, 50);
const succeeded = completeApprovedActionExecution(executing, {
owner: 'admin-1',
leaseToken: 'lease-1',
expectedVersion: executing.version,
resultMutationId: 'complete-1',
outcome: 'succeeded',
resultCode: 'package_admitted',
resultDigest: 'c'.repeat(64),
completedAtMs: 1_100,
});
assert.equal(succeeded.status, 'succeeded');
assert.equal(succeeded.resultDigest, 'c'.repeat(64));
assert.deepEqual(
normalizeApprovedActionExecutionRecord(succeeded),
succeeded,
);
});
test('never blindly takes over an execution after its start lease expires', () => {
const approvedDispatch = dispatch();
const leased = claimApprovedActionExecution(
createApprovedActionExecution(approvedDispatch),
{
owner: 'admin-1',
leaseToken: 'lease-1',
nowMs: 40,
leaseDurationMs: 100,
},
);
const executing = startApprovedActionExecution(
{ dispatch: approvedDispatch, execution: leased },
{
dispatchId: approvedDispatch.id,
approvalRequestId: approvedDispatch.approvalRequestId,
actionDigest: approvedDispatch.action.actionDigest,
owner: 'admin-1',
leaseToken: 'lease-1',
expectedVersion: leased.version,
startedAtMs: 50,
},
);
assert.equal(
approvedActionExecutionEffectiveStatus(executing, 140),
'recovery_required',
);
assert.throws(
() =>
claimApprovedActionExecution(executing, {
owner: 'admin-2',
leaseToken: 'lease-2',
nowMs: 140,
leaseDurationMs: 100,
}),
{ code: 'APPROVED_ACTION_EXECUTION_STATE_CONFLICT' },
);
});
test('retries only before start and blocks on exhausted or indeterminate work', () => {
const approvedDispatch = dispatch();
const leased = claimApprovedActionExecution(
createApprovedActionExecution(approvedDispatch, 2),
{
owner: 'admin-1',
leaseToken: 'lease-1',
nowMs: 40,
leaseDurationMs: 100,
},
);
const retrying = releaseApprovedActionExecutionBeforeStart(leased, {
owner: 'admin-1',
leaseToken: 'lease-1',
expectedVersion: leased.version,
resultMutationId: 'release-1',
resultCode: 'proposal_unavailable',
atMs: 50,
retryAtMs: 70,
});
assert.equal(retrying.status, 'retry_wait');
const finalLease = claimApprovedActionExecution(retrying, {
owner: 'admin-2',
leaseToken: 'lease-2',
nowMs: 70,
leaseDurationMs: 100,
});
const blocked = releaseApprovedActionExecutionBeforeStart(finalLease, {
owner: 'admin-2',
leaseToken: 'lease-2',
expectedVersion: finalLease.version,
resultMutationId: 'release-2',
resultCode: 'proposal_unavailable',
atMs: 80,
retryAtMs: 90,
});
assert.equal(blocked.status, 'blocked');
assert.equal(blocked.startedAtMs, null);
assert.throws(
() =>
completeApprovedActionExecution(finalLease, {
owner: 'admin-2',
leaseToken: 'lease-2',
expectedVersion: finalLease.version,
resultMutationId: 'complete-2',
outcome: 'succeeded',
resultCode: 'package_admitted',
completedAtMs: 90,
}),
ApprovedActionExecutionFenceConflictError,
);
});
test('detects persisted execution digest drift', () => {
const record = createApprovedActionExecution(dispatch());
assert.throws(
() =>
normalizeApprovedActionExecutionRecord({
...record,
maxAttempts: record.maxAttempts + 1,
}),
InvalidApprovedActionExecutionError,
);
});
@@ -0,0 +1,133 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidTaskDefinitionAdministrationReadError,
normalizeAuthorizedTaskDefinitionInspection,
normalizeAuthorizedTaskDefinitionList,
} = require('@qinglong/runtime-core/task-definition-administration');
const {
InvalidTriggerAdministrationReadError,
normalizeAuthorizedTriggerInspection,
normalizeAuthorizedTriggerList,
} = require('@qinglong/runtime-core/trigger-administration');
const actor = Object.freeze({ type: 'user', id: 'operator-a' });
const fence = Object.freeze({ projectVersion: 3, bindingVersion: 5 });
function audit(operationId, eventId) {
return Object.freeze({
eventId,
requestId: `request-${operationId}`,
operationId,
projectId: 'project-a',
subject: actor,
authenticationId: 'oidc:automation-session',
outcome: 'allowed',
reasons: Object.freeze(['role_grant']),
fence,
occurredAtMs: 1_000,
});
}
test('normalizes exact Task inspection and bounded keyset list authority', () => {
assert.deepEqual(
normalizeAuthorizedTaskDefinitionInspection({
projectId: 'project-a',
taskId: 'task-a',
actor,
fence,
audit: audit('task.read', '123e4567-e89b-42d3-a456-426614174010'),
}),
{
projectId: 'project-a',
taskId: 'task-a',
actor,
fence,
audit: audit('task.read', '123e4567-e89b-42d3-a456-426614174010'),
},
);
const list = normalizeAuthorizedTaskDefinitionList({
projectId: 'project-a',
limit: 2,
after: { taskId: 'task-0' },
actor,
fence,
audit: audit('task.read', '123e4567-e89b-42d3-a456-426614174011'),
});
assert.deepEqual(list.after, { taskId: 'task-0' });
assert.equal(Object.isFrozen(list), true);
assert.throws(
() =>
normalizeAuthorizedTaskDefinitionList({
projectId: 'project-a',
limit: 257,
actor,
fence,
audit: audit('task.read', '123e4567-e89b-42d3-a456-426614174012'),
}),
InvalidTaskDefinitionAdministrationReadError,
);
});
test('rejects Task read audit or actor drift before storage', () => {
assert.throws(
() =>
normalizeAuthorizedTaskDefinitionInspection({
projectId: 'project-a',
taskId: 'task-a',
actor,
fence,
audit: {
...audit('trigger.read', '123e4567-e89b-42d3-a456-426614174013'),
subject: { type: 'user', id: 'operator-b' },
},
}),
InvalidTaskDefinitionAdministrationReadError,
);
});
test('normalizes exact Trigger inspection and bounded keyset list authority', () => {
const inspection = normalizeAuthorizedTriggerInspection({
projectId: 'project-a',
triggerId: 'trigger-a',
actor,
fence,
audit: audit('trigger.read', '123e4567-e89b-42d3-a456-426614174014'),
});
assert.equal(inspection.triggerId, 'trigger-a');
const list = normalizeAuthorizedTriggerList({
projectId: 'project-a',
limit: 1,
after: { triggerId: 'trigger-0' },
actor,
fence,
audit: audit('trigger.read', '123e4567-e89b-42d3-a456-426614174015'),
});
assert.deepEqual(list.after, { triggerId: 'trigger-0' });
assert.throws(
() =>
normalizeAuthorizedTriggerList({
...list,
extra: true,
}),
InvalidTriggerAdministrationReadError,
);
});
test('rejects Trigger read fence drift before storage', () => {
assert.throws(
() =>
normalizeAuthorizedTriggerInspection({
projectId: 'project-a',
triggerId: 'trigger-a',
actor,
fence,
audit: {
...audit('trigger.read', '123e4567-e89b-42d3-a456-426614174016'),
fence: { projectVersion: 4, bindingVersion: 5 },
},
}),
InvalidTriggerAdministrationReadError,
);
});
@@ -0,0 +1,224 @@
const assert = require('node:assert/strict');
const { spawnSync } = require('node:child_process');
const path = require('node:path');
const { test } = require('node:test');
const {
BoundedRunEventListProjectionUnavailableError,
DEFAULT_BOUNDED_RUN_EVENT_LIST_LIMIT,
InvalidBoundedRunEventListProjectionError,
MAX_BOUNDED_RUN_EVENT_LIST_LIMIT,
executeBoundedRunEventListProjection,
} = require('../dist/run/projection/boundedRunEventListProjection.js');
function run(projectId = 'prj_default') {
return Object.freeze({ id: 'run-1', projectId });
}
function event(sequence, overrides = {}) {
return Object.freeze({
id: `event-${sequence}`,
runId: 'run-1',
sequence,
type: `run.event.${sequence}`,
dedupeKey: `private-dedupe-${sequence}`,
actorType: 'system',
actorId: 'private-actor',
payload: Object.freeze({ secret: 'must-not-cross-projection' }),
createdAtMs: 1_000 + sequence,
...overrides,
});
}
test('projects one bounded payload-free page and validates the sentinel row', async () => {
const calls = [];
const result = await executeBoundedRunEventListProjection(
{
async findRunById(runId) {
calls.push(['run', runId]);
return run();
},
async listEvents(runId, options) {
calls.push(['events', runId, options]);
return [event(3), event(5), event(8)];
},
},
'prj_default',
'run-1',
{ afterSequence: 2, limit: 2 },
);
assert.deepEqual(calls, [
['run', 'run-1'],
['events', 'run-1', { afterSequence: 2, limit: 3 }],
]);
assert.deepEqual(result, {
found: true,
events: [
{
sequence: 3,
type: 'run.event.3',
actorType: 'system',
createdAtMs: 1_003,
},
{
sequence: 5,
type: 'run.event.5',
actorType: 'system',
createdAtMs: 1_005,
},
],
hasMore: true,
nextAfterSequence: 5,
});
assert.equal(JSON.stringify(result).includes('private'), false);
assert.equal(JSON.stringify(result).includes('secret'), false);
});
test('uses default and maximum bounds and preserves an empty-page cursor', async () => {
const calls = [];
const reader = {
async findRunById() {
return run();
},
async listEvents(_runId, options) {
calls.push(options);
return [];
},
};
assert.deepEqual(
await executeBoundedRunEventListProjection(
reader,
'prj_default',
'run-1',
{},
),
{ found: true, events: [], hasMore: false, nextAfterSequence: 0 },
);
assert.deepEqual(
await executeBoundedRunEventListProjection(reader, 'prj_default', 'run-1', {
afterSequence: 7,
limit: MAX_BOUNDED_RUN_EVENT_LIST_LIMIT,
}),
{ found: true, events: [], hasMore: false, nextAfterSequence: 7 },
);
assert.deepEqual(calls, [
{ afterSequence: 0, limit: DEFAULT_BOUNDED_RUN_EVENT_LIST_LIMIT + 1 },
{ afterSequence: 7, limit: MAX_BOUNDED_RUN_EVENT_LIST_LIMIT + 1 },
]);
});
test('masks absence and Project mismatch without reading events', async () => {
for (const value of [null, run('prj_other')]) {
let reads = 0;
const result = await executeBoundedRunEventListProjection(
{
async findRunById() {
return value;
},
async listEvents() {
reads += 1;
return [];
},
},
'prj_default',
'run-1',
{ afterSequence: 7 },
);
assert.deepEqual(result, {
found: false,
events: [],
hasMore: false,
nextAfterSequence: 7,
});
assert.equal(reads, 0);
}
});
test('fails closed on invalid input, repository failure and corrupt ordering', async () => {
const reader = {
async findRunById() {
return run();
},
async listEvents() {
return [];
},
};
for (const input of [
null,
{ afterSequence: -1 },
{ limit: 0 },
{ limit: 65 },
{ extra: true },
]) {
await assert.rejects(
executeBoundedRunEventListProjection(
reader,
'prj_default',
'run-1',
input,
),
InvalidBoundedRunEventListProjectionError,
);
}
for (const rows of [
[event(2), event(1)],
[event(1), event(1)],
[event(1, { runId: 'run-other' })],
[event(1, { actorType: 'invented' })],
[event(1), event(2, { type: '' })],
]) {
await assert.rejects(
executeBoundedRunEventListProjection(
{
async findRunById() {
return run();
},
async listEvents() {
return rows;
},
},
'prj_default',
'run-1',
{ limit: 1 },
),
BoundedRunEventListProjectionUnavailableError,
);
}
await assert.rejects(
executeBoundedRunEventListProjection(
{
async findRunById() {
throw new Error('offline');
},
async listEvents() {
return [];
},
},
'prj_default',
'run-1',
{},
),
BoundedRunEventListProjectionUnavailableError,
);
});
test('leaf import does not load Tool Registry or SemVer', () => {
const entry = path.resolve(
__dirname,
'../dist/run/projection/boundedRunEventListProjection.js',
);
const result = spawnSync(
process.execPath,
[
'-e',
`require(${JSON.stringify(entry)});
const loaded = Object.keys(require.cache);
if (loaded.some((value) => /node_modules[\\\\/]semver(?:[\\\\/]|$)/.test(value))) process.exit(2);
if (loaded.some((value) => /tool-execution[\\\\/]tool-registry/.test(value))) process.exit(3);
process.stdout.write(String(loaded.length));`,
],
{ encoding: 'utf8' },
);
assert.equal(result.status, 0, result.stderr);
assert.ok(Number(result.stdout) <= 4);
});
@@ -0,0 +1,170 @@
const assert = require('node:assert/strict');
const { spawnSync } = require('node:child_process');
const path = require('node:path');
const { test } = require('node:test');
const {
BoundedRunListProjectionUnavailableError,
DEFAULT_BOUNDED_RUN_LIST_LIMIT,
InvalidBoundedRunListProjectionError,
MAX_BOUNDED_RUN_LIST_LIMIT,
executeBoundedRunListProjection,
} = require('../dist/run/projection/boundedRunListProjection.js');
function run(id, createdAtMs, overrides = {}) {
return Object.freeze({
id,
projectId: 'prj_default',
taskId: `task-${id}`,
taskRevision: 'revision-1',
triggerType: 'manual',
executionOrigin: 'manual',
executionOwner: 'runtime',
status: 'succeeded',
version: 2,
eventSequence: 3,
priority: 0,
createdAtMs,
finishedAtMs: createdAtMs + 1,
privateRef: 'must-not-cross-projection',
...overrides,
});
}
test('projects one descending bounded page and a stable keyset cursor', async () => {
const calls = [];
const result = await executeBoundedRunListProjection(
{
async listRunsByProject(query) {
calls.push(query);
return [run('run-c', 30), run('run-b', 20), run('run-a', 10)];
},
},
'prj_default',
{ limit: 2 },
);
assert.deepEqual(calls, [{ projectId: 'prj_default', limit: 3 }]);
assert.deepEqual(result, {
runs: [
{
id: 'run-c',
taskId: 'task-run-c',
taskRevision: 'revision-1',
status: 'succeeded',
version: 2,
eventSequence: 3,
priority: 0,
executionOrigin: 'manual',
executionOwner: 'runtime',
createdAtMs: 30,
finishedAtMs: 31,
},
{
id: 'run-b',
taskId: 'task-run-b',
taskRevision: 'revision-1',
status: 'succeeded',
version: 2,
eventSequence: 3,
priority: 0,
executionOrigin: 'manual',
executionOwner: 'runtime',
createdAtMs: 20,
finishedAtMs: 21,
},
],
hasMore: true,
next: { createdAtMs: 20, runId: 'run-b' },
});
assert.equal(JSON.stringify(result).includes('must-not-cross'), false);
});
test('uses default and maximum bounds and passes an exact cursor', async () => {
const seen = [];
const reader = {
async listRunsByProject(query) {
seen.push(query);
return [];
},
};
assert.deepEqual(
await executeBoundedRunListProjection(reader, 'prj_default', {}),
{ runs: [], hasMore: false },
);
assert.deepEqual(
await executeBoundedRunListProjection(reader, 'prj_default', {
limit: MAX_BOUNDED_RUN_LIST_LIMIT,
after: { createdAtMs: 20, runId: 'run-b' },
}),
{ runs: [], hasMore: false },
);
assert.deepEqual(seen, [
{ projectId: 'prj_default', limit: DEFAULT_BOUNDED_RUN_LIST_LIMIT + 1 },
{
projectId: 'prj_default',
limit: MAX_BOUNDED_RUN_LIST_LIMIT + 1,
after: { createdAtMs: 20, runId: 'run-b' },
},
]);
});
test('fails closed on malformed inputs, rows, ordering and repository failures', async () => {
const reader = { async listRunsByProject() { return []; } };
for (const input of [
null,
{ limit: 0 },
{ limit: 65 },
{ extra: true },
{ after: null },
{ after: { createdAtMs: -1, runId: 'run-a' } },
]) {
await assert.rejects(
executeBoundedRunListProjection(reader, 'prj_default', input),
InvalidBoundedRunListProjectionError,
);
}
for (const rows of [
[run('run-a', 10, { projectId: 'prj_other' })],
[run('run-a', 10), run('run-b', 20)],
[run('run-a', 10), run('run-a', 10)],
[run('run-a', 10, { status: 'invented' })],
]) {
await assert.rejects(
executeBoundedRunListProjection(
{ async listRunsByProject() { return rows; } },
'prj_default',
{},
),
BoundedRunListProjectionUnavailableError,
);
}
await assert.rejects(
executeBoundedRunListProjection(
{ async listRunsByProject() { throw new Error('offline'); } },
'prj_default',
{},
),
BoundedRunListProjectionUnavailableError,
);
});
test('leaf import does not load Tool Registry or SemVer', () => {
const entry = path.resolve(
__dirname,
'../dist/run/projection/boundedRunListProjection.js',
);
const result = spawnSync(
process.execPath,
[
'-e',
`require(${JSON.stringify(entry)});
const loaded = Object.keys(require.cache);
if (loaded.some((value) => /node_modules[\\\\/]semver(?:[\\\\/]|$)/.test(value))) process.exit(2);
if (loaded.some((value) => /tool-execution[\\\\/]tool-registry/.test(value))) process.exit(3);
process.stdout.write(String(loaded.length));`,
],
{ encoding: 'utf8' },
);
assert.equal(result.status, 0, result.stderr);
assert.ok(Number(result.stdout) <= 4);
});
@@ -0,0 +1,79 @@
const assert = require('node:assert/strict');
const { spawnSync } = require('node:child_process');
const path = require('node:path');
const { test } = require('node:test');
const {
BoundedRunReadProjectionUnavailableError,
executeBoundedRunReadProjection,
} = require('../dist/run/projection/boundedRunReadProjection.js');
function run(overrides = {}) {
return {
id: 'run_123',
projectId: 'prj_default',
taskId: 'task_1',
taskRevision: 'revision_7',
triggerType: 'manual',
executionOrigin: 'manual',
executionOwner: 'runtime',
status: 'running',
version: 0,
eventSequence: 2,
priority: 10,
createdAtMs: 1_000,
...overrides,
};
}
test('projects only bounded low-sensitive Run facts', async () => {
const projection = await executeBoundedRunReadProjection(
{ async findRunById() { return run({ privateValue: 'secret' }); } },
'prj_default',
'run_123',
);
assert.equal(projection.found, true);
assert.equal(projection.version, 0);
assert.equal(JSON.stringify(projection).includes('secret'), false);
});
test('collapses absence and project mismatch and rejects malformed repository facts', async () => {
for (const value of [null, run({ projectId: 'prj_other' })]) {
assert.deepEqual(
await executeBoundedRunReadProjection(
{ async findRunById() { return value; } },
'prj_default',
'run_123',
),
{ found: false },
);
}
await assert.rejects(
executeBoundedRunReadProjection(
{ async findRunById() { return run({ status: 'invented' }); } },
'prj_default',
'run_123',
),
BoundedRunReadProjectionUnavailableError,
);
});
test('leaf import does not load Tool Registry or SemVer', () => {
const entry = path.resolve(
__dirname,
'../dist/run/projection/boundedRunReadProjection.js',
);
const result = spawnSync(
process.execPath,
[
'-e',
`require(${JSON.stringify(entry)});
const loaded = Object.keys(require.cache);
if (loaded.some((value) => /node_modules[\\\\/]semver(?:[\\\\/]|$)/.test(value))) process.exit(2);
process.stdout.write(String(loaded.length));`,
],
{ encoding: 'utf8' },
);
assert.equal(result.status, 0, result.stderr);
assert.ok(Number(result.stdout) <= 4);
});
@@ -0,0 +1,282 @@
const assert = require('node:assert/strict');
const { spawnSync } = require('node:child_process');
const path = require('node:path');
const { test } = require('node:test');
const {
BoundedRunStepListProjectionUnavailableError,
DEFAULT_BOUNDED_RUN_STEP_LIST_LIMIT,
InvalidBoundedRunStepListProjectionError,
MAX_BOUNDED_RUN_STEP_LIST_LIMIT,
executeBoundedRunStepListProjection,
} = require('../dist/run/projection/boundedRunStepListProjection.js');
const { createStepRunRecord } = require('../dist/run/stepRun.js');
function run(projectId = 'prj_default') {
return Object.freeze({ id: 'run-1', projectId });
}
function step(id, stepKey, overrides = {}) {
return createStepRunRecord({
id,
runId: 'run-1',
parentStepRunId: 'step-parent',
stepKey,
kind: 'tool',
definitionRef: 'tool:private.internal@1.0.0',
definitionDigest: 'a'.repeat(64),
required: true,
initialStatus: 'ready',
inputRef: 'artifact:private-input',
mutationId: `create-${id}`,
createdAtMs: 1_000,
...overrides,
});
}
test('projects one bounded low-sensitive Step page and stable cursor', async () => {
const calls = [];
const first = step('step-1', 'build');
const second = step('step-2', 'deploy');
const result = await executeBoundedRunStepListProjection(
{
async findRunById(runId) {
calls.push(['run', runId]);
return run();
},
},
{
async listByRun(query) {
calls.push(['steps', query]);
return {
stepRuns: [first, second],
truncated: true,
next: { stepKey: second.stepKey, id: second.id },
};
},
},
'prj_default',
'run-1',
{ after: { stepKey: 'admit', stepRunId: 'step-0' }, limit: 2 },
);
assert.deepEqual(calls, [
['run', 'run-1'],
[
'steps',
{
runId: 'run-1',
limit: 2,
after: { stepKey: 'admit', id: 'step-0' },
},
],
]);
assert.deepEqual(result, {
found: true,
steps: [
{
id: 'step-1',
parentStepRunId: 'step-parent',
stepKey: 'build',
kind: 'tool',
required: true,
status: 'ready',
version: 1,
attemptCount: 0,
readyAtMs: 1_000,
startedAtMs: null,
finishedAtMs: null,
resultCode: null,
createdAtMs: 1_000,
updatedAtMs: 1_000,
},
{
id: 'step-2',
parentStepRunId: 'step-parent',
stepKey: 'deploy',
kind: 'tool',
required: true,
status: 'ready',
version: 1,
attemptCount: 0,
readyAtMs: 1_000,
startedAtMs: null,
finishedAtMs: null,
resultCode: null,
createdAtMs: 1_000,
updatedAtMs: 1_000,
},
],
hasMore: true,
next: { stepKey: 'deploy', stepRunId: 'step-2' },
});
const serialized = JSON.stringify(result);
for (const hidden of [
'definition',
'private-input',
'approvalRequestId',
'errorSummary',
'stepRunDigest',
]) {
assert.equal(serialized.includes(hidden), false);
}
});
test('uses default and maximum bounds and preserves an empty page', async () => {
const calls = [];
const stepRuns = {
async listByRun(query) {
calls.push(query);
return { stepRuns: [], truncated: false };
},
};
const runs = {
async findRunById() {
return run();
},
};
assert.deepEqual(
await executeBoundedRunStepListProjection(
runs,
stepRuns,
'prj_default',
'run-1',
{},
),
{ found: true, steps: [], hasMore: false, next: null },
);
await executeBoundedRunStepListProjection(
runs,
stepRuns,
'prj_default',
'run-1',
{ limit: MAX_BOUNDED_RUN_STEP_LIST_LIMIT },
);
assert.deepEqual(calls, [
{ runId: 'run-1', limit: DEFAULT_BOUNDED_RUN_STEP_LIST_LIMIT },
{ runId: 'run-1', limit: MAX_BOUNDED_RUN_STEP_LIST_LIMIT },
]);
});
test('masks absence and Project mismatch without reading StepRuns', async () => {
for (const value of [null, run('prj_other')]) {
let reads = 0;
const result = await executeBoundedRunStepListProjection(
{
async findRunById() {
return value;
},
},
{
async listByRun() {
reads += 1;
return { stepRuns: [], truncated: false };
},
},
'prj_default',
'run-1',
{},
);
assert.deepEqual(result, {
found: false,
steps: [],
hasMore: false,
next: null,
});
assert.equal(reads, 0);
}
});
test('fails closed on invalid input, repository failure and corrupt pages', async () => {
const runs = {
async findRunById() {
return run();
},
};
const empty = {
async listByRun() {
return { stepRuns: [], truncated: false };
},
};
for (const input of [
null,
{ limit: 0 },
{ limit: 65 },
{ after: { stepKey: 'build' } },
{ after: { stepKey: 'build', stepRunId: 'step-1', extra: true } },
{ extra: true },
]) {
await assert.rejects(
executeBoundedRunStepListProjection(
runs,
empty,
'prj_default',
'run-1',
input,
),
InvalidBoundedRunStepListProjectionError,
);
}
const duplicateStepKey = [step('step-1', 'build'), step('step-2', 'build')];
for (const page of [
{ stepRuns: duplicateStepKey, truncated: false },
{
stepRuns: [step('step-1', 'build')],
truncated: true,
next: { stepKey: 'other', id: 'step-1' },
},
{
stepRuns: [{ ...step('step-1', 'build'), status: 'succeeded' }],
truncated: false,
},
]) {
await assert.rejects(
executeBoundedRunStepListProjection(
runs,
{
async listByRun() {
return page;
},
},
'prj_default',
'run-1',
{ limit: 2 },
),
BoundedRunStepListProjectionUnavailableError,
);
}
await assert.rejects(
executeBoundedRunStepListProjection(
{
async findRunById() {
throw new Error('offline');
},
},
empty,
'prj_default',
'run-1',
{},
),
BoundedRunStepListProjectionUnavailableError,
);
});
test('leaf import does not load Tool Registry or SemVer', () => {
const entry = path.resolve(
__dirname,
'../dist/run/projection/boundedRunStepListProjection.js',
);
const result = spawnSync(
process.execPath,
[
'-e',
`require(${JSON.stringify(entry)});
const loaded = Object.keys(require.cache);
if (loaded.some((value) => /node_modules[\\/]semver(?:[\\/]|$)/.test(value))) process.exit(2);
if (loaded.some((value) => /tool-execution[\\/]tool-registry/.test(value))) process.exit(3);
process.stdout.write(String(loaded.length));`,
],
{ encoding: 'utf8' },
);
assert.equal(result.status, 0, result.stderr);
assert.ok(Number(result.stdout) <= 5);
});
@@ -0,0 +1,190 @@
const assert = require('node:assert/strict');
const { spawnSync } = require('node:child_process');
const path = require('node:path');
const { test } = require('node:test');
const {
BoundedTaskListProjectionUnavailableError,
DEFAULT_BOUNDED_TASK_LIST_LIMIT,
InvalidBoundedTaskListProjectionError,
MAX_BOUNDED_TASK_LIST_LIMIT,
executeBoundedTaskListProjection,
} = require('../dist/task-definition/projection/boundedTaskListProjection.js');
function task(taskId, overrides = {}) {
return Object.freeze({
projectId: 'prj_default',
taskId,
revision: 2,
name: `Task ${taskId}`,
description: 'must-not-cross-projection',
kind: 'command',
spec: Object.freeze({
schema: 'qinglong/command@v1',
config: Object.freeze({ command: ['private'] }),
}),
labels: Object.freeze({ private: 'value' }),
enabled: true,
mutationId: 'mutation-private',
contentDigest: 'digest-private',
createdAtMs: 10,
updatedAtMs: 20,
...overrides,
});
}
test('projects one bounded ascending current-head page and stable cursor', async () => {
const calls = [];
const result = await executeBoundedTaskListProjection(
{
async listTaskDefinitions(query) {
calls.push(query);
return {
definitions: [
task('task-a'),
task('task-b', { enabled: false }),
],
truncated: true,
next: { taskId: 'task-b' },
};
},
},
'prj_default',
{ limit: 2 },
);
assert.deepEqual(calls, [{ projectId: 'prj_default', limit: 2 }]);
assert.deepEqual(result, {
tasks: [
{
taskId: 'task-a',
revision: 2,
name: 'Task task-a',
kind: 'command',
specSchema: 'qinglong/command@v1',
enabled: true,
updatedAtMs: 20,
},
{
taskId: 'task-b',
revision: 2,
name: 'Task task-b',
kind: 'command',
specSchema: 'qinglong/command@v1',
enabled: false,
updatedAtMs: 20,
},
],
hasMore: true,
next: { taskId: 'task-b' },
});
assert.equal(JSON.stringify(result).includes('private'), false);
});
test('uses default and maximum bounds and passes an exact cursor', async () => {
const seen = [];
const source = {
async listTaskDefinitions(query) {
seen.push(query);
return { definitions: [], truncated: false };
},
};
assert.deepEqual(
await executeBoundedTaskListProjection(source, 'prj_default', {}),
{ tasks: [], hasMore: false },
);
assert.deepEqual(
await executeBoundedTaskListProjection(source, 'prj_default', {
limit: MAX_BOUNDED_TASK_LIST_LIMIT,
after: { taskId: 'task-a' },
}),
{ tasks: [], hasMore: false },
);
assert.deepEqual(seen, [
{ projectId: 'prj_default', limit: DEFAULT_BOUNDED_TASK_LIST_LIMIT },
{
projectId: 'prj_default',
limit: MAX_BOUNDED_TASK_LIST_LIMIT,
after: { taskId: 'task-a' },
},
]);
});
test('fails closed on malformed input before storage', async () => {
let calls = 0;
const source = {
async listTaskDefinitions() {
calls += 1;
return { definitions: [], truncated: false };
},
};
for (const input of [
null,
{ limit: 0 },
{ limit: 65 },
{ extra: true },
{ after: null },
{ after: { taskId: '' } },
{ after: { taskId: 'task-a', extra: true } },
]) {
await assert.rejects(
executeBoundedTaskListProjection(source, 'prj_default', input),
InvalidBoundedTaskListProjectionError,
);
}
assert.equal(calls, 0);
});
test('fails closed on cross-Project, ordering, shape and continuation drift', async () => {
for (const page of [
{ definitions: [task('task-a', { projectId: 'prj_other' })], truncated: false },
{ definitions: [task('task-b'), task('task-a')], truncated: false },
{ definitions: [task('task-a'), task('task-a')], truncated: false },
{ definitions: [task('task-a', { kind: 'invented' })], truncated: false },
{ definitions: [task('task-a')], truncated: true },
{
definitions: [task('task-a')],
truncated: true,
next: { taskId: 'task-b' },
},
{ definitions: [], truncated: true, next: { taskId: 'task-a' } },
{ definitions: [task('task-a'), task('task-b')], truncated: false },
]) {
await assert.rejects(
executeBoundedTaskListProjection(
{ async listTaskDefinitions() { return page; } },
'prj_default',
page.definitions.length > 1 ? { limit: 1 } : {},
),
BoundedTaskListProjectionUnavailableError,
);
}
await assert.rejects(
executeBoundedTaskListProjection(
{ async listTaskDefinitions() { throw new Error('offline'); } },
'prj_default',
{},
),
BoundedTaskListProjectionUnavailableError,
);
});
test('leaf import does not load Tool Registry or SemVer', () => {
const entry = path.resolve(
__dirname,
'../dist/task-definition/projection/boundedTaskListProjection.js',
);
const result = spawnSync(
process.execPath,
[
'-e',
`require(${JSON.stringify(entry)});
const loaded = Object.keys(require.cache);
if (loaded.some((value) => /node_modules[\\/]semver(?:[\\/]|$)/.test(value))) process.exit(2);
if (loaded.some((value) => /tool-execution[\\/]tool-registry/.test(value))) process.exit(3);
process.stdout.write(String(loaded.length));`,
],
{ encoding: 'utf8' },
);
assert.equal(result.status, 0, result.stderr);
assert.ok(Number(result.stdout) <= 4);
});
@@ -0,0 +1,160 @@
const assert = require('node:assert/strict');
const { spawnSync } = require('node:child_process');
const path = require('node:path');
const { test } = require('node:test');
const {
createTaskDefinitionRecord,
} = require('../dist/task-definition/taskDefinition.js');
const {
BoundedTaskReadProjectionUnavailableError,
InvalidBoundedTaskReadProjectionError,
executeBoundedTaskReadProjection,
} = require('../dist/task-definition/projection/boundedTaskReadProjection.js');
function task(overrides = {}) {
return createTaskDefinitionRecord(
{
projectId: 'prj_default',
taskId: 'task-a',
expectedRevision: null,
mutationId: '123e4567-e89b-42d3-a456-426614174001',
name: 'Task A',
description: 'must-not-cross-projection',
kind: 'command',
spec: {
schema: 'qinglong/command@v1',
config: { command: { kind: 'shell', command: 'private' } },
},
labels: { private: 'value' },
enabled: true,
occurredAtMs: 20,
...overrides,
},
10,
);
}
test('projects one exact current Task with an immutable start fence', async () => {
const calls = [];
const definition = task({ enabled: false });
const result = await executeBoundedTaskReadProjection(
{
async findCurrentTaskDefinition(projectId, taskId) {
calls.push([projectId, taskId]);
return definition;
},
},
'prj_default',
'task-a',
);
assert.deepEqual(calls, [['prj_default', 'task-a']]);
assert.deepEqual(result, {
found: true,
taskId: 'task-a',
revision: 1,
name: 'Task A',
kind: 'command',
specSchema: 'qinglong/command@v1',
enabled: false,
contentDigest: definition.contentDigest,
createdAtMs: 10,
updatedAtMs: 20,
});
const serialized = JSON.stringify(result);
assert.equal(serialized.includes('private'), false);
assert.equal(serialized.includes('must-not-cross'), false);
assert.equal(serialized.includes('mutationId'), false);
});
test('masks absent and cross-Project current Tasks', async () => {
assert.deepEqual(
await executeBoundedTaskReadProjection(
{ async findCurrentTaskDefinition() { return null; } },
'prj_default',
'task-a',
),
{ found: false },
);
assert.deepEqual(
await executeBoundedTaskReadProjection(
{
async findCurrentTaskDefinition() {
return task({ projectId: 'prj_other' });
},
},
'prj_default',
'task-a',
),
{ found: false },
);
});
test('rejects invalid input before storage', async () => {
let calls = 0;
const source = {
async findCurrentTaskDefinition() {
calls += 1;
return null;
},
};
for (const [projectId, taskId] of [
['', 'task-a'],
['prj_default', ''],
['prj_default', 'x'.repeat(129)],
['prj_default', 'task\nother'],
]) {
await assert.rejects(
executeBoundedTaskReadProjection(source, projectId, taskId),
InvalidBoundedTaskReadProjectionError,
);
}
assert.equal(calls, 0);
});
test('fails closed on corrupt identity, digest, time and repository errors', async () => {
const definition = task();
for (const value of [
{ ...definition, taskId: 'task-b' },
{ ...definition, contentDigest: '0'.repeat(64) },
{ ...definition, updatedAtMs: 9 },
]) {
await assert.rejects(
executeBoundedTaskReadProjection(
{ async findCurrentTaskDefinition() { return value; } },
'prj_default',
'task-a',
),
BoundedTaskReadProjectionUnavailableError,
);
}
await assert.rejects(
executeBoundedTaskReadProjection(
{ async findCurrentTaskDefinition() { throw new Error('offline'); } },
'prj_default',
'task-a',
),
BoundedTaskReadProjectionUnavailableError,
);
});
test('leaf import does not load Tool Registry or SemVer', () => {
const entry = path.resolve(
__dirname,
'../dist/task-definition/projection/boundedTaskReadProjection.js',
);
const result = spawnSync(
process.execPath,
[
'-e',
`require(${JSON.stringify(entry)});
const loaded = Object.keys(require.cache);
if (loaded.some((value) => /node_modules[\\/]semver(?:[\\/]|$)/.test(value))) process.exit(2);
if (loaded.some((value) => /tool-execution[\\/]tool-registry/.test(value))) process.exit(3);
process.stdout.write(String(loaded.length));`,
],
{ encoding: 'utf8' },
);
assert.equal(result.status, 0, result.stderr);
assert.ok(Number(result.stdout) <= 4);
});
@@ -0,0 +1,202 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const { activateClusterControlRuntime } = require('../dist');
const EVIDENCE = Object.freeze({
contractName: 'control-core',
contractVersion: 2,
serverMajor: 16,
migrationIds: Object.freeze([
'pg-0001-schema-capability',
'pg-0002-run-core',
'pg-0003-run-retry-policy',
]),
});
function stack(events, recovery = { safe: true, remaining: 0, failed: 0 }) {
return {
async reconcile() {
events.push('reconcile');
return recovery;
},
async startLifecycles() {
events.push('start-lifecycles');
return true;
},
installAdmission() {
events.push('install-admission');
return () => events.push('dispose-admission');
},
async stop() {
events.push('stop-stack');
return 'stopped';
},
};
}
function options(events, overrides = {}) {
return {
enabled: true,
profile: 'cluster-control',
readiness: {
async assertReady() {
events.push('readiness');
return EVIDENCE;
},
},
create() {
events.push('create');
return stack(events);
},
audit(record) {
events.push(`audit:${record.state}`);
},
...overrides,
};
}
test('disabled and wrong-profile paths never probe readiness', async () => {
const disabledEvents = [];
const disabled = await activateClusterControlRuntime(
options(disabledEvents, { enabled: false }),
);
assert.equal(disabled.status, 'disabled');
assert.deepEqual(disabledEvents, ['audit:disabled']);
const wrongProfileEvents = [];
await assert.rejects(
activateClusterControlRuntime(
options(wrongProfileEvents, { profile: 'standalone' }),
),
/cannot activate cluster-control/,
);
assert.deepEqual(wrongProfileEvents, []);
});
test('orders readiness, recovery, lifecycles and admission', async () => {
const events = [];
const result = await activateClusterControlRuntime(options(events));
assert.equal(result.status, 'active');
assert.deepEqual(events, [
'readiness',
'audit:schema_ready',
'create',
'reconcile',
'audit:reconciled',
'start-lifecycles',
'install-admission',
'audit:active',
]);
const first = result.stop();
assert.equal(first, result.stop());
assert.equal(await first, 'stopped');
assert.deepEqual(events.slice(-3), [
'dispose-admission',
'stop-stack',
'audit:stopped',
]);
});
test('readiness failure never constructs a stack', async () => {
const events = [];
const unavailable = new Error('database unavailable');
await assert.rejects(
activateClusterControlRuntime(
options(events, {
readiness: {
async assertReady() {
events.push('readiness');
throw unavailable;
},
},
}),
),
(error) => error === unavailable,
);
assert.deepEqual(events, ['readiness', 'audit:failed']);
});
test('unsafe recovery stops the stack before lifecycles and admission', async () => {
const events = [];
await assert.rejects(
activateClusterControlRuntime(
options(events, {
create() {
events.push('create');
return stack(events, { safe: false, remaining: 1, failed: 0 });
},
}),
),
/did not converge safely/,
);
assert.equal(events.includes('start-lifecycles'), false);
assert.equal(events.includes('install-admission'), false);
assert.deepEqual(events.slice(-2), ['stop-stack', 'audit:failed']);
});
test('admission cleanup failure still stops the stack and remains idempotent', async () => {
const events = [];
const cleanupFailure = new Error('admission cleanup failed');
const result = await activateClusterControlRuntime(
options(events, {
create() {
events.push('create');
return {
...stack(events),
installAdmission() {
events.push('install-admission');
return () => {
events.push('dispose-admission');
throw cleanupFailure;
};
},
};
},
}),
);
const first = result.stop();
assert.equal(first, result.stop());
await assert.rejects(first, (error) => error === cleanupFailure);
assert.deepEqual(events.slice(-3), [
'dispose-admission',
'stop-stack',
'audit:failed',
]);
});
test('awaits asynchronous admission drain before stopping the stack', async () => {
const events = [];
let releaseDrain;
const drain = new Promise((resolve) => {
releaseDrain = resolve;
});
const result = await activateClusterControlRuntime(
options(events, {
create() {
events.push('create');
return {
...stack(events),
installAdmission() {
events.push('install-admission');
return async () => {
events.push('drain-admission');
await drain;
events.push('admission-drained');
};
},
};
},
}),
);
const stopping = result.stop();
await new Promise((resolve) => setImmediate(resolve));
assert.deepEqual(events.slice(-1), ['drain-admission']);
assert.equal(events.includes('stop-stack'), false);
releaseDrain();
assert.equal(await stopping, 'stopped');
assert.deepEqual(events.slice(-3), [
'admission-drained',
'stop-stack',
'audit:stopped',
]);
});
@@ -0,0 +1,70 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
ClusterControlRecoveryConvergenceVerifier,
MAX_CLUSTER_CONTROL_RECOVERY_PAGE_SIZE,
} = require('../dist');
test('proves convergence with one bounded recovery-source read', async () => {
const limits = [];
const verifier = new ClusterControlRecoveryConvergenceVerifier({
async listOutstanding(limit) {
limits.push(limit);
return { observedAtMs: 123, candidates: [], hasMore: false };
},
});
assert.deepEqual(await verifier.verify(), {
safe: true,
remaining: 0,
failed: 0,
});
assert.deepEqual(limits, [1]);
assert.equal(MAX_CLUSTER_CONTROL_RECOVERY_PAGE_SIZE, 128);
});
test('fails closed with a lower-bound remaining count', async () => {
const verifier = new ClusterControlRecoveryConvergenceVerifier({
async listOutstanding() {
return {
observedAtMs: 123,
candidates: [
{
kind: 'run',
id: 'run-1',
runId: 'run-1',
status: 'running',
createdAtMs: 1,
},
],
hasMore: true,
};
},
});
assert.deepEqual(await verifier.verify(), {
safe: false,
remaining: 2,
failed: 0,
});
});
test('rejects an internally inconsistent recovery page', async () => {
const verifier = new ClusterControlRecoveryConvergenceVerifier({
async listOutstanding() {
return { observedAtMs: 123, candidates: [], hasMore: true };
},
});
await assert.rejects(verifier.verify(), /hasMore without a candidate/);
});
test('rejects an invalid durable-source observation', async () => {
const verifier = new ClusterControlRecoveryConvergenceVerifier({
async listOutstanding() {
return { observedAtMs: Number.NaN, candidates: [], hasMore: false };
},
});
await assert.rejects(verifier.verify(), /observation is invalid/);
});
@@ -0,0 +1,240 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
ClusterControlRecoveryEvidenceRegistry,
MAX_CLUSTER_CONTROL_RECOVERY_EVIDENCE_PROVIDERS,
} = require('../dist');
function claim() {
return {
candidate: {
kind: 'attempt',
id: 'attempt-1',
runId: 'run-1',
status: 'running',
createdAtMs: 1,
},
observedAtMs: 100,
ownerId: 'replica-a',
token: '123e4567-e89b-42d3-a456-426614174000',
version: 1,
expiresAtMs: 30_100,
};
}
function target(overrides = {}) {
return {
runId: 'run-1',
attemptId: 'attempt-1',
attemptStatus: 'running',
executorType: 'remote_worker',
callbackSequence: 3,
workerId: 'worker-a',
executorHandle: 'offer-1',
leaseToken: 'lease-token-123456',
leaseExpiresAtMs: 99,
startedAtMs: 10,
...overrides,
};
}
test('routes one exact executor identity without exposing the recovery claim', async () => {
const calls = [];
const provider = {
executorType: 'remote_worker',
requiredIdentity: ['workerId', 'executorHandle', 'leaseToken'],
async inspect(current, context) {
calls.push([current, context]);
assert.equal(Object.isFrozen(current), true);
assert.equal(Object.isFrozen(context), true);
assert.equal(context.timeoutMs, 100);
assert.equal(context.signal.aborted, false);
assert.equal('token' in current, false);
assert.equal('ownerId' in current, false);
return { status: 'running', ignored: 'not propagated' };
},
};
const registry = new ClusterControlRecoveryEvidenceRegistry([provider], {
timeoutMs: 100,
});
provider.inspect = async () => ({ status: 'not_running' });
assert.deepEqual(await registry.inspect(claim(), target()), {
status: 'running',
});
assert.equal(calls.length, 1);
registry.dispose();
});
test('fails closed for unknown executors and incomplete or malformed identities', async () => {
let calls = 0;
const registry = new ClusterControlRecoveryEvidenceRegistry([
{
executorType: 'remote_worker',
requiredIdentity: ['workerId', 'leaseToken'],
async inspect() {
calls += 1;
return { status: 'not_running' };
},
},
]);
assert.deepEqual(
await registry.inspect(claim(), target({ executorType: 'kubernetes' })),
{ status: 'unknown', reason: 'identity_unverifiable' },
);
assert.deepEqual(
await registry.inspect(claim(), target({ leaseToken: undefined })),
{ status: 'unknown', reason: 'identity_unverifiable' },
);
assert.deepEqual(
await registry.inspect(claim(), target({ callbackSequence: -1 })),
{ status: 'unknown', reason: 'identity_unverifiable' },
);
assert.equal(calls, 0);
registry.dispose();
});
test('maps provider failure and malformed evidence without leaking errors', async () => {
const failing = new ClusterControlRecoveryEvidenceRegistry([
{
executorType: 'remote_worker',
requiredIdentity: ['workerId'],
async inspect() {
throw new Error('sensitive transport failure');
},
},
]);
assert.deepEqual(await failing.inspect(claim(), target()), {
status: 'unknown',
reason: 'provider_unavailable',
});
failing.dispose();
const malformed = new ClusterControlRecoveryEvidenceRegistry([
{
executorType: 'remote_worker',
requiredIdentity: ['workerId'],
async inspect() {
return { status: 'not_running', reason: 'untrusted-extra' };
},
},
]);
assert.deepEqual(await malformed.inspect(claim(), target()), {
status: 'not_running',
});
malformed.dispose();
});
test('times out once per provider and prevents abandoned probe accumulation', async () => {
const keepAlive = setInterval(() => {}, 1_000);
let release;
let calls = 0;
let firstSignal;
const registry = new ClusterControlRecoveryEvidenceRegistry(
[
{
executorType: 'remote_worker',
requiredIdentity: ['workerId'],
inspect(_target, context) {
calls += 1;
firstSignal = context.signal;
return new Promise((resolve) => {
release = resolve;
});
},
},
],
{ timeoutMs: 5 },
);
try {
assert.deepEqual(await registry.inspect(claim(), target()), {
status: 'unknown',
reason: 'provider_unavailable',
});
assert.equal(firstSignal.aborted, true);
assert.deepEqual(await registry.inspect(claim(), target()), {
status: 'unknown',
reason: 'provider_unavailable',
});
assert.equal(calls, 1);
release({ status: 'running' });
await new Promise((resolve) => setImmediate(resolve));
} finally {
clearInterval(keepAlive);
registry.dispose();
}
});
test('dispose aborts an active provider and permanently fails closed', async () => {
let signal;
const registry = new ClusterControlRecoveryEvidenceRegistry(
[
{
executorType: 'remote_worker',
requiredIdentity: ['workerId'],
inspect(_target, context) {
signal = context.signal;
return new Promise(() => {});
},
},
],
{ timeoutMs: 1_000 },
);
const inspection = registry.inspect(claim(), target());
await new Promise((resolve) => setImmediate(resolve));
registry.dispose();
assert.equal(signal.aborted, true);
assert.deepEqual(await inspection, {
status: 'unknown',
reason: 'provider_unavailable',
});
assert.deepEqual(await registry.inspect(claim(), target()), {
status: 'unknown',
reason: 'provider_unavailable',
});
});
test('rejects duplicate, wildcard, identity-free and unbounded registrations', () => {
const provider = {
executorType: 'remote_worker',
requiredIdentity: ['workerId'],
async inspect() {
return { status: 'running' };
},
};
assert.throws(
() => new ClusterControlRecoveryEvidenceRegistry([provider, provider]),
/Duplicate/,
);
assert.throws(
() =>
new ClusterControlRecoveryEvidenceRegistry([
{ ...provider, executorType: '*' },
]),
/executorType/,
);
assert.throws(
() =>
new ClusterControlRecoveryEvidenceRegistry([
{ ...provider, requiredIdentity: [] },
]),
/requires an execution identity/,
);
assert.throws(
() =>
new ClusterControlRecoveryEvidenceRegistry(
Array.from(
{ length: MAX_CLUSTER_CONTROL_RECOVERY_EVIDENCE_PROVIDERS + 1 },
(_, index) => ({
...provider,
executorType: `worker_${index}`,
}),
),
),
/cannot exceed/,
);
});
@@ -0,0 +1,360 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
ClusterControlRecoveryFenceLostError,
EvidenceBasedClusterControlRecoveryProcessor,
InvalidClusterControlRecoveryTransitionError,
buildClusterControlRecoveryLostTransition,
} = require('../dist');
function run(overrides = {}) {
return {
id: 'run-1',
projectId: 'default',
taskId: 'task-1',
taskRevision: 'v1',
triggerType: 'manual',
executionOrigin: 'manual',
executionOwner: 'runtime',
status: 'dispatching',
version: 1,
eventSequence: 0,
priority: 0,
createdAtMs: 100,
...overrides,
};
}
function attempt(overrides = {}) {
return {
id: 'attempt-1',
runId: 'run-1',
attempt: 1,
status: 'claimed',
executorType: 'worker',
workerId: 'worker-1',
leaseToken: 'lease-token',
leaseExpiresAtMs: 900,
callbackSequence: 0,
createdAtMs: 200,
...overrides,
};
}
function claim(overrides = {}) {
return {
candidate: {
kind: 'attempt',
id: 'attempt-1',
runId: 'run-1',
status: 'claimed',
createdAtMs: 200,
},
observedAtMs: 1000,
ownerId: 'replica-a',
token: '00000000-0000-4000-8000-000000000001',
version: 1,
expiresAtMs: 31000,
...overrides,
};
}
function snapshot(overrides = {}) {
return {
observedAtMs: 1000,
run: run(),
attempt: attempt(),
...overrides,
};
}
test('builds an Attempt-lost then Run-lost aggregate without creating work', () => {
const transition = buildClusterControlRecoveryLostTransition(
run(),
attempt(),
{
kind: 'mark_attempt_and_run_lost',
reason: 'unstarted_claim_expired',
},
1000,
);
assert.equal(transition.attempt.attempt.status, 'lost');
assert.equal(transition.attempt.attempt.finishedAtMs, 1000);
assert.equal(
transition.attempt.attempt.errorCode,
'CLUSTER_RECOVERY_UNSTARTED_CLAIM_EXPIRED',
);
assert.equal(transition.attempt.run.version, 2);
assert.equal(transition.attempt.event.type, 'attempt.lost');
assert.equal(transition.run.run.status, 'lost');
assert.equal(transition.run.run.version, 3);
assert.equal(transition.run.run.eventSequence, 2);
assert.equal(transition.run.event.type, 'run.lost');
assert.equal('finishedAtMs' in transition.run.run, false);
});
test('supports Run-only and Attempt-only convergence but rejects widened authority', () => {
const runOnly = buildClusterControlRecoveryLostTransition(
run({ status: 'running' }),
attempt({ status: 'lost', finishedAtMs: 900 }),
{ kind: 'mark_run_lost', reason: 'attempt_already_lost' },
1000,
);
assert.equal(runOnly.attempt, undefined);
assert.equal(runOnly.run.run.status, 'lost');
const attemptOnly = buildClusterControlRecoveryLostTransition(
run({ status: 'lost' }),
attempt({ status: 'running', startedAtMs: 300 }),
{ kind: 'mark_attempt_lost', reason: 'execution_not_running' },
1000,
);
assert.equal(attemptOnly.run, undefined);
assert.equal(attemptOnly.attempt.attempt.status, 'lost');
assert.throws(
() =>
buildClusterControlRecoveryLostTransition(
run({ cancelRequestedAtMs: 800, cancelReason: 'user' }),
attempt(),
{
kind: 'mark_attempt_and_run_lost',
reason: 'unstarted_claim_expired',
},
1000,
),
InvalidClusterControlRecoveryTransitionError,
);
assert.throws(
() =>
buildClusterControlRecoveryLostTransition(
run({ executionOwner: 'legacy' }),
attempt(),
{
kind: 'mark_attempt_and_run_lost',
reason: 'unstarted_claim_expired',
},
1000,
),
InvalidClusterControlRecoveryTransitionError,
);
});
test('marks an expired unstarted claim lost without consulting external evidence', async () => {
const calls = [];
const processor = new EvidenceBasedClusterControlRecoveryProcessor(
{
async load() {
calls.push('load');
return snapshot();
},
async applyLost(_claim, _snapshot, action) {
calls.push(action);
return 'applied';
},
},
{
async inspect() {
throw new Error('unstarted work must not be probed');
},
},
);
assert.deepEqual(await processor.process(claim()), { status: 'resolved' });
assert.deepEqual(calls, [
'load',
{
kind: 'mark_attempt_and_run_lost',
reason: 'unstarted_claim_expired',
},
]);
});
test('routes an admission-bound Workflow Task to its dedicated recovery action', async () => {
const actions = [];
const processor = new EvidenceBasedClusterControlRecoveryProcessor(
{
async load() {
return snapshot({
run: run({
triggerType: 'plugin_package_workflow',
executionOrigin: 'system',
status: 'running',
}),
attempt: attempt({ stepRunId: 'step-1' }),
workflowTask: {
admission: {
attemptId: 'attempt-1',
runId: 'run-1',
stepRunId: 'step-1',
},
stepRun: {
id: 'step-1',
runId: 'run-1',
},
},
});
},
async applyLost(_claim, _snapshot, action) {
actions.push(action);
return 'applied';
},
},
{
async inspect() {
throw new Error('unstarted work must not be probed');
},
},
);
assert.deepEqual(await processor.process(claim()), { status: 'resolved' });
assert.deepEqual(actions, [
{
kind: 'recover_workflow_task',
reason: 'unstarted_claim_expired',
},
]);
});
test('requires trusted absence evidence after the start barrier', async () => {
const actions = [];
const evidence = [];
const processor = new EvidenceBasedClusterControlRecoveryProcessor(
{
async load() {
return snapshot({
attempt: attempt({ status: 'running', startedAtMs: 300 }),
});
},
async applyLost(_claim, _snapshot, action) {
actions.push(action);
return 'applied';
},
},
{
async inspect(_claim, target) {
evidence.push(target);
return { status: 'not_running' };
},
},
);
assert.deepEqual(await processor.process(claim()), { status: 'resolved' });
assert.equal(evidence[0].attemptId, 'attempt-1');
assert.equal(evidence[0].attemptStatus, 'running');
assert.deepEqual(actions, [
{
kind: 'mark_attempt_and_run_lost',
reason: 'execution_not_running',
},
]);
});
test('keeps running and unavailable evidence retryable, and ambiguity manual', async () => {
const values = [
{ status: 'running' },
{ status: 'unknown', reason: 'provider_unavailable' },
{ status: 'unknown', reason: 'identity_unverifiable' },
];
const processor = new EvidenceBasedClusterControlRecoveryProcessor(
{
async load() {
return snapshot({
attempt: attempt({ status: 'starting', startedAtMs: 300 }),
});
},
async applyLost() {
throw new Error('uncertain evidence must not mutate');
},
},
{
async inspect() {
return values.shift();
},
},
{ retryDelayMs: 2500 },
);
assert.deepEqual(await processor.process(claim()), {
status: 'retry',
delayMs: 2500,
});
assert.deepEqual(await processor.process(claim()), {
status: 'retry',
delayMs: 2500,
});
assert.deepEqual(await processor.process(claim()), { status: 'manual' });
});
test('resolves restored ownership and stale state without mutation', async () => {
const snapshots = [
snapshot({
attempt: attempt({ leaseExpiresAtMs: 5000 }),
}),
snapshot({
run: run({ status: 'lost' }),
attempt: attempt({ status: 'lost', finishedAtMs: 900 }),
}),
];
let applies = 0;
const processor = new EvidenceBasedClusterControlRecoveryProcessor(
{
async load() {
return snapshots.shift();
},
async applyLost() {
applies += 1;
return 'applied';
},
},
{
async inspect() {
throw new Error('not expected');
},
},
);
assert.deepEqual(await processor.process(claim()), { status: 'resolved' });
assert.deepEqual(await processor.process(claim()), { status: 'resolved' });
assert.equal(applies, 0);
});
test('surfaces a lost claim fence and treats a CAS-stale snapshot as resolved', async () => {
const fencedLoad = new EvidenceBasedClusterControlRecoveryProcessor(
{
async load() {
return 'fenced';
},
async applyLost() {
throw new Error('not expected');
},
},
{
async inspect() {
throw new Error('not expected');
},
},
);
await assert.rejects(
fencedLoad.process(claim()),
ClusterControlRecoveryFenceLostError,
);
const staleApply = new EvidenceBasedClusterControlRecoveryProcessor(
{
async load() {
return snapshot();
},
async applyLost() {
return 'stale';
},
},
{
async inspect() {
throw new Error('not expected');
},
},
);
assert.deepEqual(await staleApply.process(claim()), { status: 'resolved' });
});
@@ -0,0 +1,155 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
ClusterControlRecoverySupervisor,
MAX_CLUSTER_CONTROL_RECOVERY_CLAIMS_PER_PASS,
} = require('../dist');
function claim(id, version = 1) {
return {
candidate: {
kind: 'run',
id,
runId: id,
status: 'running',
createdAtMs: 1,
},
observedAtMs: 100,
ownerId: 'node-a',
token: '123e4567-e89b-42d3-a456-426614174000',
version,
expiresAtMs: 1_100,
};
}
test('settles one bounded recovery page sequentially', async () => {
const events = [];
const repository = {
async claim(options) {
events.push(['claim', options]);
return {
claims: [claim('run-1'), claim('run-2')],
discovered: 2,
hasMore: false,
};
},
async settle(current, disposition) {
events.push(['settle', current.candidate.id, disposition]);
return 'settled';
},
};
const supervisor = new ClusterControlRecoverySupervisor(
repository,
{
async process(current) {
events.push(['process', current.candidate.id]);
return { status: 'resolved' };
},
},
{ ownerId: 'node-a', limit: 2, leaseMs: 1_000 },
);
assert.deepEqual(await supervisor.reconcile(), {
safe: true,
remaining: 0,
failed: 0,
});
assert.deepEqual(events, [
['claim', { ownerId: 'node-a', limit: 2, leaseMs: 1_000 }],
['process', 'run-1'],
['settle', 'run-1', { status: 'resolved' }],
['process', 'run-2'],
['settle', 'run-2', { status: 'resolved' }],
]);
});
test('keeps unclaimed, retry, manual and fenced work unsafe', async () => {
const dispositions = new Map([
['run-retry', { status: 'retry', delayMs: 10 }],
['run-manual', { status: 'manual' }],
['run-fenced', { status: 'resolved' }],
]);
const supervisor = new ClusterControlRecoverySupervisor(
{
async claim() {
return {
claims: [
claim('run-retry'),
claim('run-manual'),
claim('run-fenced'),
],
discovered: 4,
hasMore: true,
};
},
async settle(current) {
return current.candidate.id === 'run-fenced' ? 'fenced' : 'settled';
},
},
{
async process(current) {
return dispositions.get(current.candidate.id);
},
},
{ ownerId: 'node-a', limit: 4 },
);
assert.deepEqual(await supervisor.reconcile(), {
safe: false,
remaining: 5,
failed: 2,
});
});
test('turns a processor failure into a durable bounded retry', async () => {
const settled = [];
const supervisor = new ClusterControlRecoverySupervisor(
{
async claim() {
return { claims: [claim('run-1')], discovered: 1, hasMore: false };
},
async settle(current, disposition) {
settled.push([current.candidate.id, disposition]);
return 'settled';
},
},
{
async process() {
throw new Error('sensitive processor failure');
},
},
{ ownerId: 'node-a', retryDelayMs: 123 },
);
assert.deepEqual(await supervisor.reconcile(), {
safe: false,
remaining: 1,
failed: 1,
});
assert.deepEqual(settled, [['run-1', { status: 'retry', delayMs: 123 }]]);
});
test('rejects malformed pages and unbounded options before processing', async () => {
assert.equal(MAX_CLUSTER_CONTROL_RECOVERY_CLAIMS_PER_PASS, 128);
assert.throws(
() =>
new ClusterControlRecoverySupervisor(
{},
{},
{
ownerId: 'unsafe owner',
},
),
/ownerId/,
);
const supervisor = new ClusterControlRecoverySupervisor(
{
async claim() {
return { claims: [claim('run-1')], discovered: 0, hasMore: false };
},
},
{},
{ ownerId: 'node-a' },
);
await assert.rejects(supervisor.reconcile(), /invalid claim page/);
});
@@ -0,0 +1,81 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
ClusterControlStartupRecoveryCoordinator,
MAX_CLUSTER_CONTROL_STARTUP_RECOVERY_PASSES,
} = require('../dist');
test('runs bounded startup pages until recovery converges', async () => {
const summaries = [
{ safe: false, remaining: 1, failed: 0 },
{ safe: false, remaining: 1, failed: 0 },
{ safe: true, remaining: 0, failed: 0 },
];
let calls = 0;
const coordinator = new ClusterControlStartupRecoveryCoordinator(
{
async reconcile() {
return summaries[calls++];
},
},
{ maxPasses: 3 },
);
assert.deepEqual(await coordinator.reconcile(), summaries[2]);
assert.equal(calls, 3);
});
test('stops immediately when retry or manual work remains', async () => {
let calls = 0;
const coordinator = new ClusterControlStartupRecoveryCoordinator({
async reconcile() {
calls += 1;
return { safe: false, remaining: 2, failed: 1 };
},
});
assert.deepEqual(await coordinator.reconcile(), {
safe: false,
remaining: 2,
failed: 1,
});
assert.equal(calls, 1);
});
test('returns the final lower bound when the hard pass budget is exhausted', async () => {
let calls = 0;
const coordinator = new ClusterControlStartupRecoveryCoordinator(
{
async reconcile() {
calls += 1;
return { safe: false, remaining: calls + 1, failed: 0 };
},
},
{ maxPasses: 2 },
);
assert.deepEqual(await coordinator.reconcile(), {
safe: false,
remaining: 3,
failed: 0,
});
assert.equal(calls, 2);
});
test('rejects inconsistent summaries and unbounded configuration', async () => {
assert.equal(MAX_CLUSTER_CONTROL_STARTUP_RECOVERY_PASSES, 64);
assert.throws(
() =>
new ClusterControlStartupRecoveryCoordinator(
{ async reconcile() {} },
{ maxPasses: 65 },
),
/maxPasses/,
);
const coordinator = new ClusterControlStartupRecoveryCoordinator({
async reconcile() {
return { safe: true, remaining: 1, failed: 0 };
},
});
await assert.rejects(coordinator.reconcile(), /invalid summary/);
});
@@ -0,0 +1,97 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidClusterExecutionRevisionError,
compileClusterCommandTaskDefinition,
normalizeClusterTaskExecutionRevision,
} = require('../dist/task-definition/clusterExecutionRevision');
const {
createTaskDefinitionRecord,
normalizeAppendTaskDefinitionRevisionCommand,
} = require('../dist/task-definition/taskDefinition');
const {
createBuiltInTaskSpecSemanticRegistry,
} = require('../dist/task-definition/taskSpecSemantic');
const { createSecretRef } = require('../dist/secret/secretReference');
function definition() {
const registry = createBuiltInTaskSpecSemanticRegistry();
const command = normalizeAppendTaskDefinitionRevisionCommand({
projectId: 'default',
taskId: 'task-1',
expectedRevision: null,
mutationId: '019f7600-0000-7000-8000-000000000001',
name: 'Cluster command',
kind: 'command',
spec: {
schema: 'qinglong/command@v1',
config: {
command: { kind: 'argv', file: '/bin/echo', args: ['ready'] },
environment: [
{ kind: 'public', name: 'MODE', value: 'cluster' },
{
kind: 'secret',
name: 'TOKEN',
secretRef: createSecretRef({ projectId: 'default', name: 'TOKEN' }),
},
],
timeoutMs: 5000,
},
},
labels: {},
enabled: true,
occurredAtMs: 100,
});
return {
registry,
record: createTaskDefinitionRecord({
...command,
spec: registry.normalize({
projectId: command.projectId,
taskId: command.taskId,
kind: command.kind,
spec: command.spec,
}),
}, 90),
};
}
test('compiles one digest-bound remote Worker execution revision', () => {
const input = definition();
const revision = compileClusterCommandTaskDefinition(
input.record,
input.registry,
);
assert.equal(revision.executorType, 'remote_worker');
assert.equal(revision.planSchema, 'qinglong/command-execution@v1');
assert.equal(revision.sourceRevision, input.record.revision);
assert.equal(revision.sourceContentDigest, input.record.contentDigest);
assert.match(revision.contentDigest, /^[0-9a-f]{64}$/);
assert.deepEqual(normalizeClusterTaskExecutionRevision(revision), revision);
});
test('rejects digest drift and cross-Project Secret references', () => {
const input = definition();
const revision = compileClusterCommandTaskDefinition(
input.record,
input.registry,
);
assert.throws(
() => normalizeClusterTaskExecutionRevision({
...revision,
contentDigest: '0'.repeat(64),
}),
InvalidClusterExecutionRevisionError,
);
assert.throws(
() => normalizeClusterTaskExecutionRevision({
...revision,
environment: [{
kind: 'secret',
name: 'TOKEN',
secretRef: createSecretRef({ projectId: 'another', name: 'TOKEN' }),
}],
}),
InvalidClusterExecutionRevisionError,
);
});
@@ -0,0 +1,201 @@
'use strict';
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
CLUSTER_RUN_CANCELLATION_SCHEMA,
createClusterRunCancellationResponseBody,
normalizeClusterRunCancellationCommand,
normalizeClusterRunCancellationResult,
parseClusterRunCancellationRequestBody,
parseClusterRunCancellationResponseBody,
} = require('../dist/run/clusterRunCancellation');
const {
RUN_CANCELLATION_SCHEMA,
parseRunCancellationRequestBody,
} = require('@qinglong/runtime-core/run-cancellation');
function command(overrides = {}) {
return {
projectId: 'project-1',
runId: 'run-1',
mutationId: 'mutation-1',
eventId: '018f0000-0000-7000-8000-000000000001',
subject: { type: 'user', id: 'user-1' },
policyFence: { projectVersion: 2, bindingVersion: 3 },
...overrides,
};
}
test('accepts one exact cancellation wire body and complete authority', () => {
assert.equal(RUN_CANCELLATION_SCHEMA, 'qinglong/run-cancellation@v1');
assert.equal(CLUSTER_RUN_CANCELLATION_SCHEMA, RUN_CANCELLATION_SCHEMA);
assert.deepEqual(parseClusterRunCancellationRequestBody({
schema: CLUSTER_RUN_CANCELLATION_SCHEMA,
mutationId: 'mutation-1',
}), {
schema: CLUSTER_RUN_CANCELLATION_SCHEMA,
mutationId: 'mutation-1',
});
assert.deepEqual(
parseRunCancellationRequestBody({
schema: RUN_CANCELLATION_SCHEMA,
mutationId: 'mutation-1',
}),
{
schema: RUN_CANCELLATION_SCHEMA,
mutationId: 'mutation-1',
},
);
assert.deepEqual(normalizeClusterRunCancellationCommand(command()), command());
});
test('normalizes an exact optional Plugin Package Workflow target', () => {
const targeted = command({
workflowTarget: { packageName: 'example-package', workflowId: 'daily' },
});
assert.deepEqual(normalizeClusterRunCancellationCommand(targeted), targeted);
assert.throws(
() =>
normalizeClusterRunCancellationCommand(
command({
workflowTarget: {
packageName: 'Example',
workflowId: 'daily',
},
}),
),
/workflowTarget is invalid/,
);
assert.throws(
() =>
normalizeClusterRunCancellationCommand(
command({
workflowTarget: {
packageName: 'example',
workflowId: 'daily',
generation: 1,
},
}),
),
/shape is invalid/,
);
});
test('rejects unknown body fields and incomplete policy fences', () => {
assert.throws(() => parseClusterRunCancellationRequestBody({
schema: CLUSTER_RUN_CANCELLATION_SCHEMA,
mutationId: 'mutation-1',
reason: 'shutdown',
}), /shape is invalid/);
assert.throws(() => normalizeClusterRunCancellationCommand(command({
policyFence: { projectVersion: 2, bindingVersion: null },
})), /authorization fence is incomplete/);
});
test('normalizes accepted, replayed and terminal projections', () => {
assert.deepEqual(normalizeClusterRunCancellationResult({
status: 'accepted',
projectId: 'project-1',
runId: 'run-1',
runStatus: 'running',
runVersion: 5,
eventSequence: 7,
cancelRequestedAtMs: 1_800_000_000_000,
cancelReason: 'user',
}), {
status: 'accepted',
projectId: 'project-1',
runId: 'run-1',
runStatus: 'running',
runVersion: 5,
eventSequence: 7,
cancelRequestedAtMs: 1_800_000_000_000,
cancelReason: 'user',
});
assert.equal(normalizeClusterRunCancellationResult({
status: 'already_requested',
projectId: 'project-1',
runId: 'run-1',
runStatus: 'dispatching',
runVersion: 5,
eventSequence: 7,
cancelRequestedAtMs: 900,
cancelReason: 'timeout',
}).cancelReason, 'timeout');
assert.deepEqual(normalizeClusterRunCancellationResult({
status: 'already_terminal',
projectId: 'project-1',
runId: 'run-1',
runStatus: 'succeeded',
runVersion: 6,
eventSequence: 8,
}), {
status: 'already_terminal',
projectId: 'project-1',
runId: 'run-1',
runStatus: 'succeeded',
runVersion: 6,
eventSequence: 8,
});
});
test('keeps lost Runs cancellable because retry authority is still open', () => {
assert.deepEqual(normalizeClusterRunCancellationResult({
status: 'accepted',
projectId: 'project-1',
runId: 'run-1',
runStatus: 'lost',
runVersion: 3,
eventSequence: 2,
cancelRequestedAtMs: 1_750_000_000_000,
cancelReason: 'user',
}), {
status: 'accepted',
projectId: 'project-1',
runId: 'run-1',
runStatus: 'lost',
runVersion: 3,
eventSequence: 2,
cancelRequestedAtMs: 1_750_000_000_000,
cancelReason: 'user',
});
});
test('round-trips one exact versioned cancellation response', () => {
const body = createClusterRunCancellationResponseBody({
status: 'accepted',
projectId: 'project-1',
runId: 'run-1',
runStatus: 'running',
runVersion: 5,
eventSequence: 7,
cancelRequestedAtMs: 1_000,
cancelReason: 'user',
});
assert.equal(body.schema, CLUSTER_RUN_CANCELLATION_SCHEMA);
assert.deepEqual(parseClusterRunCancellationResponseBody(body), body);
assert.throws(() => parseClusterRunCancellationResponseBody({
...body,
extra: true,
}), /shape is invalid/);
});
test('rejects contradictory cancellation projections', () => {
assert.throws(() => normalizeClusterRunCancellationResult({
status: 'accepted',
projectId: 'project-1',
runId: 'run-1',
runStatus: 'running',
runVersion: 5,
eventSequence: 7,
}), /result state is invalid/);
assert.throws(() => normalizeClusterRunCancellationResult({
status: 'already_terminal',
projectId: 'project-1',
runId: 'run-1',
runStatus: 'running',
runVersion: 5,
eventSequence: 7,
}), /result state is invalid/);
});
@@ -0,0 +1,162 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
ClusterRunCancellationConvergenceCoordinator,
ClusterRunCancellationConvergenceUnavailableError,
normalizeClusterRunCancellationConvergencePageCommand,
normalizeClusterRunCancellationConvergencePageResult,
} = require('../dist/run/clusterRunCancellationConvergence');
test('normalizes one exact bounded convergence page command and result', () => {
assert.deepEqual(
normalizeClusterRunCancellationConvergencePageCommand({
limit: 2,
}),
{ limit: 2 },
);
assert.deepEqual(
normalizeClusterRunCancellationConvergencePageResult({
scanned: 2,
settledRuns: 2,
settledAttempts: 3,
blocked: 0,
hasMore: false,
}, 2),
{
scanned: 2,
settledRuns: 2,
settledAttempts: 3,
blocked: 0,
hasMore: false,
},
);
});
test('rejects widened and internally inconsistent page facts', () => {
assert.throws(() => normalizeClusterRunCancellationConvergencePageCommand({
limit: 1,
extra: true,
}));
assert.throws(() => normalizeClusterRunCancellationConvergencePageResult({
scanned: 1,
settledRuns: 2,
settledAttempts: 0,
blocked: 0,
hasMore: false,
}, 1));
assert.throws(() => normalizeClusterRunCancellationConvergencePageResult({
scanned: 1,
settledRuns: 1,
settledAttempts: 129,
blocked: 0,
hasMore: false,
}, 1));
});
test('coalesces callers and aggregates a bounded multi-page cycle', async () => {
const calls = [];
let release;
let page = 0;
const coordinator = new ClusterRunCancellationConvergenceCoordinator({
async convergePage(command) {
calls.push(command);
page += 1;
if (page === 1) await new Promise((resolve) => { release = resolve; });
return page === 1
? {
scanned: 2,
settledRuns: 2,
settledAttempts: 1,
blocked: 0,
hasMore: true,
}
: {
scanned: 1,
settledRuns: 1,
settledAttempts: 0,
blocked: 0,
hasMore: false,
};
},
}, {
pageSize: 2,
maxPages: 4,
});
const first = coordinator.reconcile();
const second = coordinator.reconcile();
assert.equal(first, second);
while (!release) await new Promise((resolve) => setImmediate(resolve));
release();
assert.deepEqual(await first, {
pages: 2,
scanned: 3,
settledRuns: 3,
settledAttempts: 1,
blocked: 0,
hasMore: false,
remaining: false,
stopReason: 'complete',
});
assert.equal(calls.length, 2);
assert.deepEqual(calls[0], { limit: 2 });
});
test('stops on blocked state and exposes page-limit continuation', async () => {
const blocked = new ClusterRunCancellationConvergenceCoordinator({
async convergePage() {
return {
scanned: 1,
settledRuns: 0,
settledAttempts: 0,
blocked: 1,
hasMore: true,
};
},
}, {});
assert.deepEqual(await blocked.reconcile(), {
pages: 1,
scanned: 1,
settledRuns: 0,
settledAttempts: 0,
blocked: 1,
hasMore: true,
remaining: true,
stopReason: 'blocked',
});
const limited = new ClusterRunCancellationConvergenceCoordinator({
async convergePage() {
return {
scanned: 1,
settledRuns: 1,
settledAttempts: 0,
blocked: 0,
hasMore: true,
};
},
}, {
pageSize: 1,
maxPages: 2,
});
assert.equal((await limited.reconcile()).stopReason, 'page_limit');
});
test('wraps malformed or stalled repositories as unavailable', async () => {
const coordinator = new ClusterRunCancellationConvergenceCoordinator({
async convergePage() {
return {
scanned: 0,
settledRuns: 0,
settledAttempts: 0,
blocked: 0,
hasMore: true,
};
},
}, {});
await assert.rejects(
coordinator.reconcile(),
ClusterRunCancellationConvergenceUnavailableError,
);
});
@@ -0,0 +1,261 @@
'use strict';
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
ClusterRunLostRetryCoordinator,
ClusterRunLostRetryUnavailableError,
buildClusterRunLostRetryTransition,
normalizeClusterRunLostRetryPageCommand,
normalizeClusterRunLostRetryPageResult,
} = require('../dist/run/clusterRunLostRetry');
function lostRun(status = 'lost') {
return {
id: 'run-1',
projectId: 'project-1',
taskId: 'task-1',
taskRevision: 'revision-1',
triggerType: 'manual',
executionOrigin: 'manual',
executionOwner: 'runtime',
status,
version: 4,
eventSequence: 4,
priority: 0,
createdAtMs: 100,
queuedAtMs: 110,
startedAtMs: 150,
errorCode: 'CLUSTER_RECOVERY_EXECUTION_NOT_RUNNING',
errorSummary: 'lost',
};
}
function lostAttempt(attempt = 1) {
return {
id: `attempt-${attempt}`,
runId: 'run-1',
attempt,
status: 'lost',
executorType: 'remote_worker',
callbackSequence: 0,
createdAtMs: 120,
startedAtMs: 150,
finishedAtMs: 200,
errorCode: 'CLUSTER_RECOVERY_EXECUTION_NOT_RUNNING',
errorSummary: 'lost',
};
}
function policy(overrides = {}) {
return {
runId: 'run-1',
maxAttempts: 3,
retryOnLost: true,
safety: 'idempotent',
backoffBaseMs: 1_000,
backoffMaxMs: 8_000,
version: 0,
createdAtMs: 100,
updatedAtMs: 100,
...overrides,
};
}
test('schedules a safe lost Run from its admitted immutable policy', () => {
const result = buildClusterRunLostRetryTransition({
run: lostRun(),
attempt: lostAttempt(),
policy: policy(),
observedAtMs: 300,
runEventId: 'event-1',
});
assert.equal(result.disposition, 'scheduled');
assert.equal(result.runTransitions.length, 1);
assert.equal(result.runTransitions[0].status, 'retry_wait');
assert.equal(result.runTransitions[0].version, 5);
assert.equal(result.policy.nextAttemptAtMs, 1_200);
assert.equal(result.policy.version, 1);
assert.deepEqual(
result.events.map((event) => [event.type, event.sequence]),
[['run.retry_wait', 5]],
);
});
test('requeues a due retry_wait Run with one fresh unleased Attempt', () => {
const result = buildClusterRunLostRetryTransition({
run: lostRun('retry_wait'),
attempt: lostAttempt(),
policy: policy({ nextAttemptAtMs: 250 }),
observedAtMs: 300,
runEventId: 'event-queued',
attemptId: 'attempt-2',
attemptEventId: 'event-claimed',
});
assert.equal(result.disposition, 'requeued');
assert.deepEqual(
result.runTransitions.map((run) => [run.status, run.version]),
[
['queued', 5],
['queued', 6],
],
);
assert.deepEqual(result.attempt, {
id: 'attempt-2',
runId: 'run-1',
attempt: 2,
status: 'claimed',
executorType: 'remote_worker',
callbackSequence: 0,
createdAtMs: 300,
});
assert.equal(
Object.prototype.hasOwnProperty.call(result.policy, 'nextAttemptAtMs'),
false,
);
assert.deepEqual(
result.events.map((event) => [event.type, event.sequence]),
[
['run.queued', 5],
['attempt.claimed', 6],
],
);
});
test('terminalizes disabled, unsafe and exhausted policies without retrying', () => {
const cases = [
[null, lostAttempt(), 'failed_disabled', 'RUN_LOST_RETRY_DISABLED'],
[
policy({ safety: 'unknown' }),
lostAttempt(),
'failed_unsafe',
'RUN_LOST_RETRY_UNSAFE',
],
[
policy({ maxAttempts: 3 }),
lostAttempt(3),
'failed_exhausted',
'RUN_LOST_RETRY_EXHAUSTED',
],
];
for (const [admittedPolicy, attempt, disposition, errorCode] of cases) {
const result = buildClusterRunLostRetryTransition({
run: lostRun(),
attempt,
policy: admittedPolicy,
observedAtMs: 300,
runEventId: `event-${disposition}`,
});
assert.equal(result.disposition, disposition);
assert.equal(result.runTransitions[0].status, 'failed');
assert.equal(result.runTransitions[0].errorCode, errorCode);
assert.equal(result.runTransitions[0].finishedAtMs, 300);
}
});
test('rejects cancellation, Workflow aggregates and early retry_wait', () => {
assert.throws(() =>
buildClusterRunLostRetryTransition({
run: { ...lostRun(), cancelRequestedAtMs: 250, cancelReason: 'user' },
attempt: lostAttempt(),
policy: policy(),
observedAtMs: 300,
runEventId: 'event-cancelled',
}),
);
assert.throws(() =>
buildClusterRunLostRetryTransition({
run: { ...lostRun(), triggerType: 'plugin_package_workflow' },
attempt: lostAttempt(),
policy: policy(),
observedAtMs: 300,
runEventId: 'event-workflow',
}),
);
assert.throws(() =>
buildClusterRunLostRetryTransition({
run: lostRun('retry_wait'),
attempt: lostAttempt(),
policy: policy({ nextAttemptAtMs: 301 }),
observedAtMs: 300,
runEventId: 'event-early',
attemptId: 'attempt-2',
attemptEventId: 'event-2',
}),
);
});
test('normalizes one bounded page and coalesces overlapping callers', async () => {
assert.deepEqual(normalizeClusterRunLostRetryPageCommand({ limit: 2 }), {
limit: 2,
});
assert.deepEqual(
normalizeClusterRunLostRetryPageResult(
{
scanned: 2,
scheduled: 1,
requeued: 0,
failed: 0,
raced: 1,
hasMore: false,
},
2,
),
{
scanned: 2,
scheduled: 1,
requeued: 0,
failed: 0,
raced: 1,
hasMore: false,
},
);
let release;
const coordinator = new ClusterRunLostRetryCoordinator(
{
async reconcilePage(command) {
await new Promise((resolve) => {
release = resolve;
});
return {
scanned: command.limit,
scheduled: command.limit,
requeued: 0,
failed: 0,
raced: 0,
hasMore: false,
};
},
},
{ pageSize: 2 },
);
const first = coordinator.reconcile();
const second = coordinator.reconcile();
assert.equal(first, second);
while (!release) await new Promise((resolve) => setImmediate(resolve));
release();
assert.equal((await first).scheduled, 2);
});
test('wraps malformed repository results as unavailable', async () => {
const coordinator = new ClusterRunLostRetryCoordinator({
async reconcilePage() {
return {
scanned: 1,
scheduled: 1,
requeued: 1,
failed: 0,
raced: 0,
hasMore: false,
};
},
});
await assert.rejects(
coordinator.reconcile(),
ClusterRunLostRetryUnavailableError,
);
});
@@ -0,0 +1,132 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidClusterScheduleError,
normalizeClaimClusterScheduleCommand,
normalizeClusterScheduleClaim,
normalizeCommitClusterScheduleDecisionCommand,
resolveClusterScheduleDecision,
} = require('../dist/scheduler/clusterScheduler');
function nextMinute(schedule, afterMs) {
if (schedule.expression !== '* * * * *' || schedule.timezone !== 'UTC') {
throw new Error('unsupported test schedule');
}
return Math.floor(afterMs / 60_000 + 1) * 60_000;
}
function claim(overrides = {}) {
return {
projectId: 'default',
triggerId: 'trigger-1',
triggerRevision: 1,
triggerContentDigest: 'a'.repeat(64),
triggerUpdatedAtMs: 1,
taskId: 'task-1',
taskRevision: 1,
taskContentDigest: 'b'.repeat(64),
expression: '* * * * *',
timezone: 'UTC',
misfirePolicy: 'skip',
stateVersion: 2,
nextFireAtMs: 60_000,
claimOwner: 'scheduler-a',
claimToken: '019f7700-0000-7000-8000-000000000001',
claimVersion: 1,
claimAcquiredAtMs: 60_000,
claimExpiresAtMs: 120_000,
...overrides,
};
}
test('normalizes a database-timed schedule claim and resolves one occurrence', () => {
assert.deepEqual(normalizeClusterScheduleClaim(claim()), claim());
assert.equal(
resolveClusterScheduleDecision(claim(), 5_000, nextMinute).disposition,
'admit',
);
assert.deepEqual(
normalizeClaimClusterScheduleCommand({
ownerId: 'scheduler-a',
claimToken: '019f7700-0000-7000-8000-000000000002',
leaseMs: 30_000,
}),
{
ownerId: 'scheduler-a',
claimToken: '019f7700-0000-7000-8000-000000000002',
leaseMs: 30_000,
},
);
});
test('rejects widened, caller-timed and weak schedule claims', () => {
assert.throws(
() => normalizeClusterScheduleClaim(claim({ claimAcquiredAtMs: 120_000 })),
InvalidClusterScheduleError,
);
assert.throws(
() => normalizeClusterScheduleClaim({ ...claim(), extra: true }),
InvalidClusterScheduleError,
);
assert.throws(
() =>
normalizeClaimClusterScheduleCommand({
ownerId: 'scheduler-a',
claimToken: 'not-a-uuid',
leaseMs: 1,
}),
InvalidClusterScheduleError,
);
assert.throws(
() =>
normalizeClaimClusterScheduleCommand({
ownerId: 'scheduler-a',
claimToken: '019f7700-0000-7000-8000-000000000002',
observedAtMs: 60_000,
leaseMs: 30_000,
}),
InvalidClusterScheduleError,
);
});
test('normalizes an exact admission command and binds every decision fact', () => {
const claimed = claim();
const decision = resolveClusterScheduleDecision(claimed, 5_000, nextMinute);
const command = {
claim: claimed,
decision,
runId: '019f7700-0000-7000-8000-000000000003',
attemptId: '019f7700-0000-7000-8000-000000000004',
createdEventId: '019f7700-0000-7000-8000-000000000005',
queuedEventId: '019f7700-0000-7000-8000-000000000006',
};
assert.deepEqual(
normalizeCommitClusterScheduleDecisionCommand(command),
command,
);
assert.throws(
() =>
normalizeCommitClusterScheduleDecisionCommand({
...command,
decision: {
...decision,
candidate: { ...decision.candidate, stateVersion: 3 },
},
}),
InvalidClusterScheduleError,
);
assert.throws(
() =>
normalizeCommitClusterScheduleDecisionCommand({
claim: claimed,
decision: {
candidate: decision.candidate,
observedAtMs: 60_001,
nextFireAtMs: decision.nextFireAtMs,
disposition: 'skip',
},
runId: command.runId,
}),
InvalidClusterScheduleError,
);
});
@@ -0,0 +1,79 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidIdentityAdministrationValueError,
normalizeAppendIdentitySubjectCommand,
} = require('@qinglong/runtime-core/identity-administration');
function command(overrides = {}) {
const mutation = {
mutationId: '123e4567-e89b-42d3-a456-426614174201',
operation: 'register',
subject: { type: 'api_app', id: 'app_primary' },
subjectVersion: 1,
expectedPreviousVersion: 0,
status: 'active',
changedBy: { type: 'user', id: 'usr_admin' },
createdAtMs: 100,
...overrides.mutation,
};
return {
expectedCurrentVersion: 0,
mutation,
audit: {
eventId: mutation.mutationId,
requestId: 'request-identity-register',
operationId: `identity.${mutation.operation}`,
projectId: null,
subject: mutation.changedBy,
authenticationId: 'admin:usr_admin:1',
outcome: 'allowed',
reasons: ['identity_admin'],
fence: null,
occurredAtMs: mutation.createdAtMs,
...overrides.audit,
},
...overrides.command,
};
}
test('normalizes an auditable identity registration command', () => {
const input = command();
const normalized = normalizeAppendIdentitySubjectCommand(input);
assert.deepEqual(normalized, input);
input.mutation.subject.id = 'mutated';
assert.equal(normalized.mutation.subject.id, 'app_primary');
assert.equal(Object.isFrozen(normalized.mutation), true);
});
test('enforces transitions, strong actor types and audit coupling', () => {
for (const input of [
command({ mutation: { subjectVersion: 2 } }),
command({ mutation: { changedBy: { type: 'agent', id: 'agent-1' } } }),
command({ mutation: { operation: 'disable', status: 'disabled' } }),
command({ audit: { eventId: '123e4567-e89b-42d3-a456-426614174299' } }),
command({ command: { unexpected: true } }),
]) {
assert.throws(
() => normalizeAppendIdentitySubjectCommand(input),
InvalidIdentityAdministrationValueError,
);
}
});
test('accepts a version-fenced disable command', () => {
const input = command({
mutation: {
mutationId: '123e4567-e89b-42d3-a456-426614174202',
operation: 'disable',
subjectVersion: 3,
expectedPreviousVersion: 2,
status: 'disabled',
},
command: { expectedCurrentVersion: 2 },
});
assert.equal(
normalizeAppendIdentitySubjectCommand(input).mutation.subjectVersion,
3,
);
});
@@ -0,0 +1,63 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
MAX_LOCAL_COMPLETION_RECEIPT_JOURNAL_PAGE,
assertLocalCompletionReceiptId,
assertLocalCompletionReceiptJournalCursor,
assertLocalCompletionReceiptJournalLimit,
assertLocalCompletionReceiptTimestamp,
} = require('../dist/local-runtime/localCompletionReceiptJournal');
const ATTEMPT_ID = '019f70c0-0000-7000-8000-000000000001';
test('accepts bounded portable receipt identities without path syntax', () => {
assert.doesNotThrow(() =>
assertLocalCompletionReceiptId(ATTEMPT_ID, 'attemptId'),
);
assert.doesNotThrow(() =>
assertLocalCompletionReceiptId(
'wta:0123456789abcdef0123456789abcdef',
'attemptId',
),
);
for (const value of [
'',
'../attempt-1',
'attempt/1',
'attempt\\1',
'attempt 1',
`attempt-${'a'.repeat(36)}`,
]) {
assert.throws(
() => assertLocalCompletionReceiptId(value, 'attemptId'),
/bounded portable execution ID/,
);
}
});
test('bounds timestamps, cursors and page sizes', () => {
assert.doesNotThrow(() => assertLocalCompletionReceiptTimestamp(0, 'time'));
assert.doesNotThrow(() =>
assertLocalCompletionReceiptJournalCursor({
updatedAtMs: 1,
attemptId: ATTEMPT_ID,
}),
);
assert.doesNotThrow(() =>
assertLocalCompletionReceiptJournalLimit(
MAX_LOCAL_COMPLETION_RECEIPT_JOURNAL_PAGE,
),
);
for (const value of [-1, 1.5, Number.MAX_SAFE_INTEGER + 1]) {
assert.throws(
() => assertLocalCompletionReceiptTimestamp(value, 'time'),
/non-negative safe integer/,
);
}
for (const value of [0, 1.5, MAX_LOCAL_COMPLETION_RECEIPT_JOURNAL_PAGE + 1]) {
assert.throws(
() => assertLocalCompletionReceiptJournalLimit(value),
/limit must be between/,
);
}
});
@@ -0,0 +1,103 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
createLocalExecutionContextRecipe,
createLocalTaskExecutionRevision,
localTaskExecutionRevisionDigest,
normalizeLocalDispatchCandidate,
normalizeLocalTaskExecutionRevision,
} = require('../dist/local-runtime/localDispatch');
test('context recipes are content-addressed and canonical', () => {
const recipe = createLocalExecutionContextRecipe({
environment: [
{ name: 'Z_VALUE', kind: 'public', value: 'z' },
{ name: 'A_VALUE', kind: 'secret', secretRef: 'secret-a' },
],
createdAtMs: 1,
});
assert.match(recipe.contextRef, /^localctx:sha256:[a-f0-9]{64}$/);
assert.equal(recipe.contextRef, `localctx:sha256:${recipe.contentDigest}`);
assert.deepEqual(
recipe.environment.map(({ name }) => name),
['A_VALUE', 'Z_VALUE'],
);
assert.throws(
() =>
createLocalExecutionContextRecipe({
environment: [
{ name: 'QL3_RECEIPT_TOKEN', kind: 'public', value: 'forged' },
],
createdAtMs: 1,
}),
/invalid or duplicated/,
);
});
test('local revisions use bounded absolute commands and immutable context refs', () => {
const recipe = createLocalExecutionContextRecipe({
environment: [],
createdAtMs: 1,
});
const revision = createLocalTaskExecutionRevision({
projectId: 'default',
taskId: 'task-1',
taskRevision: 'revision-1',
executorType: 'local_process',
command: { kind: 'argv', file: '/bin/echo', args: ['hello'] },
contextRef: recipe.contextRef,
createdAtMs: 1,
});
assert.equal(Object.isFrozen(revision), true);
assert.equal(Object.isFrozen(revision.command), true);
assert.match(revision.contentDigest, /^[a-f0-9]{64}$/);
assert.equal(
revision.contentDigest,
localTaskExecutionRevisionDigest(revision),
);
assert.equal(
createLocalTaskExecutionRevision({ ...revision, createdAtMs: 2 })
.contentDigest,
revision.contentDigest,
);
assert.throws(
() =>
normalizeLocalTaskExecutionRevision({
...revision,
contentDigest: '0'.repeat(64),
}),
/digest does not match/,
);
assert.throws(
() =>
normalizeLocalTaskExecutionRevision({
...revision,
command: { kind: 'argv', file: 'echo', args: [] },
}),
/absolute/,
);
});
test('dispatch candidates reject non-local executors and invalid ordering facts', () => {
const candidate = {
runId: 'run-1',
attemptId: 'attempt-1',
projectId: 'default',
taskId: 'task-1',
taskRevision: 'revision-1',
attemptNumber: 1,
executorType: 'local_process',
priority: 1,
queuedAtMs: 1,
attemptCreatedAtMs: 1,
};
assert.deepEqual(normalizeLocalDispatchCandidate(candidate), candidate);
assert.throws(
() =>
normalizeLocalDispatchCandidate({
...candidate,
executorType: 'remote_worker',
}),
/executor type/,
);
});
@@ -0,0 +1,92 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
MAX_LOCAL_EXECUTION_CONTROL_PAGE,
assertLocalExecutionControlLimit,
normalizeLocalActiveExecutionCandidate,
normalizeLocalActiveExecutionCursor,
normalizeLocalExecutionControlCandidate,
normalizeLocalExecutionControlCursor,
} = require('../dist/local-runtime/localExecutionControl');
test('normalizes bounded deadline, cancellation and active candidates', () => {
assert.deepEqual(
normalizeLocalExecutionControlCandidate({
kind: 'deadline',
runId: 'run-1',
attemptId: 'attempt-1',
dueAtMs: 10,
}),
{
kind: 'deadline',
runId: 'run-1',
attemptId: 'attempt-1',
dueAtMs: 10,
},
);
assert.equal(
normalizeLocalExecutionControlCandidate({
kind: 'cancellation',
runId: 'run-1',
attemptId: 'attempt-1',
dueAtMs: 11,
cancelReason: 'shutdown',
}).cancelReason,
'shutdown',
);
assert.equal(
normalizeLocalActiveExecutionCandidate({
runId: 'run-1',
attemptId: 'attempt-1',
attemptCreatedAtMs: 1,
}).attemptCreatedAtMs,
1,
);
assert.equal(
normalizeLocalExecutionControlCursor({
dueAtMs: 10,
kind: 'deadline',
attemptId: 'attempt-1',
}).attemptId,
'attempt-1',
);
assert.equal(
normalizeLocalActiveExecutionCursor({
attemptCreatedAtMs: 1,
attemptId: 'attempt-1',
}).attemptId,
'attempt-1',
);
});
test('rejects widened candidates and unbounded control pages', () => {
assert.throws(
() =>
normalizeLocalExecutionControlCandidate({
kind: 'deadline',
runId: 'run-1',
attemptId: 'attempt-1',
dueAtMs: 1,
cancelReason: 'timeout',
}),
/shape/,
);
assert.throws(
() =>
normalizeLocalExecutionControlCandidate({
kind: 'cancellation',
runId: 'run-1',
attemptId: 'attempt-1',
dueAtMs: 1,
cancelReason: 'invalid',
}),
/reason/,
);
assert.doesNotThrow(() =>
assertLocalExecutionControlLimit(MAX_LOCAL_EXECUTION_CONTROL_PAGE),
);
assert.throws(
() => assertLocalExecutionControlLimit(MAX_LOCAL_EXECUTION_CONTROL_PAGE + 1),
/limit/,
);
});
@@ -0,0 +1,128 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidLocalOwnerBootstrapValueError,
localOwnerBootstrapDigestMatches,
localOwnerBootstrapTokenDigest,
normalizeClaimLocalOwnerCommand,
normalizeLocalOwnerSecretDeliveryAcknowledgementRecord,
} = require('../dist/local-owner/localOwnerBootstrap');
const NOW = 1_760_000_000_000;
const TOKEN = Buffer.alloc(32, 7).toString('base64url');
const CHALLENGE_ID = Buffer.alloc(16, 8).toString('base64url');
function claim(overrides = {}) {
const principal = {
subject: { type: 'user', id: 'user-1' },
authenticationId: 'local_credential:owner:1',
authenticatedAtMs: NOW,
expiresAtMs: NOW + 60_000,
assurance: 'single_factor',
};
return {
projectId: 'default',
mutationId: '00000000-0000-4000-8000-000000000201',
requestId: 'claim-201',
challengeId: CHALLENGE_ID,
tokenDigest: localOwnerBootstrapTokenDigest('default', CHALLENGE_ID, TOKEN),
principal,
credentialId: 'owner',
credentialVersion: 1,
claimedAtMs: NOW,
audit: {
eventId: '00000000-0000-4000-8000-000000000201',
requestId: 'claim-201',
operationId: 'project.owner_bootstrap_claim',
projectId: 'default',
subject: principal.subject,
authenticationId: principal.authenticationId,
outcome: 'allowed',
reasons: ['owner_bootstrap_claim'],
fence: { projectVersion: 1, bindingVersion: 1 },
occurredAtMs: NOW,
},
...overrides,
};
}
test('challenge digest is domain-bound and timing-safe comparable', () => {
const digest = localOwnerBootstrapTokenDigest('default', CHALLENGE_ID, TOKEN);
assert.match(digest, /^[0-9a-f]{64}$/);
assert.equal(localOwnerBootstrapDigestMatches(digest, digest), true);
assert.notEqual(
digest,
localOwnerBootstrapTokenDigest('other', CHALLENGE_ID, TOKEN),
);
});
test('claim only accepts single-factor authenticated User credentials', () => {
assert.equal(
normalizeClaimLocalOwnerCommand(claim()).principal.assurance,
'single_factor',
);
const invalid = claim();
assert.throws(
() =>
normalizeClaimLocalOwnerCommand({
...invalid,
principal: { ...invalid.principal, assurance: 'local_console' },
}),
InvalidLocalOwnerBootstrapValueError,
);
});
test('claim rejects widened transport-controlled identity shape', () => {
assert.throws(
() => normalizeClaimLocalOwnerCommand({ ...claim(), userId: 'forged' }),
InvalidLocalOwnerBootstrapValueError,
);
});
test('normalizes exact secret-free delivery acknowledgement records', () => {
const credential = normalizeLocalOwnerSecretDeliveryAcknowledgementRecord({
kind: 'credential',
mutationId: '00000000-0000-4000-8000-000000000202',
requestId: 'provision-202',
subjectId: `usr_${Buffer.alloc(16, 9).toString('base64url')}`,
credentialId: `own_${Buffer.alloc(16, 10).toString('base64url')}`,
factDigest: 'a'.repeat(64),
ttlMs: 86_400_000,
deliveryDigest: 'b'.repeat(64),
acknowledgedAtMs: NOW,
});
assert.equal(credential.kind, 'credential');
assert.equal('secret' in credential, false);
const challenge = normalizeLocalOwnerSecretDeliveryAcknowledgementRecord({
kind: 'challenge',
projectId: 'default',
mutationId: '00000000-0000-4000-8000-000000000203',
requestId: 'issue-203',
challengeId: CHALLENGE_ID,
factDigest: 'c'.repeat(64),
ttlMs: 600_000,
deliveryDigest: 'd'.repeat(64),
acknowledgedAtMs: NOW,
});
assert.equal(challenge.kind, 'challenge');
});
test('rejects widened or malformed delivery acknowledgements', () => {
assert.throws(
() =>
normalizeLocalOwnerSecretDeliveryAcknowledgementRecord({
kind: 'challenge',
projectId: 'default',
mutationId: '00000000-0000-4000-8000-000000000204',
requestId: 'issue-204',
challengeId: CHALLENGE_ID,
factDigest: 'c'.repeat(64),
ttlMs: 600_000,
deliveryDigest: 'd'.repeat(64),
acknowledgedAtMs: NOW,
secret: TOKEN,
}),
InvalidLocalOwnerBootstrapValueError,
);
});
@@ -0,0 +1,119 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidLocalOwnerDeliveryAcknowledgementGcValueError,
MIN_LOCAL_OWNER_ACKNOWLEDGEMENT_AUDIT_RETENTION_MS,
MIN_LOCAL_OWNER_ACKNOWLEDGEMENT_REPLAY_RETENTION_MS,
localOwnerDeliveryAcknowledgementGcRetentionPolicyDigest,
normalizeCompactLocalOwnerDeliveryAcknowledgementCommand,
} = require('../dist/local-owner/localOwnerDeliveryAcknowledgementGc');
const {
localOwnerSecretDeliveryAcknowledgementSemanticDigest,
} = require('../dist/local-owner/localOwnerBootstrap');
const ACK_MUTATION_ID = '00000000-0000-4000-8000-000000000a01';
const GC_MUTATION_ID = '00000000-0000-4000-8000-000000000a02';
const COMPACTED_AT_MS = 4_000_000_000;
function policy() {
return {
version: 1,
replayRetentionMs: MIN_LOCAL_OWNER_ACKNOWLEDGEMENT_REPLAY_RETENTION_MS,
auditRetentionMs: MIN_LOCAL_OWNER_ACKNOWLEDGEMENT_AUDIT_RETENTION_MS,
};
}
function command() {
return {
mutationId: GC_MUTATION_ID,
requestId: 'acknowledgement-gc-1',
acknowledgementMutationId: ACK_MUTATION_ID,
expectedKind: 'credential',
expectedDeliveryDigest: 'd'.repeat(64),
bridgeClearEvidence: {
kind: 'credential',
acknowledgementMutationId: ACK_MUTATION_ID,
inspectedAtMs: COMPACTED_AT_MS,
evidenceDigest: 'e'.repeat(64),
},
retentionPolicy: policy(),
compactedAtMs: COMPACTED_AT_MS,
audit: {
eventId: GC_MUTATION_ID,
requestId: 'acknowledgement-gc-1',
operationId: 'owner.delivery_acknowledgement.gc',
projectId: null,
subject: { type: 'system', id: 'owner-acknowledgement-gc' },
authenticationId: 'local-owner-console',
outcome: 'allowed',
reasons: ['delivery_acknowledgement_gc'],
fence: null,
occurredAtMs: COMPACTED_AT_MS,
},
};
}
test('normalizes exact acknowledgement GC policy and bridge-bound command', () => {
const normalized = normalizeCompactLocalOwnerDeliveryAcknowledgementCommand(
command(),
);
assert.equal(Object.isFrozen(normalized), true);
assert.equal(Object.isFrozen(normalized.bridgeClearEvidence), true);
assert.equal(
localOwnerDeliveryAcknowledgementGcRetentionPolicyDigest(policy()),
localOwnerDeliveryAcknowledgementGcRetentionPolicyDigest({ ...policy() }),
);
});
test('rejects widened commands, weak retention and bridge identity drift', () => {
assert.throws(
() =>
normalizeCompactLocalOwnerDeliveryAcknowledgementCommand({
...command(),
force: true,
}),
InvalidLocalOwnerDeliveryAcknowledgementGcValueError,
);
assert.throws(
() =>
normalizeCompactLocalOwnerDeliveryAcknowledgementCommand({
...command(),
retentionPolicy: { ...policy(), replayRetentionMs: 1 },
}),
InvalidLocalOwnerDeliveryAcknowledgementGcValueError,
);
assert.throws(
() =>
normalizeCompactLocalOwnerDeliveryAcknowledgementCommand({
...command(),
bridgeClearEvidence: {
...command().bridgeClearEvidence,
kind: 'challenge',
},
}),
InvalidLocalOwnerDeliveryAcknowledgementGcValueError,
);
});
test('acknowledgement semantic digest binds kind-specific identity and time', () => {
const record = {
kind: 'credential',
mutationId: ACK_MUTATION_ID,
requestId: 'owner-provision-1',
subjectId: `usr_${'a'.repeat(22)}`,
credentialId: `own_${'b'.repeat(22)}`,
factDigest: 'c'.repeat(64),
ttlMs: 600_000,
deliveryDigest: 'd'.repeat(64),
acknowledgedAtMs: 10,
};
const digest = localOwnerSecretDeliveryAcknowledgementSemanticDigest(record);
assert.match(digest, /^[0-9a-f]{64}$/);
assert.notEqual(
digest,
localOwnerSecretDeliveryAcknowledgementSemanticDigest({
...record,
acknowledgedAtMs: 11,
}),
);
});
@@ -0,0 +1,76 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidLocalOwnerPepperValueError,
normalizeActivateLocalOwnerPepperKeyCommand,
normalizeRegisterLocalOwnerPepperKeyCommand,
} = require('../dist/local-owner/localOwnerPepper');
const mutationId = '018f4f58-7d5a-4d82-8f7d-5da12f05c001';
test('normalizes exact register and activation CAS commands', () => {
const register = normalizeRegisterLocalOwnerPepperKeyCommand({
mutationId,
pepperKeyId: 'owner-2026-01',
materialDigest: 'a'.repeat(64),
backupDigest: 'b'.repeat(64),
registeredAtMs: 10,
});
const activate = normalizeActivateLocalOwnerPepperKeyCommand({
mutationId,
pepperKeyId: register.pepperKeyId,
expectedGeneration: 0,
activatedAtMs: 11,
});
assert.equal(Object.isFrozen(register), true);
assert.equal(Object.isFrozen(activate), true);
});
test('accepts production millisecond timestamps beyond the 32-bit version range', () => {
const registeredAtMs = 1_760_000_000_000;
const activatedAtMs = registeredAtMs + 1;
assert.equal(
normalizeRegisterLocalOwnerPepperKeyCommand({
mutationId,
pepperKeyId: 'owner-2026-01',
materialDigest: 'a'.repeat(64),
backupDigest: 'b'.repeat(64),
registeredAtMs,
}).registeredAtMs,
registeredAtMs,
);
assert.equal(
normalizeActivateLocalOwnerPepperKeyCommand({
mutationId,
pepperKeyId: 'owner-2026-01',
expectedGeneration: 0,
activatedAtMs,
}).activatedAtMs,
activatedAtMs,
);
});
test('rejects widened, malformed and unfenced pepper commands', () => {
assert.throws(
() =>
normalizeRegisterLocalOwnerPepperKeyCommand({
mutationId,
pepperKeyId: 'owner-2026-01',
materialDigest: 'a'.repeat(64),
backupDigest: 'b'.repeat(64),
registeredAtMs: 10,
material: 'secret',
}),
InvalidLocalOwnerPepperValueError,
);
assert.throws(
() =>
normalizeActivateLocalOwnerPepperKeyCommand({
mutationId: 'bad',
pepperKeyId: 'owner-2026-01',
expectedGeneration: -1,
activatedAtMs: 11,
}),
InvalidLocalOwnerPepperValueError,
);
});
@@ -0,0 +1,131 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidLocalOwnerPepperMaterialGcValueError,
MAX_LOCAL_OWNER_PEPPER_RETENTION_MS,
MIN_LOCAL_OWNER_PEPPER_ACK_RETENTION_MS,
MIN_LOCAL_OWNER_PEPPER_AUDIT_RETENTION_MS,
MIN_LOCAL_OWNER_PEPPER_BACKUP_RETENTION_MS,
localOwnerPepperMaterialGcRetentionPolicyDigest,
normalizeCompleteLocalOwnerPepperMaterialGcCommand,
normalizePrepareLocalOwnerPepperMaterialGcCommand,
} = require('../dist/local-owner/localOwnerPepperMaterialGc');
const PREPARE_MUTATION_ID = '00000000-0000-4000-8000-000000000901';
const COMPLETE_MUTATION_ID = '00000000-0000-4000-8000-000000000902';
function policy() {
return {
version: 1,
acknowledgementRetentionMs: MIN_LOCAL_OWNER_PEPPER_ACK_RETENTION_MS,
auditRetentionMs: MIN_LOCAL_OWNER_PEPPER_AUDIT_RETENTION_MS,
backupRetentionMs: MIN_LOCAL_OWNER_PEPPER_BACKUP_RETENTION_MS,
};
}
function audit(eventId, requestId, operation, occurredAtMs) {
return {
eventId,
requestId,
operationId: `owner.pepper.material_gc.${operation}`,
projectId: null,
subject: { type: 'system', id: 'owner-pepper-gc' },
authenticationId: 'local-owner-console',
outcome: 'allowed',
reasons: ['pepper_material_gc'],
fence: null,
occurredAtMs,
};
}
function prepareCommand() {
return {
mutationId: PREPARE_MUTATION_ID,
requestId: 'pepper-gc-prepare',
pepperKeyId: 'owner-key-retired',
expectedMaterialDigest: 'a'.repeat(64),
expectedBackupMaterialDigest: 'b'.repeat(64),
expectedActivePepperKeyId: 'owner-key-active',
expectedActiveGeneration: 2,
expectedActiveMaterialDigest: 'c'.repeat(64),
retentionPolicy: policy(),
preparedAtMs: 3_000_000_000,
audit: audit(
PREPARE_MUTATION_ID,
'pepper-gc-prepare',
'prepare',
3_000_000_000,
),
};
}
test('normalizes exact GC commands and stable minimum retention policy', () => {
const firstDigest = localOwnerPepperMaterialGcRetentionPolicyDigest(policy());
const secondDigest = localOwnerPepperMaterialGcRetentionPolicyDigest({
...policy(),
});
assert.equal(firstDigest, secondDigest);
assert.match(firstDigest, /^[0-9a-f]{64}$/);
const prepared = normalizePrepareLocalOwnerPepperMaterialGcCommand(
prepareCommand(),
);
const completed = normalizeCompleteLocalOwnerPepperMaterialGcCommand({
prepareMutationId: PREPARE_MUTATION_ID,
mutationId: COMPLETE_MUTATION_ID,
requestId: 'pepper-gc-complete',
destructionProofDigest: 'd'.repeat(64),
completedAtMs: 3_000_000_001,
audit: audit(
COMPLETE_MUTATION_ID,
'pepper-gc-complete',
'complete',
3_000_000_001,
),
});
assert.equal(Object.isFrozen(prepared), true);
assert.equal(Object.isFrozen(prepared.retentionPolicy), true);
assert.equal(Object.isFrozen(completed), true);
});
test('rejects retention below reviewed bounds and above the maximum', () => {
assert.throws(
() =>
localOwnerPepperMaterialGcRetentionPolicyDigest({
...policy(),
acknowledgementRetentionMs: MIN_LOCAL_OWNER_PEPPER_ACK_RETENTION_MS - 1,
}),
InvalidLocalOwnerPepperMaterialGcValueError,
);
assert.throws(
() =>
localOwnerPepperMaterialGcRetentionPolicyDigest({
...policy(),
auditRetentionMs: MAX_LOCAL_OWNER_PEPPER_RETENTION_MS + 1,
}),
InvalidLocalOwnerPepperMaterialGcValueError,
);
});
test('rejects widened commands and audit identities not bound to the mutation', () => {
assert.throws(
() =>
normalizePrepareLocalOwnerPepperMaterialGcCommand({
...prepareCommand(),
force: true,
}),
InvalidLocalOwnerPepperMaterialGcValueError,
);
const command = prepareCommand();
assert.throws(
() =>
normalizePrepareLocalOwnerPepperMaterialGcCommand({
...command,
audit: {
...command.audit,
authenticationId: 'local-runtime',
},
}),
InvalidLocalOwnerPepperMaterialGcValueError,
);
});
@@ -0,0 +1,130 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidLocalScheduleError,
assertLocalSchedulePageSize,
resolveLocalScheduleDecision,
} = require('../dist/scheduler/localScheduler');
const MINUTE = 60_000;
function nextMinute(schedule, afterMs) {
if (schedule.expression !== '* * * * *' || schedule.timezone !== 'UTC') {
throw new Error('unsupported test schedule');
}
return Math.floor(afterMs / MINUTE + 1) * MINUTE;
}
function candidate(overrides = {}) {
return {
projectId: 'default',
triggerId: 'trigger-1',
triggerRevision: 1,
triggerContentDigest: 'a'.repeat(64),
triggerUpdatedAtMs: 1,
taskId: 'task-1',
taskRevision: 1,
taskContentDigest: 'b'.repeat(64),
expression: '* * * * *',
timezone: 'UTC',
misfirePolicy: 'skip',
stateVersion: 0,
nextFireAtMs: MINUTE,
...overrides,
};
}
test('admits one on-time occurrence and advances beyond the observation', () => {
assert.deepEqual(
resolveLocalScheduleDecision(
candidate(),
MINUTE + 1_000,
5_000,
nextMinute,
),
{
candidate: candidate(),
observedAtMs: MINUTE + 1_000,
scheduledForMs: MINUTE,
nextFireAtMs: 2 * MINUTE,
disposition: 'admit',
},
);
});
test('applies skip and fire-once misfire without replaying a backlog', () => {
const observedAtMs = 10 * MINUTE + 30_000;
const skipped = resolveLocalScheduleDecision(
candidate(),
observedAtMs,
5_000,
nextMinute,
);
assert.equal(skipped.disposition, 'skip');
assert.equal(skipped.nextFireAtMs, 11 * MINUTE);
const admitted = resolveLocalScheduleDecision(
candidate({ misfirePolicy: 'fire_once' }),
observedAtMs,
5_000,
nextMinute,
);
assert.equal(admitted.disposition, 'admit');
assert.equal(admitted.scheduledForMs, MINUTE);
assert.equal(admitted.nextFireAtMs, 11 * MINUTE);
});
test('initializes migrated state without inventing a due occurrence', () => {
const decision = resolveLocalScheduleDecision(
candidate({ triggerUpdatedAtMs: 30_000, nextFireAtMs: null }),
40_000,
5_000,
nextMinute,
);
assert.deepEqual(
{
disposition: decision.disposition,
nextFireAtMs: decision.nextFireAtMs,
scheduledForMs: decision.scheduledForMs,
},
{
disposition: 'initialize',
nextFireAtMs: MINUTE,
scheduledForMs: undefined,
},
);
});
test('rejects widened candidates, invalid cron and unbounded pages', () => {
assert.throws(
() =>
resolveLocalScheduleDecision(
{ ...candidate(), extra: true },
MINUTE,
0,
nextMinute,
),
InvalidLocalScheduleError,
);
assert.throws(
() =>
resolveLocalScheduleDecision(
candidate({ expression: 'invalid cron' }),
MINUTE,
0,
nextMinute,
),
InvalidLocalScheduleError,
);
assert.throws(
() =>
resolveLocalScheduleDecision(
candidate(),
MINUTE,
0,
(_schedule, afterMs) => afterMs,
),
InvalidLocalScheduleError,
);
assert.throws(() => assertLocalSchedulePageSize(257), RangeError);
});
@@ -0,0 +1,99 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidLocalSecretError,
LOCAL_SECRET_ALGORITHM,
MAX_LOCAL_SECRET_PLAINTEXT_BYTES,
createLocalSecretRef,
localSecretBinary,
localSecretEnvelopeAad,
normalizeLocalSecretEnvelope,
parseLocalSecretRef,
} = require('../dist/secret/localSecret');
test('local Secret references are canonical, exact-shape Project capabilities', () => {
const current = createLocalSecretRef({ projectId: 'project-1', name: 'TOKEN' });
const historical = createLocalSecretRef({
projectId: 'project-1',
name: 'TOKEN',
version: 7,
});
assert.deepEqual(parseLocalSecretRef(current), {
projectId: 'project-1',
name: 'TOKEN',
});
assert.deepEqual(parseLocalSecretRef(historical), {
projectId: 'project-1',
name: 'TOKEN',
version: 7,
});
assert.equal(Object.isFrozen(parseLocalSecretRef(current)), true);
const unknownField = `qlsecret:v1:${Buffer.from(
JSON.stringify({ projectId: 'project-1', name: 'TOKEN', scope: 'global' }),
).toString('base64url')}`;
const reordered = `qlsecret:v1:${Buffer.from(
JSON.stringify({ name: 'TOKEN', projectId: 'project-1' }),
).toString('base64url')}`;
assert.throws(() => parseLocalSecretRef(unknownField), InvalidLocalSecretError);
assert.throws(() => parseLocalSecretRef(reordered), InvalidLocalSecretError);
assert.throws(
() => createLocalSecretRef({ projectId: 'project-1', name: 'TOKEN', extra: true }),
InvalidLocalSecretError,
);
});
test('local Secret binary fields and envelopes enforce bounded exact contracts', () => {
const envelope = {
projectId: 'project-1',
name: 'TOKEN',
version: 1,
mutationId: 'mutation-1',
keyId: 'key-1',
algorithm: LOCAL_SECRET_ALGORITHM,
nonce: Buffer.alloc(12, 1).toString('base64url'),
ciphertext: Buffer.from('secret').toString('base64url'),
authTag: Buffer.alloc(16, 2).toString('base64url'),
createdAtMs: 1,
};
const normalized = normalizeLocalSecretEnvelope(envelope);
assert.deepEqual(normalized, envelope);
assert.equal(Object.isFrozen(normalized), true);
assert.throws(
() => normalizeLocalSecretEnvelope({ ...envelope, plaintext: 'secret' }),
InvalidLocalSecretError,
);
assert.throws(
() => localSecretBinary('nonce', Buffer.alloc(11).toString('base64url')),
InvalidLocalSecretError,
);
assert.throws(
() =>
localSecretBinary(
'ciphertext',
Buffer.alloc(MAX_LOCAL_SECRET_PLAINTEXT_BYTES + 1).toString('base64url'),
),
InvalidLocalSecretError,
);
});
test('local Secret AAD is stable and binds every routing and version fact', () => {
const facts = {
projectId: 'project-1',
name: 'TOKEN',
version: 3,
mutationId: 'mutation-3',
keyId: 'key-2',
algorithm: LOCAL_SECRET_ALGORITHM,
};
assert.equal(
localSecretEnvelopeAad(facts).toString('utf8'),
'{"projectId":"project-1","name":"TOKEN","version":3,"mutationId":"mutation-3","keyId":"key-2","algorithm":"aes-256-gcm"}',
);
assert.notDeepEqual(
localSecretEnvelopeAad(facts),
localSecretEnvelopeAad({ ...facts, projectId: 'project-2' }),
);
});
@@ -0,0 +1,51 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidLocalSecurityAuditRetentionValueError,
localSecurityAuditCompactionPayload,
} = require('@qinglong/runtime-core/local-security-audit-retention');
function record(eventId, occurredAtMs) {
return {
eventId,
requestId: `request-${eventId}`,
operationId: 'security.audit.list',
projectId: 'default',
subject: { type: 'user', id: 'owner-user' },
authenticationId: 'local_security_audit:test',
outcome: 'allowed',
reasons: ['instance_authority_security_audit_query'],
fence: { projectVersion: 1, bindingVersion: 1 },
occurredAtMs,
};
}
test('creates a deterministic domain-separated digest over the exact ordered rows', () => {
const first = record('ba000000-0000-4000-8000-000000000001', 1_000);
const second = record('ba000000-0000-4000-8000-000000000002', 2_000);
const payload = localSecurityAuditCompactionPayload([first, second]);
assert.match(payload.recordsDigest, /^[0-9a-f]{64}$/);
assert.equal(payload.payloadBytes > 0, true);
assert.deepEqual(
localSecurityAuditCompactionPayload([first, second]),
payload,
);
assert.notEqual(
localSecurityAuditCompactionPayload([second, first]).recordsDigest,
payload.recordsDigest,
);
});
test('records an explicit empty digest without charging payload bytes', () => {
const payload = localSecurityAuditCompactionPayload([]);
assert.equal(payload.payloadBytes, 0);
assert.match(payload.recordsDigest, /^[0-9a-f]{64}$/);
});
test('rejects malformed records before producing compaction evidence', () => {
assert.throws(
() => localSecurityAuditCompactionPayload([{}]),
InvalidLocalSecurityAuditRetentionValueError,
);
});
@@ -0,0 +1,207 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
auditMigrationStreamHistory,
InvalidMigrationStreamError,
MigrationStreamAheadOfCodeError,
MigrationStreamChecksumMismatchError,
MigrationStreamHistoryCorruptionError,
runMigrationStream,
} = require('@qinglong/runtime-core/migration-stream');
const CHECKSUM_A = 'a'.repeat(64);
const CHECKSUM_B = 'b'.repeat(64);
function stream(migrations) {
return {
id: 'postgresql-main',
dialect: 'postgresql',
migrationIdScheme: 'postgres-prefixed',
checksumScheme: 'sha256',
migrations,
};
}
function memoryStore(initial = []) {
const records = new Map(
initial.map((record) => [record.migrationId, { ...record }]),
);
let ensured = 0;
return {
records,
get ensured() {
return ensured;
},
store: {
async ensureHistory() {
ensured += 1;
},
async listAll() {
return [...records.values()].map((record) => ({ ...record }));
},
async findById(id) {
const record = records.get(id);
return record ? { ...record } : null;
},
async transaction(work) {
const staged = new Map(
[...records].map(([id, record]) => [id, { ...record }]),
);
const result = await work({
context: { statements: [] },
async findById(id) {
const record = staged.get(id);
return record ? { ...record } : null;
},
async insert(record) {
if (staged.has(record.migrationId)) throw new Error('duplicate');
staged.set(record.migrationId, { ...record });
},
});
records.clear();
for (const [id, record] of staged) records.set(id, record);
return result;
},
},
};
}
test('applies one prefixed migration atomically and replays it exactly once', async () => {
const state = memoryStore();
const logs = [];
let calls = 0;
const definition = stream([
{
id: 'pg-0001-schema-history',
checksum: CHECKSUM_A,
async up(context) {
calls += 1;
context.statements.push('create schema metadata');
},
},
]);
await runMigrationStream({
stream: definition,
store: state.store,
clock: () => 100,
logger: { info: (message) => logs.push(message) },
});
await runMigrationStream({ stream: definition, store: state.store });
assert.equal(calls, 1);
assert.equal(state.ensured, 2);
assert.deepEqual(
[...state.records.values()],
[
{
streamId: 'postgresql-main',
dialect: 'postgresql',
migrationId: 'pg-0001-schema-history',
checksum: CHECKSUM_A,
appliedAtMs: 100,
},
],
);
assert.deepEqual(logs, [
'[migration:postgresql-main] Applied pg-0001-schema-history',
]);
});
test('rejects checksum drift, ahead history and non-prefix gaps', async () => {
const first = {
id: 'pg-0001-schema-history',
checksum: CHECKSUM_A,
async up() {},
};
const second = {
id: 'pg-0002-run-core',
checksum: CHECKSUM_B,
async up() {},
};
const record = (migrationId, checksum = CHECKSUM_A) => ({
streamId: 'postgresql-main',
dialect: 'postgresql',
migrationId,
checksum,
appliedAtMs: 1,
});
await assert.rejects(
runMigrationStream({
stream: stream([{ ...first, checksum: CHECKSUM_B }]),
store: memoryStore([record(first.id)]).store,
}),
MigrationStreamChecksumMismatchError,
);
await assert.rejects(
runMigrationStream({
stream: stream([first, second]),
store: memoryStore([record('pg-0003-ahead')]).store,
}),
MigrationStreamAheadOfCodeError,
);
await assert.rejects(
runMigrationStream({
stream: stream([first, second]),
store: memoryStore([record(second.id, second.checksum)]).store,
}),
MigrationStreamHistoryCorruptionError,
);
});
test('rolls migration work and history back together', async () => {
const state = memoryStore();
await assert.rejects(
runMigrationStream({
stream: stream([
{
id: 'pg-0001-schema-history',
checksum: CHECKSUM_A,
async up() {
throw new Error('ddl failed');
},
},
]),
store: state.store,
}),
/ddl failed/,
);
assert.equal(state.records.size, 0);
});
test('validates stream identity and immutable migration shape before storage', async () => {
const state = memoryStore();
for (const definition of [
{ ...stream([]), id: 'PostgreSQL' },
{ ...stream([]), migrationIdScheme: 'sqlite-numbered' },
stream([{ id: '0001', checksum: CHECKSUM_A, async up() {} }]),
stream([{ id: 'pg-0001', checksum: 'short', async up() {} }]),
]) {
await assert.rejects(
runMigrationStream({ stream: definition, store: state.store }),
InvalidMigrationStreamError,
);
}
assert.equal(state.ensured, 0);
});
test('audits a metadata-only manifest but requires executable steps to migrate', async () => {
const manifest = stream([
{ id: 'pg-0001-schema-history', checksum: CHECKSUM_A },
]);
const history = [
{
streamId: manifest.id,
dialect: manifest.dialect,
migrationId: manifest.migrations[0].id,
checksum: manifest.migrations[0].checksum,
appliedAtMs: 1,
},
];
assert.deepEqual(
[...auditMigrationStreamHistory(history, manifest)],
['pg-0001-schema-history'],
);
await assert.rejects(
runMigrationStream({ stream: manifest, store: memoryStore().store }),
InvalidMigrationStreamError,
);
});
@@ -0,0 +1,20 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const { semver } = require('../dist/versioning/pinnedSemver');
test('delegates exact SemVer behavior to the pinned production provider', () => {
const provider = semver();
assert.equal(provider, semver());
assert.equal(provider.valid('1.2.3'), '1.2.3');
assert.equal(provider.valid('v1.2.3'), '1.2.3');
assert.equal(provider.validRange('^1.2.3'), '>=1.2.3 <2.0.0-0');
assert.equal(provider.compare('1.2.3', '1.2.4'), -1);
assert.equal(provider.satisfies('1.9.0', '^1.2.3'), true);
assert.equal(
provider.satisfies('2.0.0-beta.1', '>=2.0.0-beta.0 <2.0.0', {
includePrerelease: true,
}),
true,
);
});
@@ -0,0 +1,365 @@
const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const { join } = require('node:path');
const { test } = require('node:test');
const {
InvalidPluginPackageInstallEnvironmentError,
InvalidPluginPackageManifestError,
PLUGIN_PACKAGE_API_VERSION,
PLUGIN_PACKAGE_KIND,
normalizePluginPackageManifest,
planPluginPackageInstall,
} = require('../dist/plugin-package/pluginPackage');
function manifest(overrides = {}) {
const value = {
apiVersion: PLUGIN_PACKAGE_API_VERSION,
kind: PLUGIN_PACKAGE_KIND,
metadata: {
name: 'example-monitor',
displayName: 'Example Monitor',
version: '1.2.0',
description: 'Collects a bounded report',
license: 'Apache-2.0',
},
spec: {
compatibility: {
qinglong: '>=3.0.0-0 <4.0.0',
architectures: ['arm64', 'amd64'],
deploymentProfiles: ['standalone', 'edge'],
},
runtimes: [{ name: 'python', version: '>=3.10.0 <4.0.0' }],
resources: {
memory: { recommended: '128Mi' },
disk: { install: '20Mi', working: '100Mi' },
},
permissions: {
network: { allowedHosts: ['api.example.com'] },
secrets: [{ name: 'EXAMPLE_TOKEN', required: true }],
tools: ['notification.send'],
},
contents: {
tasks: ['tasks/collect.yaml'],
workflows: ['workflows/daily-report.yaml'],
prompts: ['prompts/analyze-error.md'],
tools: ['tools/query-data.yaml'],
},
},
};
return {
...value,
...overrides,
metadata: { ...value.metadata, ...overrides.metadata },
spec: {
...value.spec,
...overrides.spec,
compatibility: {
...value.spec.compatibility,
...overrides.spec?.compatibility,
},
resources: {
...value.spec.resources,
...overrides.spec?.resources,
memory: {
...value.spec.resources.memory,
...overrides.spec?.resources?.memory,
},
disk: {
...value.spec.resources.disk,
...overrides.spec?.resources?.disk,
},
},
permissions: {
...value.spec.permissions,
...overrides.spec?.permissions,
network: {
...value.spec.permissions.network,
...overrides.spec?.permissions?.network,
},
},
contents: {
...value.spec.contents,
...overrides.spec?.contents,
},
},
};
}
function environment(overrides = {}) {
return {
qinglongVersion: '3.0.0-alpha.0',
architecture: 'arm64',
deploymentProfile: 'edge',
runtimes: [{ name: 'python', version: '3.12.4' }],
availableMemoryBytes: 256 * 1024 * 1024,
availableDiskBytes: 512 * 1024 * 1024,
...overrides,
};
}
test('normalizes and deeply freezes one bounded Package manifest', () => {
const normalized = normalizePluginPackageManifest(manifest());
assert.equal(Object.isFrozen(normalized), true);
assert.equal(Object.isFrozen(normalized.spec.permissions.secrets), true);
assert.deepEqual(normalized.spec.compatibility.architectures, [
'amd64',
'arm64',
]);
assert.deepEqual(normalized.spec.compatibility.deploymentProfiles, [
'edge',
'standalone',
]);
assert.deepEqual(normalized.spec.contents, {
tasks: ['tasks/collect.yaml'],
workflows: ['workflows/daily-report.yaml'],
prompts: ['prompts/analyze-error.md'],
tools: ['tools/query-data.yaml'],
});
});
test('keeps the reviewed Node 24 candidate architecture vocabulary', () => {
const normalized = normalizePluginPackageManifest(
manifest({
spec: {
compatibility: {
architectures: ['s390x', 'ppc64le', 'arm/v7', 'arm64', 'amd64'],
},
},
}),
);
assert.deepEqual(normalized.spec.compatibility.architectures, [
'amd64',
'arm/v7',
'arm64',
'ppc64le',
's390x',
]);
});
test('publishes the contract through the root and plugin-package subpath', () => {
const root = require('../dist');
const subpath = require('@qinglong/runtime-core/plugin-package');
assert.equal(
root.normalizePluginPackageManifest,
normalizePluginPackageManifest,
);
assert.equal(subpath.planPluginPackageInstall, planPluginPackageInstall);
});
test('rejects unknown fields, unsupported kinds and non-canonical versions', () => {
assert.throws(
() => normalizePluginPackageManifest({ ...manifest(), extra: true }),
InvalidPluginPackageManifestError,
);
assert.throws(
() => normalizePluginPackageManifest(manifest({ kind: 'Extension' })),
/apiVersion or kind is unsupported/,
);
assert.throws(
() =>
normalizePluginPackageManifest(
manifest({ metadata: { version: 'v1.2.0' } }),
),
/metadata version is invalid/,
);
});
test('rejects traversal, wildcard hosts, duplicate authority and core migrations', () => {
const invalid = [
manifest({ spec: { contents: { tasks: ['tasks/../migration.sql'] } } }),
manifest({
spec: {
contents: {
tasks: ['migrations/0001.sql'],
},
},
}),
manifest({
spec: {
permissions: {
network: { allowedHosts: ['*.example.com'] },
},
},
}),
manifest({
spec: {
permissions: {
secrets: [
{ name: 'TOKEN', required: true },
{ name: 'TOKEN', required: false },
],
},
},
}),
manifest({
spec: {
runtimes: [
{ name: 'python', version: '>=3.10.0' },
{ name: 'python', version: '>=3.11.0' },
],
},
}),
];
for (const value of invalid) {
assert.throws(
() => normalizePluginPackageManifest(value),
InvalidPluginPackageManifestError,
);
}
});
test('rejects unreviewed profiles, architectures, permissions and resource units', () => {
const invalid = [
manifest({
spec: { compatibility: { architectures: ['386'] } },
}),
manifest({
spec: { compatibility: { deploymentProfiles: ['control'] } },
}),
manifest({
spec: { permissions: { tools: ['database.superuser'] } },
}),
manifest({
spec: { resources: { memory: { recommended: '128MB' } } },
}),
manifest({
spec: { resources: { disk: { working: '2048Gi' } } },
}),
];
for (const value of invalid) {
assert.throws(
() => normalizePluginPackageManifest(value),
InvalidPluginPackageManifestError,
);
}
});
test('plans a compatible install with explicit resources and permissions', () => {
const plan = planPluginPackageInstall(manifest(), environment());
assert.deepEqual(plan, {
package: {
name: 'example-monitor',
toVersion: '1.2.0',
},
operation: 'install',
compatible: true,
risk: 'medium',
approvalRequired: true,
permissionReapprovalRequired: true,
permissionDelta: {
added: [
'network:api.example.com',
'secret:EXAMPLE_TOKEN:required',
'tool:notification.send',
],
removed: [],
},
resources: {
memoryRecommendedBytes: 128 * 1024 * 1024,
diskInstallBytes: 20 * 1024 * 1024,
diskWorkingBytes: 100 * 1024 * 1024,
},
contents: {
tasks: 1,
workflows: 1,
prompts: 1,
tools: 1,
},
findings: [],
});
assert.equal(Object.isFrozen(plan.permissionDelta.added), true);
});
test('fails compatibility for runtime, profile, version and disk without hiding warnings', () => {
const plan = planPluginPackageInstall(
manifest(),
environment({
qinglongVersion: '4.0.0',
architecture: 's390x',
deploymentProfile: 'worker',
runtimes: [{ name: 'python', version: '2.7.18' }],
availableMemoryBytes: 64 * 1024 * 1024,
availableDiskBytes: 64 * 1024 * 1024,
}),
);
assert.equal(plan.compatible, false);
assert.deepEqual(
plan.findings.map(({ code, severity }) => [code, severity]),
[
['architecture_unsupported', 'error'],
['deployment_profile_unsupported', 'error'],
['disk_insufficient', 'error'],
['qinglong_version_unsupported', 'error'],
['runtime_version_unsupported', 'error'],
['memory_below_recommendation', 'warning'],
],
);
});
test('detects upgrade permission expansion and permits reviewed rollback planning', () => {
const previous = manifest({
metadata: { version: '1.1.0' },
spec: {
permissions: {
network: { allowedHosts: [] },
secrets: [],
tools: [],
},
},
});
const upgrade = planPluginPackageInstall(manifest(), environment(), previous);
assert.equal(upgrade.operation, 'upgrade');
assert.equal(upgrade.permissionReapprovalRequired, true);
assert.deepEqual(upgrade.package, {
name: 'example-monitor',
fromVersion: '1.1.0',
toVersion: '1.2.0',
});
const rollback = planPluginPackageInstall(
previous,
environment(),
manifest(),
);
assert.equal(rollback.operation, 'rollback');
assert.equal(rollback.permissionReapprovalRequired, false);
assert.deepEqual(rollback.permissionDelta.added, []);
assert.equal(rollback.permissionDelta.removed.length, 3);
});
test('rejects ambiguous install environments and cross-package upgrades', () => {
assert.throws(
() =>
planPluginPackageInstall(manifest(), {
...environment(),
extra: true,
}),
InvalidPluginPackageInstallEnvironmentError,
);
assert.throws(
() =>
planPluginPackageInstall(
manifest(),
environment(),
manifest({ metadata: { name: 'different-package' } }),
),
/package names differ/,
);
});
test('keeps the core contract free of filesystem, process, timer and network authority', () => {
const source = readFileSync(
join(__dirname, '../src/plugin-package/pluginPackage.ts'),
'utf8',
);
for (const authority of [
"from 'node:child_process'",
"from 'node:fs'",
"from 'node:http'",
"from 'node:https'",
'setInterval(',
'setTimeout(',
]) {
assert.equal(source.includes(authority), false, authority);
}
});
@@ -0,0 +1,370 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
PLUGIN_PACKAGE_API_VERSION,
PLUGIN_PACKAGE_KIND,
planPluginPackageInstall,
} = require('../dist/plugin-package/pluginPackage');
const {
PluginPackageInstallTransitionConflictError,
createPluginPackageInstall,
createPluginPackageLock,
pluginPackageActivationIntentDigest,
pluginPackageInstallActionDigest,
pluginPackageInstallCommit,
pluginPackageInstallPlanDigest,
transitionPluginPackageInstall,
} = require('../dist/plugin-package/installation/pluginPackageInstall');
const {
PluginPackageActivationConflictError,
PluginPackageActivationCoordinator,
PluginPackageActivationUnavailableError,
createPluginPackageActivationIntent,
normalizePluginPackageActivationIntent,
} = require('../dist/plugin-package/installation/pluginPackageActivation');
const {
createPluginPackageResourceGenerationFromReferences,
} = require('../dist/plugin-package/pluginPackageResourceGeneration');
const ARTIFACT_DIGEST = 'a'.repeat(64);
const CONTENT_DIGEST = 'b'.repeat(64);
function fixture() {
const manifest = {
apiVersion: PLUGIN_PACKAGE_API_VERSION,
kind: PLUGIN_PACKAGE_KIND,
metadata: {
name: 'example-monitor',
displayName: 'Example Monitor',
version: '1.2.0',
description: 'One bounded package',
license: 'Apache-2.0',
},
spec: {
compatibility: {
qinglong: '>=3.0.0-0 <4.0.0',
architectures: ['arm64'],
deploymentProfiles: ['edge'],
},
runtimes: [],
resources: {
memory: { recommended: '16Mi' },
disk: { install: '4Mi', working: '16Mi' },
},
permissions: {
network: { allowedHosts: [] },
secrets: [],
tools: [],
},
contents: { tasks: [], workflows: [], prompts: [], tools: [] },
},
};
const environment = {
qinglongVersion: '3.0.0-alpha.0',
architecture: 'arm64',
deploymentProfile: 'edge',
runtimes: [],
availableMemoryBytes: 128 * 1024 * 1024,
availableDiskBytes: 256 * 1024 * 1024,
};
const plan = planPluginPackageInstall(manifest, environment);
const action = {
lockId: 'lock-001',
projectId: 'default',
manifest,
plan,
environment,
source: {
kind: 'offline',
locator: `offline:sha256:${ARTIFACT_DIGEST}`,
artifactDigest: ARTIFACT_DIGEST,
artifactBytes: 2048,
contentDigest: CONTENT_DIGEST,
},
architecture: 'arm64',
deploymentProfile: 'edge',
targetGeneration: 1,
};
const lock = createPluginPackageLock({
...action,
approval: {
requestId: 'approval-001',
requestVersion: 1,
dispatchId: 'dispatch-001',
actionDigest: pluginPackageInstallActionDigest(action),
previewDigest: pluginPackageInstallPlanDigest(plan),
approvedBy: { type: 'user', id: 'owner-001' },
approvedAtMs: 100,
expiresAtMs: 10_000,
fence: { projectVersion: 1, bindingVersion: 1 },
},
createdAtMs: 200,
});
const queued = createPluginPackageInstall(lock, {
installationId: 'install-001',
mutationId: 'mutation-create',
occurredAtMs: 201,
});
const staged = transitionPluginPackageInstall(lock, queued, {
type: 'stage_completed',
mutationId: 'mutation-stage',
occurredAtMs: 202,
stageRef: `local-stage:${lock.lockDigest}`,
artifactDigest: lock.source.artifactDigest,
manifestDigest: lock.manifestDigest,
contentDigest: lock.source.contentDigest,
evidenceDigest: 'e'.repeat(64),
});
return { lock, staged };
}
class MemoryRepository {
constructor(lock, record) {
this.lock = lock;
this.record = record;
this.commits = [];
}
async find(projectId, packageName) {
return this.record.projectId === projectId &&
this.record.packageName === packageName
? this.record
: null;
}
async findLock(lockDigest) {
return this.lock.lockDigest === lockDigest ? this.lock : null;
}
async commit(command) {
const canonical = pluginPackageInstallCommit(this.record, command.record);
assert.deepEqual(command, canonical);
this.record = command.record;
this.commits.push(command);
return { status: 'committed', record: this.record };
}
}
function publishedReceipt(lock, record, activatedAtMs = 204) {
const intent = createPluginPackageActivationIntent(lock, record);
return transitionPluginPackageInstall(lock, record, {
type: 'activation_committed',
mutationId: 'receipt-preview',
occurredAtMs: activatedAtMs,
activationRef: `active:${lock.lockDigest}`,
intentDigest: intent.intentDigest,
generation: lock.targetGeneration,
contentDigest: lock.source.contentDigest,
}).activationReceipt;
}
function activateOptions() {
return {
projectId: 'default',
packageName: 'example-monitor',
installationId: 'install-001',
activationStartedMutationId: 'mutation-activate',
activationCommittedMutationId: 'mutation-commit',
startedAtMs: 203,
};
}
test('binds one activation intent to the exact durable install and stage', () => {
const { lock, staged } = fixture();
const activating = transitionPluginPackageInstall(lock, staged, {
type: 'activation_started',
mutationId: 'mutation-activate',
occurredAtMs: 203,
});
const intent = createPluginPackageActivationIntent(lock, activating);
assert.equal(
intent.intentDigest,
pluginPackageActivationIntentDigest(lock, activating),
);
assert.deepEqual(normalizePluginPackageActivationIntent(intent), intent);
assert.equal(intent.stageReceiptDigest, staged.stageReceipt.receiptDigest);
assert.deepEqual(intent.resourceGeneration.resources, lock.resources);
assert.throws(
() =>
normalizePluginPackageActivationIntent({
...intent,
resourceGeneration: createPluginPackageResourceGenerationFromReferences(
{
installationId: intent.installationId,
projectId: 'other',
packageName: intent.packageName,
lockDigest: intent.lockDigest,
generation: intent.targetGeneration,
previousActiveLockDigest: intent.previousActiveLockDigest,
contentDigest: intent.contentDigest,
resources: intent.resourceGeneration.resources,
},
),
}),
/activation resource generation does not match/,
);
assert.throws(
() =>
normalizePluginPackageActivationIntent({
...intent,
schema: 'qinglong/plugin-package-activation-intent@v1',
}),
/activation intent schema is invalid/,
);
assert.throws(
() =>
normalizePluginPackageActivationIntent({
...intent,
targetGeneration: 0,
}),
/activation target generation is invalid/,
);
assert.throws(
() =>
transitionPluginPackageInstall(lock, activating, {
type: 'activation_committed',
mutationId: 'mutation-commit',
occurredAtMs: 204,
activationRef: 'active:wrong',
intentDigest: 'f'.repeat(64),
generation: 1,
contentDigest: CONTENT_DIGEST,
}),
PluginPackageInstallTransitionConflictError,
);
});
test('persists activating before publication and commits only an exact receipt', async () => {
const { lock, staged } = fixture();
const repository = new MemoryRepository(lock, staged);
const calls = [];
const coordinator = new PluginPackageActivationCoordinator({
repository,
publisher: {
async inspect() {
throw new Error('inspect must not run on the fresh path');
},
async publish(intent) {
calls.push(intent);
return publishedReceipt(lock, repository.record);
},
},
});
const active = await coordinator.activate(activateOptions());
assert.equal(active.state, 'active');
assert.equal(active.activeLockDigest, lock.lockDigest);
assert.equal(repository.commits.length, 2);
assert.equal(calls.length, 1);
assert.equal(calls[0].intentDigest, active.activationReceipt.intentDigest);
});
test('recovers publish-response loss through inspect without republishing', async () => {
const { lock, staged } = fixture();
const repository = new MemoryRepository(lock, staged);
let durableReceipt;
const publisher = {
async publish() {
durableReceipt = publishedReceipt(lock, repository.record);
throw new Error('response lost');
},
async inspect() {
return { status: 'published', receipt: durableReceipt };
},
};
const coordinator = new PluginPackageActivationCoordinator({
repository,
publisher,
});
await assert.rejects(
coordinator.activate(activateOptions()),
PluginPackageActivationUnavailableError,
);
assert.equal(repository.record.state, 'activating');
const active = await coordinator.inspect({
projectId: 'default',
packageName: 'example-monitor',
installationId: 'install-001',
activationCommittedMutationId: 'mutation-commit-recovery',
activationFailedMutationId: 'mutation-fail-recovery',
observedAtMs: 205,
});
assert.equal(active.state, 'active');
assert.equal(repository.commits.length, 2);
});
test('fails a recovered activating record when exact publication is absent', async () => {
const { lock, staged } = fixture();
const activating = transitionPluginPackageInstall(lock, staged, {
type: 'activation_started',
mutationId: 'mutation-activate',
occurredAtMs: 203,
});
const repository = new MemoryRepository(lock, activating);
const coordinator = new PluginPackageActivationCoordinator({
repository,
publisher: {
async publish() {
throw new Error('publish must not run during recovery');
},
async inspect() {
return { status: 'not_published' };
},
},
});
const failed = await coordinator.inspect({
projectId: 'default',
packageName: 'example-monitor',
installationId: 'install-001',
activationCommittedMutationId: 'mutation-commit-recovery',
activationFailedMutationId: 'mutation-fail-recovery',
observedAtMs: 204,
});
assert.equal(failed.state, 'failed');
assert.equal(failed.failure.reason, 'activation_failed');
assert.equal(failed.activeLockDigest, null);
});
test('records a conflicting external fact without replacing the old pointer', async () => {
const { lock, staged } = fixture();
const activating = transitionPluginPackageInstall(lock, staged, {
type: 'activation_started',
mutationId: 'mutation-activate',
occurredAtMs: 203,
});
const repository = new MemoryRepository(lock, activating);
const coordinator = new PluginPackageActivationCoordinator({
repository,
publisher: {
async publish() {
throw new Error('publish must not run during recovery');
},
async inspect() {
throw new PluginPackageActivationConflictError();
},
},
});
const failed = await coordinator.inspect({
projectId: 'default',
packageName: 'example-monitor',
installationId: 'install-001',
activationCommittedMutationId: 'mutation-commit-recovery',
activationFailedMutationId: 'mutation-fact-conflict',
observedAtMs: 204,
});
assert.equal(failed.state, 'failed');
assert.equal(failed.failure.reason, 'activation_fact_conflict');
assert.equal(failed.activeLockDigest, null);
});
test('publishes the coordinator only through its explicit subpath', () => {
assert.equal(
require('../dist').PluginPackageActivationCoordinator,
undefined,
);
assert.equal(
require('@qinglong/runtime-core/plugin-package-activation')
.PluginPackageActivationCoordinator,
PluginPackageActivationCoordinator,
);
});
@@ -0,0 +1,302 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
consumeApprovalRequest,
createApprovalRequest,
decideApprovalRequest,
} = require('@qinglong/runtime-core/approved-action');
const {
PLUGIN_PACKAGE_ADMISSION_RECEIPT_SCHEMA,
PLUGIN_PACKAGE_INSTALL_ACTION_TYPE,
PluginPackageAdmissionBindingConflictError,
InvalidPluginPackageAdmissionError,
assertPluginPackageAdmissionReplay,
bindPluginPackageAdmission,
normalizePluginPackageAdmissionReceipt,
} = require('@qinglong/runtime-core/plugin-package-admission');
const {
claimApprovedActionExecution,
createApprovedActionExecution,
startApprovedActionExecution,
} = require('@qinglong/runtime-core/approved-action-execution');
const {
createPluginPackageInstallProposal,
resolvePluginPackageInstallProposal,
} = require('@qinglong/runtime-core/plugin-package-proposal');
const {
pluginPackageInstallActionDigest,
pluginPackageInstallPlanDigest,
} = require('@qinglong/runtime-core/plugin-package-install');
const {
PLUGIN_PACKAGE_API_VERSION,
PLUGIN_PACKAGE_KIND,
planPluginPackageInstall,
} = require('@qinglong/runtime-core/plugin-package');
const REQUESTER = Object.freeze({ type: 'user', id: 'usr_owner' });
const SYSTEM = Object.freeze({ type: 'system', id: 'package_dispatcher' });
const FENCE = Object.freeze({ projectVersion: 1, bindingVersion: 1 });
function lockAction() {
const manifest = {
apiVersion: PLUGIN_PACKAGE_API_VERSION,
kind: PLUGIN_PACKAGE_KIND,
metadata: {
name: 'example-monitor',
displayName: 'Example Monitor',
version: '1.2.0',
description: 'One bounded package',
license: 'Apache-2.0',
},
spec: {
compatibility: {
qinglong: '>=3.0.0-0 <4.0.0',
architectures: ['arm64'],
deploymentProfiles: ['edge'],
},
runtimes: [],
resources: {
memory: { recommended: '16Mi' },
disk: { install: '4Mi', working: '16Mi' },
},
permissions: {
network: { allowedHosts: [] },
secrets: [],
tools: [],
},
contents: { tasks: [], workflows: [], prompts: [], tools: [] },
},
};
const environment = {
qinglongVersion: '3.0.0-alpha.0',
architecture: 'arm64',
deploymentProfile: 'edge',
runtimes: [],
availableMemoryBytes: 128 * 1024 * 1024,
availableDiskBytes: 256 * 1024 * 1024,
};
const plan = planPluginPackageInstall(manifest, environment);
return {
input: {
lockId: 'proposal-monitor-v1',
projectId: 'default',
manifest,
plan,
environment,
source: {
kind: 'offline',
locator: `offline:sha256:${'a'.repeat(64)}`,
artifactDigest: 'a'.repeat(64),
artifactBytes: 2048,
contentDigest: 'b'.repeat(64),
},
architecture: 'arm64',
deploymentProfile: 'edge',
targetGeneration: 1,
},
plan,
};
}
function fixture() {
const action = lockAction();
const binding = {
permission: 'package.manage',
actionType: PLUGIN_PACKAGE_INSTALL_ACTION_TYPE,
actionRef: 'proposal:monitor-v1',
actionDigest: pluginPackageInstallActionDigest(action.input),
previewDigest: pluginPackageInstallPlanDigest(action.plan),
};
const pending = createApprovalRequest({
id: 'approval-monitor-v1',
projectId: 'default',
action: binding,
risk: 'high',
decisionMode: 'human_confirmation',
requestedBy: REQUESTER,
requestedAtMs: 10,
expiresAtMs: 1_000,
requestFence: FENCE,
});
const approved = decideApprovalRequest(pending, {
expectedVersion: 1,
decisionId: 'decision-monitor-v1',
decision: 'approved',
reasonCode: 'reviewed',
principal: {
subject: REQUESTER,
authenticationId: 'auth-owner-step-up',
authenticatedAtMs: 15,
expiresAtMs: 500,
assurance: 'local_console',
},
decidedAtMs: 20,
authorizationFence: FENCE,
});
const consumed = consumeApprovalRequest(approved, {
expectedVersion: 2,
consumptionId: 'consume-monitor-v1',
dispatchId: 'dispatch-monitor-v1',
action: binding,
requestedBy: REQUESTER,
consumedBy: SYSTEM,
consumedAtMs: 30,
authorizationFence: FENCE,
});
const proposal = createPluginPackageInstallProposal({
actionRef: binding.actionRef,
actionInput: action.input,
proposedBy: REQUESTER,
proposalFence: FENCE,
createdAtMs: 5,
});
const claimedExecution = claimApprovedActionExecution(
createApprovedActionExecution(consumed.dispatch),
{
owner: 'package_dispatcher',
leaseToken: 'lease-monitor-v1',
nowMs: 35,
leaseDurationMs: 100,
},
);
const execution = startApprovedActionExecution(
{ dispatch: consumed.dispatch, execution: claimedExecution },
{
dispatchId: consumed.dispatch.id,
approvalRequestId: consumed.dispatch.approvalRequestId,
actionDigest: consumed.dispatch.action.actionDigest,
owner: 'package_dispatcher',
leaseToken: 'lease-monitor-v1',
expectedVersion: claimedExecution.version,
startedAtMs: 40,
},
);
const lock = resolvePluginPackageInstallProposal(
proposal,
consumed.dispatch,
40,
);
const request = {
lock,
proposalDigest: proposal.proposalDigest,
execution,
installationId: 'install-monitor-v1',
mutationId: 'admit-monitor-v1',
admittedAtMs: 50,
audit: {
eventId: '10000000-0000-4000-8000-000000000010',
requestId: consumed.dispatch.id,
operationId: 'plugin_package.admit',
projectId: 'default',
subject: SYSTEM,
authenticationId: 'auth-package-dispatcher',
outcome: 'allowed',
reasons: ['approved_action'],
fence: FENCE,
occurredAtMs: 50,
},
};
return { dispatch: consumed.dispatch, proposal, execution, request };
}
test('binds one approved dispatch to a queued install and immutable receipt', () => {
const { dispatch, proposal, execution, request } = fixture();
const bound = bindPluginPackageAdmission(
dispatch,
proposal,
execution,
request,
null,
50,
);
assert.equal(bound.create.record.state, 'queued');
assert.equal(bound.receipt.schema, PLUGIN_PACKAGE_ADMISSION_RECEIPT_SCHEMA);
assert.equal(bound.receipt.dispatchId, dispatch.id);
assert.equal(bound.receipt.installationId, request.installationId);
assert.equal(bound.receipt.recordDigest, bound.create.record.recordDigest);
assert.deepEqual(
normalizePluginPackageAdmissionReceipt(bound.receipt),
bound.receipt,
);
assert.doesNotThrow(() =>
assertPluginPackageAdmissionReplay(
dispatch,
proposal,
request,
bound.receipt,
bound.create.record,
),
);
});
test('rejects dispatch, approval, audit and lifetime drift', () => {
const { dispatch, proposal, execution, request } = fixture();
for (const candidate of [
{
dispatch: {
...dispatch,
action: { ...dispatch.action, actionType: 'task.run' },
},
request,
ErrorType: PluginPackageAdmissionBindingConflictError,
},
{
dispatch,
request: {
...request,
lock: {
...request.lock,
approval: { ...request.lock.approval, requestVersion: 2 },
},
},
ErrorType: TypeError,
},
{
dispatch,
request: {
...request,
audit: { ...request.audit, reasons: ['role_grant'] },
},
ErrorType: PluginPackageAdmissionBindingConflictError,
},
{
dispatch,
request: { ...request, admittedAtMs: 1_000 },
ErrorType: PluginPackageAdmissionBindingConflictError,
},
]) {
assert.throws(
() =>
bindPluginPackageAdmission(
candidate.dispatch,
proposal,
execution,
candidate.request,
null,
50,
),
candidate.ErrorType,
);
}
});
test('rejects receipt digest drift', () => {
const { dispatch, proposal, execution, request } = fixture();
const bound = bindPluginPackageAdmission(
dispatch,
proposal,
execution,
request,
null,
50,
);
assert.throws(
() =>
normalizePluginPackageAdmissionReceipt({
...bound.receipt,
admittedAtMs: 51,
}),
InvalidPluginPackageAdmissionError,
);
});
@@ -0,0 +1,319 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
consumeApprovalRequest,
createApprovalRequest,
decideApprovalRequest,
} = require('@qinglong/runtime-core/approved-action');
const {
claimApprovedActionExecution,
createApprovedActionExecution,
startApprovedActionExecution,
} = require('@qinglong/runtime-core/approved-action-execution');
const {
PluginPackageAdmissionBindingConflictError,
bindPluginPackageAdmission,
} = require('@qinglong/runtime-core/plugin-package-admission');
const {
PluginPackageApprovedActionHandler,
} = require('@qinglong/runtime-core/plugin-package-approved-action');
const {
createPluginPackageInstallProposal,
} = require('@qinglong/runtime-core/plugin-package-proposal');
const {
pluginPackageInstallActionDigest,
pluginPackageInstallPlanDigest,
} = require('@qinglong/runtime-core/plugin-package-install');
const {
PLUGIN_PACKAGE_API_VERSION,
PLUGIN_PACKAGE_KIND,
planPluginPackageInstall,
} = require('@qinglong/runtime-core/plugin-package');
const REQUESTER = Object.freeze({ type: 'user', id: 'usr_owner' });
const CONSUMER = Object.freeze({ type: 'system', id: 'package_dispatcher' });
const FENCE = Object.freeze({ projectVersion: 1, bindingVersion: 1 });
function actionInput() {
const manifest = {
apiVersion: PLUGIN_PACKAGE_API_VERSION,
kind: PLUGIN_PACKAGE_KIND,
metadata: {
name: 'handler-monitor',
displayName: 'Handler Monitor',
version: '1.0.0',
description: 'One deterministic handler package',
license: 'Apache-2.0',
},
spec: {
compatibility: {
qinglong: '>=3.0.0-0 <4.0.0',
architectures: ['arm64'],
deploymentProfiles: ['edge'],
},
runtimes: [],
resources: {
memory: { recommended: '16Mi' },
disk: { install: '4Mi', working: '16Mi' },
},
permissions: {
network: { allowedHosts: [] },
secrets: [],
tools: [],
},
contents: { tasks: [], workflows: [], prompts: [], tools: [] },
},
};
const environment = {
qinglongVersion: '3.0.0-alpha.0',
architecture: 'arm64',
deploymentProfile: 'edge',
runtimes: [],
availableMemoryBytes: 128 * 1024 * 1024,
availableDiskBytes: 256 * 1024 * 1024,
};
const plan = planPluginPackageInstall(manifest, environment);
return {
lockId: 'proposal-handler-v1',
projectId: 'default',
manifest,
plan,
environment,
source: {
kind: 'offline',
locator: `offline:sha256:${'a'.repeat(64)}`,
artifactDigest: 'a'.repeat(64),
artifactBytes: 1024,
contentDigest: 'b'.repeat(64),
},
architecture: 'arm64',
deploymentProfile: 'edge',
targetGeneration: 1,
};
}
function fixture() {
const input = actionInput();
const action = {
permission: 'package.manage',
actionType: 'plugin_package.install',
actionRef: 'proposal:handler-v1',
actionDigest: pluginPackageInstallActionDigest(input),
previewDigest: pluginPackageInstallPlanDigest(input.plan),
};
const pending = createApprovalRequest({
id: 'approval-handler-v1',
projectId: 'default',
action,
risk: 'high',
decisionMode: 'human_confirmation',
requestedBy: REQUESTER,
requestedAtMs: 10,
expiresAtMs: 10_000,
requestFence: FENCE,
});
const approved = decideApprovalRequest(pending, {
expectedVersion: 1,
decisionId: 'decision-handler-v1',
decision: 'approved',
reasonCode: 'reviewed',
principal: {
subject: REQUESTER,
authenticationId: 'auth-owner',
authenticatedAtMs: 15,
expiresAtMs: 5_000,
assurance: 'local_console',
},
decidedAtMs: 20,
authorizationFence: FENCE,
});
const dispatch = consumeApprovalRequest(approved, {
expectedVersion: 2,
consumptionId: 'consume-handler-v1',
dispatchId: 'dispatch-handler-v1',
action,
requestedBy: REQUESTER,
consumedBy: CONSUMER,
consumedAtMs: 30,
authorizationFence: FENCE,
}).dispatch;
const proposal = createPluginPackageInstallProposal({
actionRef: action.actionRef,
actionInput: input,
proposedBy: REQUESTER,
proposalFence: FENCE,
createdAtMs: 5,
});
const claimed = claimApprovedActionExecution(
createApprovedActionExecution(dispatch),
{
owner: 'dispatcher_instance_1',
leaseToken: 'lease-handler-v1',
nowMs: 35,
leaseDurationMs: 1_000,
},
);
const execution = startApprovedActionExecution(
{ dispatch, execution: claimed },
{
dispatchId: dispatch.id,
approvalRequestId: dispatch.approvalRequestId,
actionDigest: dispatch.action.actionDigest,
owner: 'dispatcher_instance_1',
leaseToken: 'lease-handler-v1',
expectedVersion: claimed.version,
startedAtMs: 40,
},
);
return {
dispatch,
proposal,
execution,
context: {
dispatch,
execution,
idempotencyKey: dispatch.id,
fence: {
owner: execution.leaseOwner,
leaseToken: execution.leaseToken,
version: execution.version,
},
},
};
}
class ProposalAuthority {
constructor(proposal, mode = 'found') {
this.proposal = proposal;
this.mode = mode;
}
async findProposalByActionRef() {
if (this.mode === 'unavailable') throw new Error('proposal unavailable');
return this.mode === 'missing' ? null : this.proposal;
}
async createProposal() {
throw new Error('handler is read-only over proposal authority');
}
}
class AdmissionAuthority {
constructor(value, options = {}) {
this.value = value;
this.loseResponse = options.loseResponse === true;
this.reject = options.reject === true;
this.requests = [];
this.receipt = null;
this.record = null;
}
async admit(request) {
this.requests.push(request);
if (this.reject) throw new PluginPackageAdmissionBindingConflictError();
const bound = bindPluginPackageAdmission(
this.value.dispatch,
this.value.proposal,
this.value.execution,
request,
null,
this.value.execution.startedAtMs,
);
this.receipt = bound.receipt;
this.record = bound.create.record;
if (this.loseResponse) throw new Error('commit response lost');
return {
status: 'admitted',
receipt: this.receipt,
record: this.record,
};
}
async findAdmissionReceipt(dispatchId) {
return this.receipt?.dispatchId === dispatchId ? this.receipt : null;
}
async find(projectId, packageName) {
return this.record?.projectId === projectId &&
this.record?.packageName === packageName
? this.record
: null;
}
}
test('inspects the immutable proposal and emits one deterministic admission', async () => {
const value = fixture();
const admissions = new AdmissionAuthority(value);
const handler = new PluginPackageApprovedActionHandler(
new ProposalAuthority(value.proposal),
admissions,
);
assert.deepEqual(await handler.inspect(value.dispatch), {
status: 'ready',
actionDigest: value.dispatch.action.actionDigest,
});
const first = await handler.execute(value.context);
const second = await handler.execute(value.context);
assert.deepEqual(first, second);
assert.equal(first.outcome, 'succeeded');
assert.equal(first.resultDigest, admissions.receipt.receiptDigest);
assert.equal(admissions.requests.length, 2);
assert.equal(
admissions.requests[0].installationId,
admissions.requests[1].installationId,
);
assert.equal(
admissions.requests[0].mutationId,
admissions.requests[1].mutationId,
);
assert.equal(
admissions.requests[0].audit.eventId,
admissions.requests[1].audit.eventId,
);
assert.match(
admissions.requests[0].audit.eventId,
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,
);
});
test('converges an admission commit response loss from the durable receipt', async () => {
const value = fixture();
const admissions = new AdmissionAuthority(value, { loseResponse: true });
const result = await new PluginPackageApprovedActionHandler(
new ProposalAuthority(value.proposal),
admissions,
).execute(value.context);
assert.equal(result.outcome, 'succeeded');
assert.equal(result.resultCode, 'package_admitted');
assert.equal(result.resultDigest, admissions.receipt.receiptDigest);
assert.equal(admissions.requests.length, 1);
});
test('classifies proposal and admission failures without widening authority', async () => {
const value = fixture();
const missing = new PluginPackageApprovedActionHandler(
new ProposalAuthority(value.proposal, 'missing'),
new AdmissionAuthority(value),
);
assert.deepEqual(await missing.inspect(value.dispatch), {
status: 'blocked',
resultCode: 'package_proposal_missing',
});
const unavailable = new PluginPackageApprovedActionHandler(
new ProposalAuthority(value.proposal, 'unavailable'),
new AdmissionAuthority(value),
);
assert.deepEqual(await unavailable.inspect(value.dispatch), {
status: 'retry',
resultCode: 'package_proposal_unavailable',
});
const rejected = await new PluginPackageApprovedActionHandler(
new ProposalAuthority(value.proposal),
new AdmissionAuthority(value, { reject: true }),
).execute(value.context);
assert.deepEqual(rejected, {
outcome: 'failed',
resultCode: 'package_admission_rejected',
});
});
@@ -0,0 +1,567 @@
const assert = require('node:assert/strict');
const { createHash } = require('node:crypto');
const { test } = require('node:test');
const {
assertPluginPackageAutomationPublicationSuccessor,
createInitialPluginPackageAutomationPublication,
createNextPluginPackageAutomationPublication,
createPluginPackageAutomationLifecyclePublication,
InvalidPluginPackageAutomationPublicationError,
normalizePluginPackageAutomationPublication,
PluginPackageAutomationPublicationConflictError,
PluginPackageAutomationPublicationCoordinator,
PluginPackageAutomationPublicationRecoveryCoordinator,
PluginPackageAutomationPublicationUnavailableError,
pluginPackageAutomationDefinitionsFromRevision,
pluginPackageAutomationPublicationDigest,
} = require('../dist/plugin-package/pluginPackageAutomationPublication');
const {
pluginPackageTaskReconciliationFixture,
} = require('../../../test/contracts/pluginPackageTaskReconciliationRepositoryContract.cjs');
function digest(value) {
return createHash('sha256').update(value).digest('hex');
}
function automationFixture(namespace = 'automation-publication') {
return pluginPackageTaskReconciliationFixture(namespace, {
workflows: [
{
schema: 'qinglong/plugin-package-workflow-resource@v1',
id: 'daily',
name: 'Daily workflow',
enabled: true,
steps: [
{
id: 'run',
task: 'alpha',
needs: [],
},
],
},
],
prompts: [
{
schema: 'qinglong/plugin-package-prompt-resource@v1',
id: 'greeting',
name: 'Greeting prompt',
template: 'Hello {{name}}',
parameters: [
{
name: 'name',
required: true,
},
],
},
],
});
}
function automationCoordinatorAuthorities(
namespace = 'automation-publication-coordinator',
) {
const first = automationFixture(namespace);
let generation = first.revision.generation;
let head = null;
let observations = 0;
const revisions = new Map([
[first.revision.generation.generationDigest, first.revision],
]);
const publications = new Map();
const generationSource = {
async findActiveResourceGeneration() {
observations += 1;
return generation;
},
};
const materializedRepository = {
async find(generationDigest) {
return revisions.get(generationDigest) ?? null;
},
};
const repository = {
async findCurrent() {
return head;
},
async findByDigest(publicationDigest) {
return publications.get(publicationDigest) ?? null;
},
async publish(publication) {
const existing = publications.get(publication.publicationDigest);
if (existing) return { status: 'existing', publication: existing };
publications.set(publication.publicationDigest, publication);
head = publication;
return { status: 'created', publication };
},
};
const coordinator = new PluginPackageAutomationPublicationCoordinator({
generationSource,
materializedRepository,
repository,
taskSpecSemanticRegistry: first.registry,
now: () => 2_000 + observations,
});
return {
first,
coordinator,
generationSource,
materializedRepository,
repository,
revisions,
get generation() {
return generation;
},
set generation(value) {
generation = value;
},
get head() {
return head;
},
};
}
test('creates one deterministic publication for Workflow and Prompt definitions', () => {
const value = automationFixture();
const definitions = pluginPackageAutomationDefinitionsFromRevision(
value.revision,
value.registry,
);
assert.deepEqual(
definitions.workflows.map(({ id }) => id),
['daily'],
);
assert.deepEqual(
definitions.prompts.map(({ id }) => id),
['greeting'],
);
const publication = createInitialPluginPackageAutomationPublication(
value.revision,
value.registry,
1_000,
);
assert.equal(publication.state, 'active');
assert.equal(publication.version, 1);
assert.equal(publication.previousPublicationDigest, null);
assert.equal(publication.lifecycleEventDigest, null);
assert.equal(
publication.target.materializedRevisionDigest,
value.revision.revisionDigest,
);
assert.equal(
publication.publicationDigest,
pluginPackageAutomationPublicationDigest(publication),
);
assert.deepEqual(
normalizePluginPackageAutomationPublication(publication),
publication,
);
assert.equal(
createInitialPluginPackageAutomationPublication(
value.revision,
value.registry,
1_000,
).publicationDigest,
publication.publicationDigest,
);
});
test('withdraws and restores the same immutable definitions through a digest chain', () => {
const value = automationFixture('automation-lifecycle');
const initial = createInitialPluginPackageAutomationPublication(
value.revision,
value.registry,
1_000,
);
const disabledEventDigest = digest('disabled');
const withdrawn = createPluginPackageAutomationLifecyclePublication({
previous: initial,
state: 'withdrawn',
lifecycleEventDigest: disabledEventDigest,
publishedAtMs: 1_001,
});
assert.equal(withdrawn.state, 'withdrawn');
assert.equal(withdrawn.version, 2);
assert.equal(
withdrawn.previousPublicationDigest,
initial.publicationDigest,
);
assert.equal(withdrawn.lifecycleEventDigest, disabledEventDigest);
assert.deepEqual(withdrawn.definitions, initial.definitions);
const enabledEventDigest = digest('enabled');
const restored = createPluginPackageAutomationLifecyclePublication({
previous: withdrawn,
state: 'active',
lifecycleEventDigest: enabledEventDigest,
publishedAtMs: 1_002,
});
assert.equal(restored.state, 'active');
assert.equal(restored.version, 3);
assert.equal(
restored.previousPublicationDigest,
withdrawn.publicationDigest,
);
assert.equal(restored.lifecycleEventDigest, enabledEventDigest);
assert.deepEqual(restored.definitions, initial.definitions);
});
test('replaces one active publication with the next materialized generation', () => {
const first = automationFixture('automation-upgrade');
const initial = createInitialPluginPackageAutomationPublication(
first.revision,
first.registry,
1_000,
);
const second = pluginPackageTaskReconciliationFixture(first.namespace, {
previous: first,
tasks: [
['alpha', 'alpha-v2'],
['beta', 'beta'],
],
workflows: [
{
schema: 'qinglong/plugin-package-workflow-resource@v1',
id: 'hourly',
name: 'Hourly workflow',
enabled: true,
steps: [{ id: 'run', task: 'alpha', needs: [] }],
},
],
prompts: [
{
schema: 'qinglong/plugin-package-prompt-resource@v1',
id: 'summary',
name: 'Summary prompt',
template: 'Summarize {{topic}}',
parameters: [{ name: 'topic', required: true }],
},
],
});
const next = createNextPluginPackageAutomationPublication(
second.revision,
second.registry,
initial,
1_100,
);
assert.equal(next.version, 2);
assert.equal(next.state, 'active');
assert.equal(next.lifecycleEventDigest, null);
assert.equal(next.previousPublicationDigest, initial.publicationDigest);
assert.equal(next.target.generation, 2);
assert.deepEqual(
next.definitions.workflows.map(({ id }) => id),
['hourly'],
);
assert.doesNotThrow(() =>
assertPluginPackageAutomationPublicationSuccessor(initial, next),
);
});
test('rejects tampering and invalid lifecycle transitions', () => {
const value = automationFixture('automation-invalid');
const initial = createInitialPluginPackageAutomationPublication(
value.revision,
value.registry,
1_000,
);
assert.throws(
() =>
normalizePluginPackageAutomationPublication({
...initial,
publishedAtMs: 1_001,
}),
/publicationDigest does not match publication/,
);
assert.throws(
() =>
createPluginPackageAutomationLifecyclePublication({
previous: initial,
state: 'active',
lifecycleEventDigest: digest('same-state'),
publishedAtMs: 1_001,
}),
/must toggle its state/,
);
assert.throws(
() =>
createPluginPackageAutomationLifecyclePublication({
previous: initial,
state: 'withdrawn',
lifecycleEventDigest: digest('time-travel'),
publishedAtMs: 999,
}),
/precedes the previous publication/,
);
assert.throws(
() =>
assertPluginPackageAutomationPublicationSuccessor(initial, {
...initial,
version: 2,
previousPublicationDigest: initial.publicationDigest,
publicationDigest: pluginPackageAutomationPublicationDigest({
...initial,
version: 2,
previousPublicationDigest: initial.publicationDigest,
}),
}),
/generation successor is invalid/,
);
});
test('publishes an absent tombstone for a generation without automation', () => {
const value = pluginPackageTaskReconciliationFixture('automation-empty');
assert.equal(
pluginPackageAutomationDefinitionsFromRevision(
value.revision,
value.registry,
),
null,
);
const publication = createInitialPluginPackageAutomationPublication(
value.revision,
value.registry,
1_000,
);
assert.equal(publication.state, 'absent');
assert.equal(publication.version, 1);
assert.deepEqual(publication.definitions, {
workflows: [],
prompts: [],
});
assert.throws(
() =>
createPluginPackageAutomationLifecyclePublication({
previous: publication,
state: 'active',
lifecycleEventDigest: digest('invalid-absent-toggle'),
publishedAtMs: 1_001,
}),
/must toggle its state/,
);
});
test('chains active, absent and active across every Package generation', () => {
const first = automationFixture('automation-tombstone-chain');
const initial = createInitialPluginPackageAutomationPublication(
first.revision,
first.registry,
1_000,
);
const second = pluginPackageTaskReconciliationFixture(first.namespace, {
previous: first,
});
const absent = createNextPluginPackageAutomationPublication(
second.revision,
second.registry,
initial,
1_100,
);
assert.equal(absent.state, 'absent');
assert.equal(absent.target.generation, 2);
assert.deepEqual(absent.definitions, { workflows: [], prompts: [] });
const third = pluginPackageTaskReconciliationFixture(first.namespace, {
previous: second,
workflows: [
{
schema: 'qinglong/plugin-package-workflow-resource@v1',
id: 'restored',
name: 'Restored workflow',
enabled: true,
steps: [{ id: 'run', task: 'alpha', needs: [] }],
},
],
});
const restored = createNextPluginPackageAutomationPublication(
third.revision,
third.registry,
absent,
1_200,
);
assert.equal(restored.state, 'active');
assert.equal(restored.target.generation, 3);
assert.equal(
restored.previousPublicationDigest,
absent.publicationDigest,
);
assert.deepEqual(
restored.definitions.workflows.map(({ id }) => id),
['restored'],
);
});
test('coordinator publishes each materialized generation and preserves lifecycle state on replay', async () => {
const value = automationCoordinatorAuthorities();
const initial = await value.coordinator.publishActive(
value.first.projectId,
value.first.packageName,
);
assert.equal(initial.status, 'current');
assert.equal(initial.publication, 'created');
assert.equal(initial.record.state, 'active');
const withdrawn = createPluginPackageAutomationLifecyclePublication({
previous: initial.record,
state: 'withdrawn',
lifecycleEventDigest: digest('coordinator-disabled'),
publishedAtMs: 2_100,
});
await value.repository.publish(withdrawn);
const replay = await value.coordinator.publishActive(
value.first.projectId,
value.first.packageName,
);
assert.equal(replay.status, 'current');
assert.equal(replay.publication, 'existing');
assert.equal(replay.record.state, 'withdrawn');
const empty = pluginPackageTaskReconciliationFixture(value.first.namespace, {
previous: value.first,
});
value.revisions.set(
empty.revision.generation.generationDigest,
empty.revision,
);
value.generation = empty.revision.generation;
const tombstone = await value.coordinator.publishActive(
value.first.projectId,
value.first.packageName,
);
assert.equal(tombstone.status, 'current');
assert.equal(tombstone.record.state, 'absent');
assert.equal(tombstone.record.version, 3);
assert.deepEqual(tombstone.record.definitions, {
workflows: [],
prompts: [],
});
});
test('coordinator treats a final generation switch as superseded', async () => {
const value = automationCoordinatorAuthorities(
'automation-publication-superseded',
);
let observations = 0;
const source = {
async findActiveResourceGeneration() {
observations += 1;
return observations === 1 ? value.generation : null;
},
};
const coordinator = new PluginPackageAutomationPublicationCoordinator({
generationSource: source,
materializedRepository: value.materializedRepository,
repository: value.repository,
taskSpecSemanticRegistry: value.first.registry,
now: () => 3_000,
});
assert.deepEqual(
await coordinator.publishActive(
value.first.projectId,
value.first.packageName,
),
{
status: 'superseded',
generationDigest:
value.first.revision.generation.generationDigest,
},
);
});
test('bounded automation recovery converges and classifies manual and retry failures', async () => {
const value = automationCoordinatorAuthorities(
'automation-publication-recovery',
);
let pending = [
{
projectId: value.first.projectId,
packageName: value.first.packageName,
},
];
const source = {
async listPendingPage({ limit }) {
return {
candidates: pending.slice(0, limit),
truncated: false,
};
},
};
const publisher = Object.create(
PluginPackageAutomationPublicationCoordinator.prototype,
);
publisher.publishActive = async (projectId, packageName) => {
const result = await value.coordinator.publishActive(
projectId,
packageName,
);
if (result.status === 'current') pending = [];
return result;
};
const recovery =
new PluginPackageAutomationPublicationRecoveryCoordinator({
source,
publisher,
});
assert.deepEqual(
await recovery.recover({ pageSize: 1, maxPages: 1 }),
{
pages: 1,
scanned: 1,
settled: 1,
retry: 0,
manualRequired: 0,
superseded: 0,
remaining: false,
safeToAdmit: true,
},
);
const failures = Object.create(
PluginPackageAutomationPublicationCoordinator.prototype,
);
failures.publishActive = async (_projectId, packageName) => {
if (packageName === 'manual') {
throw new PluginPackageAutomationPublicationConflictError('conflict');
}
throw new PluginPackageAutomationPublicationUnavailableError();
};
const failedRecovery =
new PluginPackageAutomationPublicationRecoveryCoordinator({
source: {
async listPendingPage({ limit }) {
const candidates = [
{ projectId: value.first.projectId, packageName: 'manual' },
{ projectId: value.first.projectId, packageName: 'retry' },
].slice(0, limit);
const truncated = limit < 2;
const last = candidates.at(-1);
return {
candidates,
truncated,
...(truncated
? {
next: {
projectId: last.projectId,
packageName: last.packageName,
},
}
: {}),
};
},
},
publisher: failures,
});
const result = await failedRecovery.recover({
pageSize: 2,
maxPages: 1,
});
assert.equal(result.manualRequired, 1);
assert.equal(result.retry, 1);
assert.equal(result.remaining, true);
assert.equal(result.safeToAdmit, false);
await assert.rejects(
() => failedRecovery.recover({ pageSize: 0 }),
InvalidPluginPackageAutomationPublicationError,
);
});
@@ -0,0 +1,467 @@
const assert = require('node:assert/strict');
const { createHash, generateKeyPairSync, sign } = require('node:crypto');
const { readFileSync } = require('node:fs');
const { join } = require('node:path');
const { test } = require('node:test');
const {
InvalidPluginPackageBundleError,
InvalidPluginPackagePublisherTrustError,
PLUGIN_PACKAGE_BUNDLE_MEDIA_TYPE,
PLUGIN_PACKAGE_SIGNATURE_SCHEMA,
PluginPackageBundleUnavailableError,
PluginPackagePublisherTrustRegistry,
UntrustedPluginPackagePublisherError,
inspectPluginPackageBundle,
pluginPackageContentTreeDigest,
pluginPackagePublisherSignaturePayload,
} = require('../dist/plugin-package/pluginPackageBundle');
const {
createPluginPackageLock,
pluginPackageInstallActionDigest,
pluginPackageInstallPlanDigest,
pluginPackageManifestDigest,
serializePluginPackageManifest,
} = require('../dist/plugin-package/installation/pluginPackageInstall');
const {
PLUGIN_PACKAGE_API_VERSION,
PLUGIN_PACKAGE_KIND,
planPluginPackageInstall,
} = require('../dist/plugin-package/pluginPackage');
const PUBLISHER = 'packages.example.com';
const KEY_ID = 'release-2026';
const OBSERVED_AT_MS = 500;
function manifest() {
return {
apiVersion: PLUGIN_PACKAGE_API_VERSION,
kind: PLUGIN_PACKAGE_KIND,
metadata: {
name: 'example-monitor',
displayName: 'Example Monitor',
version: '1.2.0',
description: 'Collects one bounded report',
license: 'Apache-2.0',
},
spec: {
compatibility: {
qinglong: '>=3.0.0-0 <4.0.0',
architectures: ['arm64'],
deploymentProfiles: ['edge'],
},
runtimes: [{ name: 'python', version: '>=3.10.0 <4.0.0' }],
resources: {
memory: { recommended: '32Mi' },
disk: { install: '8Mi', working: '32Mi' },
},
permissions: {
network: { allowedHosts: ['api.example.com'] },
secrets: [{ name: 'EXAMPLE_TOKEN', required: true }],
tools: ['notification.send'],
},
contents: {
tasks: ['tasks/collect.yaml'],
workflows: ['workflows/daily.yaml'],
prompts: [],
tools: [],
},
},
};
}
function environment() {
return {
qinglongVersion: '3.0.0-alpha.0',
architecture: 'arm64',
deploymentProfile: 'edge',
runtimes: [{ name: 'python', version: '3.12.4' }],
availableMemoryBytes: 256 * 1024 * 1024,
availableDiskBytes: 512 * 1024 * 1024,
};
}
function octal(value, bytes) {
return Buffer.from(
`${value.toString(8).padStart(bytes - 1, '0')}\0`,
'ascii',
);
}
function tarHeader(path, bytes) {
const header = Buffer.alloc(512);
const pathBytes = Buffer.from(path);
if (pathBytes.byteLength > 100) throw new Error('test path is too long');
pathBytes.copy(header, 0);
Buffer.from('0000644\0').copy(header, 100);
Buffer.from('0000000\0').copy(header, 108);
Buffer.from('0000000\0').copy(header, 116);
octal(bytes, 12).copy(header, 124);
Buffer.from('00000000000\0').copy(header, 136);
header.fill(0x20, 148, 156);
Buffer.from('0').copy(header, 156);
Buffer.from('ustar\0').copy(header, 257);
Buffer.from('00').copy(header, 263);
const checksum = header.reduce((total, byte) => total + byte, 0);
Buffer.from(`${checksum.toString(8).padStart(6, '0')}\0 `).copy(header, 148);
return header;
}
function tar(entries) {
const parts = [];
for (const entry of entries) {
parts.push(tarHeader(entry.path, entry.body.byteLength), entry.body);
const padding = (512 - (entry.body.byteLength % 512)) % 512;
if (padding > 0) parts.push(Buffer.alloc(padding));
}
parts.push(Buffer.alloc(1024));
return Buffer.concat(parts);
}
function sha256(value) {
return createHash('sha256').update(value).digest('hex');
}
function fixture() {
const packageManifest = manifest();
const canonicalManifest = Buffer.from(
serializePluginPackageManifest(packageManifest),
);
const contents = [
{
path: 'tasks/collect.yaml',
body: Buffer.from('apiVersion: qinglong.io/v1\\nkind: Task\\n'),
},
{
path: 'workflows/daily.yaml',
body: Buffer.from('apiVersion: qinglong.io/v1\\nkind: Workflow\\n'),
},
];
const artifact = tar([
{ path: 'package.json', body: canonicalManifest },
...contents,
]);
const contentDescriptors = contents.map(({ path, body }) => ({
path,
bytes: body.byteLength,
digest: sha256(body),
}));
const installEnvironment = environment();
const plan = planPluginPackageInstall(packageManifest, installEnvironment);
const source = {
kind: 'offline',
locator: `offline:sha256:${sha256(artifact)}`,
artifactDigest: sha256(artifact),
artifactBytes: artifact.byteLength,
contentDigest: pluginPackageContentTreeDigest(contentDescriptors),
};
const actionInput = {
lockId: 'lock-bundle-001',
projectId: 'project-001',
manifest: packageManifest,
plan,
environment: installEnvironment,
source,
architecture: 'arm64',
deploymentProfile: 'edge',
targetGeneration: 1,
};
const lock = createPluginPackageLock({
...actionInput,
approval: {
requestId: 'approval-001',
requestVersion: 1,
dispatchId: 'dispatch-001',
actionDigest: pluginPackageInstallActionDigest(actionInput),
previewDigest: pluginPackageInstallPlanDigest(plan),
approvedBy: { type: 'user', id: 'owner-001' },
approvedAtMs: 100,
expiresAtMs: 1_000,
fence: { projectVersion: 3, bindingVersion: 4 },
},
createdAtMs: 200,
});
const { publicKey, privateKey } = generateKeyPairSync('ed25519');
const trust = new PluginPackagePublisherTrustRegistry([
{
publisher: PUBLISHER,
keyId: KEY_ID,
publicKeyPem: publicKey.export({ format: 'pem', type: 'spki' }),
notBeforeMs: 100,
notAfterMs: 1_000,
},
]);
const signature = {
schema: PLUGIN_PACKAGE_SIGNATURE_SCHEMA,
publisher: PUBLISHER,
keyId: KEY_ID,
signature: sign(
null,
pluginPackagePublisherSignaturePayload(lock, PUBLISHER, KEY_ID),
privateKey,
).toString('base64url'),
};
return {
artifact,
canonicalManifest,
contentDescriptors,
lock,
packageManifest,
privateKey,
signature,
trust,
};
}
async function* chunks(value, widths = [1, 17, 509, 3, 1024]) {
let offset = 0;
let index = 0;
while (offset < value.byteLength) {
const end = Math.min(
value.byteLength,
offset + widths[index % widths.length],
);
yield value.subarray(offset, end);
offset = end;
index += 1;
}
}
function inspect(value, overrides = {}) {
return inspectPluginPackageBundle({
lock: value.lock,
manifest: value.packageManifest,
signature: value.signature,
trust: value.trust,
observedAtMs: OBSERVED_AT_MS,
chunks: chunks(value.artifact),
...overrides,
});
}
test('inspects one canonical streaming USTAR bundle and publisher signature', async () => {
const value = fixture();
const inspection = await inspect(value);
assert.equal(inspection.mediaType, PLUGIN_PACKAGE_BUNDLE_MEDIA_TYPE);
assert.equal(inspection.lockDigest, value.lock.lockDigest);
assert.equal(inspection.artifactDigest, value.lock.source.artifactDigest);
assert.equal(
inspection.manifestDigest,
pluginPackageManifestDigest(manifest()),
);
assert.equal(inspection.contentDigest, value.lock.source.contentDigest);
assert.deepEqual(
inspection.entries.map(({ path }) => path),
['package.json', 'tasks/collect.yaml', 'workflows/daily.yaml'],
);
assert.equal(inspection.signature.publisher, PUBLISHER);
assert.equal(Object.isFrozen(inspection), true);
});
test('streams exact entry bytes through a transactional sink', async () => {
const value = fixture();
const events = [];
const bodies = [];
let current = [];
await inspect(value, {
chunks: chunks(value.artifact, [7]),
sink: {
begin(entry) {
events.push(`begin:${entry.path}`);
current = [];
},
write(chunk) {
current.push(Buffer.from(chunk));
},
end(entry) {
events.push(`end:${entry.path}`);
bodies.push(Buffer.concat(current));
},
commit(inspection) {
events.push(`commit:${inspection.lockDigest}`);
},
abort() {
events.push('abort');
},
},
});
assert.deepEqual(bodies[0], value.canonicalManifest);
assert.equal(
bodies[1].toString(),
'apiVersion: qinglong.io/v1\\nkind: Task\\n',
);
assert.equal(events.at(-1), `commit:${value.lock.lockDigest}`);
assert.equal(events.includes('abort'), false);
});
test('rejects missing, extra, reordered and non-canonical archive entries', async () => {
const value = fixture();
const taskBody = Buffer.from('apiVersion: qinglong.io/v1\\nkind: Task\\n');
const workflowBody = Buffer.from(
'apiVersion: qinglong.io/v1\\nkind: Workflow\\n',
);
const variants = [
tar([
{ path: 'package.json', body: value.canonicalManifest },
{ path: 'workflows/daily.yaml', body: workflowBody },
{ path: 'tasks/collect.yaml', body: taskBody },
]),
tar([
{ path: 'package.json', body: value.canonicalManifest },
{ path: 'tasks/collect.yaml', body: taskBody },
]),
];
for (const artifact of variants) {
await assert.rejects(
inspect(value, { chunks: chunks(artifact) }),
InvalidPluginPackageBundleError,
);
}
const invalidMode = Buffer.from(value.artifact);
Buffer.from('0000755\0').copy(invalidMode, 100);
await assert.rejects(
inspect(value, { chunks: chunks(invalidMode) }),
InvalidPluginPackageBundleError,
);
const splitPath = Buffer.from(value.artifact);
const splitHeaderOffset =
512 + Math.ceil(value.canonicalManifest.byteLength / 512) * 512;
assert.equal(
splitPath
.subarray(splitHeaderOffset, splitHeaderOffset + 100)
.toString('utf8')
.replace(/\0+$/, ''),
'tasks/collect.yaml',
);
splitPath.fill(0, splitHeaderOffset, splitHeaderOffset + 100);
Buffer.from('collect.yaml').copy(splitPath, splitHeaderOffset);
Buffer.from('tasks').copy(splitPath, splitHeaderOffset + 345);
splitPath.fill(0x20, splitHeaderOffset + 148, splitHeaderOffset + 156);
const splitChecksum = splitPath
.subarray(splitHeaderOffset, splitHeaderOffset + 512)
.reduce((total, byte) => total + byte, 0);
Buffer.from(`${splitChecksum.toString(8).padStart(6, '0')}\0 `).copy(
splitPath,
splitHeaderOffset + 148,
);
await assert.rejects(
inspect(value, { chunks: chunks(splitPath) }),
InvalidPluginPackageBundleError,
);
await assert.rejects(
inspect(value, {
chunks: chunks(Buffer.concat([value.artifact, Buffer.alloc(512)])),
}),
InvalidPluginPackageBundleError,
);
});
test('binds artifact, manifest and content digests to the immutable PackageLock', async () => {
const value = fixture();
const tampered = Buffer.from(value.artifact);
tampered[512] ^= 1;
await assert.rejects(
inspect(value, { chunks: chunks(tampered) }),
InvalidPluginPackageBundleError,
);
await assert.rejects(
inspect(value, {
manifest: {
...value.packageManifest,
metadata: {
...value.packageManifest.metadata,
description: 'changed after approval',
},
},
}),
InvalidPluginPackageBundleError,
);
});
test('rejects unknown, expired and invalid Ed25519 publisher signatures', async () => {
const value = fixture();
const invalidSignature = Buffer.from(
value.signature.signature,
'base64url',
);
invalidSignature[0] ^= 1;
await assert.rejects(
inspect(value, { observedAtMs: 1_000 }),
UntrustedPluginPackagePublisherError,
);
await assert.rejects(
inspect(value, {
signature: {
...value.signature,
signature: invalidSignature.toString('base64url'),
},
}),
UntrustedPluginPackagePublisherError,
);
assert.throws(
() =>
new PluginPackagePublisherTrustRegistry([
{
publisher: PUBLISHER,
keyId: KEY_ID,
publicKeyPem: 'not a public key',
notBeforeMs: 0,
notAfterMs: 1,
},
]),
InvalidPluginPackagePublisherTrustError,
);
});
test('aborts a sink exactly once and hides infrastructure failure details', async () => {
const value = fixture();
let aborts = 0;
await assert.rejects(
inspect(value, {
sink: {
begin() {},
write() {
throw new Error('private filesystem detail');
},
end() {},
commit() {},
abort() {
aborts += 1;
},
},
}),
PluginPackageBundleUnavailableError,
);
assert.equal(aborts, 1);
});
test('rejects unsafe public content descriptors and oversized chunks', async () => {
assert.throws(
() =>
pluginPackageContentTreeDigest([
{ path: '../escape', bytes: 1, digest: 'a'.repeat(64) },
]),
InvalidPluginPackageBundleError,
);
const value = fixture();
async function* oversized() {
yield Buffer.alloc(1024 * 1024 + 1);
}
await assert.rejects(
inspect(value, { chunks: oversized() }),
InvalidPluginPackageBundleError,
);
});
test('publishes bundle authority only through its explicit subpath', () => {
const root = require('../dist');
const subpath = require('@qinglong/runtime-core/plugin-package-bundle');
assert.equal(root.inspectPluginPackageBundle, undefined);
assert.equal(subpath.inspectPluginPackageBundle, inspectPluginPackageBundle);
const source = readFileSync(
join(__dirname, '..', 'src', 'plugin-package', 'pluginPackageBundle.ts'),
'utf8',
);
assert.doesNotMatch(source, /node:(?:fs|net|http|https|tls|dgram)/);
assert.doesNotMatch(source, /\b(?:setTimeout|setInterval|process)\b/);
});
@@ -0,0 +1,693 @@
const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const { join } = require('node:path');
const { test } = require('node:test');
const {
InvalidPluginPackageInstallError,
InvalidPluginPackageLockError,
MAX_PLUGIN_PACKAGE_INSTALL_INVENTORY_PAGE_SIZE,
MAX_PLUGIN_PACKAGE_INSTALL_RECOVERY_PAGE_SIZE,
PLUGIN_PACKAGE_API_VERSION,
PLUGIN_PACKAGE_KIND,
PluginPackageInstallMutationConflictError,
PluginPackageInstallTransitionConflictError,
assertPluginPackageInstallInventoryPageSize,
assertPluginPackageInstallRecoveryPageSize,
createPluginPackageInstall,
createPluginPackageLock,
normalizePluginPackageInstallRecord,
normalizePluginPackageInstallInventoryCursor,
normalizePluginPackageInstallRecoveryCursor,
normalizePluginPackageInstallCreate,
normalizePluginPackageLock,
planPluginPackageInstall,
pluginPackageInstallActionDigest,
pluginPackageActivationIntentDigest,
pluginPackageInstallCommit,
pluginPackageInstallCreate,
pluginPackageInstallPlanDigest,
pluginPackageInstallRecoveryAction,
transitionPluginPackageInstall,
} = require('../dist');
test('bounds and canonicalizes current installation inventory pages', () => {
assert.doesNotThrow(() =>
assertPluginPackageInstallInventoryPageSize(
MAX_PLUGIN_PACKAGE_INSTALL_INVENTORY_PAGE_SIZE,
),
);
assert.throws(
() =>
assertPluginPackageInstallInventoryPageSize(
MAX_PLUGIN_PACKAGE_INSTALL_INVENTORY_PAGE_SIZE + 1,
),
InvalidPluginPackageInstallError,
);
const cursor = normalizePluginPackageInstallInventoryCursor({
packageName: 'example-monitor',
});
assert.deepEqual(cursor, { packageName: 'example-monitor' });
assert.equal(Object.isFrozen(cursor), true);
assert.throws(
() =>
normalizePluginPackageInstallInventoryCursor({
packageName: '../escape',
}),
InvalidPluginPackageInstallError,
);
assert.throws(
() =>
normalizePluginPackageInstallInventoryCursor({
packageName: 'example-monitor',
installationId: 'unexpected',
}),
InvalidPluginPackageInstallError,
);
});
const ARTIFACT_DIGEST = 'a'.repeat(64);
const OCI_MANIFEST_DIGEST = 'f'.repeat(64);
const CONTENT_DIGEST = 'b'.repeat(64);
const PREVIOUS_LOCK_DIGEST = 'c'.repeat(64);
function manifest(overrides = {}) {
const value = {
apiVersion: PLUGIN_PACKAGE_API_VERSION,
kind: PLUGIN_PACKAGE_KIND,
metadata: {
name: 'example-monitor',
displayName: 'Example Monitor',
version: '1.2.0',
description: 'Collects one bounded report',
license: 'Apache-2.0',
},
spec: {
compatibility: {
qinglong: '>=3.0.0-0 <4.0.0',
architectures: ['arm64', 'amd64'],
deploymentProfiles: ['standalone', 'edge'],
},
runtimes: [{ name: 'python', version: '>=3.10.0 <4.0.0' }],
resources: {
memory: { recommended: '128Mi' },
disk: { install: '20Mi', working: '100Mi' },
},
permissions: {
network: { allowedHosts: ['api.example.com'] },
secrets: [{ name: 'EXAMPLE_TOKEN', required: true }],
tools: ['notification.send'],
},
contents: {
tasks: ['tasks/collect.yaml'],
workflows: ['workflows/daily-report.yaml'],
prompts: ['prompts/analyze-error.md'],
tools: ['tools/query-data.yaml'],
},
},
};
return {
...value,
...overrides,
metadata: { ...value.metadata, ...overrides.metadata },
spec: {
...value.spec,
...overrides.spec,
compatibility: {
...value.spec.compatibility,
...overrides.spec?.compatibility,
},
resources: {
...value.spec.resources,
...overrides.spec?.resources,
memory: {
...value.spec.resources.memory,
...overrides.spec?.resources?.memory,
},
disk: {
...value.spec.resources.disk,
...overrides.spec?.resources?.disk,
},
},
permissions: {
...value.spec.permissions,
...overrides.spec?.permissions,
network: {
...value.spec.permissions.network,
...overrides.spec?.permissions?.network,
},
},
contents: {
...value.spec.contents,
...overrides.spec?.contents,
},
},
};
}
function environment(overrides = {}) {
return {
qinglongVersion: '3.0.0-alpha.0',
architecture: 'arm64',
deploymentProfile: 'edge',
runtimes: [{ name: 'python', version: '3.12.4' }],
availableMemoryBytes: 256 * 1024 * 1024,
availableDiskBytes: 512 * 1024 * 1024,
...overrides,
};
}
function lockInput(overrides = {}) {
const candidate = overrides.manifest ?? manifest();
const previous = overrides.previousManifest;
const installEnvironment = {
...environment(),
...overrides.environment,
};
const plan =
overrides.plan ??
planPluginPackageInstall(candidate, installEnvironment, previous);
const operation = plan.operation;
const targetGeneration =
overrides.targetGeneration ?? (operation === 'install' ? 1 : 2);
const previousLockDigest =
overrides.previousLockDigest ??
(operation === 'install' ? undefined : PREVIOUS_LOCK_DIGEST);
const source = {
kind: 'oci',
locator: `oci://registry.example.com/qinglong/example-monitor@sha256:${OCI_MANIFEST_DIGEST}`,
artifactDigest: ARTIFACT_DIGEST,
artifactBytes: 1024,
contentDigest: CONTENT_DIGEST,
...overrides.source,
};
const actionInput = {
lockId: overrides.lockId ?? 'lock-001',
projectId: overrides.projectId ?? 'project-001',
manifest: candidate,
plan,
environment: installEnvironment,
...(previous === undefined ? {} : { previousManifest: previous }),
source,
architecture: overrides.architecture ?? 'arm64',
deploymentProfile: overrides.deploymentProfile ?? 'edge',
targetGeneration,
...(previousLockDigest === undefined ? {} : { previousLockDigest }),
};
const actionDigest = pluginPackageInstallActionDigest(actionInput);
const previewDigest = pluginPackageInstallPlanDigest(plan);
return {
...actionInput,
approval: {
requestId: 'approval-001',
requestVersion: 2,
dispatchId: 'dispatch-001',
actionDigest,
previewDigest,
approvedBy: { type: 'user', id: 'owner-001' },
approvedAtMs: 100,
expiresAtMs: 1_000,
fence: { projectVersion: 3, bindingVersion: 4 },
...overrides.approval,
},
createdAtMs: overrides.createdAtMs ?? 200,
};
}
function installFixture(lockOverrides = {}) {
const lock = createPluginPackageLock(lockInput(lockOverrides));
const install = createPluginPackageInstall(lock, {
installationId: 'install-001',
mutationId: 'mutation-create',
occurredAtMs: 201,
});
return { lock, install };
}
function stageEvent(lock, overrides = {}) {
return {
type: 'stage_completed',
mutationId: 'mutation-stage',
occurredAtMs: 202,
stageRef: 'stage-001',
artifactDigest: lock.source.artifactDigest,
manifestDigest: lock.manifestDigest,
contentDigest: lock.source.contentDigest,
evidenceDigest: 'e'.repeat(64),
...overrides,
};
}
test('creates one immutable OCI PackageLock bound to plan and approval', () => {
const input = lockInput();
const lock = createPluginPackageLock(input);
assert.equal(lock.schema, 'qinglong/plugin-package-lock@v2');
assert.equal(lock.operation, 'install');
assert.equal(lock.targetGeneration, 1);
assert.equal(lock.approval.actionDigest, lock.actionDigest);
assert.equal(lock.approval.previewDigest, lock.planDigest);
assert.match(lock.environmentDigest, /^[0-9a-f]{64}$/);
assert.match(lock.lockDigest, /^[0-9a-f]{64}$/);
assert.equal(Object.isFrozen(lock), true);
assert.equal(Object.isFrozen(lock.source), true);
assert.deepEqual(lock.resources, [
{ kind: 'prompt', path: 'prompts/analyze-error.md' },
{ kind: 'task', path: 'tasks/collect.yaml' },
{ kind: 'tool', path: 'tools/query-data.yaml' },
{ kind: 'workflow', path: 'workflows/daily-report.yaml' },
]);
assert.equal(
lock.source.locator,
`oci://registry.example.com/qinglong/example-monitor@sha256:${OCI_MANIFEST_DIGEST}`,
);
assert.notEqual(OCI_MANIFEST_DIGEST, lock.source.artifactDigest);
assert.deepEqual(normalizePluginPackageLock(lock), lock);
assert.throws(
() =>
normalizePluginPackageLock({
...lock,
schema: 'qinglong/plugin-package-lock@v1',
}),
/lock vocabulary is invalid/,
);
});
test('accepts content-addressed offline bundles without persisting a host path', () => {
const input = lockInput({
source: {
kind: 'offline',
locator: `offline:sha256:${ARTIFACT_DIGEST}`,
},
});
const lock = createPluginPackageLock(input);
assert.equal(lock.source.kind, 'offline');
assert.equal(lock.source.locator, `offline:sha256:${ARTIFACT_DIGEST}`);
assert.equal(lock.source.locator.includes('/'), false);
});
test('rejects mutable sources and offline source digest mismatches', () => {
assert.throws(
() =>
lockInput({
source: {
locator: 'oci://registry.example.com/qinglong/example-monitor:latest',
},
}),
InvalidPluginPackageLockError,
);
assert.throws(
() =>
lockInput({
source: {
kind: 'offline',
locator: `oci://registry.example.com/qinglong/example-monitor@sha256:${'d'.repeat(
64,
)}`,
},
}),
/source locator is not immutable/,
);
assert.throws(
() =>
lockInput({
source: {
kind: 'offline',
locator: `offline:sha256:${'d'.repeat(64)}`,
},
}),
/offline source locator does not match its artifact digest/,
);
for (const locator of [
`oci://registry..example.com/qinglong/example-monitor@sha256:${ARTIFACT_DIGEST}`,
`oci://registry.example.com:99999/qinglong/example-monitor@sha256:${ARTIFACT_DIGEST}`,
]) {
assert.throws(
() => lockInput({ source: { locator } }),
InvalidPluginPackageLockError,
);
}
});
test('rejects expired or digest-detached approval bindings', () => {
const detached = lockInput();
detached.approval.actionDigest = 'd'.repeat(64);
assert.throws(
() => createPluginPackageLock(detached),
/approval is not bound/,
);
const expired = lockInput();
expired.approval.expiresAtMs = expired.createdAtMs;
assert.throws(() => createPluginPackageLock(expired), /is not active/);
const automated = lockInput();
automated.approval.approvedBy = { type: 'agent', id: 'agent-001' };
assert.throws(
() => createPluginPackageLock(automated),
/requires a human approval/,
);
});
test('recomputes the approved plan from the exact environment and previous manifest', () => {
const candidate = manifest();
const reviewed = planPluginPackageInstall(candidate, environment());
assert.throws(
() => lockInput({ plan: { ...reviewed, risk: 'low' } }),
/manifest, environment or previous manifest does not match/,
);
assert.throws(
() => lockInput({ architecture: 'amd64' }),
/does not match the install environment/,
);
});
test('requires a previous immutable lock for upgrade and rollback generations', () => {
const previous = manifest({ metadata: { version: '1.1.0' } });
const upgrade = createPluginPackageLock(
lockInput({ previousManifest: previous }),
);
assert.equal(upgrade.operation, 'upgrade');
assert.equal(upgrade.targetGeneration, 2);
assert.equal(upgrade.previousLockDigest, PREVIOUS_LOCK_DIGEST);
const rollbackManifest = manifest({ metadata: { version: '1.1.0' } });
const rollback = createPluginPackageLock(
lockInput({
manifest: rollbackManifest,
previousManifest: manifest(),
}),
);
assert.equal(rollback.operation, 'rollback');
assert.equal(rollback.previousLockDigest, PREVIOUS_LOCK_DIGEST);
assert.throws(
() =>
createPluginPackageLock(
lockInput({
previousManifest: previous,
previousLockDigest: undefined,
targetGeneration: 1,
}),
),
/operation does not match/,
);
});
test('creates a queued durable record while preserving the previous active lock', () => {
const previous = manifest({ metadata: { version: '1.1.0' } });
const { install } = installFixture({ previousManifest: previous });
assert.equal(install.state, 'queued');
assert.equal(install.version, 1);
assert.equal(install.previousActiveLockDigest, PREVIOUS_LOCK_DIGEST);
assert.equal(install.activeLockDigest, PREVIOUS_LOCK_DIGEST);
assert.equal(pluginPackageInstallRecoveryAction(install), 'resume_stage');
assert.match(install.recordDigest, /^[0-9a-f]{64}$/);
});
test('builds an exact first-create envelope and fences replacement heads', () => {
const { lock, install } = installFixture();
const initial = pluginPackageInstallCreate(lock, install, null);
assert.deepEqual(initial, {
installationId: install.installationId,
mutationId: install.lastMutationId,
mutationDigest: initial.mutationDigest,
expectedHead: null,
lock,
record: install,
});
assert.match(initial.mutationDigest, /^[0-9a-f]{64}$/);
assert.notEqual(initial.mutationDigest, install.lastMutationDigest);
assert.equal(Object.isFrozen(initial), true);
const failed = transitionPluginPackageInstall(lock, install, {
type: 'failed',
mutationId: 'mutation-fail',
occurredAtMs: 202,
reason: 'stage_failed',
});
const replacementLock = createPluginPackageLock(
lockInput({ lockId: 'lock-002' }),
);
const replacement = createPluginPackageInstall(replacementLock, {
installationId: 'install-002',
mutationId: 'mutation-retry',
occurredAtMs: 203,
});
const retry = pluginPackageInstallCreate(
replacementLock,
replacement,
failed,
);
assert.deepEqual(retry.expectedHead, {
installationId: failed.installationId,
version: failed.version,
recordDigest: failed.recordDigest,
});
assert.throws(
() => pluginPackageInstallCreate(replacementLock, replacement, install),
PluginPackageInstallTransitionConflictError,
);
assert.throws(
() =>
pluginPackageInstallCreate(
replacementLock,
{ ...replacement, lastMutationDigest: 'f'.repeat(64) },
failed,
),
InvalidPluginPackageInstallError,
);
assert.throws(
() =>
normalizePluginPackageInstallCreate({
...initial,
expectedHead: retry.expectedHead,
}),
InvalidPluginPackageInstallError,
);
});
test('records exact staging evidence before activation can begin', () => {
const { lock, install } = installFixture();
const staged = transitionPluginPackageInstall(
lock,
install,
stageEvent(lock),
);
assert.equal(staged.state, 'staged');
assert.equal(staged.version, 2);
assert.equal(staged.activeLockDigest, null);
assert.equal(staged.stageReceipt.contentDigest, CONTENT_DIGEST);
assert.match(staged.stageReceipt.receiptDigest, /^[0-9a-f]{64}$/);
assert.equal(pluginPackageInstallRecoveryAction(staged), 'resume_activation');
});
test('rejects staging evidence detached from the immutable lock', () => {
const { lock, install } = installFixture();
assert.throws(
() =>
transitionPluginPackageInstall(
lock,
install,
stageEvent(lock, { contentDigest: 'd'.repeat(64) }),
),
PluginPackageInstallTransitionConflictError,
);
});
test('keeps the previous active lock through activating and swaps only on commit', () => {
const previous = manifest({ metadata: { version: '1.1.0' } });
const { lock, install } = installFixture({ previousManifest: previous });
const staged = transitionPluginPackageInstall(
lock,
install,
stageEvent(lock),
);
const activating = transitionPluginPackageInstall(lock, staged, {
type: 'activation_started',
mutationId: 'mutation-activate',
occurredAtMs: 203,
});
assert.equal(activating.state, 'activating');
assert.equal(activating.activeLockDigest, PREVIOUS_LOCK_DIGEST);
assert.equal(
pluginPackageInstallRecoveryAction(activating),
'inspect_activation',
);
const active = transitionPluginPackageInstall(lock, activating, {
type: 'activation_committed',
mutationId: 'mutation-commit',
occurredAtMs: 204,
activationRef: 'activation-generation-2',
intentDigest: pluginPackageActivationIntentDigest(lock, activating),
generation: 2,
contentDigest: CONTENT_DIGEST,
});
assert.equal(active.state, 'active');
assert.equal(active.activeLockDigest, lock.lockDigest);
assert.equal(active.activationReceipt.generation, 2);
assert.equal(pluginPackageInstallRecoveryAction(active), 'none');
});
test('fails closed without replacing the prior active generation', () => {
const previous = manifest({ metadata: { version: '1.1.0' } });
const { lock, install } = installFixture({ previousManifest: previous });
const staged = transitionPluginPackageInstall(
lock,
install,
stageEvent(lock),
);
const failed = transitionPluginPackageInstall(lock, staged, {
type: 'failed',
mutationId: 'mutation-fail',
occurredAtMs: 203,
reason: 'activation_failed',
});
assert.equal(failed.state, 'failed');
assert.equal(failed.activeLockDigest, PREVIOUS_LOCK_DIGEST);
assert.equal(failed.failure.failedFrom, 'staged');
assert.equal(pluginPackageInstallRecoveryAction(failed), 'none');
});
test('makes the last mutation replay idempotent and rejects mutation reuse', () => {
const { lock, install } = installFixture();
const event = stageEvent(lock);
const staged = transitionPluginPackageInstall(lock, install, event);
assert.deepEqual(transitionPluginPackageInstall(lock, staged, event), staged);
assert.throws(
() =>
transitionPluginPackageInstall(lock, staged, {
...event,
stageRef: 'different-stage',
}),
PluginPackageInstallMutationConflictError,
);
});
test('rejects illegal transitions, time reversal and tampered durable records', () => {
const { lock, install } = installFixture();
assert.throws(
() =>
transitionPluginPackageInstall(lock, install, {
type: 'activation_started',
mutationId: 'mutation-skip-stage',
occurredAtMs: 202,
}),
PluginPackageInstallTransitionConflictError,
);
assert.throws(
() =>
transitionPluginPackageInstall(
lock,
install,
stageEvent(lock, { occurredAtMs: 199 }),
),
PluginPackageInstallTransitionConflictError,
);
assert.throws(
() =>
normalizePluginPackageInstallRecord({
...install,
activeLockDigest: lock.lockDigest,
}),
InvalidPluginPackageInstallError,
);
});
test('builds an exact CAS commit envelope for durable adapters', () => {
const { lock, install } = installFixture();
const staged = transitionPluginPackageInstall(
lock,
install,
stageEvent(lock),
);
const commit = pluginPackageInstallCommit(install, staged);
assert.deepEqual(commit, {
installationId: 'install-001',
expectedVersion: 1,
expectedRecordDigest: install.recordDigest,
mutationId: 'mutation-stage',
mutationDigest: staged.lastMutationDigest,
record: staged,
});
assert.equal(Object.isFrozen(commit), true);
const otherLock = createPluginPackageLock(
lockInput({ projectId: 'different-project' }),
);
const otherInstall = createPluginPackageInstall(otherLock, {
installationId: 'install-001',
mutationId: 'mutation-create',
occurredAtMs: 201,
});
const otherStaged = transitionPluginPackageInstall(
otherLock,
otherInstall,
stageEvent(otherLock),
);
assert.throws(
() => pluginPackageInstallCommit(install, otherStaged),
PluginPackageInstallTransitionConflictError,
);
});
test('bounds recovery scans and publishes root plus dedicated subpath', () => {
assert.doesNotThrow(() =>
assertPluginPackageInstallRecoveryPageSize(
MAX_PLUGIN_PACKAGE_INSTALL_RECOVERY_PAGE_SIZE,
),
);
assert.throws(
() =>
assertPluginPackageInstallRecoveryPageSize(
MAX_PLUGIN_PACKAGE_INSTALL_RECOVERY_PAGE_SIZE + 1,
),
InvalidPluginPackageInstallError,
);
assert.deepEqual(
normalizePluginPackageInstallRecoveryCursor({
packageName: 'example-monitor',
installationId: 'install-001',
}),
{
packageName: 'example-monitor',
installationId: 'install-001',
},
);
assert.throws(
() =>
normalizePluginPackageInstallRecoveryCursor({
packageName: 'example-monitor',
installationId: '../escape',
}),
InvalidPluginPackageInstallError,
);
const root = require('../dist');
const subpath = require('@qinglong/runtime-core/plugin-package-install');
assert.equal(
subpath.transitionPluginPackageInstall,
root.transitionPluginPackageInstall,
);
assert.equal(subpath.createPluginPackageLock, createPluginPackageLock);
const source = readFileSync(
join(
__dirname,
'../src/plugin-package/installation/pluginPackageInstall.ts',
),
'utf8',
);
for (const forbidden of [
"from 'node:child_process'",
"from 'node:fs'",
"from 'node:http'",
"from 'node:https'",
"from 'node:net'",
"from 'node:timers'",
'setInterval(',
'setTimeout(',
'fetch(',
]) {
assert.equal(source.includes(forbidden), false, forbidden);
}
});
@@ -0,0 +1,361 @@
const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const { join } = require('node:path');
const { test } = require('node:test');
const {
InvalidPluginPackageLifecycleError,
assertPluginPackageLifecycleReceiptMatchesEvent,
createPluginPackageLifecycleEvent,
createPluginPackageLifecycleImpact,
createPluginPackageLifecycleReceipt,
normalizePluginPackageLifecycleEvent,
normalizePluginPackageLifecycleImpact,
normalizePluginPackageLifecycleReceipt,
pluginPackageLifecycleActionDigest,
pluginPackageLifecycleMutationId,
pluginPackageLifecycleNextDisposition,
pluginPackageLifecycleReferenceGraphDigest,
pluginPackageLifecycleTaskMutationId,
} = require('../dist/plugin-package/lifecycle/pluginPackageLifecycle');
const digest = (value) => value.repeat(64);
function target() {
return {
projectId: 'default',
packageName: 'example-monitor',
installationId: 'install-example-v1',
lockDigest: digest('a'),
installVersion: 4,
installRecordDigest: digest('b'),
};
}
function expectation(disposition = 'active', version = 0, eventDigest = null) {
return { disposition, version, eventDigest };
}
function impactInput(action = 'disable', overrides = {}) {
const input = {
action,
target: target(),
expected:
action === 'disable'
? expectation()
: expectation('disabled', 1, digest('c')),
generationDigest: digest('d'),
materializedRevisionDigest: digest('e'),
currentToolSnapshotDigest: digest('f'),
taskIds: ['report', 'collect'],
resourceCounts: {
tasks: 2,
tools: 1,
workflows: 1,
prompts: 1,
},
blockingReferences: [],
...overrides,
};
return {
...input,
referenceGraphDigest: pluginPackageLifecycleReferenceGraphDigest({
target: input.target,
generationDigest: input.generationDigest,
materializedRevisionDigest: input.materializedRevisionDigest,
taskIds: input.taskIds,
resourceCounts: input.resourceCounts,
blockingReferences: input.blockingReferences,
}),
};
}
function taskTransitions(status) {
return [
{
taskId: 'report',
previousRevision: 4,
currentRevision: 5,
previousContentDigest: digest('2'),
currentContentDigest: digest('3'),
previousEnabled: status === 'withdrawn',
currentEnabled: status === 'restored',
},
{
taskId: 'collect',
previousRevision: 7,
currentRevision: 8,
previousContentDigest: digest('4'),
currentContentDigest: digest('5'),
previousEnabled: status === 'withdrawn',
currentEnabled: status === 'restored',
},
];
}
function capability(status) {
const unchanged = status === 'retired';
return {
status,
taskTransitions: unchanged ? [] : taskTransitions(status),
previousActiveVectorDigest: digest('6'),
currentActiveVectorDigest: unchanged ? digest('6') : digest('7'),
currentToolSnapshotDigest: digest('8'),
retainedSourceCount: 2,
};
}
function lifecycleHead(event, disposition, version, committedAtMs) {
const lifecycleTarget = target();
return {
projectId: lifecycleTarget.projectId,
packageName: lifecycleTarget.packageName,
installationId: lifecycleTarget.installationId,
lockDigest: lifecycleTarget.lockDigest,
installRecordDigest: lifecycleTarget.installRecordDigest,
version,
disposition,
eventDigest: event.eventDigest,
updatedAtMs: committedAtMs,
};
}
test('binds one human-confirmed disable to exact resources and capability withdrawal', () => {
const impact = createPluginPackageLifecycleImpact(impactInput());
assert.deepEqual(impact.taskIds, ['collect', 'report']);
assert.equal(impact.resourceCounts.workflows, 1);
const event = createPluginPackageLifecycleEvent({
dispatchId: 'dispatch-disable-v1',
impact,
requestedBy: { type: 'user', id: 'owner-a' },
approvedBy: { type: 'user', id: 'owner-a' },
authorizationMode: 'human_confirmation',
occurredAtMs: 100,
});
assert.equal(event.actionDigest, pluginPackageLifecycleActionDigest(impact));
assert.equal(
event.mutationId,
pluginPackageLifecycleMutationId(event.dispatchId, impact.impactDigest),
);
const receipt = createPluginPackageLifecycleReceipt({
eventDigest: event.eventDigest,
action: 'disable',
target: event.impact.target,
lifecycle: lifecycleHead(event, 'disabled', 1, 101),
capability: capability('withdrawn'),
committedAtMs: 101,
});
assert.deepEqual(normalizePluginPackageLifecycleImpact(impact), impact);
assert.deepEqual(normalizePluginPackageLifecycleEvent(event), event);
assert.deepEqual(normalizePluginPackageLifecycleReceipt(receipt), receipt);
assert.doesNotThrow(() =>
assertPluginPackageLifecycleReceiptMatchesEvent(event, receipt),
);
assert.match(
pluginPackageLifecycleTaskMutationId(event.eventDigest, 'collect'),
/^[0-9a-f-]{36}$/,
);
});
test('allows only active-disable, disabled-enable and disabled-uninstall transitions', () => {
assert.equal(
pluginPackageLifecycleNextDisposition('disable', 'active'),
'disabled',
);
assert.equal(
pluginPackageLifecycleNextDisposition('enable', 'disabled'),
'active',
);
assert.equal(
pluginPackageLifecycleNextDisposition('uninstall', 'disabled'),
'uninstalled',
);
for (const [action, disposition] of [
['disable', 'disabled'],
['enable', 'active'],
['enable', 'uninstalled'],
['uninstall', 'active'],
['uninstall', 'uninstalled'],
]) {
assert.throws(
() => pluginPackageLifecycleNextDisposition(action, disposition),
InvalidPluginPackageLifecycleError,
);
}
});
test('requires exact local or separation-of-duty authorization and blocks referenced uninstall', () => {
const disable = createPluginPackageLifecycleImpact(impactInput());
assert.throws(
() =>
createPluginPackageLifecycleEvent({
dispatchId: 'dispatch-invalid-local',
impact: disable,
requestedBy: { type: 'user', id: 'owner-a' },
approvedBy: { type: 'user', id: 'owner-b' },
authorizationMode: 'human_confirmation',
occurredAtMs: 100,
}),
InvalidPluginPackageLifecycleError,
);
assert.throws(
() =>
createPluginPackageLifecycleEvent({
dispatchId: 'dispatch-invalid-cluster',
impact: disable,
requestedBy: { type: 'user', id: 'owner-a' },
approvedBy: { type: 'user', id: 'owner-a' },
authorizationMode: 'separation_of_duty',
occurredAtMs: 100,
}),
InvalidPluginPackageLifecycleError,
);
const uninstall = createPluginPackageLifecycleImpact(
impactInput('uninstall', {
blockingReferences: [
{
kind: 'workflow',
ownerId: 'workflow-a',
referenceDigest: digest('9'),
},
],
}),
);
assert.throws(
() =>
createPluginPackageLifecycleEvent({
dispatchId: 'dispatch-blocked-uninstall',
impact: uninstall,
requestedBy: { type: 'user', id: 'owner-a' },
approvedBy: { type: 'user', id: 'owner-b' },
authorizationMode: 'separation_of_duty',
occurredAtMs: 100,
}),
/blocking references/,
);
});
test('binds enable and uninstall receipts to distinct restored and retired facts', () => {
for (const fixture of [
{
action: 'enable',
disposition: 'active',
status: 'restored',
dispatchId: 'dispatch-enable-v2',
},
{
action: 'uninstall',
disposition: 'uninstalled',
status: 'retired',
dispatchId: 'dispatch-uninstall-v2',
},
]) {
const impact = createPluginPackageLifecycleImpact(
impactInput(fixture.action),
);
const event = createPluginPackageLifecycleEvent({
dispatchId: fixture.dispatchId,
impact,
requestedBy: { type: 'user', id: 'owner-a' },
approvedBy: { type: 'user', id: 'owner-b' },
authorizationMode: 'separation_of_duty',
occurredAtMs: 200,
});
const receipt = createPluginPackageLifecycleReceipt({
eventDigest: event.eventDigest,
action: fixture.action,
target: event.impact.target,
lifecycle: lifecycleHead(event, fixture.disposition, 2, 201),
capability: capability(fixture.status),
committedAtMs: 201,
});
assert.doesNotThrow(() =>
assertPluginPackageLifecycleReceiptMatchesEvent(event, receipt),
);
}
});
test('rejects digest, resource-count and receipt transition drift', () => {
const impact = createPluginPackageLifecycleImpact(impactInput());
assert.throws(
() =>
normalizePluginPackageLifecycleImpact({
...impact,
impactDigest: digest('0'),
}),
/impactDigest/,
);
assert.throws(
() =>
normalizePluginPackageLifecycleImpact({
...impact,
referenceGraphDigest: digest('0'),
}),
/referenceGraphDigest/,
);
assert.throws(
() =>
createPluginPackageLifecycleImpact(
impactInput('disable', {
resourceCounts: {
tasks: 1,
tools: 1,
workflows: 1,
prompts: 1,
},
}),
),
/taskIds/,
);
const event = createPluginPackageLifecycleEvent({
dispatchId: 'dispatch-disable-drift',
impact,
requestedBy: { type: 'user', id: 'owner-a' },
approvedBy: { type: 'user', id: 'owner-a' },
authorizationMode: 'human_confirmation',
occurredAtMs: 100,
});
assert.throws(
() =>
createPluginPackageLifecycleReceipt({
eventDigest: event.eventDigest,
action: 'disable',
target: event.impact.target,
lifecycle: lifecycleHead(event, 'disabled', 1, 101),
capability: {
...capability('withdrawn'),
currentActiveVectorDigest: digest('6'),
},
committedAtMs: 101,
}),
/active vector/,
);
});
test('keeps originally disabled Package Tasks outside the lifecycle transition set', () => {
const impact = createPluginPackageLifecycleImpact(
impactInput('disable', {
resourceCounts: {
tasks: 3,
tools: 1,
workflows: 1,
prompts: 1,
},
}),
);
assert.equal(impact.resourceCounts.tasks, 3);
assert.deepEqual(impact.taskIds, ['collect', 'report']);
});
test('publishes lifecycle only through its explicit runtime-core subpath', () => {
const root = require('../dist');
assert.equal(root.createPluginPackageLifecycleImpact, undefined);
const manifest = JSON.parse(
readFileSync(join(__dirname, '../package.json'), 'utf8'),
);
assert.deepEqual(manifest.exports['./plugin-package-lifecycle'], {
types: './dist/plugin-package/lifecycle/pluginPackageLifecycle.d.ts',
require: './dist/plugin-package/lifecycle/pluginPackageLifecycle.js',
default: './dist/plugin-package/lifecycle/pluginPackageLifecycle.js',
});
});
@@ -0,0 +1,99 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
createPluginPackageLifecycleImpact,
pluginPackageLifecycleReferenceGraphDigest,
} = require('@qinglong/runtime-core/plugin-package-lifecycle');
const {
InvalidPluginPackageLifecyclePlanError,
createPluginPackageLifecyclePlan,
normalizePluginPackageLifecyclePlan,
} = require('@qinglong/runtime-core/plugin-package-lifecycle-plan');
function impact() {
const graph = {
target: {
projectId: 'default',
packageName: 'cluster-monitor',
installationId: 'install-cluster-monitor',
lockDigest: '1'.repeat(64),
installVersion: 1,
installRecordDigest: '2'.repeat(64),
},
generationDigest: '3'.repeat(64),
materializedRevisionDigest: '4'.repeat(64),
taskIds: ['collect'],
resourceCounts: {
tasks: 1,
tools: 0,
workflows: 0,
prompts: 0,
},
blockingReferences: [],
};
return createPluginPackageLifecycleImpact({
action: 'disable',
...graph,
expected: {
version: 0,
disposition: 'active',
eventDigest: null,
},
currentToolSnapshotDigest: '5'.repeat(64),
referenceGraphDigest: pluginPackageLifecycleReferenceGraphDigest(graph),
});
}
test('creates one canonical short-lived Cluster lifecycle plan', () => {
const plan = createPluginPackageLifecyclePlan({
actionRef: 'lifecycle-plan:cluster-monitor-v1',
impact: impact(),
requestedBy: { type: 'user', id: 'cluster-owner' },
plannedAtMs: 10_000,
expiresAtMs: 20_000,
});
assert.deepEqual(normalizePluginPackageLifecyclePlan(plan), plan);
assert.match(plan.planDigest, /^[0-9a-f]{64}$/);
assert.equal(plan.impact.action, 'disable');
});
test('rejects digest drift, weak subjects and an unbounded lifetime', () => {
const plan = createPluginPackageLifecyclePlan({
actionRef: 'lifecycle-plan:cluster-monitor-v1',
impact: impact(),
requestedBy: { type: 'user', id: 'cluster-owner' },
plannedAtMs: 10_000,
expiresAtMs: 20_000,
});
assert.throws(
() =>
normalizePluginPackageLifecyclePlan({
...plan,
planDigest: 'f'.repeat(64),
}),
InvalidPluginPackageLifecyclePlanError,
);
assert.throws(
() =>
createPluginPackageLifecyclePlan({
actionRef: plan.actionRef,
impact: plan.impact,
requestedBy: { type: 'system', id: 'executor' },
plannedAtMs: plan.plannedAtMs,
expiresAtMs: plan.expiresAtMs,
}),
InvalidPluginPackageLifecyclePlanError,
);
assert.throws(
() =>
createPluginPackageLifecyclePlan({
actionRef: plan.actionRef,
impact: plan.impact,
requestedBy: plan.requestedBy,
plannedAtMs: plan.plannedAtMs,
expiresAtMs: plan.plannedAtMs + 15 * 60 * 1000 + 1,
}),
InvalidPluginPackageLifecyclePlanError,
);
});
@@ -0,0 +1,420 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
consumeApprovalRequest,
decideApprovalRequest,
} = require('@qinglong/runtime-core/approved-action');
const {
PLUGIN_PACKAGE_API_VERSION,
PLUGIN_PACKAGE_KIND,
planPluginPackageInstall,
} = require('@qinglong/runtime-core/plugin-package');
const {
createPluginPackageManagementService,
PluginPackageManagementAuthorizationError,
PluginPackageManagementQuotaExceededError,
} = require('@qinglong/runtime-core/plugin-package-management');
const {
ProjectPolicyEngine,
} = require('@qinglong/runtime-core/project-policy');
const REQUESTER = Object.freeze({ type: 'user', id: 'usr_requester' });
const REVIEWER = Object.freeze({ type: 'user', id: 'usr_reviewer' });
const FENCE = Object.freeze({ projectVersion: 1, bindingVersion: 1 });
function actionInput() {
const manifest = {
apiVersion: PLUGIN_PACKAGE_API_VERSION,
kind: PLUGIN_PACKAGE_KIND,
metadata: {
name: 'management-test',
displayName: 'Management Test',
version: '1.0.0',
description: 'Management facade contract',
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: [],
tools: [],
},
contents: { tasks: [], workflows: [], prompts: [], tools: [] },
},
};
const environment = {
qinglongVersion: '3.0.0-alpha.0',
architecture: 'arm64',
deploymentProfile: 'cluster-control',
runtimes: [],
availableMemoryBytes: 512 * 1024 * 1024,
availableDiskBytes: 1024 * 1024 * 1024,
};
return {
lockId: 'management-test-lock-v1',
projectId: 'default',
manifest,
plan: planPluginPackageInstall(manifest, environment),
environment,
source: {
kind: 'oci',
locator: `oci://registry.example/qinglong/management-test@sha256:${'a'.repeat(
64,
)}`,
artifactDigest: 'b'.repeat(64),
artifactBytes: 4_096,
contentDigest: 'c'.repeat(64),
},
architecture: 'arm64',
deploymentProfile: 'cluster-control',
targetGeneration: 1,
};
}
function principal(subject, assurance, now) {
return {
subject,
authenticationId: `auth-${subject.id}-${assurance}`,
authenticatedAtMs: now - 10,
expiresAtMs: now + 10_000,
assurance,
};
}
class MemoryProposalRepository {
proposal = null;
command = null;
async findProposalByActionRef(actionRef) {
return this.proposal?.actionRef === actionRef ? this.proposal : null;
}
async createProposal(command) {
this.command = command;
this.proposal = command.proposal;
return { status: 'created', proposal: this.proposal };
}
}
class MemoryApprovalRepository {
request = null;
dispatch = null;
audits = [];
async findById(id) {
return this.request?.id === id ? this.request : null;
}
async findDispatchById(id) {
return this.dispatch?.id === id ? this.dispatch : null;
}
async create(command) {
this.request = command.request;
this.audits.push(command.audit);
return { status: 'created', request: this.request };
}
async decide(command) {
const { requestId: _requestId, audit, ...domainCommand } = command;
this.request = decideApprovalRequest(this.request, domainCommand);
this.audits.push(audit);
return { status: 'decided', request: this.request };
}
async consume(command) {
const { requestId: _requestId, audit, ...domainCommand } = command;
const result = consumeApprovalRequest(this.request, domainCommand);
this.request = result.request;
this.dispatch = result.dispatch;
this.audits.push(audit);
return { status: 'consumed', ...result };
}
}
function fixture(decisionMode = 'separation_of_duty', quota) {
const policyRepository = {
async resolve(projectId, subject) {
if (projectId !== 'default') return null;
const role =
subject.id === REQUESTER.id
? 'owner'
: subject.id === REVIEWER.id
? 'admin'
: subject.id === 'usr_operator'
? 'operator'
: null;
return {
project: {
id: 'default',
name: 'Default',
slug: 'default',
status: 'active',
version: 1,
createdAtMs: 0,
updatedAtMs: 0,
},
...(role
? {
binding: {
projectId: 'default',
subject,
version: 1,
state: 'active',
role,
mutationId: `grant-${subject.id}`,
changedBy: REQUESTER,
createdAtMs: 0,
},
}
: {}),
};
},
async append() {
throw new Error('management facade must not mutate Project Policy');
},
};
const proposals = new MemoryProposalRepository();
const approvals = new MemoryApprovalRepository();
const dispatchCalls = [];
let now = 1_000;
const service = createPluginPackageManagementService(
new ProjectPolicyEngine(policyRepository),
proposals,
approvals,
{
async dispatchBatch(options) {
dispatchCalls.push(options);
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,
};
},
},
{
decisionMode,
consumer: {
subject: { type: 'system', id: 'package_dispatcher' },
authenticationId: 'package-dispatcher-auth',
},
now: () => now,
...(quota ? { quota } : {}),
},
);
return {
service,
proposals,
approvals,
dispatchCalls,
setNow(value) {
now = value;
},
};
}
test('orchestrates one separation-of-duty Package approval without transport authority', async () => {
const value = fixture();
const proposed = await value.service.propose({
actionRef: 'proposal:management-test-v1',
approvalRequestId: 'approval-management-test-v1',
proposalAuditEventId: '30000000-0000-4000-8000-000000000001',
approvalAuditEventId: '30000000-0000-4000-8000-000000000002',
requestedAtMs: 1_000,
actionInput: actionInput(),
principal: principal(REQUESTER, 'single_factor', 1_000),
});
assert.equal(proposed.approvalRequest.decisionMode, 'separation_of_duty');
assert.equal(
value.proposals.command.audit.operationId,
'plugin_package.propose',
);
assert.equal(value.approvals.audits[0].operationId, 'approval.request');
value.setNow(1_100);
await assert.rejects(
value.service.decide({
approvalRequestId: 'approval-management-test-v1',
expectedVersion: 1,
decisionId: 'decision-self-v1',
auditEventId: '30000000-0000-4000-8000-000000000003',
decision: 'approved',
reasonCode: 'reviewed',
decidedAtMs: 1_100,
principal: principal(REQUESTER, 'hardware', 1_100),
}),
{ code: 'APPROVAL_SEPARATION_OF_DUTY_REQUIRED' },
);
const decided = await value.service.decide({
approvalRequestId: 'approval-management-test-v1',
expectedVersion: 1,
decisionId: 'decision-reviewer-v1',
auditEventId: '30000000-0000-4000-8000-000000000004',
decision: 'approved',
reasonCode: 'reviewed',
decidedAtMs: 1_100,
principal: principal(REVIEWER, 'hardware', 1_100),
});
assert.equal(decided.request.decidedBy.id, REVIEWER.id);
value.setNow(1_200);
const consumed = await value.service.consume({
approvalRequestId: 'approval-management-test-v1',
expectedVersion: 2,
consumptionId: 'consume-management-test-v1',
dispatchId: 'dispatch-management-test-v1',
auditEventId: '30000000-0000-4000-8000-000000000005',
consumedAtMs: 1_200,
});
assert.equal(consumed.dispatch.consumedBy.type, 'system');
assert.equal(consumed.dispatch.consumedBy.id, 'package_dispatcher');
assert.equal((await value.service.dispatch(16)).scanned, 0);
assert.deepEqual(value.dispatchCalls, [{ limit: 16 }]);
assert.equal(
require('../dist').createPluginPackageManagementService,
undefined,
);
});
test('consumes durable quota only after Project authorization and before mutation', async () => {
assert.throws(
() => new PluginPackageManagementQuotaExceededError(0),
TypeError,
);
assert.throws(
() => new PluginPackageManagementQuotaExceededError(300_001),
TypeError,
);
const quotaCalls = [];
const value = fixture('separation_of_duty', {
async consume(command) {
quotaCalls.push(command);
return { remaining: 9, resetAtMs: 60_000, observedAtMs: 1_000 };
},
});
await value.service.propose({
actionRef: 'proposal:quota-v1',
approvalRequestId: 'approval-quota-v1',
proposalAuditEventId: '50000000-0000-4000-8000-000000000001',
approvalAuditEventId: '50000000-0000-4000-8000-000000000002',
requestedAtMs: 1_000,
actionInput: actionInput(),
principal: principal(REQUESTER, 'multi_factor', 1_000),
});
assert.deepEqual(quotaCalls, [
{
projectId: 'default',
subject: REQUESTER,
operation: 'plugin-package.propose',
idempotencyKey: 'proposal:quota-v1',
},
]);
value.setNow(1_100);
await value.service.decide({
approvalRequestId: 'approval-quota-v1',
expectedVersion: 1,
decisionId: 'decision-quota-v1',
auditEventId: '50000000-0000-4000-8000-000000000003',
decision: 'approved',
reasonCode: 'reviewed',
decidedAtMs: 1_100,
principal: principal(REVIEWER, 'hardware', 1_100),
});
assert.deepEqual(quotaCalls[1], {
projectId: 'default',
subject: REVIEWER,
operation: 'plugin-package.decide',
idempotencyKey: 'decision-quota-v1',
});
const deniedCalls = [];
const denied = fixture('human_confirmation', {
async consume(command) {
deniedCalls.push(command);
throw new PluginPackageManagementQuotaExceededError(5_000);
},
});
await assert.rejects(
denied.service.propose({
actionRef: 'proposal:quota-denied-v1',
approvalRequestId: 'approval-quota-denied-v1',
proposalAuditEventId: '50000000-0000-4000-8000-000000000004',
approvalAuditEventId: '50000000-0000-4000-8000-000000000005',
requestedAtMs: 1_000,
actionInput: actionInput(),
principal: principal(REQUESTER, 'multi_factor', 1_000),
}),
PluginPackageManagementQuotaExceededError,
);
assert.equal(deniedCalls.length, 1);
assert.equal(denied.proposals.proposal, null);
assert.equal(denied.approvals.request, null);
const unauthorized = fixture('human_confirmation', {
async consume(command) {
deniedCalls.push(command);
throw new Error('must not run');
},
});
await assert.rejects(
unauthorized.service.propose({
actionRef: 'proposal:quota-unauthorized-v1',
approvalRequestId: 'approval-quota-unauthorized-v1',
proposalAuditEventId: '50000000-0000-4000-8000-000000000006',
approvalAuditEventId: '50000000-0000-4000-8000-000000000007',
requestedAtMs: 1_000,
actionInput: actionInput(),
principal: principal(
{ type: 'user', id: 'usr_operator' },
'multi_factor',
1_000,
),
}),
PluginPackageManagementAuthorizationError,
);
assert.equal(deniedCalls.length, 1);
});
test('denies operator Package proposals before proposal or Approval mutation', async () => {
const value = fixture('human_confirmation');
await assert.rejects(
value.service.propose({
actionRef: 'proposal:operator-v1',
approvalRequestId: 'approval-operator-v1',
proposalAuditEventId: '40000000-0000-4000-8000-000000000001',
approvalAuditEventId: '40000000-0000-4000-8000-000000000002',
requestedAtMs: 1_000,
actionInput: actionInput(),
principal: principal(
{ type: 'user', id: 'usr_operator' },
'single_factor',
1_000,
),
}),
PluginPackageManagementAuthorizationError,
);
assert.equal(value.proposals.proposal, null);
assert.equal(value.approvals.request, null);
});
@@ -0,0 +1,178 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
consumeApprovalRequest,
createApprovalRequest,
decideApprovalRequest,
} = require('@qinglong/runtime-core/approved-action');
const {
PLUGIN_PACKAGE_API_VERSION,
PLUGIN_PACKAGE_KIND,
planPluginPackageInstall,
} = require('@qinglong/runtime-core/plugin-package');
const {
createPluginPackageInstallProposal,
normalizePluginPackageInstallProposal,
resolvePluginPackageInstallProposal,
PluginPackageInstallProposalBindingConflictError,
} = require('@qinglong/runtime-core/plugin-package-proposal');
const REQUESTER = Object.freeze({ type: 'user', id: 'usr_owner' });
const SYSTEM = Object.freeze({ type: 'system', id: 'package_dispatcher' });
const FENCE = Object.freeze({ projectVersion: 1, bindingVersion: 1 });
function proposal() {
const manifest = {
apiVersion: PLUGIN_PACKAGE_API_VERSION,
kind: PLUGIN_PACKAGE_KIND,
metadata: {
name: 'example-monitor',
displayName: 'Example Monitor',
version: '1.2.0',
description: 'One bounded package',
license: 'Apache-2.0',
},
spec: {
compatibility: {
qinglong: '>=3.0.0-0 <4.0.0',
architectures: ['arm64'],
deploymentProfiles: ['edge'],
},
runtimes: [],
resources: {
memory: { recommended: '16Mi' },
disk: { install: '4Mi', working: '16Mi' },
},
permissions: {
network: { allowedHosts: [] },
secrets: [],
tools: [],
},
contents: { tasks: [], workflows: [], prompts: [], tools: [] },
},
};
const environment = {
qinglongVersion: '3.0.0-alpha.0',
architecture: 'arm64',
deploymentProfile: 'edge',
runtimes: [],
availableMemoryBytes: 128 * 1024 * 1024,
availableDiskBytes: 256 * 1024 * 1024,
};
return createPluginPackageInstallProposal({
actionRef: 'proposal:monitor-v1',
actionInput: {
lockId: 'proposal-monitor-v1',
projectId: 'default',
manifest,
plan: planPluginPackageInstall(manifest, environment),
environment,
source: {
kind: 'offline',
locator: `offline:sha256:${'a'.repeat(64)}`,
artifactDigest: 'a'.repeat(64),
artifactBytes: 2_048,
contentDigest: 'b'.repeat(64),
},
architecture: 'arm64',
deploymentProfile: 'edge',
targetGeneration: 1,
},
proposedBy: REQUESTER,
proposalFence: FENCE,
createdAtMs: 5,
});
}
function dispatch(candidate) {
const action = {
permission: candidate.permission,
actionType: candidate.actionType,
actionRef: candidate.actionRef,
actionDigest: candidate.actionDigest,
previewDigest: candidate.previewDigest,
};
const pending = createApprovalRequest({
id: 'approval-monitor-v1',
projectId: candidate.projectId,
action,
risk: 'high',
decisionMode: 'human_confirmation',
requestedBy: REQUESTER,
requestedAtMs: 10,
expiresAtMs: 1_000,
requestFence: FENCE,
});
const approved = decideApprovalRequest(pending, {
expectedVersion: 1,
decisionId: 'decision-monitor-v1',
decision: 'approved',
reasonCode: 'reviewed',
principal: {
subject: REQUESTER,
authenticationId: 'auth-owner-step-up',
authenticatedAtMs: 15,
expiresAtMs: 500,
assurance: 'local_console',
},
decidedAtMs: 20,
authorizationFence: FENCE,
});
return consumeApprovalRequest(approved, {
expectedVersion: 2,
consumptionId: 'consume-monitor-v1',
dispatchId: 'dispatch-monitor-v1',
action,
requestedBy: REQUESTER,
consumedBy: SYSTEM,
consumedAtMs: 30,
authorizationFence: FENCE,
}).dispatch;
}
test('freezes the complete install input before approval and resolves the exact lock', () => {
const candidate = proposal();
assert.deepEqual(normalizePluginPackageInstallProposal(candidate), candidate);
const approvedDispatch = dispatch(candidate);
const lock = resolvePluginPackageInstallProposal(
candidate,
approvedDispatch,
40,
);
assert.equal(lock.actionDigest, candidate.actionDigest);
assert.equal(lock.planDigest, candidate.previewDigest);
assert.equal(lock.approval.dispatchId, approvedDispatch.id);
assert.equal(lock.packageName, 'example-monitor');
});
test('rejects proposal content drift and dispatch substitution', () => {
const candidate = proposal();
assert.throws(
() =>
normalizePluginPackageInstallProposal({
...candidate,
actionInput: {
...candidate.actionInput,
source: {
...candidate.actionInput.source,
contentDigest: 'c'.repeat(64),
},
},
}),
TypeError,
);
const approvedDispatch = dispatch(candidate);
assert.throws(
() =>
resolvePluginPackageInstallProposal(
candidate,
{
...approvedDispatch,
requestedBy: { type: 'user', id: 'usr_other' },
},
40,
),
PluginPackageInstallProposalBindingConflictError,
);
});
@@ -0,0 +1,127 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
MAX_PLUGIN_PACKAGE_PUBLISHER_REVOCATION_IMPACT_ITEMS,
InvalidPluginPackagePublisherProvenanceError,
createPluginPackagePublisherProvenance,
createPluginPackagePublisherRevocationImpact,
createPluginPackagePublisherRevocationReceipt,
normalizePluginPackagePublisherProvenance,
normalizePluginPackagePublisherRevocationImpact,
normalizePluginPackagePublisherRevocationReceipt,
} = require('@qinglong/runtime-core/plugin-package-publisher-provenance');
const digest = (value) => value.repeat(64);
function provenance(installationId = 'install-1') {
return createPluginPackagePublisherProvenance({
projectId: 'project-1',
packageName: 'package-one',
installationId,
lockDigest: digest('1'),
artifactDigest: digest('2'),
manifestDigest: digest('3'),
contentDigest: digest('4'),
stageEvidenceDigest: digest('5'),
signature: {
publisher: 'packages.example.test',
keyId: 'publisher-key-1',
signatureDigest: digest('6'),
keyNotBeforeMs: 1_000,
keyNotAfterMs: 10_000,
verifiedAtMs: 2_000,
},
});
}
function receipt() {
return createPluginPackagePublisherRevocationReceipt({
mutationId: 'revoke-publisher-key-1',
publisher: 'packages.example.test',
keyId: 'publisher-key-1',
previousTrustDigest: digest('7'),
currentTrustDigest: digest('8'),
proposer: { type: 'user', id: 'owner-a' },
confirmer: { type: 'user', id: 'owner-b' },
authorizationMode: 'dual_control',
reasonCode: 'confirmed_key_compromise',
revokedAtMs: 3_000,
});
}
test('binds immutable publisher evidence to one staged installation', () => {
const value = provenance();
assert.deepEqual(normalizePluginPackagePublisherProvenance(value), value);
assert.equal(value.publisher, 'packages.example.test');
assert.equal(value.keyId, 'publisher-key-1');
assert.match(value.provenanceDigest, /^[0-9a-f]{64}$/);
assert.equal(Object.isFrozen(value), true);
});
test('binds dual-control revocation to one immutable trust transition', () => {
const value = receipt();
assert.deepEqual(
normalizePluginPackagePublisherRevocationReceipt(value),
value,
);
assert.match(value.receiptDigest, /^[0-9a-f]{64}$/);
assert.throws(
() =>
createPluginPackagePublisherRevocationReceipt({
...value,
previousTrustDigest: value.currentTrustDigest,
receiptDigest: undefined,
schema: undefined,
}),
InvalidPluginPackagePublisherProvenanceError,
);
});
test('sorts and bounds one stable revocation impact snapshot', () => {
const revoked = receipt();
const first = provenance('install-a');
const second = {
...provenance('install-b'),
projectId: 'project-2',
};
const impact = createPluginPackagePublisherRevocationImpact({
revocationReceiptDigest: revoked.receiptDigest,
items: [
{
projectId: second.projectId,
packageName: second.packageName,
installationId: second.installationId,
lockDigest: second.lockDigest,
provenanceDigest: second.provenanceDigest,
},
{
projectId: first.projectId,
packageName: first.packageName,
installationId: first.installationId,
lockDigest: first.lockDigest,
provenanceDigest: first.provenanceDigest,
},
],
generatedAtMs: 3_001,
});
assert.deepEqual(
impact.items.map(({ projectId }) => projectId),
['project-1', 'project-2'],
);
assert.deepEqual(
normalizePluginPackagePublisherRevocationImpact(impact),
impact,
);
assert.throws(
() =>
createPluginPackagePublisherRevocationImpact({
revocationReceiptDigest: revoked.receiptDigest,
items: new Array(
MAX_PLUGIN_PACKAGE_PUBLISHER_REVOCATION_IMPACT_ITEMS + 1,
).fill(impact.items[0]),
generatedAtMs: 3_001,
}),
InvalidPluginPackagePublisherProvenanceError,
);
});
@@ -0,0 +1,212 @@
const assert = require('node:assert/strict');
const { generateKeyPairSync } = require('node:crypto');
const { test } = require('node:test');
const {
consumeApprovalRequest,
createApprovalRequest,
decideApprovalRequest,
} = require('@qinglong/runtime-core/approved-action');
const {
createPluginPackagePublisherTrustSnapshot,
} = require('@qinglong/runtime-core/plugin-package-publisher-trust');
const {
InvalidPluginPackagePublisherRevocationProposalError,
PluginPackagePublisherRevocationProposalBindingConflictError,
createPluginPackagePublisherRevocationProposal,
normalizePluginPackagePublisherRevocationProposal,
resolvePluginPackagePublisherRevocationProposal,
} = require('@qinglong/runtime-core/plugin-package-publisher-revocation-proposal');
const REQUESTER = Object.freeze({ type: 'user', id: 'usr_owner' });
const REVIEWER = Object.freeze({ type: 'user', id: 'usr_security' });
const SYSTEM = Object.freeze({ type: 'system', id: 'package_executor' });
const FENCE = Object.freeze({ projectVersion: 4, bindingVersion: 7 });
function trustSnapshot() {
const { publicKey } = generateKeyPairSync('ed25519');
return createPluginPackagePublisherTrustSnapshot([
{
publisher: 'publisher-a.example',
keyId: 'key-a',
publicKeyPem: publicKey.export({ type: 'spki', format: 'pem' }),
notBeforeMs: 1_000,
notAfterMs: 10_000,
},
]);
}
function proposal(overrides = {}) {
return createPluginPackagePublisherRevocationProposal({
actionRef: 'publisher-revoke:publisher-a.example:key-a',
authorityProjectId: 'cluster-trust-authority',
trustAuthorityId: 'cluster',
trustGeneration: 3,
trustSnapshot: trustSnapshot(),
publisher: 'publisher-a.example',
keyId: 'key-a',
authorizationMode: 'dual_control',
reasonCode: 'suspected_key_compromise',
proposedBy: REQUESTER,
proposerAssurance: 'multi_factor',
proposalFence: FENCE,
createdAtMs: 5,
...overrides,
});
}
function dispatch(candidate, options = {}) {
const {
approvedBy = REVIEWER,
assurance = 'multi_factor',
decisionMode = 'separation_of_duty',
} = options;
const action = {
permission: candidate.permission,
actionType: candidate.actionType,
actionRef: candidate.actionRef,
actionDigest: candidate.actionDigest,
previewDigest: candidate.previewDigest,
};
const pending = createApprovalRequest({
id: `approval-${candidate.actionInput.authorizationMode}`,
projectId: candidate.projectId,
action,
risk: 'critical',
decisionMode,
requestedBy: REQUESTER,
requestedAtMs: 10,
expiresAtMs: 1_000,
requestFence: FENCE,
});
const approved = decideApprovalRequest(pending, {
expectedVersion: 1,
decisionId: `decision-${candidate.actionInput.authorizationMode}`,
decision: 'approved',
reasonCode: 'publisher_key_reviewed',
principal: {
subject: approvedBy,
authenticationId: `auth-${approvedBy.id}`,
authenticatedAtMs: 15,
expiresAtMs: 500,
assurance,
},
decidedAtMs: 20,
authorizationFence: FENCE,
});
return consumeApprovalRequest(approved, {
expectedVersion: 2,
consumptionId: `consume-${candidate.actionInput.authorizationMode}`,
dispatchId: `dispatch-${candidate.actionInput.authorizationMode}`,
action,
requestedBy: REQUESTER,
consumedBy: SYSTEM,
consumedAtMs: 30,
authorizationFence: FENCE,
}).dispatch;
}
test('derives low-sensitive trust transition and resolves dual-control receipt', () => {
const candidate = proposal();
assert.deepEqual(
normalizePluginPackagePublisherRevocationProposal(candidate),
candidate,
);
assert.notEqual(
candidate.actionInput.previousTrustDigest,
candidate.actionInput.currentTrustDigest,
);
assert.equal('trustSnapshot' in candidate, false);
assert.equal('publicKeyPem' in candidate.actionInput, false);
const receipt = resolvePluginPackagePublisherRevocationProposal(
candidate,
dispatch(candidate),
40,
);
assert.equal(receipt.mutationId, 'dispatch-dual_control');
assert.deepEqual(receipt.proposer, REQUESTER);
assert.deepEqual(receipt.confirmer, REVIEWER);
assert.equal(receipt.authorizationMode, 'dual_control');
assert.equal(
receipt.previousTrustDigest,
candidate.actionInput.previousTrustDigest,
);
});
test('allows same-subject break-glass only with hardware assurance end to end', () => {
const candidate = proposal({
authorizationMode: 'break_glass',
reasonCode: 'confirmed_key_compromise',
proposerAssurance: 'hardware',
});
const receipt = resolvePluginPackagePublisherRevocationProposal(
candidate,
dispatch(candidate, {
approvedBy: REQUESTER,
assurance: 'hardware',
decisionMode: 'human_confirmation',
}),
40,
);
assert.deepEqual(receipt.proposer, receipt.confirmer);
assert.throws(
() =>
resolvePluginPackagePublisherRevocationProposal(
candidate,
{
...dispatch(candidate, {
approvedBy: REQUESTER,
assurance: 'hardware',
decisionMode: 'human_confirmation',
}),
approvalAssurance: 'multi_factor',
},
40,
),
PluginPackagePublisherRevocationProposalBindingConflictError,
);
assert.throws(
() =>
proposal({
authorizationMode: 'break_glass',
proposerAssurance: 'multi_factor',
}),
InvalidPluginPackagePublisherRevocationProposalError,
);
});
test('rejects client digest injection, proposal drift and dispatch substitution', () => {
assert.throws(
() =>
proposal({
previousTrustDigest: '0'.repeat(64),
currentTrustDigest: '1'.repeat(64),
}),
InvalidPluginPackagePublisherRevocationProposalError,
);
const candidate = proposal();
assert.throws(
() =>
normalizePluginPackagePublisherRevocationProposal({
...candidate,
actionInput: {
...candidate.actionInput,
reasonCode: 'confirmed_key_compromise',
},
}),
InvalidPluginPackagePublisherRevocationProposalError,
);
assert.throws(
() =>
resolvePluginPackagePublisherRevocationProposal(
candidate,
{
...dispatch(candidate),
requestedBy: { type: 'user', id: 'usr_other' },
},
40,
),
PluginPackagePublisherRevocationProposalBindingConflictError,
);
});
@@ -0,0 +1,191 @@
const assert = require('node:assert/strict');
const { generateKeyPairSync } = require('node:crypto');
const { test } = require('node:test');
const {
InvalidPluginPackagePublisherTrustSnapshotError,
createPluginPackagePublisherEffectiveTrustRegistry,
createPluginPackagePublisherTrustOverlapAdditionSnapshot,
createPluginPackagePublisherTrustRetirementSnapshot,
createPluginPackagePublisherTrustSnapshot,
normalizePluginPackagePublisherTrustSnapshot,
pluginPackagePublisherTrustRevokedDigest,
} = require('@qinglong/runtime-core/plugin-package-publisher-trust');
function definition(publisher, keyId) {
const { publicKey } = generateKeyPairSync('ed25519');
return {
publisher,
keyId,
publicKeyPem: publicKey.export({ type: 'spki', format: 'pem' }),
notBeforeMs: 1_000,
notAfterMs: 10_000,
};
}
test('creates a canonical low-sensitive snapshot from reviewed publisher keys', () => {
const snapshot = createPluginPackagePublisherTrustSnapshot([
definition('publisher-b.example', 'key-b'),
definition('publisher-a.example', 'key-a'),
]);
assert.deepEqual(
snapshot.keys.map(({ publisher }) => publisher),
['publisher-a.example', 'publisher-b.example'],
);
assert.equal('publicKeyPem' in snapshot.keys[0], false);
assert.match(snapshot.snapshotDigest, /^[0-9a-f]{64}$/);
assert.deepEqual(
normalizePluginPackagePublisherTrustSnapshot(snapshot),
snapshot,
);
});
test('binds mounted key material to the durable effective snapshot', () => {
const established = definition('publisher-a.example', 'key-a');
const candidate = definition('publisher-a.example', 'key-b');
const effective = createPluginPackagePublisherTrustSnapshot([
established,
]);
const registry = createPluginPackagePublisherEffectiveTrustRegistry(
[candidate, established],
effective,
);
assert.equal(registry.size, 1);
const replacementMaterial = definition(
'publisher-a.example',
'key-a',
);
assert.throws(
() =>
createPluginPackagePublisherEffectiveTrustRegistry(
[replacementMaterial, candidate],
effective,
),
/not backed by mounted key material/,
);
});
test('derives exact one-key overlap addition and same-publisher retirement', () => {
const oldKey = definition('publisher-a.example', 'key-a');
const newKey = definition('publisher-a.example', 'key-b');
const unrelated = definition('publisher-b.example', 'key-c');
const current = createPluginPackagePublisherTrustSnapshot([
oldKey,
unrelated,
]);
const overlap = createPluginPackagePublisherTrustSnapshot([
oldKey,
newKey,
unrelated,
]);
assert.deepEqual(
createPluginPackagePublisherTrustOverlapAdditionSnapshot(
current,
overlap,
'publisher-a.example',
'key-b',
2_000,
),
overlap,
);
const retired = createPluginPackagePublisherTrustRetirementSnapshot(
overlap,
'publisher-a.example',
'key-a',
2_000,
);
assert.deepEqual(
retired.keys.map(({ keyId }) => keyId),
['key-b', 'key-c'],
);
});
test('rejects rewritten overlap and retirement without a live successor', () => {
const oldKey = definition('publisher-a.example', 'key-a');
const newKey = definition('publisher-a.example', 'key-b');
const current = createPluginPackagePublisherTrustSnapshot([oldKey]);
assert.throws(
() =>
createPluginPackagePublisherTrustOverlapAdditionSnapshot(
current,
createPluginPackagePublisherTrustSnapshot([
{ ...oldKey, notAfterMs: 20_000 },
newKey,
]),
'publisher-a.example',
'key-b',
2_000,
),
/must preserve every key/,
);
assert.throws(
() =>
createPluginPackagePublisherTrustRetirementSnapshot(
createPluginPackagePublisherTrustSnapshot([
oldKey,
definition('publisher-b.example', 'key-c'),
]),
'publisher-a.example',
'key-a',
2_000,
),
/retain an active publisher key/,
);
});
test('derives the effective trust digest only for a key in the snapshot', () => {
const snapshot = createPluginPackagePublisherTrustSnapshot([
definition('publisher-a.example', 'key-a'),
definition('publisher-b.example', 'key-b'),
]);
const revoked = pluginPackagePublisherTrustRevokedDigest(
snapshot,
'publisher-a.example',
'key-a',
);
assert.match(revoked, /^[0-9a-f]{64}$/);
assert.notEqual(revoked, snapshot.snapshotDigest);
assert.throws(
() =>
pluginPackagePublisherTrustRevokedDigest(
snapshot,
'publisher-c.example',
'key-c',
),
InvalidPluginPackagePublisherTrustSnapshotError,
);
});
test('rejects duplicate, non-Ed25519 and tampered trust snapshots', () => {
const key = definition('publisher-a.example', 'key-a');
assert.throws(
() => createPluginPackagePublisherTrustSnapshot([key, key]),
InvalidPluginPackagePublisherTrustSnapshotError,
);
const { publicKey } = generateKeyPairSync('rsa', {
modulusLength: 2048,
});
assert.throws(
() =>
createPluginPackagePublisherTrustSnapshot([
{
...key,
publicKeyPem: publicKey.export({
type: 'spki',
format: 'pem',
}),
},
]),
InvalidPluginPackagePublisherTrustSnapshotError,
);
const snapshot = createPluginPackagePublisherTrustSnapshot([key]);
assert.throws(
() =>
normalizePluginPackagePublisherTrustSnapshot({
...snapshot,
snapshotDigest: '0'.repeat(64),
}),
InvalidPluginPackagePublisherTrustSnapshotError,
);
});
@@ -0,0 +1,198 @@
const assert = require('node:assert/strict');
const { generateKeyPairSync } = require('node:crypto');
const { test } = require('node:test');
const {
consumeApprovalRequest,
createApprovalRequest,
decideApprovalRequest,
} = require('@qinglong/runtime-core/approved-action');
const {
createPluginPackagePublisherTrustSnapshot,
} = require('@qinglong/runtime-core/plugin-package-publisher-trust');
const {
InvalidPluginPackagePublisherTrustTransitionError,
PluginPackagePublisherTrustTransitionBindingConflictError,
createPluginPackagePublisherTrustTransitionProposal,
normalizePluginPackagePublisherTrustTransitionProposal,
normalizePluginPackagePublisherTrustTransitionReceipt,
resolvePluginPackagePublisherTrustTransitionProposal,
} = require('@qinglong/runtime-core/plugin-package-publisher-trust-transition-proposal');
const OWNER = Object.freeze({ type: 'user', id: 'usr_owner' });
const REVIEWER = Object.freeze({ type: 'user', id: 'usr_security' });
const SYSTEM = Object.freeze({ type: 'system', id: 'package_executor' });
const FENCE = Object.freeze({ projectVersion: 4, bindingVersion: 7 });
function definition(keyId) {
const { publicKey } = generateKeyPairSync('ed25519');
return {
publisher: 'publisher-a.example',
keyId,
publicKeyPem: publicKey.export({ type: 'spki', format: 'pem' }),
notBeforeMs: 1_000,
notAfterMs: 10_000,
};
}
function dispatch(proposal) {
const action = {
permission: proposal.permission,
actionType: proposal.actionType,
actionRef: proposal.actionRef,
actionDigest: proposal.actionDigest,
previewDigest: proposal.previewDigest,
};
const pending = createApprovalRequest({
id: `approval-${proposal.actionInput.mode}`,
projectId: proposal.projectId,
action,
risk: 'critical',
decisionMode: 'separation_of_duty',
requestedBy: OWNER,
requestedAtMs: 5_010,
expiresAtMs: 6_000,
requestFence: FENCE,
});
const approved = decideApprovalRequest(pending, {
expectedVersion: 1,
decisionId: `decision-${proposal.actionInput.mode}`,
decision: 'approved',
reasonCode: 'publisher_key_reviewed',
principal: {
subject: REVIEWER,
authenticationId: 'auth-reviewer',
authenticatedAtMs: 5_015,
expiresAtMs: 5_500,
assurance: 'multi_factor',
},
decidedAtMs: 5_020,
authorizationFence: FENCE,
});
return consumeApprovalRequest(approved, {
expectedVersion: 2,
consumptionId: `consume-${proposal.actionInput.mode}`,
dispatchId: `dispatch-${proposal.actionInput.mode}`,
action,
requestedBy: OWNER,
consumedBy: SYSTEM,
consumedAtMs: 5_025,
authorizationFence: FENCE,
}).dispatch;
}
test('derives one overlap-add proposal and dual-control receipt', () => {
const oldKey = definition('key-a');
const newKey = definition('key-b');
const current = createPluginPackagePublisherTrustSnapshot([oldKey]);
const material = createPluginPackagePublisherTrustSnapshot([
oldKey,
newKey,
]);
const created = createPluginPackagePublisherTrustTransitionProposal({
actionRef: 'publisher-overlap:publisher-a.example:key-b',
authorityProjectId: 'cluster-trust-authority',
trustAuthorityId: 'cluster',
trustGeneration: 3,
mode: 'overlap_add',
trustSnapshot: current,
materialSnapshot: material,
publisher: 'publisher-a.example',
keyId: 'key-b',
proposedBy: OWNER,
proposerAssurance: 'multi_factor',
proposalFence: FENCE,
createdAtMs: 5_000,
});
assert.equal(created.proposal.actionInput.previousTrustDigest, current.snapshotDigest);
assert.equal(created.proposal.actionInput.currentTrustDigest, material.snapshotDigest);
assert.deepEqual(
normalizePluginPackagePublisherTrustTransitionProposal(created.proposal),
created.proposal,
);
const receipt =
resolvePluginPackagePublisherTrustTransitionProposal(
created.proposal,
dispatch(created.proposal),
5_040,
null,
);
assert.equal(receipt.currentGeneration, 4);
assert.equal(receipt.retirementMatchingInstallations, null);
assert.deepEqual(
normalizePluginPackagePublisherTrustTransitionReceipt(receipt),
receipt,
);
});
test('derives safe retirement and requires zero-impact distinct review', () => {
const current = createPluginPackagePublisherTrustSnapshot([
definition('key-a'),
definition('key-b'),
]);
const { proposal, candidateSnapshot } =
createPluginPackagePublisherTrustTransitionProposal({
actionRef: 'publisher-retire:publisher-a.example:key-a',
authorityProjectId: 'cluster-trust-authority',
trustAuthorityId: 'cluster',
trustGeneration: 8,
mode: 'safe_retire',
trustSnapshot: current,
publisher: 'publisher-a.example',
keyId: 'key-a',
proposedBy: OWNER,
proposerAssurance: 'hardware',
proposalFence: FENCE,
createdAtMs: 5_000,
});
assert.equal(candidateSnapshot.keys.length, 1);
const receipt =
resolvePluginPackagePublisherTrustTransitionProposal(
proposal,
dispatch(proposal),
5_040,
0,
);
assert.equal(receipt.mode, 'safe_retire');
assert.equal(receipt.retirementMatchingInstallations, 0);
assert.throws(
() =>
resolvePluginPackagePublisherTrustTransitionProposal(
proposal,
dispatch(proposal),
5_040,
null,
),
PluginPackagePublisherTrustTransitionBindingConflictError,
);
});
test('rejects client digest surfaces, weak principals and transition drift', () => {
const current = createPluginPackagePublisherTrustSnapshot([
definition('key-a'),
]);
const material = createPluginPackagePublisherTrustSnapshot([
definition('key-a'),
definition('key-b'),
]);
assert.throws(
() =>
createPluginPackagePublisherTrustTransitionProposal({
actionRef: 'publisher-overlap:publisher-a.example:key-b',
authorityProjectId: 'cluster-trust-authority',
trustAuthorityId: 'cluster',
trustGeneration: 1,
mode: 'overlap_add',
trustSnapshot: current,
materialSnapshot: material,
publisher: 'publisher-a.example',
keyId: 'key-b',
proposedBy: { type: 'agent', id: 'agent-a' },
proposerAssurance: 'service',
proposalFence: FENCE,
createdAtMs: 5_000,
previousTrustDigest: '0'.repeat(64),
}),
InvalidPluginPackagePublisherTrustTransitionError,
);
});
@@ -0,0 +1,293 @@
const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const { join } = require('node:path');
const { test } = require('node:test');
const {
InvalidPluginPackageQuarantineError,
MAX_PLUGIN_PACKAGE_QUARANTINE_TASK_WITHDRAWALS,
assertPluginPackageWithdrawalMatchesEvent,
createPluginPackageQuarantineEvent,
createPluginPackageWithdrawalReceipt,
normalizePluginPackageQuarantineEvent,
normalizePluginPackageWithdrawalReceipt,
pluginPackageQuarantineMutationId,
pluginPackageQuarantineTaskMutationId,
} = require('../dist/plugin-package/lifecycle/pluginPackageQuarantine');
const digest = (value) => value.repeat(64);
function target(state = 'active') {
return {
projectId: 'default',
packageName: 'example-monitor',
installationId: 'install-example-v1',
lockDigest: digest('a'),
installState: state,
installVersion: 4,
installRecordDigest: digest('b'),
activeLockDigest: state === 'active' ? digest('a') : digest('c'),
};
}
function eventInput(overrides = {}) {
return {
mutationId: 'quarantine-example-v1',
revocationReceiptDigest: digest('d'),
impactDigest: digest('e'),
target: target(),
proposer: { type: 'user', id: 'owner-a' },
confirmer: { type: 'user', id: 'owner-b' },
authorizationMode: 'dual_control',
reasonCode: 'confirmed_key_compromise',
occurredAtMs: 100,
...overrides,
};
}
function activeCapability(overrides = {}) {
return {
status: 'withdrawn',
taskWithdrawals: [
{
taskId: 'collect',
previousRevision: 2,
disabledRevision: 3,
previousContentDigest: digest('f'),
disabledContentDigest: digest('1'),
},
{
taskId: 'report',
previousRevision: 7,
disabledRevision: 8,
previousContentDigest: digest('2'),
disabledContentDigest: digest('3'),
},
],
previousActiveVectorDigest: digest('4'),
currentActiveVectorDigest: digest('5'),
currentToolSnapshotDigest: digest('6'),
retainedSourceCount: 2,
...overrides,
};
}
test('binds dual-control quarantine to one exact active capability withdrawal', () => {
const event = createPluginPackageQuarantineEvent(eventInput());
const reordered = createPluginPackageQuarantineEvent({
...eventInput(),
target: {
activeLockDigest: digest('a'),
installRecordDigest: digest('b'),
installVersion: 4,
installState: 'active',
lockDigest: digest('a'),
installationId: 'install-example-v1',
packageName: 'example-monitor',
projectId: 'default',
},
});
assert.equal(reordered.eventDigest, event.eventDigest);
const receipt = createPluginPackageWithdrawalReceipt({
eventDigest: event.eventDigest,
target: event.target,
capability: activeCapability(),
committedAtMs: 101,
});
assert.deepEqual(normalizePluginPackageQuarantineEvent(event), event);
assert.deepEqual(normalizePluginPackageWithdrawalReceipt(receipt), receipt);
assert.doesNotThrow(() =>
assertPluginPackageWithdrawalMatchesEvent(event, receipt),
);
assert.equal(receipt.capability.taskWithdrawals.length, 2);
assert.notEqual(
receipt.capability.previousActiveVectorDigest,
receipt.capability.currentActiveVectorDigest,
);
});
test('publishes quarantine only through its explicit subpath', () => {
const root = require('../dist');
assert.equal(root.createPluginPackageQuarantineEvent, undefined);
const manifest = JSON.parse(
readFileSync(join(__dirname, '../package.json'), 'utf8'),
);
assert.deepEqual(manifest.exports['./plugin-package-quarantine'], {
types: './dist/plugin-package/lifecycle/pluginPackageQuarantine.d.ts',
require: './dist/plugin-package/lifecycle/pluginPackageQuarantine.js',
default: './dist/plugin-package/lifecycle/pluginPackageQuarantine.js',
});
});
test('requires distinct subjects for dual-control and permits explicit break-glass', () => {
assert.throws(
() =>
createPluginPackageQuarantineEvent(
eventInput({
confirmer: { type: 'user', id: 'owner-a' },
}),
),
/distinct subjects/,
);
const event = createPluginPackageQuarantineEvent(
eventInput({
confirmer: { type: 'user', id: 'owner-a' },
authorizationMode: 'break_glass',
reasonCode: 'suspected_key_compromise',
}),
);
assert.equal(event.authorizationMode, 'break_glass');
});
test('records non-active locks without inventing Task or Tool withdrawal', () => {
for (const state of ['queued', 'staged', 'activating']) {
const event = createPluginPackageQuarantineEvent(
eventInput({ target: target(state) }),
);
const receipt = createPluginPackageWithdrawalReceipt({
eventDigest: event.eventDigest,
target: event.target,
capability: {
status: 'not_active',
taskWithdrawals: [],
previousActiveVectorDigest: null,
currentActiveVectorDigest: null,
currentToolSnapshotDigest: null,
retainedSourceCount: 0,
},
committedAtMs: 101,
});
assert.doesNotThrow(() =>
assertPluginPackageWithdrawalMatchesEvent(event, receipt),
);
}
const activeEvent = createPluginPackageQuarantineEvent(eventInput());
assert.throws(
() =>
createPluginPackageWithdrawalReceipt({
eventDigest: activeEvent.eventDigest,
target: activeEvent.target,
capability: {
status: 'not_active',
taskWithdrawals: [],
previousActiveVectorDigest: null,
currentActiveVectorDigest: null,
currentToolSnapshotDigest: null,
retainedSourceCount: 0,
},
committedAtMs: 101,
}),
/inconsistent/,
);
});
test('fails closed on tampering, unsorted tasks and reviewed bounds', () => {
const event = createPluginPackageQuarantineEvent(eventInput());
assert.throws(
() =>
normalizePluginPackageQuarantineEvent({
...event,
impactDigest: digest('9'),
}),
/eventDigest/,
);
assert.throws(
() =>
createPluginPackageWithdrawalReceipt({
eventDigest: event.eventDigest,
target: event.target,
capability: activeCapability({
taskWithdrawals: [...activeCapability().taskWithdrawals].reverse(),
}),
committedAtMs: 101,
}),
/unique and sorted/,
);
assert.throws(
() =>
createPluginPackageWithdrawalReceipt({
eventDigest: event.eventDigest,
target: event.target,
capability: activeCapability({
taskWithdrawals: Array.from(
{
length: MAX_PLUGIN_PACKAGE_QUARANTINE_TASK_WITHDRAWALS + 1,
},
(_, index) => ({
taskId: `task-${index.toString().padStart(3, '0')}`,
previousRevision: 1,
disabledRevision: 2,
previousContentDigest: digest('7'),
disabledContentDigest: digest('8'),
}),
),
}),
committedAtMs: 101,
}),
/disposition is invalid/,
);
const receipt = createPluginPackageWithdrawalReceipt({
eventDigest: event.eventDigest,
target: event.target,
capability: activeCapability(),
committedAtMs: 101,
});
assert.throws(
() =>
normalizePluginPackageWithdrawalReceipt({
...receipt,
committedAtMs: 102,
}),
/receiptDigest/,
);
assert.throws(
() =>
assertPluginPackageWithdrawalMatchesEvent(
event,
createPluginPackageWithdrawalReceipt({
eventDigest: event.eventDigest,
target: { ...event.target, installVersion: 5 },
capability: activeCapability(),
committedAtMs: 101,
}),
),
InvalidPluginPackageQuarantineError,
);
});
test('derives stable distinct UUID task mutation identities from quarantine evidence', () => {
const event = createPluginPackageQuarantineEvent(eventInput());
const collect = pluginPackageQuarantineTaskMutationId(
event.eventDigest,
'collect',
);
assert.match(
collect,
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-a[0-9a-f]{3}-[0-9a-f]{12}$/,
);
assert.equal(
collect,
pluginPackageQuarantineTaskMutationId(event.eventDigest, 'collect'),
);
assert.notEqual(
collect,
pluginPackageQuarantineTaskMutationId(event.eventDigest, 'report'),
);
assert.match(
pluginPackageQuarantineMutationId(
event.revocationReceiptDigest,
event.target,
),
/^quarantine:[0-9a-f]{64}$/,
);
assert.equal(
pluginPackageQuarantineMutationId(
event.revocationReceiptDigest,
event.target,
),
pluginPackageQuarantineMutationId(
event.revocationReceiptDigest,
event.target,
),
);
});
@@ -0,0 +1,545 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
PLUGIN_PACKAGE_API_VERSION,
PLUGIN_PACKAGE_KIND,
planPluginPackageInstall,
} = require('../dist/plugin-package/pluginPackage');
const {
PluginPackageInstallTransitionConflictError,
createPluginPackageInstall,
createPluginPackageLock,
pluginPackageInstallActionDigest,
pluginPackageInstallPlanDigest,
transitionPluginPackageInstall,
} = require('../dist/plugin-package/installation/pluginPackageInstall');
const {
createPluginPackageActivationIntent,
} = require('../dist/plugin-package/installation/pluginPackageActivation');
const {
PluginPackageRecoveryCoordinator,
} = require('../dist/plugin-package/installation/pluginPackageRecovery');
const ARTIFACT_DIGEST = 'a'.repeat(64);
const CONTENT_DIGEST = 'b'.repeat(64);
function fixture(
packageName = 'example-monitor',
installationId = 'install-001',
) {
const manifest = {
apiVersion: PLUGIN_PACKAGE_API_VERSION,
kind: PLUGIN_PACKAGE_KIND,
metadata: {
name: packageName,
displayName: packageName,
version: '1.2.0',
description: 'One bounded package',
license: 'Apache-2.0',
},
spec: {
compatibility: {
qinglong: '>=3.0.0-0 <4.0.0',
architectures: ['arm64'],
deploymentProfiles: ['edge'],
},
runtimes: [],
resources: {
memory: { recommended: '16Mi' },
disk: { install: '4Mi', working: '16Mi' },
},
permissions: {
network: { allowedHosts: [] },
secrets: [],
tools: [],
},
contents: { tasks: [], workflows: [], prompts: [], tools: [] },
},
};
const environment = {
qinglongVersion: '3.0.0-alpha.0',
architecture: 'arm64',
deploymentProfile: 'edge',
runtimes: [],
availableMemoryBytes: 128 * 1024 * 1024,
availableDiskBytes: 256 * 1024 * 1024,
};
const plan = planPluginPackageInstall(manifest, environment);
const action = {
lockId: `lock-${packageName}`,
projectId: 'default',
manifest,
plan,
environment,
source: {
kind: 'offline',
locator: `offline:sha256:${ARTIFACT_DIGEST}`,
artifactDigest: ARTIFACT_DIGEST,
artifactBytes: 2048,
contentDigest: CONTENT_DIGEST,
},
architecture: 'arm64',
deploymentProfile: 'edge',
targetGeneration: 1,
};
const lock = createPluginPackageLock({
...action,
approval: {
requestId: `approval-${packageName}`,
requestVersion: 1,
dispatchId: `dispatch-${packageName}`,
actionDigest: pluginPackageInstallActionDigest(action),
previewDigest: pluginPackageInstallPlanDigest(plan),
approvedBy: { type: 'user', id: 'owner-001' },
approvedAtMs: 100,
expiresAtMs: 10_000,
fence: { projectVersion: 1, bindingVersion: 1 },
},
createdAtMs: 200,
});
const queued = createPluginPackageInstall(lock, {
installationId,
mutationId: `mutation-create-${packageName}`,
occurredAtMs: 201,
});
return { lock, queued };
}
function stageEvidence(lock) {
return {
stageRef: `local-stage:${lock.lockDigest}`,
artifactDigest: lock.source.artifactDigest,
manifestDigest: lock.manifestDigest,
contentDigest: lock.source.contentDigest,
evidenceDigest: 'e'.repeat(64),
};
}
function stagedFixture(packageName, installationId) {
const value = fixture(packageName, installationId);
const staged = transitionPluginPackageInstall(value.lock, value.queued, {
type: 'stage_completed',
mutationId: `mutation-stage-${value.lock.packageName}`,
occurredAtMs: 202,
...stageEvidence(value.lock),
});
return { ...value, staged };
}
function activatingFixture(packageName, installationId) {
const value = stagedFixture(packageName, installationId);
const activating = transitionPluginPackageInstall(value.lock, value.staged, {
type: 'activation_started',
mutationId: `mutation-activate-${value.lock.packageName}`,
occurredAtMs: 203,
});
return { ...value, activating };
}
function publishedReceipt(lock, record, activatedAtMs = 204) {
const intent = createPluginPackageActivationIntent(lock, record);
return transitionPluginPackageInstall(lock, record, {
type: 'activation_committed',
mutationId: 'receipt-preview',
occurredAtMs: activatedAtMs,
activationRef: `active:${lock.lockDigest}`,
intentDigest: intent.intentDigest,
generation: lock.targetGeneration,
contentDigest: lock.source.contentDigest,
}).activationReceipt;
}
function compareRecords(left, right) {
return (
left.packageName.localeCompare(right.packageName) ||
left.installationId.localeCompare(right.installationId)
);
}
class MemoryRepository {
constructor(values) {
this.locks = new Map(values.map(({ lock }) => [lock.lockDigest, lock]));
this.records = new Map(
values.map(({ queued, record = queued }) => [
`${record.projectId}\0${record.packageName}`,
record,
]),
);
this.commits = [];
this.commitHook = undefined;
this.listHook = undefined;
this.listCalls = 0;
}
key(projectId, packageName) {
return `${projectId}\0${packageName}`;
}
async find(projectId, packageName) {
return this.records.get(this.key(projectId, packageName)) ?? null;
}
async findLock(lockDigest) {
return this.locks.get(lockDigest) ?? null;
}
async commit(command) {
if (this.commitHook) {
const hooked = await this.commitHook(command);
if (hooked) return hooked;
}
const key = this.key(command.record.projectId, command.record.packageName);
const current = this.records.get(key);
if (
!current ||
current.installationId !== command.installationId ||
current.version !== command.expectedVersion ||
current.recordDigest !== command.expectedRecordDigest
) {
throw new PluginPackageInstallTransitionConflictError();
}
this.records.set(key, command.record);
this.commits.push(command);
return { status: 'committed', record: command.record };
}
async listRecoveryPage(options) {
this.listCalls += 1;
if (this.listHook) await this.listHook(this.listCalls);
const records = [...this.records.values()]
.filter((record) =>
['queued', 'staged', 'activating'].includes(record.state),
)
.sort(compareRecords)
.filter(
(record) =>
!options.after ||
compareRecords(record, {
packageName: options.after.packageName,
installationId: options.after.installationId,
}) > 0,
);
const selected = records.slice(0, options.limit);
const truncated = records.length > selected.length;
const last = selected.at(-1);
return {
records: selected,
truncated,
...(truncated
? {
next: {
packageName: last.packageName,
installationId: last.installationId,
},
}
: {}),
};
}
}
function publisherFor(repository, calls, external = new Map()) {
return {
async publish(intent) {
calls.publish += 1;
const record = await repository.find(
intent.projectId,
intent.packageName,
);
const lock = await repository.findLock(record.lockDigest);
const receipt = publishedReceipt(lock, record, 300 + calls.publish);
external.set(intent.intentDigest, receipt);
return receipt;
},
async inspect(intent) {
calls.inspect += 1;
const receipt = external.get(intent.intentDigest);
return receipt
? { status: 'published', receipt }
: { status: 'not_published' };
},
};
}
test('recovers queued install through stage and activation without consuming approval', async () => {
const value = fixture();
const repository = new MemoryRepository([value]);
const calls = { stage: 0, publish: 0, inspect: 0 };
const coordinator = new PluginPackageRecoveryCoordinator({
repository,
stageProvider: {
async stage(lock) {
calls.stage += 1;
return stageEvidence(lock);
},
},
publisher: publisherFor(repository, calls),
now: async () => 250,
});
const cycle = await coordinator.recover({ pageSize: 1, maxPages: 2 });
assert.deepEqual(cycle, {
pages: 1,
scanned: 1,
settled: 1,
retry: 0,
manualRequired: 0,
superseded: 0,
remaining: false,
safeToAdmit: true,
});
assert.equal(
(await repository.find('default', 'example-monitor')).state,
'active',
);
assert.deepEqual(calls, { stage: 1, publish: 1, inspect: 0 });
});
test('inspects an activating install without republishing it', async () => {
const value = activatingFixture();
const repository = new MemoryRepository([
{ ...value, record: value.activating },
]);
const calls = { stage: 0, publish: 0, inspect: 0 };
const intent = createPluginPackageActivationIntent(
value.lock,
value.activating,
);
const external = new Map([
[intent.intentDigest, publishedReceipt(value.lock, value.activating)],
]);
const coordinator = new PluginPackageRecoveryCoordinator({
repository,
stageProvider: {
async stage() {
calls.stage += 1;
throw new Error('stage must not run');
},
},
publisher: publisherFor(repository, calls, external),
now: () => 250,
});
const page = await coordinator.recoverPage({ limit: 1 });
assert.equal(page.items[0].status, 'settled');
assert.equal(page.items[0].action, 'inspect_activation');
assert.equal(
(await repository.find('default', 'example-monitor')).state,
'active',
);
assert.deepEqual(calls, { stage: 0, publish: 0, inspect: 1 });
});
test('recovers publication response loss by inspecting on the next pass', async () => {
const value = stagedFixture();
const repository = new MemoryRepository([{ ...value, record: value.staged }]);
const calls = { stage: 0, publish: 0, inspect: 0 };
const external = new Map();
const basePublisher = publisherFor(repository, calls, external);
let loseResponse = true;
const coordinator = new PluginPackageRecoveryCoordinator({
repository,
stageProvider: {
async stage() {
throw new Error('stage must not run');
},
},
publisher: {
async publish(intent) {
const receipt = await basePublisher.publish(intent);
if (loseResponse) {
loseResponse = false;
throw new Error('simulated response loss');
}
return receipt;
},
inspect: basePublisher.inspect,
},
now: () => 250,
});
const first = await coordinator.recover();
assert.equal(first.retry, 1);
assert.equal(first.safeToAdmit, false);
assert.equal(
(await repository.find('default', 'example-monitor')).state,
'activating',
);
const second = await coordinator.recover();
assert.equal(second.settled, 1);
assert.equal(second.safeToAdmit, true);
assert.equal(
(await repository.find('default', 'example-monitor')).state,
'active',
);
assert.deepEqual(calls, { stage: 0, publish: 1, inspect: 1 });
});
test('does not inspect or publish when another recovery advances queued state', async () => {
const value = fixture();
const repository = new MemoryRepository([value]);
const calls = { stage: 0, publish: 0, inspect: 0 };
repository.commitHook = async (command) => {
if (command.record.state !== 'staged') return undefined;
const activating = transitionPluginPackageInstall(
value.lock,
command.record,
{
type: 'activation_started',
mutationId: 'other-recovery-activation',
occurredAtMs: 251,
},
);
repository.records.set(
repository.key(activating.projectId, activating.packageName),
activating,
);
repository.commitHook = undefined;
return { status: 'existing', record: activating };
};
const coordinator = new PluginPackageRecoveryCoordinator({
repository,
stageProvider: {
async stage(lock) {
calls.stage += 1;
return stageEvidence(lock);
},
},
publisher: publisherFor(repository, calls),
now: () => 250,
});
const page = await coordinator.recoverPage({ limit: 1 });
assert.equal(page.items[0].status, 'retry');
assert.equal(page.items[0].state, 'activating');
assert.deepEqual(calls, { stage: 1, publish: 0, inspect: 0 });
});
test('keeps unavailable stage recoverable and blocks admission', async () => {
const value = fixture();
const repository = new MemoryRepository([value]);
const coordinator = new PluginPackageRecoveryCoordinator({
repository,
stageProvider: {
async stage() {
throw new Error('artifact store unavailable');
},
},
publisher: publisherFor(repository, { publish: 0, inspect: 0 }),
now: () => 250,
});
const cycle = await coordinator.recover();
assert.equal(cycle.retry, 1);
assert.equal(cycle.remaining, true);
assert.equal(cycle.safeToAdmit, false);
assert.equal(
(await repository.find('default', 'example-monitor')).state,
'queued',
);
});
test('marks invalid durable stage evidence for manual recovery', async () => {
const value = fixture();
const repository = new MemoryRepository([value]);
const coordinator = new PluginPackageRecoveryCoordinator({
repository,
stageProvider: {
async stage(lock) {
return { ...stageEvidence(lock), evidenceDigest: 'not-a-digest' };
},
},
publisher: publisherFor(repository, { publish: 0, inspect: 0 }),
now: () => 250,
});
const cycle = await coordinator.recover();
assert.equal(cycle.manualRequired, 1);
assert.equal(cycle.safeToAdmit, false);
});
test('uses a final head probe to catch recovery work inserted before the cursor', async () => {
const first = stagedFixture('middle-package', 'install-middle');
const last = stagedFixture('zulu-package', 'install-zulu');
const inserted = stagedFixture('alpha-package', 'install-alpha');
const repository = new MemoryRepository([
{ ...first, record: first.staged },
{ ...last, record: last.staged },
]);
const calls = { stage: 0, publish: 0, inspect: 0 };
repository.listHook = async (listCall) => {
if (listCall !== 2) return;
repository.locks.set(inserted.lock.lockDigest, inserted.lock);
repository.records.set(
repository.key(inserted.staged.projectId, inserted.staged.packageName),
inserted.staged,
);
};
const coordinator = new PluginPackageRecoveryCoordinator({
repository,
stageProvider: {
async stage() {
throw new Error('stage must not run');
},
},
publisher: publisherFor(repository, calls),
now: () => 250,
});
const cycle = await coordinator.recover({ pageSize: 1, maxPages: 2 });
assert.equal(cycle.pages, 2);
assert.equal(cycle.settled, 2);
assert.equal(cycle.remaining, true);
assert.equal(cycle.safeToAdmit, false);
assert.equal(
(await repository.find('default', 'alpha-package')).state,
'staged',
);
});
test('rejects malformed recovery page ordering and continuation', async () => {
const first = stagedFixture('alpha-package', 'install-alpha');
const last = stagedFixture('zulu-package', 'install-zulu');
const repository = new MemoryRepository([
{ ...first, record: first.staged },
{ ...last, record: last.staged },
]);
repository.listRecoveryPage = async () => ({
records: [last.staged, first.staged],
truncated: true,
next: {
packageName: first.staged.packageName,
installationId: first.staged.installationId,
},
});
const coordinator = new PluginPackageRecoveryCoordinator({
repository,
stageProvider: { async stage() {} },
publisher: {
async publish() {},
async inspect() {},
},
now: () => 250,
});
await assert.rejects(
coordinator.recoverPage({ limit: 2 }),
/recovery page records are invalid/,
);
});
test('publishes recovery authority only through its explicit subpath', () => {
assert.equal(require('../dist').PluginPackageRecoveryCoordinator, undefined);
assert.equal(
require('@qinglong/runtime-core/plugin-package-recovery')
.PluginPackageRecoveryCoordinator,
PluginPackageRecoveryCoordinator,
);
});
@@ -0,0 +1,185 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidPluginPackageResourceGenerationError,
PLUGIN_PACKAGE_RESOURCE_GENERATION_SCHEMA,
createPluginPackageResourceGeneration,
createPluginPackageResourceGenerationFromReferences,
normalizePluginPackageResourceGeneration,
pluginPackageResourceReferencesFromContents,
} = require('../dist/plugin-package/pluginPackageResourceGeneration');
const LOCK_DIGEST = 'a'.repeat(64);
const CONTENT_DIGEST = 'b'.repeat(64);
function input(overrides = {}) {
return {
installationId: 'install-001',
projectId: 'default',
packageName: 'example-monitor',
lockDigest: LOCK_DIGEST,
generation: 2,
previousActiveLockDigest: 'c'.repeat(64),
contentDigest: CONTENT_DIGEST,
contents: {
tasks: ['tasks/z.yaml', 'tasks/a.yaml'],
workflows: ['workflows/daily.yaml'],
prompts: ['prompts/report.md'],
tools: ['tools/notify.json'],
},
...overrides,
};
}
test('creates one canonical bounded resource generation from manifest contents', () => {
const generation = createPluginPackageResourceGeneration(input());
assert.equal(generation.schema, PLUGIN_PACKAGE_RESOURCE_GENERATION_SCHEMA);
assert.deepEqual(generation.resources, [
{ kind: 'prompt', path: 'prompts/report.md' },
{ kind: 'task', path: 'tasks/a.yaml' },
{ kind: 'task', path: 'tasks/z.yaml' },
{ kind: 'tool', path: 'tools/notify.json' },
{ kind: 'workflow', path: 'workflows/daily.yaml' },
]);
assert.match(generation.generationDigest, /^[0-9a-f]{64}$/);
assert.equal(Object.isFrozen(generation), true);
assert.equal(Object.isFrozen(generation.resources), true);
assert.equal(Object.isFrozen(generation.resources[0]), true);
assert.deepEqual(
normalizePluginPackageResourceGeneration(generation),
generation,
);
});
test('reconstructs the same generation from an immutable lock snapshot', () => {
const fromContents = createPluginPackageResourceGeneration(input());
const fromReferences = createPluginPackageResourceGenerationFromReferences({
installationId: fromContents.installationId,
projectId: fromContents.projectId,
packageName: fromContents.packageName,
lockDigest: fromContents.lockDigest,
generation: fromContents.generation,
previousActiveLockDigest: fromContents.previousActiveLockDigest,
contentDigest: fromContents.contentDigest,
resources: fromContents.resources,
});
assert.deepEqual(fromReferences, fromContents);
assert.deepEqual(
pluginPackageResourceReferencesFromContents(input().contents),
fromContents.resources,
);
});
test('fails closed on identity, order, path and digest drift', () => {
const generation = createPluginPackageResourceGeneration(input());
assert.throws(
() =>
normalizePluginPackageResourceGeneration({
...generation,
projectId: 'other',
}),
/generation digest does not match/,
);
assert.throws(
() =>
createPluginPackageResourceGenerationFromReferences({
...input(),
contents: undefined,
resources: [...generation.resources].reverse(),
}),
InvalidPluginPackageResourceGenerationError,
);
assert.throws(
() =>
createPluginPackageResourceGeneration(
input({
contents: {
tasks: [`tasks/${'x'.repeat(250)}`],
workflows: [],
prompts: [],
tools: [],
},
}),
),
/resource path is invalid/,
);
assert.throws(
() =>
normalizePluginPackageResourceGeneration({
...generation,
generationDigest: 'f'.repeat(64),
}),
/generation digest does not match/,
);
});
test('enforces the shared 256-resource budget and rejects duplicates', () => {
const tasks = Array.from(
{ length: 256 },
(_, index) => `tasks/${String(index).padStart(3, '0')}.yaml`,
);
const maximum = createPluginPackageResourceGeneration(
input({
generation: 1,
previousActiveLockDigest: null,
contents: { tasks, workflows: [], prompts: [], tools: [] },
}),
);
assert.equal(maximum.resources.length, 256);
assert.throws(
() =>
createPluginPackageResourceGeneration(
input({
contents: {
tasks: [...tasks, 'tasks/overflow.yaml'],
workflows: [],
prompts: [],
tools: [],
},
}),
),
/task contents is invalid/,
);
assert.throws(
() =>
createPluginPackageResourceGeneration(
input({
contents: {
tasks: ['tasks/duplicate.yaml', 'tasks/duplicate.yaml'],
workflows: [],
prompts: [],
tools: [],
},
}),
),
/resource path is duplicated/,
);
const sparse = new Array(1);
assert.throws(
() =>
createPluginPackageResourceGeneration(
input({
contents: {
tasks: sparse,
workflows: [],
prompts: [],
tools: [],
},
}),
),
/dense data array/,
);
});
test('publishes generation authority only through its explicit subpath', () => {
assert.equal(
require('../dist').createPluginPackageResourceGeneration,
undefined,
);
assert.equal(
require('@qinglong/runtime-core/plugin-package-resource-generation')
.createPluginPackageResourceGeneration,
createPluginPackageResourceGeneration,
);
});
@@ -0,0 +1,600 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
createPluginPackageResourceGenerationFromReferences,
} = require('../dist/plugin-package/pluginPackageResourceGeneration');
const {
MAX_PLUGIN_PACKAGE_MANIFEST_BYTES,
PLUGIN_PACKAGE_API_VERSION,
PLUGIN_PACKAGE_KIND,
planPluginPackageInstall,
} = require('../dist/plugin-package/pluginPackage');
const {
createPluginPackageLock,
pluginPackageInstallActionDigest,
pluginPackageInstallPlanDigest,
serializePluginPackageManifest,
} = require('../dist/plugin-package/installation/pluginPackageInstall');
const {
pluginPackageContentTreeDigest,
} = require('../dist/plugin-package/pluginPackageBundle');
const {
createBuiltInTaskSpecSemanticRegistry,
} = require('../dist/task-definition/taskSpecSemantic');
const { createSecretRef } = require('../dist/secret/secretReference');
const {
InvalidPluginPackageResourceMaterializationError,
MAX_PLUGIN_PACKAGE_MATERIALIZED_RESOURCE_BYTES,
PLUGIN_PACKAGE_MATERIALIZED_REVISION_SCHEMA,
PluginPackageResourceMaterializationConflictError,
materializeActivePluginPackageResources,
materializePluginPackageResources,
normalizePluginPackageMaterializedRevision,
pluginPackageTaskDefinitionDrafts,
pluginPackageToolDefinitions,
} = require('../dist/plugin-package/pluginPackageResourceMaterialization');
const ARTIFACT_DIGEST = 'a'.repeat(64);
const OCI_MANIFEST_DIGEST = 'f'.repeat(64);
function resourceValues(overrides = {}) {
return {
'prompts/report.json': {
schema: 'qinglong/plugin-package-prompt-resource@v1',
id: 'report',
name: 'Report prompt',
description: 'Creates one bounded report',
template: 'Hello {{name}}\n',
parameters: [
{ name: 'name', description: 'Display name', required: true },
],
},
'tasks/collect.json': {
schema: 'qinglong/plugin-package-task-resource@v1',
id: 'collect',
name: 'Collect',
labels: { 'plugin.qinglong.io/source': 'example-monitor' },
enabled: true,
kind: 'command',
spec: {
schema: 'qinglong/command@v1',
config: {
command: {
kind: 'argv',
file: '/usr/bin/printf',
args: ['ok'],
},
environment: [{ name: 'MODE', kind: 'public', value: 'safe' }],
timeoutMs: 30_000,
},
},
},
'tools/query.json': {
schema: 'qinglong/plugin-package-tool-resource@v1',
definition: {
name: 'example-monitor.query',
version: '1.0.0',
description: 'Queries one bounded report',
inputSchema: {
type: 'object',
properties: {},
required: [],
additionalProperties: false,
},
effect: 'read',
risk: 'low',
requiredPermissions: ['run.read'],
timeoutSeconds: 30,
},
},
'workflows/daily.json': {
schema: 'qinglong/plugin-package-workflow-resource@v1',
id: 'daily',
name: 'Daily report',
enabled: true,
steps: [{ id: 'collect', task: 'collect', needs: [] }],
},
...overrides,
};
}
function manifest(overrides = {}) {
const value = {
apiVersion: PLUGIN_PACKAGE_API_VERSION,
kind: PLUGIN_PACKAGE_KIND,
metadata: {
name: 'example-monitor',
displayName: 'Example Monitor',
version: '1.0.0',
description: 'One bounded example package',
license: 'Apache-2.0',
},
spec: {
compatibility: {
qinglong: '>=3.0.0-0 <4.0.0',
architectures: ['arm64'],
deploymentProfiles: ['edge', 'standalone'],
},
runtimes: [],
resources: {
memory: { recommended: '32Mi' },
disk: { install: '8Mi', working: '16Mi' },
},
permissions: {
network: { allowedHosts: [] },
secrets: [],
tools: ['run.read', 'system.command'],
},
contents: {
tasks: ['tasks/collect.json'],
workflows: ['workflows/daily.json'],
prompts: ['prompts/report.json'],
tools: ['tools/query.json'],
},
},
};
return {
...value,
...overrides,
metadata: { ...value.metadata, ...overrides.metadata },
spec: {
...value.spec,
...overrides.spec,
compatibility: {
...value.spec.compatibility,
...overrides.spec?.compatibility,
},
resources: {
...value.spec.resources,
...overrides.spec?.resources,
memory: {
...value.spec.resources.memory,
...overrides.spec?.resources?.memory,
},
disk: {
...value.spec.resources.disk,
...overrides.spec?.resources?.disk,
},
},
permissions: {
...value.spec.permissions,
...overrides.spec?.permissions,
network: {
...value.spec.permissions.network,
...overrides.spec?.permissions?.network,
},
},
contents: {
...value.spec.contents,
...overrides.spec?.contents,
},
},
};
}
function environment() {
return {
qinglongVersion: '3.0.0-alpha.0',
architecture: 'arm64',
deploymentProfile: 'edge',
runtimes: [],
availableMemoryBytes: 128 * 1024 * 1024,
availableDiskBytes: 256 * 1024 * 1024,
};
}
function fixture(options = {}) {
const resourceObjects = resourceValues(options.resourceValues);
const packageManifest = manifest(options.manifest);
const resourceBytes = Object.fromEntries(
Object.entries(resourceObjects).map(([path, value]) => [
path,
Buffer.from(JSON.stringify(value)),
]),
);
const descriptors = Object.entries(resourceBytes)
.map(([path, material]) => ({
path,
bytes: material.byteLength,
digest: require('node:crypto')
.createHash('sha256')
.update(material)
.digest('hex'),
}))
.sort((left, right) => left.path.localeCompare(right.path));
const contentDigest = pluginPackageContentTreeDigest(descriptors);
const installEnvironment = environment();
const plan = planPluginPackageInstall(packageManifest, installEnvironment);
const actionInput = {
lockId: 'lock-001',
projectId: 'project-001',
manifest: packageManifest,
plan,
environment: installEnvironment,
source: {
kind: 'oci',
locator:
`oci://registry.example.com/qinglong/example-monitor@sha256:` +
OCI_MANIFEST_DIGEST,
artifactDigest: ARTIFACT_DIGEST,
artifactBytes: 4096,
contentDigest,
},
architecture: 'arm64',
deploymentProfile: 'edge',
targetGeneration: 1,
};
const lock = createPluginPackageLock({
...actionInput,
approval: {
requestId: 'approval-001',
requestVersion: 1,
dispatchId: 'dispatch-001',
actionDigest: pluginPackageInstallActionDigest(actionInput),
previewDigest: pluginPackageInstallPlanDigest(plan),
approvedBy: { type: 'user', id: 'owner-001' },
approvedAtMs: 100,
expiresAtMs: 1_000,
fence: { projectVersion: 1, bindingVersion: 1 },
},
createdAtMs: 200,
});
const generation = createPluginPackageResourceGenerationFromReferences({
installationId: 'install-001',
projectId: lock.projectId,
packageName: lock.packageName,
lockDigest: lock.lockDigest,
generation: lock.targetGeneration,
previousActiveLockDigest: null,
contentDigest,
resources: lock.resources,
});
const entries = generation.resources.map((reference) => ({
reference,
bytes: resourceBytes[reference.path],
}));
return {
manifest: packageManifest,
manifestBytes: Buffer.from(serializePluginPackageManifest(packageManifest)),
resourceBytes,
lock,
generation,
entries,
registry: createBuiltInTaskSpecSemanticRegistry(),
};
}
test('materializes exact Task, Workflow, Prompt and Tool JSON into one immutable revision', () => {
const value = fixture();
const revision = materializePluginPackageResources({
generation: value.generation,
lock: value.lock,
manifestBytes: value.manifestBytes,
resources: value.entries,
taskSpecSemanticRegistry: value.registry,
});
assert.equal(revision.schema, PLUGIN_PACKAGE_MATERIALIZED_REVISION_SCHEMA);
assert.deepEqual(
revision.resources.map(({ kind, path }) => ({ kind, path })),
value.generation.resources,
);
assert.match(revision.revisionDigest, /^[0-9a-f]{64}$/);
assert.equal(Object.isFrozen(revision), true);
assert.equal(Object.isFrozen(revision.resources), true);
assert.deepEqual(
normalizePluginPackageMaterializedRevision(revision, value.registry),
revision,
);
const drafts = pluginPackageTaskDefinitionDrafts(
revision,
value.registry,
);
assert.deepEqual(JSON.parse(JSON.stringify(drafts)), [
{
projectId: 'project-001',
taskId: 'pkg:example-monitor:collect',
name: 'Collect',
kind: 'command',
spec: {
schema: 'qinglong/command@v1',
config: {
command: {
kind: 'argv',
file: '/usr/bin/printf',
args: ['ok'],
},
environment: [{ name: 'MODE', kind: 'public', value: 'safe' }],
timeoutMs: 30_000,
},
},
labels: { 'plugin.qinglong.io/source': 'example-monitor' },
enabled: true,
},
]);
assert.equal(
pluginPackageToolDefinitions(revision, value.registry)[0].name,
'example-monitor.query',
);
});
test('fails closed on unapproved capabilities, unresolved references and source drift', () => {
const unapproved = fixture({
manifest: {
spec: {
permissions: {
tools: ['system.command'],
},
},
},
});
assert.throws(
() =>
materializePluginPackageResources({
generation: unapproved.generation,
lock: unapproved.lock,
manifestBytes: unapproved.manifestBytes,
resources: unapproved.entries,
taskSpecSemanticRegistry: unapproved.registry,
}),
/required permission is not present/,
);
const missingTask = fixture({
resourceValues: {
'workflows/daily.json': {
schema: 'qinglong/plugin-package-workflow-resource@v1',
id: 'daily',
name: 'Daily report',
enabled: true,
steps: [{ id: 'missing', task: 'missing', needs: [] }],
},
},
});
assert.throws(
() =>
materializePluginPackageResources({
generation: missingTask.generation,
lock: missingTask.lock,
manifestBytes: missingTask.manifestBytes,
resources: missingTask.entries,
taskSpecSemanticRegistry: missingTask.registry,
}),
/unknown package Task/,
);
const drift = fixture();
const changed = drift.entries.map((entry, index) =>
index === 0
? { ...entry, bytes: Buffer.from('{}') }
: entry,
);
assert.throws(
() =>
materializePluginPackageResources({
generation: drift.generation,
lock: drift.lock,
manifestBytes: drift.manifestBytes,
resources: changed,
taskSpecSemanticRegistry: drift.registry,
}),
InvalidPluginPackageResourceMaterializationError,
);
});
test('rejects secret-bearing package Tasks until an approved binding format exists', () => {
const value = fixture({
manifest: {
spec: {
permissions: {
secrets: [{ name: 'TOKEN', required: true }],
tools: ['run.read', 'secret.use', 'system.command'],
},
},
},
resourceValues: {
'tasks/collect.json': {
schema: 'qinglong/plugin-package-task-resource@v1',
id: 'collect',
name: 'Collect',
labels: {},
enabled: true,
kind: 'command',
spec: {
schema: 'qinglong/command@v1',
config: {
command: {
kind: 'argv',
file: '/usr/bin/printf',
args: ['ok'],
},
environment: [
{
name: 'TOKEN',
kind: 'secret',
secretRef: createSecretRef({
projectId: 'project-001',
name: 'TOKEN',
}),
},
],
},
},
},
},
});
assert.throws(
() =>
materializePluginPackageResources({
generation: value.generation,
lock: value.lock,
manifestBytes: value.manifestBytes,
resources: value.entries,
taskSpecSemanticRegistry: value.registry,
}),
/does not support unresolved package Secret bindings/,
);
});
test('rejects cyclic Workflows, invalid UTF-8 and per-resource byte overflow', () => {
const cyclic = fixture({
resourceValues: {
'workflows/daily.json': {
schema: 'qinglong/plugin-package-workflow-resource@v1',
id: 'daily',
name: 'Daily report',
enabled: true,
steps: [
{ id: 'first', task: 'collect', needs: ['second'] },
{ id: 'second', task: 'collect', needs: ['first'] },
],
},
},
});
assert.throws(
() =>
materializePluginPackageResources({
generation: cyclic.generation,
lock: cyclic.lock,
manifestBytes: cyclic.manifestBytes,
resources: cyclic.entries,
taskSpecSemanticRegistry: cyclic.registry,
}),
/contains a cycle/,
);
const invalidUtf8 = fixture();
assert.throws(
() =>
materializePluginPackageResources({
generation: invalidUtf8.generation,
lock: invalidUtf8.lock,
manifestBytes: invalidUtf8.manifestBytes,
resources: invalidUtf8.entries.map((entry, index) =>
index === 0 ? { ...entry, bytes: Buffer.from([0xff]) } : entry,
),
taskSpecSemanticRegistry: invalidUtf8.registry,
}),
/not strict UTF-8/,
);
const overflow = fixture();
assert.throws(
() =>
materializePluginPackageResources({
generation: overflow.generation,
lock: overflow.lock,
manifestBytes: overflow.manifestBytes,
resources: overflow.entries.map((entry, index) =>
index === 0
? {
...entry,
bytes: Buffer.alloc(
MAX_PLUGIN_PACKAGE_MATERIALIZED_RESOURCE_BYTES + 1,
),
}
: entry,
),
taskSpecSemanticRegistry: overflow.registry,
}),
/resource bytes is invalid/,
);
});
test('reads active bytes sequentially with explicit bounds and rejects a generation switch', async () => {
const value = fixture();
const reads = [];
let observations = 0;
const revision = await materializeActivePluginPackageResources({
projectId: value.generation.projectId,
packageName: value.generation.packageName,
generationSource: {
async findActiveResourceGeneration() {
observations += 1;
return value.generation;
},
},
lockSource: {
async findLock(lockDigest) {
assert.equal(lockDigest, value.lock.lockDigest);
return value.lock;
},
},
byteSource: {
async open(generation) {
assert.equal(generation.generationDigest, value.generation.generationDigest);
return {
async read(path, maximumBytes) {
reads.push({ path, maximumBytes });
return path === 'package.json'
? value.manifestBytes
: value.resourceBytes[path];
},
async close() {},
};
},
},
taskSpecSemanticRegistry: value.registry,
});
assert.equal(revision.revisionDigest.length, 64);
assert.equal(observations, 2);
assert.deepEqual(reads, [
{ path: 'package.json', maximumBytes: MAX_PLUGIN_PACKAGE_MANIFEST_BYTES },
...value.generation.resources.map(({ path }) => ({
path,
maximumBytes: MAX_PLUGIN_PACKAGE_MATERIALIZED_RESOURCE_BYTES,
})),
]);
const changed = createPluginPackageResourceGenerationFromReferences({
installationId: value.generation.installationId,
projectId: value.generation.projectId,
packageName: value.generation.packageName,
lockDigest: value.generation.lockDigest,
generation: 2,
previousActiveLockDigest: value.generation.lockDigest,
contentDigest: value.generation.contentDigest,
resources: value.generation.resources,
});
await assert.rejects(
materializeActivePluginPackageResources({
projectId: value.generation.projectId,
packageName: value.generation.packageName,
generationSource: {
calls: 0,
async findActiveResourceGeneration() {
this.calls += 1;
return this.calls === 1 ? value.generation : changed;
},
},
lockSource: { async findLock() { return value.lock; } },
byteSource: {
async open() {
return {
async read(path) {
return path === 'package.json'
? value.manifestBytes
: value.resourceBytes[path];
},
async close() {},
};
},
},
taskSpecSemanticRegistry: value.registry,
}),
PluginPackageResourceMaterializationConflictError,
);
});
test('publishes materialization only through the explicit runtime-core subpath', () => {
assert.equal(
require('../dist').materializePluginPackageResources,
undefined,
);
assert.equal(
require('@qinglong/runtime-core/plugin-package-resource-materialization')
.materializePluginPackageResources,
materializePluginPackageResources,
);
});
@@ -0,0 +1,279 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidPluginPackageTaskPublicationError,
PluginPackageTaskPublicationConflictError,
PluginPackageTaskPublicationCoordinator,
PluginPackageTaskPublicationRecoveryCoordinator,
PluginPackageTaskPublicationUnavailableError,
} = require('../dist/plugin-package/pluginPackageTaskPublication');
const {
pluginPackageTaskReconciliationFixture,
} = require('../../../test/contracts/pluginPackageTaskReconciliationRepositoryContract.cjs');
function authorities(namespace) {
const fixture = pluginPackageTaskReconciliationFixture(namespace);
let generation = fixture.revision.generation;
let durableRevision = null;
let durableReceipt = null;
let openCount = 0;
const bytesByPath = new Map([
['package.json', fixture.manifestBytes],
...fixture.resourceEntries.map(({ reference, bytes }) => [
reference.path,
bytes,
]),
]);
const generationSource = {
async findActiveResourceGeneration() {
return generation;
},
};
const materializedRepository = {
async find(digest) {
return durableRevision?.generation.generationDigest === digest
? durableRevision
: null;
},
async publish(revision) {
const status = durableRevision === null ? 'created' : 'existing';
durableRevision ??= revision;
return { status, revision: durableRevision };
},
};
const reconciliationRepository = {
async find(digest) {
return durableReceipt?.generationDigest === digest ? durableReceipt : null;
},
async reconcile(revision) {
const status = durableReceipt === null ? 'created' : 'existing';
durableReceipt ??= Object.freeze({
schema: 'qinglong/plugin-package-task-reconciliation@v1',
projectId: revision.generation.projectId,
packageName: revision.generation.packageName,
generation: revision.generation.generation,
generationDigest: revision.generation.generationDigest,
materializedRevisionDigest: revision.revisionDigest,
lockDigest: revision.generation.lockDigest,
previousLockDigest: revision.generation.previousActiveLockDigest,
committedAtMs: 1,
items: Object.freeze([]),
receiptDigest: 'a'.repeat(64),
});
return { status, receipt: durableReceipt };
},
};
const coordinator = new PluginPackageTaskPublicationCoordinator({
generationSource,
lockSource: {
async findLock(digest) {
return digest === fixture.lock.lockDigest ? fixture.lock : null;
},
},
byteSource: {
async open() {
openCount += 1;
let closed = false;
return {
async read(path, maximumBytes) {
assert.equal(closed, false);
const value = bytesByPath.get(path);
assert.ok(value);
assert.ok(value.byteLength <= maximumBytes);
return value;
},
close() {
closed = true;
},
};
},
},
materializedRepository,
reconciliationRepository,
taskSpecSemanticRegistry: fixture.registry,
});
return {
fixture,
coordinator,
materializedRepository,
reconciliationRepository,
get generation() {
return generation;
},
set generation(value) {
generation = value;
},
get openCount() {
return openCount;
},
};
}
test('materializes, durably publishes and reconciles one active generation', async () => {
const value = authorities('task-publication-create');
const created = await value.coordinator.publishActive(
value.fixture.projectId,
value.fixture.packageName,
);
assert.equal(created.status, 'current');
assert.equal(created.materialized, 'created');
assert.equal(created.reconciled, 'created');
assert.equal(value.openCount, 1);
const replay = await value.coordinator.publishActive(
value.fixture.projectId,
value.fixture.packageName,
);
assert.equal(replay.status, 'current');
assert.equal(replay.materialized, 'existing');
assert.equal(replay.reconciled, 'existing');
assert.equal(value.openCount, 1);
});
test('reports a final generation switch without treating the old receipt as current', async () => {
const value = authorities('task-publication-switch');
let observations = 0;
const original =
value.coordinator;
const source = {
async findActiveResourceGeneration() {
observations += 1;
return observations < 4 ? value.generation : null;
},
};
const switched = new PluginPackageTaskPublicationCoordinator({
generationSource: source,
lockSource: {
async findLock() {
return value.fixture.lock;
},
},
byteSource: {
async open() {
return {
async read(path) {
if (path === 'package.json') return value.fixture.manifestBytes;
return value.fixture.resourceEntries.find(
({ reference }) => reference.path === path,
).bytes;
},
close() {},
};
},
},
materializedRepository: value.materializedRepository,
reconciliationRepository: value.reconciliationRepository,
taskSpecSemanticRegistry: value.fixture.registry,
});
assert.ok(original);
assert.deepEqual(
await switched.publishActive(
value.fixture.projectId,
value.fixture.packageName,
),
{
status: 'superseded',
generationDigest: value.fixture.revision.generation.generationDigest,
},
);
});
test('bounded recovery converges pending candidates and probes from the start', async () => {
const value = authorities('task-publication-recovery');
let pending = [
{
projectId: value.fixture.projectId,
packageName: value.fixture.packageName,
},
];
const source = {
async listPendingPage({ limit, after }) {
const candidates = pending
.filter(
(candidate) =>
!after ||
candidate.projectId > after.projectId ||
(candidate.projectId === after.projectId &&
candidate.packageName > after.packageName),
)
.slice(0, limit);
return { candidates, truncated: false };
},
};
const publisher = {
async publishActive(projectId, packageName) {
const result = await value.coordinator.publishActive(projectId, packageName);
if (result.status === 'current') pending = [];
return result;
},
};
Object.setPrototypeOf(
publisher,
Object.getPrototypeOf(value.coordinator),
);
const recovery = new PluginPackageTaskPublicationRecoveryCoordinator({
source,
publisher,
});
assert.deepEqual(await recovery.recover({ pageSize: 1, maxPages: 1 }), {
pages: 1,
scanned: 1,
settled: 1,
retry: 0,
manualRequired: 0,
superseded: 0,
remaining: false,
safeToAdmit: true,
});
});
test('recovery keeps conflicts manual and availability failures retryable', async () => {
const fixture = pluginPackageTaskReconciliationFixture(
'task-publication-errors',
);
const candidates = [
{ projectId: fixture.projectId, packageName: fixture.packageName },
{ projectId: fixture.projectId, packageName: 'package-z-retry' },
];
const publisher = Object.create(
PluginPackageTaskPublicationCoordinator.prototype,
);
publisher.publishActive = async (_projectId, packageName) => {
if (packageName === fixture.packageName) {
throw new PluginPackageTaskPublicationConflictError('conflict');
}
throw new PluginPackageTaskPublicationUnavailableError();
};
const recovery = new PluginPackageTaskPublicationRecoveryCoordinator({
source: {
async listPendingPage({ limit }) {
const page = candidates.slice(0, limit);
const truncated = candidates.length > limit;
const last = page.at(-1);
return {
candidates: page,
truncated,
...(truncated
? {
next: {
projectId: last.projectId,
packageName: last.packageName,
},
}
: {}),
};
},
},
publisher,
});
const result = await recovery.recover({ pageSize: 2, maxPages: 1 });
assert.equal(result.manualRequired, 1);
assert.equal(result.retry, 1);
assert.equal(result.remaining, true);
assert.equal(result.safeToAdmit, false);
await assert.rejects(
() => recovery.recover({ pageSize: 0 }),
InvalidPluginPackageTaskPublicationError,
);
});
@@ -0,0 +1,679 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidPluginPackageWorkflowAdministrationMutationError,
PLUGIN_PACKAGE_WORKFLOW_RUN_EVENT_LIST_SCHEMA,
PLUGIN_PACKAGE_WORKFLOW_RUN_INSPECTION_SCHEMA,
PLUGIN_PACKAGE_WORKFLOW_RUN_LIST_SCHEMA,
PLUGIN_PACKAGE_WORKFLOW_STEP_RUN_LIST_SCHEMA,
normalizeAuthorizedPluginPackageWorkflowAdmission,
normalizeAuthorizedPluginPackageWorkflowCancellation,
normalizeAuthorizedPluginPackageWorkflowRunEventList,
normalizeAuthorizedPluginPackageWorkflowRunInspection,
normalizeAuthorizedPluginPackageWorkflowRunList,
normalizeAuthorizedPluginPackageWorkflowStepRunList,
normalizePluginPackageWorkflowCancellationResult,
normalizePluginPackageWorkflowRunEventListResult,
normalizePluginPackageWorkflowRunInspectionResult,
normalizePluginPackageWorkflowRunListResult,
normalizePluginPackageWorkflowStepRunListResult,
} = require('@qinglong/runtime-core/plugin-package-workflow-administration');
const {
createInitialPluginPackageAutomationPublication,
} = require('../dist/plugin-package/pluginPackageAutomationPublication');
const {
createPluginPackageWorkflowExecutionPlan,
} = require('@qinglong/runtime-core/plugin-package-workflow-execution-plan');
const {
pluginPackageTaskReconciliationFixture,
} = require('../../../test/contracts/pluginPackageTaskReconciliationRepositoryContract.cjs');
test('binds Workflow administration to one exact allowed audit and explicit subpath', () => {
const value = pluginPackageTaskReconciliationFixture(
'workflow-administration',
{
workflows: [
{
schema: 'qinglong/plugin-package-workflow-resource@v1',
id: 'daily',
name: 'Daily workflow',
enabled: true,
steps: [{ id: 'collect', task: 'alpha', needs: [] }],
},
],
},
);
const plan = createPluginPackageWorkflowExecutionPlan({
planId: 'workflow-administration-plan',
runId: 'workflow-administration-run',
workflowId: 'daily',
stepRunIds: { collect: 'workflow-administration-step' },
publication: createInitialPluginPackageAutomationPublication(
value.revision,
value.registry,
2_000,
),
revision: value.revision,
taskSpecSemanticRegistry: value.registry,
plannedAtMs: 3_000,
});
const admission = {
plan,
actor: { type: 'user', id: 'workflow-owner' },
fence: { projectVersion: 2, bindingVersion: 3 },
audit: {
eventId: '00000000-0000-4000-8000-000000000001',
requestId: 'workflow-administration-request',
operationId: 'workflow.start',
projectId: plan.target.projectId,
subject: { type: 'user', id: 'workflow-owner' },
authenticationId: 'workflow-administration-authentication',
outcome: 'allowed',
reasons: ['permission_granted'],
fence: { projectVersion: 2, bindingVersion: 3 },
occurredAtMs: plan.plannedAtMs,
},
};
assert.deepEqual(
normalizeAuthorizedPluginPackageWorkflowAdmission(admission),
admission,
);
assert.throws(
() =>
normalizeAuthorizedPluginPackageWorkflowAdmission({
...admission,
audit: { ...admission.audit, operationId: 'workflow.read' },
}),
InvalidPluginPackageWorkflowAdministrationMutationError,
);
assert.throws(
() =>
normalizeAuthorizedPluginPackageWorkflowAdmission({
...admission,
fence: { ...admission.fence, bindingVersion: 4 },
}),
InvalidPluginPackageWorkflowAdministrationMutationError,
);
const subpath = require('@qinglong/runtime-core/plugin-package-workflow-administration');
const root = require('../dist');
assert.equal(
subpath.normalizeAuthorizedPluginPackageWorkflowAdmission,
normalizeAuthorizedPluginPackageWorkflowAdmission,
);
assert.equal(
root.normalizeAuthorizedPluginPackageWorkflowAdmission,
undefined,
);
});
test('binds Workflow cancellation to run.stop audit identity and low-sensitive result', () => {
const cancellation = {
projectId: 'project-1',
packageName: 'example-package',
runId: '95000000-0000-4000-8000-000000000001',
mutationId: '9a000000-0000-4000-8000-000000000001',
runEventId: '9b000000-0000-4000-8000-000000000001',
actor: { type: 'user', id: 'workflow-owner' },
fence: { projectVersion: 2, bindingVersion: 3 },
audit: {
eventId: '9c000000-0000-4000-8000-000000000001',
requestId: 'workflow-cancel-1',
operationId: 'workflow.cancel',
projectId: 'project-1',
subject: { type: 'user', id: 'workflow-owner' },
authenticationId: 'workflow-administration-authentication',
outcome: 'allowed',
reasons: ['permission_granted'],
fence: { projectVersion: 2, bindingVersion: 3 },
occurredAtMs: 4_000,
},
};
assert.deepEqual(
normalizeAuthorizedPluginPackageWorkflowCancellation(cancellation),
cancellation,
);
assert.throws(
() =>
normalizeAuthorizedPluginPackageWorkflowCancellation({
...cancellation,
audit: { ...cancellation.audit, operationId: 'workflow.start' },
}),
InvalidPluginPackageWorkflowAdministrationMutationError,
);
assert.deepEqual(
normalizePluginPackageWorkflowCancellationResult({
status: 'accepted',
projectId: cancellation.projectId,
packageName: cancellation.packageName,
workflowId: 'daily',
runId: cancellation.runId,
runStatus: 'running',
runVersion: 5,
eventSequence: 5,
cancelRequestedAtMs: 4_000,
cancelReason: 'user',
}),
{
status: 'accepted',
projectId: cancellation.projectId,
packageName: cancellation.packageName,
workflowId: 'daily',
runId: cancellation.runId,
runStatus: 'running',
runVersion: 5,
eventSequence: 5,
cancelRequestedAtMs: 4_000,
cancelReason: 'user',
},
);
});
test('binds Workflow Run inspection to an exact allowed audit fence and target', () => {
const inspection = {
projectId: 'project-1',
packageName: 'example-package',
workflowId: 'daily',
runId: '95000000-0000-4000-8000-000000000002',
actor: { type: 'user', id: 'workflow-owner' },
fence: { projectVersion: 2, bindingVersion: 3 },
audit: {
eventId: '9c000000-0000-4000-8000-000000000002',
requestId: 'workflow-inspect-1',
operationId: 'workflow.run.read',
projectId: 'project-1',
subject: { type: 'user', id: 'workflow-owner' },
authenticationId: 'workflow-administration-authentication',
outcome: 'allowed',
reasons: ['permission_granted'],
fence: { projectVersion: 2, bindingVersion: 3 },
occurredAtMs: 4_000,
},
};
assert.deepEqual(
normalizeAuthorizedPluginPackageWorkflowRunInspection(inspection),
inspection,
);
for (const invalid of [
{
...inspection,
audit: { ...inspection.audit, operationId: 'workflow.read' },
},
{
...inspection,
audit: { ...inspection.audit, projectId: 'project-2' },
},
{
...inspection,
fence: { ...inspection.fence, bindingVersion: 4 },
},
{ ...inspection, workflowId: 'Daily' },
{ ...inspection, unexpected: true },
]) {
assert.throws(
() => normalizeAuthorizedPluginPackageWorkflowRunInspection(invalid),
InvalidPluginPackageWorkflowAdministrationMutationError,
);
}
});
test('normalizes a low-sensitive Workflow Run inspection projection and missing target', () => {
const target = {
schema: PLUGIN_PACKAGE_WORKFLOW_RUN_INSPECTION_SCHEMA,
projectId: 'project-1',
packageName: 'example-package',
workflowId: 'daily',
runId: '95000000-0000-4000-8000-000000000002',
};
const stepStatusCounts = {
pending: 0,
ready: 1,
waiting_approval: 0,
running: 1,
lost: 0,
succeeded: 1,
failed: 0,
skipped: 0,
cancelled: 0,
timed_out: 0,
};
const found = {
...target,
found: true,
run: {
status: 'running',
version: 4,
eventSequence: 3,
createdAtMs: 1_000,
queuedAtMs: 1_100,
startedAtMs: 1_200,
finishedAtMs: null,
cancelRequestedAtMs: 1_300,
cancelReason: 'user',
},
stepCount: 3,
stepStatusCounts,
};
const normalized = normalizePluginPackageWorkflowRunInspectionResult(found);
assert.deepEqual(normalized, found);
assert.ok(Object.isFrozen(normalized));
assert.ok(Object.isFrozen(normalized.run));
assert.ok(Object.isFrozen(normalized.stepStatusCounts));
assert.deepEqual(
normalizePluginPackageWorkflowRunInspectionResult({
...target,
found: false,
run: null,
stepCount: null,
stepStatusCounts: null,
}),
{
...target,
found: false,
run: null,
stepCount: null,
stepStatusCounts: null,
},
);
for (const invalid of [
{ ...found, unexpected: true },
{ ...found, stepCount: 4 },
{
...found,
run: { ...found.run, cancelRequestedAtMs: null },
},
{
...found,
stepStatusCounts: { ...stepStatusCounts, unknown: 0 },
},
{
...target,
found: false,
run: found.run,
stepCount: null,
stepStatusCounts: null,
},
]) {
assert.throws(
() => normalizePluginPackageWorkflowRunInspectionResult(invalid),
InvalidPluginPackageWorkflowAdministrationMutationError,
);
}
});
test('binds a bounded Workflow Run list to run.read authority and a newest-first cursor', () => {
const query = {
projectId: 'project-1',
packageName: 'example-package',
workflowId: 'daily',
limit: 32,
after: {
admittedAtMs: 2_000,
runId: '95000000-0000-4000-8000-000000000012',
},
actor: { type: 'user', id: 'workflow-owner' },
fence: { projectVersion: 2, bindingVersion: 3 },
audit: {
eventId: '9c000000-0000-4000-8000-000000000012',
requestId: 'workflow-run-list-1',
operationId: 'workflow.run.list',
projectId: 'project-1',
subject: { type: 'user', id: 'workflow-owner' },
authenticationId: 'workflow-administration-authentication',
outcome: 'allowed',
reasons: ['permission_granted'],
fence: { projectVersion: 2, bindingVersion: 3 },
occurredAtMs: 4_000,
},
};
assert.deepEqual(normalizeAuthorizedPluginPackageWorkflowRunList(query), query);
for (const invalid of [
{ ...query, limit: 65 },
{ ...query, after: { admittedAtMs: -1, runId: query.after.runId } },
{ ...query, audit: { ...query.audit, operationId: 'workflow.run.read' } },
{ ...query, unexpected: true },
]) {
assert.throws(
() => normalizeAuthorizedPluginPackageWorkflowRunList(invalid),
InvalidPluginPackageWorkflowAdministrationMutationError,
);
}
});
test('normalizes only a low-sensitive newest-first Workflow Run page', () => {
const target = {
schema: PLUGIN_PACKAGE_WORKFLOW_RUN_LIST_SCHEMA,
projectId: 'project-1',
packageName: 'example-package',
workflowId: 'daily',
after: null,
};
const runs = [
{
runId: '95000000-0000-4000-8000-000000000012',
status: 'running',
version: 2,
eventSequence: 1,
stepCount: 2,
admittedAtMs: 2_000,
queuedAtMs: 2_001,
startedAtMs: 2_002,
finishedAtMs: null,
cancelRequestedAtMs: null,
cancelReason: null,
},
{
runId: '95000000-0000-4000-8000-000000000011',
status: 'queued',
version: 1,
eventSequence: 0,
stepCount: 1,
admittedAtMs: 2_000,
queuedAtMs: 2_000,
startedAtMs: null,
finishedAtMs: null,
cancelRequestedAtMs: null,
cancelReason: null,
},
];
const page = {
...target,
runs,
truncated: true,
next: { admittedAtMs: 2_000, runId: runs[1].runId },
};
const normalized = normalizePluginPackageWorkflowRunListResult(page);
assert.deepEqual(normalized, page);
assert.ok(Object.isFrozen(normalized));
assert.ok(Object.isFrozen(normalized.runs));
assert.ok(Object.isFrozen(normalized.runs[0]));
assert.deepEqual(
normalizePluginPackageWorkflowRunListResult({
...target,
runs: [],
truncated: false,
next: null,
}),
{ ...target, runs: [], truncated: false, next: null },
);
for (const invalid of [
{ ...page, runs: [...runs].reverse() },
{ ...page, next: { admittedAtMs: 2_000, runId: runs[0].runId } },
{
...page,
runs: [{ ...runs[0], planDigest: 'private' }],
truncated: false,
next: null,
},
{ ...page, unexpected: true },
]) {
assert.throws(
() => normalizePluginPackageWorkflowRunListResult(invalid),
InvalidPluginPackageWorkflowAdministrationMutationError,
);
}
});
test('binds a bounded Workflow StepRun list to run.read authority and a keyset cursor', () => {
const query = {
projectId: 'project-1',
packageName: 'example-package',
workflowId: 'daily',
runId: '95000000-0000-4000-8000-000000000003',
limit: 32,
after: {
stepKey: 'collect',
id: '95000000-0000-4000-8000-000000000004',
},
actor: { type: 'user', id: 'workflow-owner' },
fence: { projectVersion: 2, bindingVersion: 3 },
audit: {
eventId: '9c000000-0000-4000-8000-000000000003',
requestId: 'workflow-step-list-1',
operationId: 'workflow.step.list',
projectId: 'project-1',
subject: { type: 'user', id: 'workflow-owner' },
authenticationId: 'workflow-administration-authentication',
outcome: 'allowed',
reasons: ['permission_granted'],
fence: { projectVersion: 2, bindingVersion: 3 },
occurredAtMs: 4_000,
},
};
assert.deepEqual(
normalizeAuthorizedPluginPackageWorkflowStepRunList(query),
query,
);
for (const invalid of [
{ ...query, limit: 65 },
{ ...query, after: { stepKey: 'collect' } },
{
...query,
audit: { ...query.audit, operationId: 'workflow.run.read' },
},
{ ...query, unexpected: true },
]) {
assert.throws(
() => normalizeAuthorizedPluginPackageWorkflowStepRunList(invalid),
InvalidPluginPackageWorkflowAdministrationMutationError,
);
}
});
test('normalizes only the low-sensitive ordered Workflow StepRun page', () => {
const target = {
schema: PLUGIN_PACKAGE_WORKFLOW_STEP_RUN_LIST_SCHEMA,
projectId: 'project-1',
packageName: 'example-package',
workflowId: 'daily',
runId: '95000000-0000-4000-8000-000000000003',
};
const stepRuns = [
{
id: '95000000-0000-4000-8000-000000000004',
parentStepRunId: null,
stepKey: 'collect',
kind: 'task',
required: true,
status: 'ready',
version: 1,
attemptCount: 0,
readyAtMs: 1_100,
startedAtMs: null,
finishedAtMs: null,
resultCode: null,
createdAtMs: 1_000,
updatedAtMs: 1_100,
},
{
id: '95000000-0000-4000-8000-000000000005',
parentStepRunId: null,
stepKey: 'summarize',
kind: 'task',
required: true,
status: 'running',
version: 2,
attemptCount: 1,
readyAtMs: 1_100,
startedAtMs: 1_200,
finishedAtMs: null,
resultCode: null,
createdAtMs: 1_000,
updatedAtMs: 1_200,
},
];
const found = {
...target,
found: true,
stepRuns,
truncated: true,
next: { stepKey: 'summarize', id: stepRuns[1].id },
};
const normalized = normalizePluginPackageWorkflowStepRunListResult(found);
assert.deepEqual(normalized, found);
assert.ok(Object.isFrozen(normalized));
assert.ok(Object.isFrozen(normalized.stepRuns));
assert.ok(Object.isFrozen(normalized.stepRuns[0]));
assert.ok(Object.isFrozen(normalized.next));
assert.deepEqual(
normalizePluginPackageWorkflowStepRunListResult({
...target,
found: false,
stepRuns: [],
truncated: false,
next: null,
}),
{
...target,
found: false,
stepRuns: [],
truncated: false,
next: null,
},
);
for (const invalid of [
{ ...found, next: { stepKey: 'collect', id: stepRuns[0].id } },
{ ...found, stepRuns: [...stepRuns].reverse() },
{
...found,
stepRuns: [{ ...stepRuns[0], inputRef: 'artifact:private' }],
truncated: false,
next: null,
},
{ ...found, unexpected: true },
]) {
assert.throws(
() => normalizePluginPackageWorkflowStepRunListResult(invalid),
InvalidPluginPackageWorkflowAdministrationMutationError,
);
}
});
test('binds a bounded Workflow RunEvent list to run.read and a sequence cursor', () => {
const query = {
projectId: 'project-1',
packageName: 'example-package',
workflowId: 'daily',
runId: '95000000-0000-4000-8000-000000000006',
limit: 32,
afterSequence: 4,
actor: { type: 'user', id: 'workflow-owner' },
fence: { projectVersion: 2, bindingVersion: 3 },
audit: {
eventId: '9c000000-0000-4000-8000-000000000004',
requestId: 'workflow-event-list-1',
operationId: 'workflow.event.list',
projectId: 'project-1',
subject: { type: 'user', id: 'workflow-owner' },
authenticationId: 'workflow-administration-authentication',
outcome: 'allowed',
reasons: ['permission_granted'],
fence: { projectVersion: 2, bindingVersion: 3 },
occurredAtMs: 4_000,
},
};
assert.deepEqual(
normalizeAuthorizedPluginPackageWorkflowRunEventList(query),
query,
);
for (const invalid of [
{ ...query, limit: 65 },
{ ...query, afterSequence: -1 },
{
...query,
audit: { ...query.audit, operationId: 'workflow.run.read' },
},
{ ...query, unexpected: true },
]) {
assert.throws(
() => normalizeAuthorizedPluginPackageWorkflowRunEventList(invalid),
InvalidPluginPackageWorkflowAdministrationMutationError,
);
}
});
test('normalizes only a contiguous content-free Workflow RunEvent page', () => {
const target = {
schema: PLUGIN_PACKAGE_WORKFLOW_RUN_EVENT_LIST_SCHEMA,
projectId: 'project-1',
packageName: 'example-package',
workflowId: 'daily',
runId: '95000000-0000-4000-8000-000000000006',
afterSequence: 1,
};
const events = [
{
id: '95000000-0000-4000-8000-000000000007',
sequence: 2,
type: 'workflow.task_attempt_admitted',
stepRunId: '95000000-0000-4000-8000-000000000004',
createdAtMs: 1_100,
},
{
id: '95000000-0000-4000-8000-000000000008',
sequence: 3,
type: 'workflow.task_attempt.running',
stepRunId: '95000000-0000-4000-8000-000000000004',
createdAtMs: 1_200,
},
];
const found = {
...target,
found: true,
headSequence: 4,
events,
truncated: true,
nextAfterSequence: 3,
};
const normalized = normalizePluginPackageWorkflowRunEventListResult(found);
assert.deepEqual(normalized, found);
assert.ok(Object.isFrozen(normalized));
assert.ok(Object.isFrozen(normalized.events));
assert.ok(Object.isFrozen(normalized.events[0]));
assert.deepEqual(
normalizePluginPackageWorkflowRunEventListResult({
...target,
found: false,
headSequence: null,
events: [],
truncated: false,
nextAfterSequence: null,
}),
{
...target,
found: false,
headSequence: null,
events: [],
truncated: false,
nextAfterSequence: null,
},
);
for (const invalid of [
{ ...found, nextAfterSequence: 2 },
{ ...found, events: [{ ...events[0], sequence: 3 }, events[1]] },
{
...found,
events: [{ ...events[0], payload: { secret: 'private' } }],
headSequence: 2,
truncated: false,
nextAfterSequence: null,
},
{
...found,
headSequence: 3,
truncated: false,
nextAfterSequence: null,
events: [events[0]],
},
]) {
assert.throws(
() => normalizePluginPackageWorkflowRunEventListResult(invalid),
InvalidPluginPackageWorkflowAdministrationMutationError,
);
}
});
@@ -0,0 +1,259 @@
'use strict';
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidPluginPackageWorkflowCancellationConvergenceError,
resolvePluginPackageWorkflowCancellation,
} = require('@qinglong/runtime-core/plugin-package-workflow-cancellation-convergence');
const {
pluginPackageWorkflowTaskAttemptAdmissionReceiptDigest,
} = require('@qinglong/runtime-core/plugin-package-workflow-task-attempt-admission');
const {
createStepRunRecord,
transitionStepRunRecord,
} = require('@qinglong/runtime-core/step-run');
function run(overrides = {}) {
return {
id: 'workflow-run-1',
projectId: 'default',
taskId: 'workflow-alpha',
taskRevision: 'b'.repeat(64),
triggerType: 'plugin_package_workflow',
executionOrigin: 'system',
executionOwner: 'runtime',
requestId: 'workflow-plan-1',
idempotencyKey: 'plugin-package-workflow:workflow-plan-1',
status: 'running',
version: 5,
eventSequence: 5,
priority: 0,
createdAtMs: 100,
startedAtMs: 200,
cancelRequestedAtMs: 800,
cancelReason: 'user',
...overrides,
};
}
function step(id, stepKey, initialStatus = 'ready', createdAtMs = 300) {
return createStepRunRecord({
id,
runId: 'workflow-run-1',
stepKey,
kind: 'task',
definitionRef: `pkg:demo:${stepKey}`,
definitionDigest: 'a'.repeat(64),
required: true,
initialStatus,
mutationId: `create-${stepKey}`,
createdAtMs,
});
}
function attempt(stepRun, overrides = {}) {
return {
id: `attempt-${stepRun.stepKey}`,
runId: 'workflow-run-1',
stepRunId: stepRun.id,
attempt: 1,
status: 'claimed',
executorType: 'remote_worker',
callbackSequence: 0,
createdAtMs: 400,
leaseExpiresAtMs: 900,
...overrides,
};
}
function admission(stepRun, currentAttempt, overrides = {}) {
const unsigned = {
schema:
'qinglong/plugin-package-workflow-task-attempt-admission@v1',
attemptId: currentAttempt.id,
planDigest: 'c'.repeat(64),
runId: 'workflow-run-1',
stepRunId: stepRun.id,
stepRunVersion: stepRun.version,
stepRunDigest: stepRun.stepRunDigest,
resourceTaskId: stepRun.stepKey,
taskReconciliationReceiptDigest: 'd'.repeat(64),
taskId: `pkg:demo:${stepRun.stepKey}`,
taskRevision: `qltd:v1:1:${'a'.repeat(64)}`,
taskDefinitionDigest: 'a'.repeat(64),
executorType: 'remote_worker',
executionDigest: 'e'.repeat(64),
attemptNumber: 1,
eventId: `admit-${stepRun.stepKey}`,
runVersion: 3,
runEventSequence: 3,
admittedAtMs: 400,
...overrides,
};
return {
...unsigned,
receiptDigest:
pluginPackageWorkflowTaskAttemptAdmissionReceiptDigest(unsigned),
};
}
function active(stepRun, currentAttempt, leaseStatus) {
return {
admission: admission(stepRun, currentAttempt),
attempt: currentAttempt,
leaseStatus,
};
}
test('cancels every non-executing StepRun and terminalizes the Workflow', () => {
const pending = step('step-prepare', 'prepare', 'pending');
const ready = step('step-execute', 'execute');
const resolution = resolvePluginPackageWorkflowCancellation({
run: run(),
stepRuns: [ready, pending],
activeTaskAttempts: [],
observedAtMs: 1_000,
});
assert.deepEqual(
resolution.stepMutations.map(({ stepRun }) => [
stepRun.stepKey,
stepRun.status,
]),
[
['execute', 'cancelled'],
['prepare', 'cancelled'],
],
);
assert.equal(resolution.attemptTransitions.length, 0);
assert.deepEqual(resolution.blockedStepRunIds, []);
assert.equal(resolution.terminalTransition.status, 'cancelled');
assert.equal(resolution.terminalTransition.event.type, 'workflow.cancelled');
assert.equal(resolution.run.status, 'cancelled');
assert.equal(resolution.run.version, 8);
assert.equal(resolution.run.eventSequence, 8);
});
test('settles an unleased claimed Task before cancelling its exact StepRun', () => {
const ready = step('step-execute', 'execute');
const claimed = attempt(ready);
const resolution = resolvePluginPackageWorkflowCancellation({
run: run(),
stepRuns: [ready],
activeTaskAttempts: [active(ready, claimed, null)],
observedAtMs: 1_000,
});
assert.equal(resolution.attemptTransitions.length, 1);
assert.equal(resolution.attemptTransitions[0].previousStatus, 'claimed');
assert.equal(resolution.attemptTransitions[0].attempt.status, 'cancelled');
assert.equal(
resolution.attemptTransitions[0].event.type,
'workflow.task_attempt.cancelled',
);
assert.equal(resolution.attemptTransitions[0].event.sequence, 6);
assert.equal(resolution.stepMutations[0].event.sequence, 7);
assert.equal(resolution.terminalTransition.event.sequence, 8);
assert.equal(resolution.run.status, 'cancelled');
});
test('cancels idle siblings but blocks on leased and running authority', () => {
const leasedStep = step('step-leased', 'leased');
const leasedAttempt = attempt(leasedStep);
const admittedRunningStep = step('step-running', 'running');
const runningStep = transitionStepRunRecord(admittedRunningStep, {
expectedVersion: admittedRunningStep.version,
expectedDigest: admittedRunningStep.stepRunDigest,
mutationId: 'start-running',
to: 'running',
atMs: 500,
});
const runningAttempt = attempt(admittedRunningStep, {
id: 'attempt-running',
status: 'running',
startedAtMs: 500,
});
const idle = step('step-idle', 'idle', 'pending');
const resolution = resolvePluginPackageWorkflowCancellation({
run: run(),
stepRuns: [runningStep, idle, leasedStep],
activeTaskAttempts: [
active(leasedStep, leasedAttempt, 'leased'),
active(admittedRunningStep, runningAttempt, 'leased'),
],
observedAtMs: 1_000,
});
assert.deepEqual(
resolution.blockedAttemptIds,
['attempt-leased', 'attempt-running'],
);
assert.deepEqual(
resolution.blockedStepRunIds,
['step-leased', 'step-running'],
);
assert.deepEqual(
resolution.stepMutations.map(({ stepRun }) => stepRun.stepKey),
['idle'],
);
assert.equal(resolution.terminalTransition, null);
assert.equal(resolution.run.status, 'running');
assert.equal(resolution.run.version, 6);
});
test('maps aggregate timeout without pretending a pending Step timed out', () => {
const pending = step('step-pending', 'pending', 'pending');
const ready = step('step-ready', 'ready');
const claimed = attempt(ready);
const resolution = resolvePluginPackageWorkflowCancellation({
run: run({ cancelReason: 'timeout' }),
stepRuns: [ready, pending],
activeTaskAttempts: [active(ready, claimed, 'released')],
observedAtMs: 1_000,
});
assert.equal(resolution.attemptTransitions[0].attempt.status, 'timed_out');
assert.deepEqual(
resolution.stepMutations.map(({ stepRun }) => [
stepRun.stepKey,
stepRun.status,
]),
[
['pending', 'cancelled'],
['ready', 'timed_out'],
],
);
assert.equal(resolution.run.status, 'timed_out');
assert.equal(resolution.run.errorCode, 'EXECUTION_TIMED_OUT');
});
test('is deterministic and fails closed on stale admission authority', () => {
const ready = step('step-execute', 'execute');
const claimed = attempt(ready);
const input = {
run: run(),
stepRuns: [ready],
activeTaskAttempts: [active(ready, claimed, null)],
observedAtMs: 1_000,
};
assert.deepEqual(
resolvePluginPackageWorkflowCancellation(input),
resolvePluginPackageWorkflowCancellation(input),
);
const refreshed = transitionStepRunRecord(ready, {
expectedVersion: ready.version,
expectedDigest: ready.stepRunDigest,
mutationId: 'refresh-ready',
to: 'ready',
atMs: 700,
});
assert.throws(
() =>
resolvePluginPackageWorkflowCancellation({
...input,
stepRuns: [refreshed],
}),
InvalidPluginPackageWorkflowCancellationConvergenceError,
);
});
@@ -0,0 +1,311 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
createInitialPluginPackageAutomationPublication,
createPluginPackageAutomationLifecyclePublication,
} = require('../dist/plugin-package/pluginPackageAutomationPublication');
const {
createPluginPackageWorkflowAdmissionBundle,
createPluginPackageWorkflowExecutionPlan,
InvalidPluginPackageWorkflowAdmissionReceiptError,
InvalidPluginPackageWorkflowExecutionPlanError,
normalizePluginPackageWorkflowAdmissionReceipt,
normalizePluginPackageWorkflowExecutionPlan,
PluginPackageWorkflowExecutionPlanConflictError,
pluginPackageWorkflowAdmissionReceiptDigest,
pluginPackageWorkflowExecutionPlanDigest,
} = require('@qinglong/runtime-core/plugin-package-workflow-execution-plan');
const {
pluginPackageTaskReconciliationFixture,
} = require('../../../test/contracts/pluginPackageTaskReconciliationRepositoryContract.cjs');
function fixture(namespace = 'workflow-execution-plan') {
const value = pluginPackageTaskReconciliationFixture(namespace, {
workflows: [
{
schema: 'qinglong/plugin-package-workflow-resource@v1',
id: 'daily',
name: 'Daily workflow',
enabled: true,
steps: [
{
id: 'collect',
task: 'alpha',
needs: [],
},
{
id: 'summarize',
task: 'beta',
needs: ['collect'],
},
],
},
],
});
return {
...value,
publication: createInitialPluginPackageAutomationPublication(
value.revision,
value.registry,
2_000,
),
};
}
function planInput(value, overrides = {}) {
return {
planId: 'workflow-plan-001',
runId: 'workflow-run-001',
workflowId: 'daily',
stepRunIds: {
collect: 'step-run-collect-001',
summarize: 'step-run-summarize-001',
},
publication: value.publication,
revision: value.revision,
taskSpecSemanticRegistry: value.registry,
plannedAtMs: 3_000,
...overrides,
};
}
test('binds one active publication and exact materialized Tasks into a canonical DAG plan', () => {
const value = fixture();
const plan = createPluginPackageWorkflowExecutionPlan(planInput(value));
assert.equal(
plan.target.publicationDigest,
value.publication.publicationDigest,
);
assert.equal(
plan.target.materializedRevisionDigest,
value.revision.revisionDigest,
);
assert.equal(plan.target.workflowId, 'daily');
assert.match(plan.target.workflowDefinitionDigest, /^[0-9a-f]{64}$/);
assert.deepEqual(
plan.steps.map(
({ stepKey, taskId, needs, initialStatus, taskDefinitionRef }) => ({
stepKey,
taskId,
needs,
initialStatus,
taskDefinitionRef,
}),
),
[
{
stepKey: 'collect',
taskId: 'alpha',
needs: [],
initialStatus: 'ready',
taskDefinitionRef: `plugin-package:${value.revision.revisionDigest}:task:alpha`,
},
{
stepKey: 'summarize',
taskId: 'beta',
needs: ['collect'],
initialStatus: 'pending',
taskDefinitionRef: `plugin-package:${value.revision.revisionDigest}:task:beta`,
},
],
);
assert.equal(
plan.steps.every(({ required }) => required),
true,
);
assert.equal(plan.planDigest, pluginPackageWorkflowExecutionPlanDigest(plan));
assert.deepEqual(normalizePluginPackageWorkflowExecutionPlan(plan), plan);
assert.deepEqual(
normalizePluginPackageWorkflowExecutionPlan(
JSON.parse(JSON.stringify(plan)),
),
plan,
);
assert.equal(
createPluginPackageWorkflowExecutionPlan(planInput(value)).planDigest,
plan.planDigest,
);
});
test('rejects withdrawn, drifted and incomplete Workflow execution inputs', () => {
const value = fixture('workflow-execution-plan-conflict');
const withdrawn = createPluginPackageAutomationLifecyclePublication({
previous: value.publication,
state: 'withdrawn',
lifecycleEventDigest: 'a'.repeat(64),
publishedAtMs: 2_001,
});
assert.throws(
() =>
createPluginPackageWorkflowExecutionPlan(
planInput(value, { publication: withdrawn }),
),
PluginPackageWorkflowExecutionPlanConflictError,
);
const replacement = fixture('workflow-execution-plan-replacement');
assert.throws(
() =>
createPluginPackageWorkflowExecutionPlan(
planInput(value, { revision: replacement.revision }),
),
PluginPackageWorkflowExecutionPlanConflictError,
);
assert.throws(
() =>
createPluginPackageWorkflowExecutionPlan(
planInput(value, {
stepRunIds: { collect: 'step-run-collect-001' },
}),
),
InvalidPluginPackageWorkflowExecutionPlanError,
);
assert.throws(
() =>
createPluginPackageWorkflowExecutionPlan(
planInput(value, {
stepRunIds: {
collect: 'step-run-shared',
summarize: 'step-run-shared',
},
}),
),
InvalidPluginPackageWorkflowExecutionPlanError,
);
});
test('fails closed when a durable plan digest or generation-bound Task reference drifts', () => {
const value = fixture('workflow-execution-plan-normalization');
const plan = createPluginPackageWorkflowExecutionPlan(planInput(value));
assert.throws(
() =>
normalizePluginPackageWorkflowExecutionPlan({
...plan,
planDigest: 'f'.repeat(64),
}),
InvalidPluginPackageWorkflowExecutionPlanError,
);
assert.throws(
() =>
normalizePluginPackageWorkflowExecutionPlan({
...plan,
steps: plan.steps.map((step) =>
step.stepKey === 'collect'
? {
...step,
taskDefinitionRef:
'plugin-package:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:task:alpha',
}
: step,
),
}),
InvalidPluginPackageWorkflowExecutionPlanError,
);
});
test('derives a deterministic atomic admission bundle and durable receipt', () => {
const value = fixture('workflow-admission-bundle');
const plan = createPluginPackageWorkflowExecutionPlan(planInput(value));
const bundle = createPluginPackageWorkflowAdmissionBundle(plan);
assert.deepEqual(bundle.plan, plan);
assert.equal(bundle.run.id, plan.runId);
assert.equal(bundle.run.status, 'running');
assert.equal(bundle.run.version, 3);
assert.equal(bundle.run.eventSequence, 3);
assert.equal(bundle.admissionEvent.sequence, 1);
assert.equal(bundle.admissionEvent.type, 'workflow.admitted');
assert.equal(bundle.admissionEvent.id.length <= 36, true);
assert.deepEqual(
bundle.stepMutations.map((mutation) => ({
stepKey: mutation.stepRun.stepKey,
status: mutation.stepRun.status,
expectedRunVersion: mutation.expectedRunVersion,
expectedRunEventSequence: mutation.expectedRunEventSequence,
eventSequence: mutation.event.sequence,
})),
[
{
stepKey: 'collect',
status: 'ready',
expectedRunVersion: 1,
expectedRunEventSequence: 1,
eventSequence: 2,
},
{
stepKey: 'summarize',
status: 'pending',
expectedRunVersion: 2,
expectedRunEventSequence: 2,
eventSequence: 3,
},
],
);
assert.equal(bundle.receipt.planDigest, plan.planDigest);
assert.equal(bundle.receipt.finalRunVersion, 3);
assert.equal(bundle.receipt.finalRunEventSequence, 3);
assert.equal(
bundle.receipt.receiptDigest,
pluginPackageWorkflowAdmissionReceiptDigest(bundle.receipt),
);
assert.equal(
bundle.stepMutations.every(
({ event }) => event.id.length <= 36 && event.dedupeKey.length <= 36,
),
true,
);
assert.deepEqual(
normalizePluginPackageWorkflowAdmissionReceipt(
JSON.parse(JSON.stringify(bundle.receipt)),
),
bundle.receipt,
);
assert.deepEqual(createPluginPackageWorkflowAdmissionBundle(plan), bundle);
});
test('rejects tampered Workflow admission receipts and counters', () => {
const value = fixture('workflow-admission-receipt-invalid');
const bundle = createPluginPackageWorkflowAdmissionBundle(
createPluginPackageWorkflowExecutionPlan(planInput(value)),
);
assert.throws(
() =>
normalizePluginPackageWorkflowAdmissionReceipt({
...bundle.receipt,
receiptDigest: 'f'.repeat(64),
}),
InvalidPluginPackageWorkflowAdmissionReceiptError,
);
assert.throws(
() =>
normalizePluginPackageWorkflowAdmissionReceipt({
...bundle.receipt,
finalRunVersion: 2,
}),
InvalidPluginPackageWorkflowAdmissionReceiptError,
);
});
test('keeps Run and RunEvent identities portable across SQLite and PostgreSQL', () => {
const value = fixture('workflow-portable-identity');
assert.throws(
() =>
createPluginPackageWorkflowExecutionPlan(
planInput(value, { runId: `r${'a'.repeat(36)}` }),
),
InvalidPluginPackageWorkflowExecutionPlanError,
);
});
test('publishes the pure planner only through its explicit runtime-core subpath', () => {
const subpath = require('@qinglong/runtime-core/plugin-package-workflow-execution-plan');
const root = require('../dist');
assert.equal(
subpath.createPluginPackageWorkflowExecutionPlan,
createPluginPackageWorkflowExecutionPlan,
);
assert.equal(root.createPluginPackageWorkflowExecutionPlan, undefined);
});
@@ -0,0 +1,324 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
createInitialPluginPackageAutomationPublication,
} = require('../dist/plugin-package/pluginPackageAutomationPublication');
const {
createPluginPackageWorkflowAdmissionBundle,
createPluginPackageWorkflowExecutionPlan,
} = require('@qinglong/runtime-core/plugin-package-workflow-execution-plan');
const {
InvalidPluginPackageWorkflowFrontierError,
resolvePluginPackageWorkflowFrontier,
} = require('@qinglong/runtime-core/plugin-package-workflow-frontier');
const {
transitionStepRunMutation,
} = require('../dist/run/stepRun');
const {
pluginPackageTaskReconciliationFixture,
} = require('../../../test/contracts/pluginPackageTaskReconciliationRepositoryContract.cjs');
function fixture(namespace = 'workflow-frontier', steps) {
const value = pluginPackageTaskReconciliationFixture(namespace, {
workflows: [
{
schema: 'qinglong/plugin-package-workflow-resource@v1',
id: 'daily',
name: 'Daily workflow',
enabled: true,
steps:
steps ??
[
{ id: 'collect', task: 'alpha', needs: [] },
{ id: 'summarize', task: 'beta', needs: ['collect'] },
],
},
],
});
const publication = createInitialPluginPackageAutomationPublication(
value.revision,
value.registry,
2_000,
);
const workflowSteps = steps ?? [
{ id: 'collect', task: 'alpha', needs: [] },
{ id: 'summarize', task: 'beta', needs: ['collect'] },
];
const plan = createPluginPackageWorkflowExecutionPlan({
planId: `${namespace}-plan`,
runId: `${namespace}-run`,
workflowId: 'daily',
stepRunIds: Object.fromEntries(
workflowSteps.map(({ id }) => [id, `${namespace}-${id}`]),
),
publication,
revision: value.revision,
taskSpecSemanticRegistry: value.registry,
plannedAtMs: 3_000,
});
return createPluginPackageWorkflowAdmissionBundle(plan);
}
function transition(stepRun, to, runVersion, runEventSequence, atMs) {
return transitionStepRunMutation(
stepRun,
{
expectedVersion: stepRun.version,
expectedDigest: stepRun.stepRunDigest,
mutationId: `test-${stepRun.stepKey}-${to}-${stepRun.version}`,
to,
atMs,
...(to === 'failed' ? { resultCode: 'task_failed' } : {}),
...(to === 'succeeded'
? { outputRef: `artifact:${stepRun.stepKey}` }
: {}),
},
{
expectedRunVersion: runVersion,
expectedRunEventSequence: runEventSequence,
eventId: `event-${stepRun.stepKey}-${to}-${stepRun.version}`,
dedupeKey: `event-${stepRun.stepKey}-${to}-${stepRun.version}`,
actor: { type: 'executor' },
},
).stepRun;
}
function admittedStepRuns(bundle) {
return bundle.stepMutations.map(({ stepRun }) => stepRun);
}
test('promotes a dependent pending Task after every need succeeds', () => {
const bundle = fixture();
const [collect, summarize] = admittedStepRuns(bundle);
const running = transition(
collect,
'running',
bundle.run.version,
bundle.run.eventSequence,
4_000,
);
const succeeded = transition(
running,
'succeeded',
bundle.run.version + 1,
bundle.run.eventSequence + 1,
5_000,
);
const resolution = resolvePluginPackageWorkflowFrontier({
plan: bundle.plan,
run: {
...bundle.run,
version: bundle.run.version + 2,
eventSequence: bundle.run.eventSequence + 2,
},
stepRuns: [succeeded, summarize],
observedAtMs: 6_000,
});
assert.equal(resolution.stepMutations.length, 1);
assert.equal(resolution.stepMutations[0].previousStatus, 'pending');
assert.equal(resolution.stepMutations[0].stepRun.status, 'ready');
assert.equal(resolution.stepMutations[0].event.id.length <= 36, true);
assert.equal(resolution.stepMutations[0].event.actorType, 'reconciler');
assert.deepEqual(resolution.readyStepRunIds, [summarize.id]);
assert.equal(resolution.terminalStatus, null);
});
test('propagates a required dependency failure through the whole DAG in one pass', () => {
const steps = [
{ id: 'collect', task: 'alpha', needs: [] },
{ id: 'prepare', task: 'beta', needs: ['collect'] },
{ id: 'publish', task: 'alpha', needs: ['prepare'] },
];
const bundle = fixture('workflow-frontier-failure', steps);
const [collect, prepare, publish] = admittedStepRuns(bundle);
const running = transition(
collect,
'running',
bundle.run.version,
bundle.run.eventSequence,
4_000,
);
const failed = transition(
running,
'failed',
bundle.run.version + 1,
bundle.run.eventSequence + 1,
5_000,
);
const resolution = resolvePluginPackageWorkflowFrontier({
plan: bundle.plan,
run: {
...bundle.run,
version: bundle.run.version + 2,
eventSequence: bundle.run.eventSequence + 2,
},
stepRuns: [failed, prepare, publish],
observedAtMs: 6_000,
});
assert.deepEqual(
resolution.stepMutations.map(({ stepRun }) => [
stepRun.stepKey,
stepRun.status,
stepRun.resultCode,
]),
[
['prepare', 'skipped', 'dependency_not_succeeded'],
['publish', 'skipped', 'dependency_not_succeeded'],
],
);
assert.equal(
resolution.stepMutations[1].expectedRunVersion,
resolution.stepMutations[0].expectedRunVersion + 1,
);
assert.deepEqual(resolution.readyStepRunIds, []);
assert.equal(resolution.terminalStatus, 'failed');
assert.equal(resolution.terminalTransition.status, 'failed');
assert.equal(
resolution.terminalTransition.errorCode,
'workflow_step_failed',
);
assert.equal(
resolution.terminalTransition.expectedRunVersion,
bundle.run.version + 4,
);
assert.equal(resolution.terminalTransition.event.id.length <= 36, true);
assert.equal(resolution.terminalTransition.event.type, 'workflow.failed');
});
test('keeps dependents pending while a required predecessor is executable', () => {
const bundle = fixture('workflow-frontier-waiting');
const resolution = resolvePluginPackageWorkflowFrontier({
plan: bundle.plan,
run: bundle.run,
stepRuns: admittedStepRuns(bundle),
observedAtMs: 4_000,
});
assert.deepEqual(resolution.stepMutations, []);
assert.deepEqual(resolution.readyStepRunIds, [
bundle.plan.steps.find(({ stepKey }) => stepKey === 'collect').stepRunId,
]);
assert.equal(resolution.terminalStatus, null);
});
test('returns succeeded only after every required StepRun succeeds', () => {
const bundle = fixture('workflow-frontier-terminal');
const [collect, summarize] = admittedStepRuns(bundle);
const collectRunning = transition(
collect,
'running',
bundle.run.version,
bundle.run.eventSequence,
4_000,
);
const collectSucceeded = transition(
collectRunning,
'succeeded',
bundle.run.version + 1,
bundle.run.eventSequence + 1,
5_000,
);
const summarizeReady = transition(
summarize,
'ready',
bundle.run.version + 2,
bundle.run.eventSequence + 2,
6_000,
);
const summarizeRunning = transition(
summarizeReady,
'running',
bundle.run.version + 3,
bundle.run.eventSequence + 3,
7_000,
);
const summarizeSucceeded = transition(
summarizeRunning,
'succeeded',
bundle.run.version + 4,
bundle.run.eventSequence + 4,
8_000,
);
const resolution = resolvePluginPackageWorkflowFrontier({
plan: bundle.plan,
run: {
...bundle.run,
version: bundle.run.version + 5,
eventSequence: bundle.run.eventSequence + 5,
},
stepRuns: [collectSucceeded, summarizeSucceeded],
observedAtMs: 9_000,
});
assert.deepEqual(resolution.stepMutations, []);
assert.deepEqual(resolution.readyStepRunIds, []);
assert.equal(resolution.terminalStatus, 'succeeded');
assert.equal(resolution.terminalTransition.status, 'succeeded');
assert.equal(resolution.terminalTransition.errorCode, null);
assert.equal(
resolution.terminalTransition.event.sequence,
bundle.run.eventSequence + 6,
);
});
test('fails closed on incomplete or definition-drifted durable StepRuns', () => {
const bundle = fixture('workflow-frontier-corrupt');
const stepRuns = admittedStepRuns(bundle);
assert.throws(
() =>
resolvePluginPackageWorkflowFrontier({
plan: bundle.plan,
run: bundle.run,
stepRuns: stepRuns.slice(0, 1),
observedAtMs: 4_000,
}),
InvalidPluginPackageWorkflowFrontierError,
);
assert.throws(
() =>
resolvePluginPackageWorkflowFrontier({
plan: bundle.plan,
run: bundle.run,
stepRuns: [
{
...stepRuns[0],
definitionDigest: 'f'.repeat(64),
},
stepRuns[1],
],
observedAtMs: 4_000,
}),
InvalidPluginPackageWorkflowFrontierError,
);
});
test('does not advance a Workflow after aggregate cancellation is requested', () => {
const bundle = fixture('workflow-frontier-cancelled');
assert.throws(
() =>
resolvePluginPackageWorkflowFrontier({
plan: bundle.plan,
run: {
...bundle.run,
cancelRequestedAtMs: 3_500,
cancelReason: 'user',
},
stepRuns: admittedStepRuns(bundle),
observedAtMs: 4_000,
}),
InvalidPluginPackageWorkflowFrontierError,
);
});
test('publishes frontier planning only through its explicit runtime-core subpath', () => {
const subpath = require('@qinglong/runtime-core/plugin-package-workflow-frontier');
const root = require('../dist');
assert.equal(
subpath.resolvePluginPackageWorkflowFrontier,
resolvePluginPackageWorkflowFrontier,
);
assert.equal(root.resolvePluginPackageWorkflowFrontier, undefined);
});
@@ -0,0 +1,254 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
createInitialPluginPackageAutomationPublication,
} = require('../dist/plugin-package/pluginPackageAutomationPublication');
const {
planPluginPackageTaskReconciliation,
pluginPackageTaskReconciliationTaskIds,
} = require('../dist/plugin-package/pluginPackageTaskReconciliation');
const {
createPluginPackageWorkflowAdmissionBundle,
createPluginPackageWorkflowExecutionPlan,
} = require('@qinglong/runtime-core/plugin-package-workflow-execution-plan');
const {
createPluginPackageWorkflowTaskAttemptAdmission,
InvalidPluginPackageWorkflowTaskAttemptAdmissionError,
normalizePluginPackageWorkflowTaskAttemptAdmissionReceipt,
} = require('@qinglong/runtime-core/plugin-package-workflow-task-attempt-admission');
const {
compileLocalCommandTaskDefinition,
} = require('../dist/task-definition/taskDefinitionExecutionCompiler');
const {
pluginPackageTaskReconciliationFixture,
} = require('../../../test/contracts/pluginPackageTaskReconciliationRepositoryContract.cjs');
function fixture(namespace = 'workflow-task-attempt') {
const value = pluginPackageTaskReconciliationFixture(namespace, {
workflows: [
{
schema: 'qinglong/plugin-package-workflow-resource@v1',
id: 'daily',
name: 'Daily workflow',
enabled: true,
steps: [
{ id: 'collect', task: 'alpha', needs: [] },
{ id: 'summarize', task: 'beta', needs: ['collect'] },
],
},
],
});
const publication = createInitialPluginPackageAutomationPublication(
value.revision,
value.registry,
2_000,
);
const plan = createPluginPackageWorkflowExecutionPlan({
planId: `wf-plan-${namespace}`,
runId: `wf-run-${namespace}`,
workflowId: 'daily',
stepRunIds: {
collect: `wf-collect-${namespace}`,
summarize: `wf-summary-${namespace}`,
},
publication,
revision: value.revision,
taskSpecSemanticRegistry: value.registry,
plannedAtMs: 3_000,
});
const admission = createPluginPackageWorkflowAdmissionBundle(plan);
const reconciliationPlan = planPluginPackageTaskReconciliation({
revision: value.revision,
previousReceipt: null,
facts: pluginPackageTaskReconciliationTaskIds(
value.revision,
null,
value.registry,
).map((taskId) => ({
taskId,
packageName: null,
current: null,
})),
committedAtMs: 2_500,
taskSpecSemanticRegistry: value.registry,
});
const taskDefinition = reconciliationPlan.writes.find(
({ definition }) =>
definition.taskId === `pkg:${value.packageName}:alpha`,
).definition;
const executionRevision = compileLocalCommandTaskDefinition(
taskDefinition,
value.registry,
).executionRevision;
const stepRun = admission.stepMutations.find(
({ stepRun }) => stepRun.stepKey === 'collect',
).stepRun;
return {
...value,
publication,
plan,
admission,
reconciliation: reconciliationPlan.receipt,
taskDefinition,
executionRevision,
stepRun,
};
}
function input(value, overrides = {}) {
return {
plan: value.plan,
run: value.admission.run,
stepRun: value.stepRun,
taskReconciliation: value.reconciliation,
execution: value.executionRevision,
attemptNumber: 1,
admittedAtMs: 4_000,
...overrides,
};
}
test('binds one ready source StepRun to one exact executable Task Attempt', () => {
const value = fixture();
const bundle = createPluginPackageWorkflowTaskAttemptAdmission(input(value));
assert.equal(bundle.attempt.runId, value.plan.runId);
assert.equal(bundle.attempt.stepRunId, value.stepRun.id);
assert.equal(bundle.attempt.status, 'claimed');
assert.equal(bundle.attempt.executorType, 'local_process');
assert.equal(bundle.attempt.callbackSequence, 0);
assert.equal(bundle.attempt.id.length <= 36, true);
assert.equal(bundle.event.id.length <= 36, true);
assert.equal(bundle.event.type, 'workflow.task_attempt_admitted');
assert.equal(bundle.event.attemptId, bundle.attempt.id);
assert.equal(bundle.event.stepRunId, value.stepRun.id);
assert.equal(bundle.run.status, 'running');
assert.equal(bundle.run.version, 4);
assert.equal(bundle.run.eventSequence, 4);
assert.equal(
bundle.receipt.resourceTaskId,
'alpha',
);
assert.equal(
bundle.receipt.taskId,
`pkg:${value.packageName}:alpha`,
);
assert.equal(
bundle.receipt.taskRevision,
value.executionRevision.taskRevision,
);
assert.equal(
bundle.receipt.taskReconciliationReceiptDigest,
value.reconciliation.receiptDigest,
);
assert.deepEqual(
normalizePluginPackageWorkflowTaskAttemptAdmissionReceipt(
bundle.receipt,
),
bundle.receipt,
);
assert.deepEqual(
createPluginPackageWorkflowTaskAttemptAdmission(input(value)),
bundle,
);
});
test('keeps Task execution generation-bound instead of reading a current head', () => {
const value = fixture('workflow-task-attempt-binding');
assert.throws(
() =>
createPluginPackageWorkflowTaskAttemptAdmission(
input(value, {
execution: {
...value.executionRevision,
taskId: `pkg:${value.packageName}:beta`,
},
}),
),
InvalidPluginPackageWorkflowTaskAttemptAdmissionError,
);
assert.throws(
() =>
createPluginPackageWorkflowTaskAttemptAdmission(
input(value, {
taskReconciliation: {
...value.reconciliation,
receiptDigest: 'f'.repeat(64),
},
}),
),
InvalidPluginPackageWorkflowTaskAttemptAdmissionError,
);
assert.throws(
() =>
createPluginPackageWorkflowTaskAttemptAdmission(
input(value, {
execution: {
...value.executionRevision,
contentDigest: 'f'.repeat(64),
},
}),
),
InvalidPluginPackageWorkflowTaskAttemptAdmissionError,
);
});
test('rejects pending, cancelled and exhausted admission fences', () => {
const value = fixture('workflow-task-attempt-fence');
const pending = value.admission.stepMutations.find(
({ stepRun }) => stepRun.stepKey === 'summarize',
).stepRun;
assert.throws(
() =>
createPluginPackageWorkflowTaskAttemptAdmission(
input(value, { stepRun: pending }),
),
InvalidPluginPackageWorkflowTaskAttemptAdmissionError,
);
assert.throws(
() =>
createPluginPackageWorkflowTaskAttemptAdmission(
input(value, {
run: {
...value.admission.run,
cancelRequestedAtMs: 3_500,
cancelReason: 'user',
},
}),
),
InvalidPluginPackageWorkflowTaskAttemptAdmissionError,
);
assert.throws(
() =>
createPluginPackageWorkflowTaskAttemptAdmission(
input(value, {
attemptNumber: 8_193,
}),
),
InvalidPluginPackageWorkflowTaskAttemptAdmissionError,
);
});
test('rejects receipt drift and publishes only the explicit subpath', () => {
const value = fixture('workflow-task-attempt-receipt');
const bundle = createPluginPackageWorkflowTaskAttemptAdmission(input(value));
assert.throws(
() =>
normalizePluginPackageWorkflowTaskAttemptAdmissionReceipt({
...bundle.receipt,
attemptNumber: 2,
}),
InvalidPluginPackageWorkflowTaskAttemptAdmissionError,
);
const authority = require('@qinglong/runtime-core/plugin-package-workflow-task-attempt-admission');
const root = require('../dist');
assert.equal(
authority.createPluginPackageWorkflowTaskAttemptAdmission,
createPluginPackageWorkflowTaskAttemptAdmission,
);
assert.equal(
root.createPluginPackageWorkflowTaskAttemptAdmission,
undefined,
);
});
@@ -0,0 +1,264 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidPluginPackageWorkflowTaskRecoveryError,
buildPluginPackageWorkflowTaskRecovery,
} = require('../dist');
const {
pluginPackageWorkflowTaskAttemptAdmissionReceiptDigest,
} = require('@qinglong/runtime-core/plugin-package-workflow-task-attempt-admission');
const {
createStepRunRecord,
transitionStepRunRecord,
} = require('../dist/run/stepRun');
function run(overrides = {}) {
return {
id: 'workflow-run-1',
projectId: 'default',
taskId: 'workflow-alpha',
taskRevision: 'b'.repeat(64),
triggerType: 'plugin_package_workflow',
executionOrigin: 'system',
executionOwner: 'runtime',
requestId: 'workflow-plan-1',
idempotencyKey: 'plugin-package-workflow:workflow-plan-1',
status: 'running',
version: 5,
eventSequence: 5,
priority: 0,
createdAtMs: 100,
startedAtMs: 200,
...overrides,
};
}
function readyStep() {
return createStepRunRecord({
id: 'workflow-step-1',
runId: 'workflow-run-1',
stepKey: 'collect',
kind: 'task',
definitionRef: 'pkg:demo:alpha',
definitionDigest: 'a'.repeat(64),
required: true,
initialStatus: 'ready',
mutationId: 'workflow-step-created',
createdAtMs: 300,
});
}
function attempt(stepRun, overrides = {}) {
return {
id: 'workflow-attempt-1',
runId: 'workflow-run-1',
stepRunId: stepRun.id,
attempt: 1,
status: 'claimed',
executorType: 'remote_worker',
callbackSequence: 0,
createdAtMs: 400,
leaseExpiresAtMs: 900,
...overrides,
};
}
function admission(stepRun, overrides = {}) {
const unsigned = {
schema:
'qinglong/plugin-package-workflow-task-attempt-admission@v1',
attemptId: 'workflow-attempt-1',
planDigest: 'c'.repeat(64),
runId: 'workflow-run-1',
stepRunId: stepRun.id,
stepRunVersion: stepRun.version,
stepRunDigest: stepRun.stepRunDigest,
resourceTaskId: 'alpha',
taskReconciliationReceiptDigest: 'd'.repeat(64),
taskId: 'pkg:demo:alpha',
taskRevision: `qltd:v1:1:${'a'.repeat(64)}`,
taskDefinitionDigest: 'a'.repeat(64),
executorType: 'remote_worker',
executionDigest: 'e'.repeat(64),
attemptNumber: 1,
eventId: 'workflow-attempt-admitted',
runVersion: 3,
runEventSequence: 3,
admittedAtMs: 400,
...overrides,
};
return {
...unsigned,
receiptDigest:
pluginPackageWorkflowTaskAttemptAdmissionReceiptDigest(unsigned),
};
}
test('loses only the expired Attempt and refreshes the exact ready epoch', () => {
const stepRun = readyStep();
const result = buildPluginPackageWorkflowTaskRecovery({
admission: admission(stepRun),
run: run(),
attempt: attempt(stepRun),
stepRun,
reason: 'unstarted_claim_expired',
observedAtMs: 1_000,
});
assert.equal(result.disposition, 'requeued');
assert.equal(result.attempt.status, 'lost');
assert.equal(
result.attempt.errorCode,
'CLUSTER_RECOVERY_UNSTARTED_CLAIM_EXPIRED',
);
assert.equal(result.attemptEvent.sequence, 6);
assert.equal(result.attemptEvent.stepRunId, stepRun.id);
assert.equal(result.run.status, 'running');
assert.equal(result.run.version, 7);
assert.equal(result.run.eventSequence, 7);
assert.equal(result.stepMutations.length, 1);
const refresh = result.stepMutations[0];
assert.equal(refresh.previousStatus, 'ready');
assert.equal(refresh.stepRun.status, 'ready');
assert.equal(refresh.stepRun.version, stepRun.version + 1);
assert.equal(refresh.stepRun.attemptCount, 0);
assert.equal(refresh.stepRun.readyAtMs, stepRun.readyAtMs);
assert.equal(refresh.stepRun.startedAtMs, null);
assert.notEqual(refresh.stepRun.stepRunDigest, stepRun.stepRunDigest);
assert.equal(refresh.event.sequence, 7);
});
test('fails a starting Attempt without pretending that the StepRun ran', () => {
const stepRun = readyStep();
const currentAttempt = attempt(stepRun, {
status: 'starting',
callbackSequence: 1,
});
const result = buildPluginPackageWorkflowTaskRecovery({
admission: admission(stepRun),
run: run(),
attempt: currentAttempt,
stepRun,
reason: 'execution_not_running',
observedAtMs: 1_000,
});
assert.equal(result.disposition, 'failed');
assert.equal(result.run.status, 'running');
assert.equal(result.run.version, 7);
assert.equal(result.attempt.status, 'lost');
assert.equal(result.stepMutations.length, 1);
const failed = result.stepMutations[0].stepRun;
assert.equal(failed.status, 'failed');
assert.equal(failed.attemptCount, 0);
assert.equal(failed.startedAtMs, null);
assert.equal(failed.finishedAtMs, 1_000);
assert.equal(
failed.resultCode,
'cluster_recovery_execution_not_running',
);
});
test('records running→lost→failed before the Workflow frontier settles', () => {
const admittedStep = readyStep();
const runningStep = transitionStepRunRecord(admittedStep, {
expectedVersion: admittedStep.version,
expectedDigest: admittedStep.stepRunDigest,
mutationId: 'workflow-step-running',
to: 'running',
atMs: 500,
});
const currentAttempt = attempt(admittedStep, {
status: 'running',
callbackSequence: 2,
startedAtMs: 500,
});
const result = buildPluginPackageWorkflowTaskRecovery({
admission: admission(admittedStep),
run: run({ version: 6, eventSequence: 6 }),
attempt: currentAttempt,
stepRun: runningStep,
reason: 'execution_not_running',
observedAtMs: 1_000,
});
assert.equal(result.run.status, 'running');
assert.equal(result.run.version, 9);
assert.deepEqual(
result.stepMutations.map(({ previousStatus, stepRun }) => [
previousStatus,
stepRun.status,
]),
[
['running', 'lost'],
['lost', 'failed'],
],
);
assert.deepEqual(
result.stepMutations.map(({ event }) => event.sequence),
[8, 9],
);
assert.equal(result.stepMutations[1].stepRun.startedAtMs, 500);
assert.equal(result.stepMutations[1].stepRun.finishedAtMs, 1_000);
});
test('is deterministic for a durable recovery observation', () => {
const stepRun = readyStep();
const input = {
admission: admission(stepRun),
run: run(),
attempt: attempt(stepRun),
stepRun,
reason: 'unstarted_claim_expired',
observedAtMs: 1_000,
};
assert.deepEqual(
buildPluginPackageWorkflowTaskRecovery(input),
buildPluginPackageWorkflowTaskRecovery(input),
);
});
test('fails closed on cancellation, stale epochs and unsafe reason widening', () => {
const stepRun = readyStep();
const base = {
admission: admission(stepRun),
run: run(),
attempt: attempt(stepRun),
stepRun,
reason: 'unstarted_claim_expired',
observedAtMs: 1_000,
};
assert.throws(
() =>
buildPluginPackageWorkflowTaskRecovery({
...base,
run: run({
cancelRequestedAtMs: 900,
cancelReason: 'user',
}),
}),
InvalidPluginPackageWorkflowTaskRecoveryError,
);
assert.throws(
() =>
buildPluginPackageWorkflowTaskRecovery({
...base,
stepRun: transitionStepRunRecord(stepRun, {
expectedVersion: stepRun.version,
expectedDigest: stepRun.stepRunDigest,
mutationId: 'stale-epoch',
to: 'ready',
atMs: 800,
}),
}),
InvalidPluginPackageWorkflowTaskRecoveryError,
);
assert.throws(
() =>
buildPluginPackageWorkflowTaskRecovery({
...base,
reason: 'execution_not_running',
}),
InvalidPluginPackageWorkflowTaskRecoveryError,
);
});
@@ -0,0 +1,230 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidProjectPolicyValueError,
ProjectPolicyEngine,
ProjectPolicyUnavailableError,
normalizeProjectPermission,
normalizeProjectPolicySnapshot,
normalizeProjectRoleBinding,
} = require('@qinglong/runtime-core/project-policy');
const PROJECT = Object.freeze({
id: 'default',
name: 'Default',
slug: 'default',
status: 'active',
version: 2,
createdAtMs: 0,
updatedAtMs: 1,
});
function binding(overrides = {}) {
return {
projectId: 'default',
subject: { type: 'user', id: 'usr_primary' },
version: 3,
state: 'active',
role: 'operator',
mutationId: 'grant-1',
changedBy: { type: 'user', id: 'usr_owner' },
createdAtMs: 2,
...overrides,
};
}
function engine(snapshot) {
return new ProjectPolicyEngine({
async resolve() {
if (snapshot instanceof Error) throw snapshot;
return snapshot;
},
async append() {
throw new Error('not used');
},
});
}
test('normalizes active and revoked bindings with exact state/role shape', () => {
assert.equal(normalizeProjectRoleBinding(binding()).role, 'operator');
const revoked = binding({ state: 'revoked' });
delete revoked.role;
assert.deepEqual(normalizeProjectRoleBinding(revoked), {
projectId: 'default',
subject: { type: 'user', id: 'usr_primary' },
version: 3,
state: 'revoked',
mutationId: 'grant-1',
changedBy: { type: 'user', id: 'usr_owner' },
createdAtMs: 2,
});
assert.throws(
() => normalizeProjectRoleBinding(binding({ state: 'revoked' })),
InvalidProjectPolicyValueError,
);
});
test('evaluates role matrix, archived state and immutable policy fences', async () => {
const policy = engine({ project: PROJECT, binding: binding() });
assert.deepEqual(
await policy.decide({
subject: { type: 'user', id: 'usr_primary' },
projectId: 'default',
permission: 'run.start',
}),
{
effect: 'allow',
reasons: ['role_grant'],
fence: { projectVersion: 2, bindingVersion: 3 },
},
);
assert.equal(
(
await policy.decide({
subject: { type: 'user', id: 'usr_primary' },
projectId: 'default',
permission: 'project.manage',
})
).effect,
'deny',
);
const archived = engine({
project: { ...PROJECT, status: 'archived' },
binding: binding({ role: 'owner' }),
});
assert.equal(
(
await archived.decide({
subject: { type: 'user', id: 'usr_primary' },
projectId: 'default',
permission: 'run.start',
})
).reasons[0],
'project_archived',
);
});
test('requires approval for an authorized agent write', async () => {
const policy = engine({
project: PROJECT,
binding: binding({
subject: { type: 'agent', id: 'agent_planner' },
role: 'operator',
}),
});
const decision = await policy.decide({
subject: { type: 'agent', id: 'agent_planner' },
projectId: 'default',
permission: 'run.start',
});
assert.equal(decision.effect, 'require_approval');
assert.deepEqual(decision.reasons, ['agent_action_requires_approval']);
});
test('treats approval discovery as read-only without granting decisions', async () => {
assert.equal(normalizeProjectPermission('approval.read'), 'approval.read');
for (const [role, expected] of [
['owner', 'allow'],
['admin', 'allow'],
['operator', 'allow'],
['viewer', 'allow'],
]) {
const subject = { type: 'agent', id: `agent_${role}` };
const decision = await engine({
project: PROJECT,
binding: binding({ subject, role }),
}).decide({ subject, projectId: 'default', permission: 'approval.read' });
assert.equal(decision.effect, expected, role);
}
const decision = await engine({
project: PROJECT,
binding: binding({
subject: { type: 'agent', id: 'agent_operator' },
role: 'operator',
}),
}).decide({
subject: { type: 'agent', id: 'agent_operator' },
projectId: 'default',
permission: 'approval.decide',
});
assert.equal(decision.effect, 'deny');
});
test('grants model invocation only to cost-bearing roles and approval-fences agents', async () => {
assert.equal(normalizeProjectPermission('model.invoke'), 'model.invoke');
for (const [role, subjectType, expected] of [
['owner', 'user', 'allow'],
['admin', 'user', 'allow'],
['operator', 'user', 'allow'],
['viewer', 'user', 'deny'],
['operator', 'agent', 'require_approval'],
]) {
const subject = { type: subjectType, id: `${subjectType}_${role}` };
const decision = await engine({
project: PROJECT,
binding: binding({ subject, role }),
}).decide({
subject,
projectId: 'default',
permission: 'model.invoke',
});
assert.equal(decision.effect, expected, `${subjectType}/${role}`);
}
});
test('limits package administration to admin/owner and approval-fences agents', async () => {
assert.equal(normalizeProjectPermission('package.manage'), 'package.manage');
assert.throws(
() => normalizeProjectPermission('package.install'),
InvalidProjectPolicyValueError,
);
for (const [role, subjectType, expected] of [
['owner', 'user', 'allow'],
['admin', 'user', 'allow'],
['operator', 'user', 'deny'],
['viewer', 'user', 'deny'],
['admin', 'agent', 'require_approval'],
]) {
const decision = await engine({
project: PROJECT,
binding: binding({
subject: { type: subjectType, id: `${subjectType}_${role}` },
role,
}),
}).decide({
subject: { type: subjectType, id: `${subjectType}_${role}` },
projectId: 'default',
permission: 'package.manage',
});
assert.equal(decision.effect, expected, `${subjectType}/${role}`);
}
});
test('denies missing bindings and fails closed on corrupt or unavailable storage', async () => {
assert.equal(
(
await engine({ project: PROJECT }).decide({
subject: { type: 'api_app', id: 'app_reader' },
projectId: 'default',
permission: 'run.read',
})
).reasons[0],
'subject_unbound',
);
await assert.rejects(
engine(new Error('driver detail')).decide({
subject: { type: 'user', id: 'usr_primary' },
projectId: 'default',
permission: 'run.read',
}),
ProjectPolicyUnavailableError,
);
assert.throws(
() =>
normalizeProjectPolicySnapshot({
project: PROJECT,
binding: binding({ projectId: 'other' }),
}),
InvalidProjectPolicyValueError,
);
});
@@ -0,0 +1,524 @@
const assert = require('node:assert/strict');
const { createHash } = require('node:crypto');
const { test } = require('node:test');
const {
createPluginPackageResourceGenerationFromReferences,
} = require('../dist/plugin-package/pluginPackageResourceGeneration');
const {
PLUGIN_PACKAGE_API_VERSION,
PLUGIN_PACKAGE_KIND,
planPluginPackageInstall,
} = require('../dist/plugin-package/pluginPackage');
const {
createPluginPackageLock,
pluginPackageInstallActionDigest,
pluginPackageInstallPlanDigest,
serializePluginPackageManifest,
} = require('../dist/plugin-package/installation/pluginPackageInstall');
const {
pluginPackageContentTreeDigest,
} = require('../dist/plugin-package/pluginPackageBundle');
const {
materializePluginPackageResources,
} = require('../dist/plugin-package/pluginPackageResourceMaterialization');
const {
createBuiltInTaskSpecSemanticRegistry,
} = require('../dist/task-definition/taskSpecSemantic');
const {
InvalidProjectToolDefinitionSnapshotError,
MAX_PROJECT_TOOL_SNAPSHOT_ACTIVE_PACKAGES,
PROJECT_TOOL_DEFINITION_SNAPSHOT_SCHEMA,
ProjectToolDefinitionSnapshotConflictError,
ProjectToolDefinitionSnapshotPublicationCoordinator,
ProjectToolDefinitionSnapshotRecoveryCoordinator,
ProjectToolDefinitionSnapshotUnavailableError,
createProjectToolDefinitionSnapshot,
normalizeProjectToolDefinitionSnapshot,
normalizeProjectToolDefinitionSnapshotRecord,
projectToolDefinitionActiveVectorDigest,
projectToolDefinitionRegistry,
projectToolDefinitionSnapshotContribution,
} = require('@qinglong/runtime-core/project-tool-definition-snapshot');
function toolDefinition(packageName, version = '1.0.0') {
return {
name: `${packageName}.query`,
version,
description: `Queries ${packageName}`,
inputSchema: {
type: 'object',
properties: {},
required: [],
additionalProperties: false,
},
effect: 'read',
risk: 'low',
requiredPermissions: ['run.read'],
timeoutSeconds: 30,
};
}
function fixture(packageName, options = {}) {
const definitions = options.definitions ?? [toolDefinition(packageName)];
const toolPaths = definitions.map(
(_definition, index) => `tools/tool-${index}.json`,
);
const resourceBytes = Object.fromEntries(
definitions.map((definition, index) => [
toolPaths[index],
Buffer.from(
JSON.stringify({
schema: 'qinglong/plugin-package-tool-resource@v1',
definition,
}),
),
]),
);
const descriptors = Object.entries(resourceBytes)
.map(([path, material]) => ({
path,
bytes: material.byteLength,
digest: createHash('sha256').update(material).digest('hex'),
}))
.sort((left, right) => left.path.localeCompare(right.path));
const contentDigest = pluginPackageContentTreeDigest(descriptors);
const manifest = {
apiVersion: PLUGIN_PACKAGE_API_VERSION,
kind: PLUGIN_PACKAGE_KIND,
metadata: {
name: packageName,
displayName: packageName,
version: options.packageVersion ?? '1.0.0',
description: `Package ${packageName}`,
license: 'Apache-2.0',
},
spec: {
compatibility: {
qinglong: '>=3.0.0-0 <4.0.0',
architectures: ['arm64'],
deploymentProfiles: ['edge', 'standalone'],
},
runtimes: [],
resources: {
memory: { recommended: '8Mi' },
disk: { install: '1Mi', working: '1Mi' },
},
permissions: {
network: { allowedHosts: [] },
secrets: [],
tools: definitions.length === 0 ? [] : ['run.read'],
},
contents: {
tasks: [],
workflows: [],
prompts: [],
tools: toolPaths,
},
},
};
const environment = {
qinglongVersion: '3.0.0-alpha.0',
architecture: 'arm64',
deploymentProfile: 'edge',
runtimes: [],
availableMemoryBytes: 128 * 1024 * 1024,
availableDiskBytes: 256 * 1024 * 1024,
};
const plan = planPluginPackageInstall(manifest, environment);
const action = {
lockId: `lock-${packageName}`,
projectId: 'project-001',
manifest,
plan,
environment,
source: {
kind: 'oci',
locator:
`oci://registry.example.com/qinglong/${packageName}@sha256:` +
'a'.repeat(64),
artifactDigest: 'b'.repeat(64),
artifactBytes: 4096,
contentDigest,
},
architecture: 'arm64',
deploymentProfile: 'edge',
targetGeneration: options.generation ?? 1,
};
const lock = createPluginPackageLock({
...action,
approval: {
requestId: `request-${packageName}`,
requestVersion: 1,
dispatchId: `dispatch-${packageName}`,
actionDigest: pluginPackageInstallActionDigest(action),
previewDigest: pluginPackageInstallPlanDigest(plan),
approvedBy: { type: 'user', id: 'owner-001' },
approvedAtMs: 100,
expiresAtMs: 1_000,
fence: { projectVersion: 1, bindingVersion: 1 },
},
createdAtMs: 200,
});
const generation = createPluginPackageResourceGenerationFromReferences({
installationId: `install-${packageName}`,
projectId: lock.projectId,
packageName: lock.packageName,
lockDigest: lock.lockDigest,
generation: lock.targetGeneration,
previousActiveLockDigest: null,
contentDigest,
resources: lock.resources,
});
const registry = createBuiltInTaskSpecSemanticRegistry();
return {
registry,
revision: materializePluginPackageResources({
generation,
lock,
manifestBytes: Buffer.from(serializePluginPackageManifest(manifest)),
resources: generation.resources.map((reference) => ({
reference,
bytes: resourceBytes[reference.path],
})),
taskSpecSemanticRegistry: registry,
}),
};
}
function contribution(value) {
return projectToolDefinitionSnapshotContribution(
value.revision,
value.registry,
);
}
function source(value) {
const planned = contribution(value);
return {
installationId: planned.generation.installationId,
packageName: planned.generation.packageName,
generation: planned.generation.generation,
generationDigest: planned.generation.generationDigest,
lockDigest: planned.generation.lockDigest,
revisionDigest: planned.revisionDigest,
};
}
function sourceAuthority(vectors, pending = []) {
let observation = 0;
const pendingProjects = new Set(pending);
return {
pendingProjects,
calls: [],
async listActiveSourcePage({ projectId, limit, after }) {
if (!after) observation += 1;
const vector = vectors[Math.min(observation - 1, vectors.length - 1)];
const start = after
? vector.findIndex((item) => item.packageName > after.packageName)
: 0;
const page = start < 0 ? [] : vector.slice(start, start + limit);
const truncated = start >= 0 && start + page.length < vector.length;
this.calls.push({
kind: 'sources',
projectId,
after: after?.packageName,
packages: page.map(({ packageName }) => packageName),
});
return {
sources: page,
truncated,
...(truncated
? { next: { packageName: page.at(-1).packageName } }
: {}),
};
},
async listPendingProjectPage({ limit, after }) {
const projects = [...pendingProjects]
.sort()
.filter((projectId) => !after || projectId > after.projectId);
const page = projects.slice(0, limit);
const truncated = page.length < projects.length;
return {
projectIds: page,
truncated,
...(truncated ? { next: { projectId: page.at(-1) } } : {}),
};
},
};
}
function publicationHarness(values, vectors, pending = []) {
const authority = sourceAuthority(vectors, pending);
const revisions = new Map(
values.map((value) => [
value.revision.generation.generationDigest,
value.revision,
]),
);
const records = new Map();
const repository = {
publications: 0,
async findCurrent(projectId) {
return records.get(projectId) ?? null;
},
async publish(snapshot) {
this.publications += 1;
const record = Object.freeze({ snapshot, committedAtMs: 500 });
records.set(snapshot.projectId, record);
authority.pendingProjects.delete(snapshot.projectId);
return Object.freeze({ status: 'created', record });
},
};
const coordinator = new ProjectToolDefinitionSnapshotPublicationCoordinator({
source: authority,
materializedRepository: {
calls: [],
async find(generationDigest) {
this.calls.push(generationDigest);
return revisions.get(generationDigest) ?? null;
},
},
repository,
taskSpecSemanticRegistry:
values[0]?.registry ?? createBuiltInTaskSpecSemanticRegistry(),
pageSize: 1,
});
return { authority, coordinator, records, repository, revisions };
}
test('builds one Project snapshot from the complete active Package vector', () => {
const alpha = fixture('alpha');
const empty = fixture('empty', { definitions: [] });
const snapshot = createProjectToolDefinitionSnapshot({
projectId: 'project-001',
contributions: [contribution(empty), contribution(alpha)],
});
assert.equal(snapshot.schema, PROJECT_TOOL_DEFINITION_SNAPSHOT_SCHEMA);
assert.deepEqual(
snapshot.sources.map(({ packageName }) => packageName),
['alpha', 'empty'],
);
assert.deepEqual(
snapshot.definitions.map(({ packageName, definition }) => ({
packageName,
name: definition.name,
version: definition.version,
})),
[{ packageName: 'alpha', name: 'alpha.query', version: '1.0.0' }],
);
assert.match(snapshot.activeVectorDigest, /^[0-9a-f]{64}$/);
assert.equal(
projectToolDefinitionActiveVectorDigest(
snapshot.projectId,
snapshot.sources,
),
snapshot.activeVectorDigest,
);
assert.match(snapshot.definitionsDigest, /^[0-9a-f]{64}$/);
assert.match(snapshot.snapshotDigest, /^[0-9a-f]{64}$/);
assert.equal(Object.isFrozen(snapshot), true);
assert.deepEqual(normalizeProjectToolDefinitionSnapshot(snapshot), snapshot);
assert.deepEqual(
normalizeProjectToolDefinitionSnapshotRecord({
snapshot,
committedAtMs: 500,
}),
{ snapshot, committedAtMs: 500 },
);
assert.equal(
projectToolDefinitionRegistry(snapshot).resolve('alpha.query', '1.0.0')
.description,
'Queries alpha',
);
});
test('binds empty Packages and source revision changes into snapshot identity', () => {
const alpha = fixture('alpha');
const first = createProjectToolDefinitionSnapshot({
projectId: 'project-001',
contributions: [contribution(alpha)],
});
const empty = fixture('empty', { definitions: [] });
const withEmpty = createProjectToolDefinitionSnapshot({
projectId: 'project-001',
contributions: [contribution(alpha), contribution(empty)],
});
assert.notEqual(first.activeVectorDigest, withEmpty.activeVectorDigest);
assert.notEqual(first.snapshotDigest, withEmpty.snapshotDigest);
const alphaV2 = fixture('alpha', {
packageVersion: '1.0.1',
definitions: [toolDefinition('alpha', '1.0.1')],
});
const next = createProjectToolDefinitionSnapshot({
projectId: 'project-001',
contributions: [contribution(alphaV2)],
});
assert.notEqual(first.activeVectorDigest, next.activeVectorDigest);
assert.notEqual(first.snapshotDigest, next.snapshotDigest);
});
test('uses the canonical Project Policy identity boundary', () => {
const snapshot = createProjectToolDefinitionSnapshot({
projectId: 'Project / 路由设备',
contributions: [],
});
assert.equal(snapshot.projectId, 'Project / 路由设备');
assert.throws(
() =>
createProjectToolDefinitionSnapshot({
projectId: 'project\0invalid',
contributions: [],
}),
InvalidProjectToolDefinitionSnapshotError,
);
});
test('rejects source, ordering, digest and Tool identity drift', () => {
const alpha = fixture('alpha');
const empty = fixture('empty', { definitions: [] });
const snapshot = createProjectToolDefinitionSnapshot({
projectId: 'project-001',
contributions: [contribution(alpha), contribution(empty)],
});
const mutable = JSON.parse(JSON.stringify(snapshot));
assert.throws(
() =>
normalizeProjectToolDefinitionSnapshot({
...mutable,
sources: [...mutable.sources].reverse(),
}),
/uniquely sorted/,
);
assert.throws(
() =>
normalizeProjectToolDefinitionSnapshot({
...mutable,
definitions: [
{
...mutable.definitions[0],
definitionDigest: 'f'.repeat(64),
},
],
}),
/definition digest does not match/,
);
assert.throws(
() =>
createProjectToolDefinitionSnapshot({
projectId: 'project-001',
contributions: [contribution(alpha), contribution(alpha)],
}),
/Package source is duplicated/,
);
});
test('enforces the active Package budget before normalizing revisions', () => {
const alpha = fixture('alpha');
assert.throws(
() =>
createProjectToolDefinitionSnapshot({
projectId: 'project-001',
contributions: Array.from(
{ length: MAX_PROJECT_TOOL_SNAPSHOT_ACTIVE_PACKAGES + 1 },
() => contribution(alpha),
),
}),
InvalidProjectToolDefinitionSnapshotError,
);
});
test('publishes one current snapshot through paged double observation', async () => {
const alpha = fixture('alpha');
const empty = fixture('empty', { definitions: [] });
const vector = [source(alpha), source(empty)];
const harness = publicationHarness([alpha, empty], [vector, vector]);
const result = await harness.coordinator.publishCurrent('project-001');
assert.equal(result.status, 'created');
assert.deepEqual(
result.record.snapshot.sources.map(({ packageName }) => packageName),
['alpha', 'empty'],
);
assert.deepEqual(
harness.authority.calls.map(({ packages }) => packages),
[['alpha'], ['empty'], ['alpha'], ['empty']],
);
assert.equal(harness.repository.publications, 1);
harness.authority.calls.length = 0;
const replay = await harness.coordinator.publishCurrent('project-001');
assert.equal(replay.status, 'existing');
assert.deepEqual(replay.record, result.record);
assert.deepEqual(harness.authority.calls, []);
});
test('fails closed when the active vector changes between observations', async () => {
const alpha = fixture('alpha');
const empty = fixture('empty', { definitions: [] });
const harness = publicationHarness(
[alpha, empty],
[[source(alpha)], [source(alpha), source(empty)]],
);
await assert.rejects(
harness.coordinator.publishCurrent('project-001'),
ProjectToolDefinitionSnapshotConflictError,
);
assert.equal(harness.repository.publications, 0);
});
test('fails closed when an observed source has no exact immutable revision', async () => {
const alpha = fixture('alpha');
const harness = publicationHarness([], [[source(alpha)], [source(alpha)]]);
await assert.rejects(
harness.coordinator.publishCurrent('project-001'),
ProjectToolDefinitionSnapshotUnavailableError,
);
assert.equal(harness.repository.publications, 0);
});
test('bounded snapshot recovery drains pending Projects and probes from the start', async () => {
const harness = publicationHarness([], [[], []], ['project-a', 'project-b']);
const recovery = new ProjectToolDefinitionSnapshotRecoveryCoordinator({
source: harness.authority,
publisher: harness.coordinator,
});
assert.deepEqual(await recovery.recover({ pageSize: 1, maxPages: 3 }), {
pages: 2,
scanned: 2,
settled: 2,
retry: 0,
manualRequired: 0,
remaining: false,
safeToAdmit: true,
});
assert.equal(harness.records.has('project-a'), true);
assert.equal(harness.records.has('project-b'), true);
});
test('publishes snapshot planning only through its explicit subpath', () => {
assert.equal(
require('../dist').createProjectToolDefinitionSnapshot,
undefined,
);
assert.equal(
typeof require('../dist/tool-execution/tool-registry/projectToolDefinitionSnapshot')
.createProjectToolDefinitionSnapshot,
'function',
);
assert.equal(
require('../dist').ProjectToolDefinitionSnapshotPublicationCoordinator,
undefined,
);
assert.equal(
typeof require('../dist/tool-execution/tool-registry/projectToolDefinitionSnapshot')
.ProjectToolDefinitionSnapshotPublicationCoordinator,
'function',
);
});
@@ -0,0 +1,156 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
canonicalRemoteWorkerCapabilities,
createClusterRemoteExecutionOffer,
effectiveRemoteWorkerPlacement,
evaluateRemoteWorkerPlacement,
} = require('../dist/remote-execution/remoteDispatch');
const {
createClusterTaskExecutionRevision,
} = require('../dist/task-definition/clusterExecutionRevision');
const { digestRunDispatchLeaseToken } = require('../dist/run/runDispatchLease');
const SESSION = '018f0000-0000-7000-8000-000000000001';
const TOKEN = 'worker_generated_lease_capability_0000000000000001';
const SOURCE_DIGEST = 'a'.repeat(64);
const TASK_REVISION = `qltd:v1:1:${SOURCE_DIGEST}`;
function worker() {
const snapshot = canonicalRemoteWorkerCapabilities({
architecture: 'arm64',
executors: ['remote-worker'],
operatingSystem: 'linux',
runtimes: [{ name: 'node', version: '24.18.0' }],
labels: { region: 'cn-east', tier: 'edge' },
capacity: { memoryBytes: 512 * 1024 * 1024 },
features: ['artifact-v1'],
});
return {
workerId: 'edge-1',
sessionId: SESSION,
generation: 2,
status: 'online',
version: 3,
capabilitiesJson: snapshot.json,
capabilitiesHash: snapshot.hash,
maxConcurrentRuns: 2,
availableSlots: 1,
registeredAtMs: 1,
lastHeartbeatAtMs: 10,
leaseExpiresAtMs: 60_000,
updatedAtMs: 10,
};
}
function revision() {
return createClusterTaskExecutionRevision({
projectId: 'project-1',
taskId: 'task-1',
taskRevision: TASK_REVISION,
sourceRevision: 1,
sourceContentDigest: SOURCE_DIGEST,
executorType: 'remote_worker',
planSchema: 'qinglong/command-execution@v1',
command: { kind: 'argv', file: '/usr/bin/node', args: ['job.js'] },
environment: [],
placement: {
required: {
architectures: ['arm64'],
runtimes: [{ name: 'node', versionRange: '^24.0.0' }],
minMemoryBytes: 256 * 1024 * 1024,
features: ['artifact-v1'],
},
preferred: [{ labels: { region: 'cn-east' }, weight: 7 }],
},
createdAtMs: 1,
});
}
test('canonicalizes bounded capabilities and applies required/preferred placement', () => {
const value = worker();
const decision = evaluateRemoteWorkerPlacement(
value,
revision().placement,
20_000,
);
assert.deepEqual(decision, { matches: true, score: 7, mismatches: [] });
assert.deepEqual(
effectiveRemoteWorkerPlacement({ required: { architectures: ['arm64'] } })
.required.executors,
['remote-worker'],
);
assert.throws(
() => effectiveRemoteWorkerPlacement({ required: { executors: ['docker'] } }),
/must require remote-worker/,
);
});
test('rejects non-canonical snapshots and reports bounded mismatch classes', () => {
const value = worker();
const reordered = {
...value,
capabilitiesJson: JSON.stringify({ executors: ['remote-worker'], architecture: 'arm64' }),
};
reordered.capabilitiesHash = require('node:crypto')
.createHash('sha256')
.update(reordered.capabilitiesJson)
.digest('hex');
assert.throws(
() => evaluateRemoteWorkerPlacement(reordered, {}, 1),
/not canonical/,
);
const decision = evaluateRemoteWorkerPlacement(
value,
{ required: { architectures: ['x64'], labels: { region: 'eu' } } },
20_000,
);
assert.deepEqual(decision.mismatches, ['architecture', 'label']);
});
test('builds one offer only when candidate, Worker, lease and revision fences agree', () => {
const executionRevision = revision();
const candidate = {
runId: 'run-1',
attemptId: 'attempt-1',
projectId: 'project-1',
taskId: 'task-1',
taskRevision: TASK_REVISION,
priority: 1,
queuedAtMs: 10,
attemptCreatedAtMs: 11,
attemptNumber: 1,
executorType: 'remote_worker',
};
const lease = {
attemptId: 'attempt-1',
runId: 'run-1',
status: 'leased',
version: 0,
leaseGeneration: 1,
workerId: 'edge-1',
workerSessionId: SESSION,
workerGeneration: 2,
leaseTokenDigest: digestRunDispatchLeaseToken(TOKEN),
acquiredAtMs: 20,
renewedAtMs: 20,
expiresAtMs: 30_020,
updatedAtMs: 20,
};
const offer = createClusterRemoteExecutionOffer({
offerId: 'offer-1',
deliveryKind: 'new_claim',
executionDigest: executionRevision.contentDigest,
candidate,
worker: { workerId: 'edge-1', sessionId: SESSION, generation: 2 },
lease,
leaseToken: TOKEN,
executionRevision,
placementScore: 7,
});
assert.equal(offer.executionRevision.placement.required.executors[0], 'remote-worker');
assert.throws(
() => createClusterRemoteExecutionOffer({ ...offer, leaseToken: `${TOKEN}x` }),
/authority does not match/,
);
});
@@ -0,0 +1,165 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
createClusterTaskExecutionRevision,
} = require('../dist/task-definition/clusterExecutionRevision');
const {
createClusterRemoteExecutionOffer,
} = require('../dist/remote-execution/remoteDispatch');
const {
digestRunDispatchLeaseToken,
} = require('../dist/run/runDispatchLease');
const {
MAX_REMOTE_EXECUTION_OFFER_RESPONSE_BYTES,
REMOTE_EXECUTION_OFFER_DELIVERY_SCHEMA,
createRemoteExecutionOfferPullBody,
parseRemoteExecutionOfferPullResponse,
} = require('../dist/remote-execution/remoteOfferDelivery');
const SESSION = '018f0000-0000-7000-8000-000000000001';
const TOKEN = 'worker_generated_lease_capability_0000000000000001';
const SOURCE_DIGEST = 'a'.repeat(64);
const TASK_REVISION = `qltd:v1:1:${SOURCE_DIGEST}`;
function authority() {
return {
workerId: 'edge-1',
workerSessionId: SESSION,
workerGeneration: 2,
offerId: 'offer-1',
leaseToken: TOKEN,
};
}
function offer() {
const executionRevision = createClusterTaskExecutionRevision({
projectId: 'project-1',
taskId: 'task-1',
taskRevision: TASK_REVISION,
sourceRevision: 1,
sourceContentDigest: SOURCE_DIGEST,
executorType: 'remote_worker',
planSchema: 'qinglong/command-execution@v1',
command: { kind: 'argv', file: '/usr/bin/node', args: ['job.js'] },
environment: [],
createdAtMs: 1,
});
return createClusterRemoteExecutionOffer({
offerId: 'offer-1',
deliveryKind: 'new_claim',
executionDigest: executionRevision.contentDigest,
candidate: {
runId: 'run-1',
attemptId: 'attempt-1',
projectId: 'project-1',
taskId: 'task-1',
taskRevision: TASK_REVISION,
priority: 1,
queuedAtMs: 10,
attemptCreatedAtMs: 11,
attemptNumber: 1,
executorType: 'remote_worker',
},
worker: { workerId: 'edge-1', sessionId: SESSION, generation: 2 },
lease: {
attemptId: 'attempt-1',
runId: 'run-1',
status: 'leased',
version: 3,
leaseGeneration: 1,
workerId: 'edge-1',
workerSessionId: SESSION,
workerGeneration: 2,
leaseTokenDigest: digestRunDispatchLeaseToken(TOKEN),
acquiredAtMs: 20,
renewedAtMs: 21,
expiresAtMs: 30_021,
updatedAtMs: 21,
},
leaseToken: TOKEN,
executionRevision,
placementScore: 0,
});
}
const stats = Object.freeze({
pages: 1,
candidates: 1,
plansUnavailable: 0,
placementMismatches: 0,
claimAttempts: 1,
claimRaces: 0,
});
test('round-trips an authenticated offer without serializing the lease capability', () => {
const body = createRemoteExecutionOfferPullBody({
status: 'offered',
offer: offer(),
stats,
truncated: false,
});
const serialized = JSON.stringify(body);
assert.equal(body.schema, REMOTE_EXECUTION_OFFER_DELIVERY_SCHEMA);
assert.equal(serialized.includes(TOKEN), false);
assert.equal(serialized.includes(digestRunDispatchLeaseToken(TOKEN)), false);
const parsed = parseRemoteExecutionOfferPullResponse(serialized, authority());
assert.equal(parsed.status, 'offered');
assert.equal(parsed.offer.leaseToken, TOKEN);
assert.equal(parsed.offer.lease.version, 3);
assert.equal(parsed.offer.executionDigest, offer().executionDigest);
});
test('rejects target drift, unknown fields and oversized responses', () => {
const body = createRemoteExecutionOfferPullBody({
status: 'offered',
offer: offer(),
stats,
truncated: false,
});
assert.throws(
() => parseRemoteExecutionOfferPullResponse(
JSON.stringify({ ...body, unexpected: true }),
authority(),
),
/shape is invalid/,
);
assert.throws(
() => parseRemoteExecutionOfferPullResponse(
JSON.stringify({
...body,
offer: {
...body.offer,
worker: { ...body.offer.worker, generation: 3 },
},
}),
authority(),
),
/Worker target does not match claim/,
);
assert.throws(
() => parseRemoteExecutionOfferPullResponse(
Buffer.alloc(MAX_REMOTE_EXECUTION_OFFER_RESPONSE_BYTES + 1),
authority(),
),
/byte size/,
);
});
test('validates bounded idle responses with the same versioned schema', () => {
const body = createRemoteExecutionOfferPullBody({
status: 'idle',
reason: 'no_candidates',
stats: { ...stats, candidates: 0, claimAttempts: 0 },
truncated: false,
});
assert.deepEqual(
parseRemoteExecutionOfferPullResponse(JSON.stringify(body), authority()),
{
status: 'idle',
reason: 'no_candidates',
stats: { ...stats, candidates: 0, claimAttempts: 0 },
truncated: false,
},
);
});
@@ -0,0 +1,68 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
assertAcknowledgeRemoteRunRunningCommand,
assertAcknowledgeRemoteRunStartingCommand,
assertFailRemoteRunStartCommand,
} = require('@qinglong/runtime-core/remote-activation');
const SESSION_ID = '018f5c64-9b9d-7f1a-8c2d-1234567890ac';
const EVENT_A = '018f5c64-9b9d-7f1a-8c2d-1234567890a1';
const EVENT_B = '018f5c64-9b9d-7f1a-8c2d-1234567890a2';
function fence() {
return {
runId: 'run-1',
attemptId: 'attempt-1',
workerId: 'edge-1',
workerSessionId: SESSION_ID,
workerGeneration: 2,
offerId: 'offer-1',
leaseGeneration: 3,
leaseToken: 'worker_generated_lease_capability_0000000000000001',
expectedLeaseVersion: 4,
};
}
test('validates starting, running and start-failure activation commands', () => {
assert.doesNotThrow(() => assertAcknowledgeRemoteRunStartingCommand({
...fence(), eventId: EVENT_A,
}));
assert.doesNotThrow(() => assertAcknowledgeRemoteRunRunningCommand({
...fence(),
attemptEventId: EVENT_A,
runEventId: EVENT_B,
executorHandle: 'remote:handle-1',
logArtifactId: 'artifact-1',
callbackSequence: 1,
callbackTokenDigest: 'a'.repeat(64),
}));
assert.doesNotThrow(() => assertFailRemoteRunStartCommand({
...fence(), attemptEventId: EVENT_A, runEventId: EVENT_B,
}));
});
test('rejects unbounded handles and malformed callback digests', () => {
assert.throws(
() => assertAcknowledgeRemoteRunRunningCommand({
...fence(),
attemptEventId: EVENT_A,
runEventId: EVENT_B,
executorHandle: 'x'.repeat(513),
callbackSequence: 1,
callbackTokenDigest: 'a'.repeat(64),
}),
/executorHandle/,
);
assert.throws(
() => assertAcknowledgeRemoteRunRunningCommand({
...fence(),
attemptEventId: EVENT_A,
runEventId: EVENT_B,
executorHandle: 'remote:handle-1',
callbackSequence: 1,
callbackTokenDigest: 'A'.repeat(64),
}),
/callbackTokenDigest/,
);
});
@@ -0,0 +1,97 @@
'use strict';
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
REMOTE_RUN_ACTIVATION_DELIVERY_SCHEMA,
createRemoteRunActivationResponseBody,
parseRemoteRunActivationResponse,
} = require('@qinglong/runtime-core/remote-activation-delivery');
function result(overrides = {}) {
return {
status: 'applied',
snapshot: {
runId: 'run-1',
attemptId: 'attempt-1',
runStatus: 'dispatching',
attemptStatus: 'starting',
leaseVersion: 4,
leaseGeneration: 3,
callbackSequence: 0,
deadlineAtMs: 35_000,
},
...overrides,
};
}
test('round-trips one exact versioned activation response', () => {
const body = createRemoteRunActivationResponseBody(result());
assert.deepEqual(body, {
schema: REMOTE_RUN_ACTIVATION_DELIVERY_SCHEMA,
...result(),
});
assert.deepEqual(
parseRemoteRunActivationResponse(JSON.stringify(body)),
result(),
);
assert.equal(Object.isFrozen(body), true);
assert.equal(Object.isFrozen(body.snapshot), true);
});
test('rejects schema drift, unknown fields and incomplete terminal snapshots', () => {
const body = createRemoteRunActivationResponseBody(result());
assert.throws(
() => parseRemoteRunActivationResponse(JSON.stringify({
...body,
schema: 'qinglong/remote-run-activation@v2',
})),
/response schema is invalid/,
);
assert.throws(
() => parseRemoteRunActivationResponse(JSON.stringify({
...body,
capability: 'must-not-cross-wire',
})),
/response shape is invalid/,
);
assert.throws(
() => createRemoteRunActivationResponseBody({
status: 'already_terminal',
snapshot: {},
}),
/snapshot shape is invalid/,
);
});
test('bounds response bytes, status values and optional diagnostic fields', () => {
assert.throws(
() => parseRemoteRunActivationResponse(Buffer.alloc(16 * 1024 + 1)),
/response byte size/,
);
assert.throws(
() => createRemoteRunActivationResponseBody(result({
snapshot: { ...result().snapshot, deadlineAtMs: -1 },
})),
/deadlineAtMs is invalid/,
);
assert.throws(
() => createRemoteRunActivationResponseBody(result({ status: 'unknown' })),
/status is invalid/,
);
assert.throws(
() => createRemoteRunActivationResponseBody(result({
status: 'already_running',
})),
/status and snapshot state disagree/,
);
assert.throws(
() => createRemoteRunActivationResponseBody(result({
snapshot: {
...result().snapshot,
executorHandle: 'x'.repeat(513),
},
})),
/executorHandle is invalid/,
);
});
@@ -0,0 +1,111 @@
'use strict';
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
MAX_REMOTE_SECRET_DELIVERY_RESPONSE_BYTES,
createRemoteWorkerSecretDeliveryRequestBody,
createRemoteWorkerSecretDeliveryResponseBody,
normalizeRemoteWorkerSecretDeliveryCommand,
parseRemoteWorkerSecretDeliveryResponse,
} = require('../dist/remote-execution/remoteSecretDelivery');
const { createSecretRef } = require('../dist/secret/secretReference');
const SESSION_ID = '018f0000-0000-7000-8000-000000000001';
const DIGEST = 'a'.repeat(64);
const SECRET_REF = createSecretRef({ projectId: 'project-1', name: 'token' });
function command(overrides = {}) {
return {
workerId: 'edge-1',
workerSessionId: SESSION_ID,
workerGeneration: 2,
runId: 'run-1',
attemptId: 'attempt-1',
projectId: 'project-1',
taskId: 'task-1',
taskRevision: 'revision-1',
executionDigest: DIGEST,
offerId: 'offer-1',
leaseGeneration: 3,
leaseToken: 'worker_generated_lease_capability_0000000000000001',
expectedLeaseVersion: 4,
secretRefs: [SECRET_REF],
...overrides,
};
}
test('creates a versioned request without duplicating path-bound identity', () => {
const body = createRemoteWorkerSecretDeliveryRequestBody(command());
assert.equal(body.schema, 'qinglong/remote-secret-delivery@v1');
assert.equal('workerId' in body, false);
assert.equal('workerSessionId' in body, false);
assert.deepEqual(body.secretRefs, [SECRET_REF]);
assert.ok(Object.isFrozen(body));
});
test('parses only an exact authority and ordered Secret set', () => {
const response = createRemoteWorkerSecretDeliveryResponseBody({
runId: 'run-1',
attemptId: 'attempt-1',
offerId: 'offer-1',
executionDigest: DIGEST,
values: [{ secretRef: SECRET_REF, value: 'private-value' }],
}, [SECRET_REF]);
const parsed = parseRemoteWorkerSecretDeliveryResponse(
JSON.stringify(response),
{
runId: 'run-1', attemptId: 'attempt-1', offerId: 'offer-1',
executionDigest: DIGEST, secretRefs: [SECRET_REF],
},
);
assert.deepEqual(parsed.values, [
{ secretRef: SECRET_REF, value: 'private-value' },
]);
assert.throws(
() => parseRemoteWorkerSecretDeliveryResponse(JSON.stringify(response), {
runId: 'run-other', attemptId: 'attempt-1', offerId: 'offer-1',
executionDigest: DIGEST, secretRefs: [SECRET_REF],
}),
/authority does not match/,
);
});
test('rejects duplicate, cross-project and oversized delivery input', () => {
assert.throws(
() => normalizeRemoteWorkerSecretDeliveryCommand(command({
secretRefs: [SECRET_REF, SECRET_REF],
})),
/secretRefs are invalid/,
);
const foreign = createSecretRef({ projectId: 'project-2', name: 'token' });
assert.throws(
() => normalizeRemoteWorkerSecretDeliveryCommand(command({
secretRefs: [foreign],
})),
/project is invalid/,
);
assert.throws(
() => parseRemoteWorkerSecretDeliveryResponse(
Buffer.alloc(MAX_REMOTE_SECRET_DELIVERY_RESPONSE_BYTES + 1),
{
runId: 'run-1', attemptId: 'attempt-1', offerId: 'offer-1',
executionDigest: DIGEST, secretRefs: [SECRET_REF],
},
),
/byte size/,
);
const refs = Array.from({ length: 5 }, (_, index) =>
createSecretRef({ projectId: 'project-1', name: `item-${index}` }));
assert.throws(
() => createRemoteWorkerSecretDeliveryResponseBody({
runId: 'run-1', attemptId: 'attempt-1', offerId: 'offer-1',
executionDigest: DIGEST,
values: refs.map((secretRef) => ({
secretRef,
value: 'x'.repeat(16 * 1024),
})),
}, refs),
/byte budget/,
);
});
@@ -0,0 +1,229 @@
'use strict';
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
MAX_REMOTE_WORKER_ARTIFACT_BYTES,
MAX_REMOTE_WORKER_ARTIFACT_RESPONSE_BYTES,
MAX_REMOTE_WORKER_COMPLETION_RESPONSE_BYTES,
REMOTE_WORKER_ARTIFACT_UPLOAD_SCHEMA,
REMOTE_WORKER_COMPLETION_SCHEMA,
createRemoteWorkerArtifactUploadPreamble,
createRemoteWorkerArtifactUploadRequestHeader,
createRemoteWorkerArtifactUploadResponseBody,
createRemoteWorkerCompletionRequestBody,
createRemoteWorkerCompletionResponseBody,
normalizeRemoteWorkerArtifactUploadCommand,
normalizeRemoteWorkerCompletionCommand,
parseRemoteWorkerArtifactUploadHeader,
parseRemoteWorkerArtifactUploadResponse,
parseRemoteWorkerCompletionRequestBody,
parseRemoteWorkerCompletionResponse,
} = require('../dist/remote-execution/remoteWorkerCompletion');
const SESSION_ID = '018f0000-0000-7000-8000-000000000001';
const LEASE_TOKEN = 'worker_generated_lease_capability_0000000000000001';
const LOG_ARTIFACT_ID = `wlog-${'a'.repeat(30)}`;
const SHA256 = 'b'.repeat(64);
const CALLBACK_TOKEN_DIGEST = 'c'.repeat(64);
function fence(overrides = {}) {
return {
workerId: 'worker-1',
workerSessionId: SESSION_ID,
workerGeneration: 2,
projectId: 'project-1',
runId: 'run-1',
attemptId: 'attempt-1',
offerId: 'offer-1',
leaseGeneration: 3,
leaseToken: LEASE_TOKEN,
expectedLeaseVersion: 4,
...overrides,
};
}
function uploadCommand(overrides = {}) {
return {
...fence(),
logArtifactId: LOG_ARTIFACT_ID,
byteLength: 17,
truncated: false,
...overrides,
};
}
function completionCommand(overrides = {}) {
return {
...fence(),
callbackSequence: 1,
callbackTokenDigest: CALLBACK_TOKEN_DIGEST,
result: {
outcome: 'succeeded',
startedAtMs: 100,
finishedAtMs: 200,
exitCode: 0,
},
artifact: {
logArtifactId: LOG_ARTIFACT_ID,
byteLength: 17,
sha256: SHA256,
truncated: false,
},
...overrides,
};
}
test('frames one exact Artifact header without duplicating path identity', () => {
const command = uploadCommand();
const header = createRemoteWorkerArtifactUploadRequestHeader(command);
assert.equal(header.schema, REMOTE_WORKER_ARTIFACT_UPLOAD_SCHEMA);
assert.equal('workerId' in header, false);
assert.equal('workerSessionId' in header, false);
assert.equal(header.truncated, false);
const preamble = createRemoteWorkerArtifactUploadPreamble(command);
const headerLength = preamble.readUInt32BE(0);
assert.equal(headerLength, preamble.byteLength - 4);
assert.deepEqual(
parseRemoteWorkerArtifactUploadHeader(
preamble.subarray(4),
{ workerId: command.workerId, workerSessionId: command.workerSessionId },
),
normalizeRemoteWorkerArtifactUploadCommand(command),
);
});
test('round-trips immutable Artifact receipts and nullable truncation', () => {
const receipt = {
status: 'stored',
projectId: 'project-1',
runId: 'run-1',
attemptId: 'attempt-1',
logArtifactId: LOG_ARTIFACT_ID,
byteLength: 17,
sha256: SHA256,
};
const body = createRemoteWorkerArtifactUploadResponseBody(receipt);
assert.equal(body.truncated, null);
assert.deepEqual(
parseRemoteWorkerArtifactUploadResponse(JSON.stringify(body)),
receipt,
);
const truncated = createRemoteWorkerArtifactUploadResponseBody({
...receipt,
status: 'already_stored',
truncated: false,
});
assert.equal(
parseRemoteWorkerArtifactUploadResponse(JSON.stringify(truncated)).truncated,
false,
);
});
test('round-trips an exact path-bound completion request and response', () => {
const command = completionCommand();
const request = createRemoteWorkerCompletionRequestBody(command);
assert.equal(request.schema, REMOTE_WORKER_COMPLETION_SCHEMA);
assert.equal('workerId' in request, false);
assert.equal('workerSessionId' in request, false);
assert.deepEqual(
parseRemoteWorkerCompletionRequestBody(request, {
workerId: command.workerId,
workerSessionId: command.workerSessionId,
}),
normalizeRemoteWorkerCompletionCommand(command),
);
const result = {
status: 'applied',
runId: 'run-1',
attemptId: 'attempt-1',
callbackSequence: 1,
};
const response = createRemoteWorkerCompletionResponseBody(result);
assert.deepEqual(
parseRemoteWorkerCompletionResponse(JSON.stringify(response)),
result,
);
assert.equal(Object.isFrozen(response), true);
});
test('rejects widened wire shapes and invalid path authority', () => {
const header = createRemoteWorkerArtifactUploadRequestHeader(uploadCommand());
assert.throws(
() => parseRemoteWorkerArtifactUploadHeader(JSON.stringify({
...header,
workerId: 'body-must-not-own-transport-identity',
}), { workerId: 'worker-1', workerSessionId: SESSION_ID }),
/header shape is invalid/,
);
const request = createRemoteWorkerCompletionRequestBody(completionCommand());
assert.throws(
() => parseRemoteWorkerCompletionRequestBody({
...request,
callbackToken: 'plaintext-is-forbidden',
}, { workerId: 'worker-1', workerSessionId: SESSION_ID }),
/request shape is invalid/,
);
assert.throws(
() => parseRemoteWorkerCompletionRequestBody(request, {
workerId: 'invalid worker id',
workerSessionId: SESSION_ID,
}),
/execution authority is invalid/,
);
});
test('rejects inconsistent completion evidence and oversized Artifacts', () => {
assert.throws(
() => normalizeRemoteWorkerCompletionCommand(completionCommand({
result: {
outcome: 'succeeded',
startedAtMs: 100,
finishedAtMs: 200,
exitCode: 1,
},
})),
/result is inconsistent/,
);
assert.throws(
() => normalizeRemoteWorkerCompletionCommand(completionCommand({
callbackTokenDigest: 'not-a-digest',
})),
/completion evidence is invalid/,
);
assert.throws(
() => normalizeRemoteWorkerArtifactUploadCommand(uploadCommand({
byteLength: MAX_REMOTE_WORKER_ARTIFACT_BYTES + 1,
})),
/byteLength is invalid/,
);
assert.throws(
() => normalizeRemoteWorkerCompletionCommand(completionCommand({
artifact: {
logArtifactId: LOG_ARTIFACT_ID,
byteLength: 17,
sha256: 'not-a-digest',
},
})),
/completion evidence is invalid/,
);
});
test('bounds Artifact and completion response envelopes', () => {
assert.throws(
() => parseRemoteWorkerArtifactUploadResponse(
Buffer.alloc(MAX_REMOTE_WORKER_ARTIFACT_RESPONSE_BYTES + 1),
),
/response byte size is invalid/,
);
assert.throws(
() => parseRemoteWorkerCompletionResponse(
Buffer.alloc(MAX_REMOTE_WORKER_COMPLETION_RESPONSE_BYTES + 1),
),
/response byte size is invalid/,
);
});
@@ -0,0 +1,104 @@
'use strict';
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidRemoteWorkerLeaseControlError,
createRemoteWorkerLeaseControlRequestBody,
createRemoteWorkerLeaseControlResponseBody,
parseRemoteWorkerLeaseControlRequestBody,
parseRemoteWorkerLeaseControlResponse,
} = require('../dist/remote-execution/remoteWorkerLeaseControl');
const SESSION_ID = '018f0000-0000-7000-8000-000000000001';
const LEASE_TOKEN = 'worker_generated_lease_capability_0000000000000001';
function command() {
return {
workerId: 'worker-1',
workerSessionId: SESSION_ID,
workerGeneration: 2,
projectId: 'project-1',
runId: 'run-1',
attemptId: 'attempt-1',
offerId: 'offer-1',
leaseGeneration: 3,
leaseToken: LEASE_TOKEN,
expectedLeaseVersion: 4,
};
}
test('round-trips one path-bound lease control request', () => {
const body = createRemoteWorkerLeaseControlRequestBody(command());
assert.equal(body.schema, 'qinglong/remote-worker-lease-control@v1');
assert.equal('workerId' in body, false);
assert.equal('workerSessionId' in body, false);
assert.deepEqual(parseRemoteWorkerLeaseControlRequestBody(body, {
workerId: 'worker-1',
workerSessionId: SESSION_ID,
}), command());
});
test('round-trips renewed, stop and terminal responses', () => {
const common = {
projectId: 'project-1',
runId: 'run-1',
attemptId: 'attempt-1',
offerId: 'offer-1',
leaseGeneration: 3,
};
for (const result of [
{
...common,
status: 'renewed',
leaseVersion: 5,
renewedAtMs: 100,
expiresAtMs: 30_100,
},
{
...common,
status: 'stop_requested',
leaseVersion: 5,
renewedAtMs: 100,
expiresAtMs: 30_100,
stop: { reason: 'timeout', requestedAtMs: 99 },
},
{
...common,
status: 'terminal',
terminalStatus: 'cancelled',
},
]) {
assert.deepEqual(
parseRemoteWorkerLeaseControlResponse(Buffer.from(JSON.stringify(
createRemoteWorkerLeaseControlResponseBody(result),
))),
result,
);
}
});
test('rejects widened or internally inconsistent control envelopes', () => {
const body = createRemoteWorkerLeaseControlRequestBody(command());
assert.throws(
() => parseRemoteWorkerLeaseControlRequestBody(
{ ...body, workerId: 'worker-1' },
{ workerId: 'worker-1', workerSessionId: SESSION_ID },
),
InvalidRemoteWorkerLeaseControlError,
);
assert.throws(
() => createRemoteWorkerLeaseControlResponseBody({
status: 'stop_requested',
projectId: 'project-1',
runId: 'run-1',
attemptId: 'attempt-1',
offerId: 'offer-1',
leaseGeneration: 3,
leaseVersion: 5,
renewedAtMs: 100,
expiresAtMs: 30_100,
}),
InvalidRemoteWorkerLeaseControlError,
);
});
@@ -0,0 +1,56 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
canonicalRemoteWorkerCapabilities,
evaluateRemoteWorkerPlacement,
normalizeRemoteWorkerPlacement,
} = require('../dist/remote-execution/remoteWorkerPlacement');
function worker(capabilities) {
const snapshot = canonicalRemoteWorkerCapabilities(capabilities);
return {
workerId: 'worker-arm64',
sessionId: '01944c19-7c00-7000-8000-000000000001',
generation: 1,
status: 'online',
version: 0,
capabilitiesJson: snapshot.json,
capabilitiesHash: snapshot.hash,
maxConcurrentRuns: 2,
availableSlots: 1,
registeredAtMs: 100,
lastHeartbeatAtMs: 200,
leaseExpiresAtMs: 10_000,
updatedAtMs: 200,
};
}
test('uses pinned SemVer for remote runtime range admission', () => {
const placement = normalizeRemoteWorkerPlacement({
required: {
architectures: ['arm64'],
runtimes: [{ name: 'node', versionRange: '>=24.18.0 <25' }],
},
});
const candidate = worker({
architecture: 'arm64',
executors: ['remote-worker'],
runtimes: [{ name: 'node', version: '24.18.0' }],
});
assert.deepEqual(evaluateRemoteWorkerPlacement(candidate, placement, 500), {
matches: true,
score: 0,
mismatches: [],
});
assert.throws(
() =>
normalizeRemoteWorkerPlacement({
required: {
runtimes: [{ name: 'node', versionRange: 'not-a-range' }],
},
}),
/versionRange is not semver/,
);
});
@@ -0,0 +1,54 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidRunDispatchLeaseValueError,
assertRunDispatchLeaseRecord,
digestRunDispatchLeaseToken,
} = require('../dist');
test('derives a one-way lease capability digest and validates its exact fence', () => {
const token = 'lease_token_000000000000000000001';
const digest = digestRunDispatchLeaseToken(token);
assert.match(digest, /^[0-9a-f]{64}$/);
assert.equal(digest.includes(token), false);
assert.doesNotThrow(() =>
assertRunDispatchLeaseRecord({
attemptId: 'attempt-1',
runId: 'run-1',
status: 'leased',
version: 0,
leaseGeneration: 1,
workerId: 'worker-a',
workerSessionId: '018f0000-0000-7000-8000-000000000001',
workerGeneration: 1,
leaseTokenDigest: digest,
acquiredAtMs: 10,
renewedAtMs: 10,
expiresAtMs: 20,
updatedAtMs: 10,
}),
);
});
test('rejects raw or malformed capability persistence and partial terminal shape', () => {
assert.throws(
() =>
assertRunDispatchLeaseRecord({
attemptId: 'attempt-1',
runId: 'run-1',
status: 'released',
version: 1,
leaseGeneration: 1,
workerId: 'worker-a',
workerSessionId: '018f0000-0000-7000-8000-000000000001',
workerGeneration: 1,
leaseTokenDigest: 'lease_token_000000000000000000001',
acquiredAtMs: 10,
renewedAtMs: 10,
expiresAtMs: 20,
releasedAtMs: 20,
updatedAtMs: 20,
}),
InvalidRunDispatchLeaseValueError,
);
});
@@ -0,0 +1,40 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidSecretReferenceError,
createSecretRef,
parseSecretRef,
} = require('../dist/secret/secretReference');
const {
createLocalSecretRef,
parseLocalSecretRef,
} = require('../dist/secret/localSecret');
test('keeps qlsecret:v1 profile-neutral and byte-compatible with local aliases', () => {
const reference = { projectId: 'default', name: 'TOKEN', version: 2 };
const value = createSecretRef(reference);
assert.match(value, /^qlsecret:v1:/);
assert.deepEqual(parseSecretRef(value), reference);
assert.equal(createLocalSecretRef(reference), value);
assert.deepEqual(parseLocalSecretRef(value), reference);
assert.equal(Object.isFrozen(parseSecretRef(value)), true);
});
test('rejects non-canonical, cross-shape and unbounded Secret references', () => {
for (const value of [
'qlsecret:v1:',
'qlsecret:v1:***',
'local-secret:default:TOKEN',
`qlsecret:v1:${Buffer.from('{"name":"TOKEN","projectId":"default"}').toString('base64url')}`,
]) {
assert.throws(() => parseSecretRef(value), InvalidSecretReferenceError);
}
assert.throws(
() => createSecretRef({ projectId: 'default', name: 'TOKEN', extra: true }),
InvalidSecretReferenceError,
);
assert.throws(
() => createSecretRef({ projectId: 'x'.repeat(129), name: 'TOKEN' }),
InvalidSecretReferenceError,
);
});
@@ -0,0 +1,89 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidSecurityContractError,
normalizeSecurityPolicyDecision,
normalizeSecurityPrincipal,
} = require('@qinglong/runtime-core/security');
const NOW = 10_000;
test('normalizes an active principal without retaining mutable input', () => {
const input = {
subject: { type: 'user', id: 'usr_primary' },
authenticationId: 'session:abc123',
authenticatedAtMs: 9_000,
expiresAtMs: 11_000,
assurance: 'multi_factor',
};
const principal = normalizeSecurityPrincipal(input, NOW);
input.subject.id = 'usr_changed';
assert.deepEqual(principal, {
subject: { type: 'user', id: 'usr_primary' },
authenticationId: 'session:abc123',
authenticatedAtMs: 9_000,
expiresAtMs: 11_000,
assurance: 'multi_factor',
});
assert.equal(Object.isFrozen(principal), true);
assert.equal(Object.isFrozen(principal.subject), true);
});
test('rejects expired, future, malformed and widened principals', () => {
const principal = {
subject: { type: 'worker', id: 'worker-1' },
authenticationId: 'mtls:worker-1',
authenticatedAtMs: 9_000,
expiresAtMs: 11_000,
assurance: 'service',
};
for (const candidate of [
{ ...principal, expiresAtMs: NOW },
{ ...principal, authenticatedAtMs: NOW + 1 },
{ ...principal, subject: { type: 'root', id: 'root' } },
{ ...principal, debug: true },
]) {
assert.throws(
() => normalizeSecurityPrincipal(candidate, NOW),
InvalidSecurityContractError,
);
}
});
test('normalizes bounded policy decisions and version fences', () => {
const input = {
effect: 'allow',
reasons: ['role_grant'],
fence: { projectVersion: 3, bindingVersion: 7 },
};
const decision = normalizeSecurityPolicyDecision(input);
input.reasons[0] = 'changed';
assert.deepEqual(decision, {
effect: 'allow',
reasons: ['role_grant'],
fence: { projectVersion: 3, bindingVersion: 7 },
});
assert.equal(Object.isFrozen(decision.reasons), true);
});
test('rejects empty or unbounded reasons and invalid fences', () => {
for (const candidate of [
{ effect: 'deny', reasons: [], fence: null },
{ effect: 'unknown', reasons: ['unknown_effect'], fence: null },
{
effect: 'allow',
reasons: ['role-grant'],
fence: { projectVersion: 1, bindingVersion: null },
},
{
effect: 'allow',
reasons: ['role_grant'],
fence: { projectVersion: 0, bindingVersion: null },
},
]) {
assert.throws(
() => normalizeSecurityPolicyDecision(candidate),
InvalidSecurityContractError,
);
}
});
@@ -0,0 +1,70 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidSecurityAuditValueError,
normalizeSecurityAuditRecord,
} = require('@qinglong/runtime-core/security-audit');
function authenticatedRecord(overrides = {}) {
return {
eventId: '123e4567-e89b-42d3-a456-426614174000',
requestId: 'request-1',
operationId: 'run.create',
projectId: 'default',
subject: { type: 'user', id: 'usr_primary' },
authenticationId: 'api_credential:primary:1',
outcome: 'allowed',
reasons: ['role_grant'],
fence: { projectVersion: 2, bindingVersion: 3 },
occurredAtMs: 1_000,
...overrides,
};
}
test('normalizes an immutable low-sensitive authenticated audit fact', () => {
const source = authenticatedRecord();
const normalized = normalizeSecurityAuditRecord(source);
source.subject.id = 'mutated';
source.reasons.push('mutated');
assert.deepEqual(normalized, authenticatedRecord());
assert.equal(Object.isFrozen(normalized), true);
assert.equal(Object.isFrozen(normalized.subject), true);
assert.equal(Object.isFrozen(normalized.reasons), true);
assert.equal(Object.isFrozen(normalized.fence), true);
});
test('accepts pre-authentication rejection only without identity fields', () => {
assert.deepEqual(
normalizeSecurityAuditRecord(
authenticatedRecord({
subject: null,
authenticationId: null,
outcome: 'authentication_rejected',
reasons: ['authentication_rejected'],
fence: null,
}),
).outcome,
'authentication_rejected',
);
});
test('rejects widened, sensitive, inconsistent and malformed audit facts', () => {
const invalid = [
{ ...authenticatedRecord(), body: { secret: true } },
authenticatedRecord({ eventId: 'request-controlled' }),
authenticatedRecord({ requestId: '../escape' }),
authenticatedRecord({ operationId: 'Run Create' }),
authenticatedRecord({ subject: null, authenticationId: null }),
authenticatedRecord({ outcome: 'authentication_rejected' }),
authenticatedRecord({ reasons: ['database password leaked'] }),
authenticatedRecord({ reasons: [] }),
authenticatedRecord({ fence: { projectVersion: 0, bindingVersion: 1 } }),
authenticatedRecord({ occurredAtMs: -1 }),
];
for (const value of invalid) {
assert.throws(
() => normalizeSecurityAuditRecord(value),
InvalidSecurityAuditValueError,
);
}
});
@@ -0,0 +1,41 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidSecurityAuditQueryError,
MAX_SECURITY_AUDIT_QUERY_PAGE_SIZE,
normalizeSecurityAuditQuery,
} = require('@qinglong/runtime-core/security-audit-query');
test('normalizes one bounded immutable audit query', () => {
const input = {
limit: 50,
before: {
occurredAtMs: 1000,
eventId: '123e4567-e89b-42d3-a456-426614174221',
},
filter: {
projectId: 'default',
subject: { type: 'user', id: 'usr_admin' },
outcome: 'allowed',
},
};
const normalized = normalizeSecurityAuditQuery(input);
assert.deepEqual(normalized, input);
input.filter.subject.id = 'mutated';
assert.equal(normalized.filter.subject.id, 'usr_admin');
});
test('rejects unbounded, malformed and widened audit queries', () => {
for (const input of [
{ limit: 0, filter: {} },
{ limit: MAX_SECURITY_AUDIT_QUERY_PAGE_SIZE + 1, filter: {} },
{ limit: 10, filter: { projectId: '../escape' } },
{ limit: 10, filter: { subject: { type: 'unknown', id: 'id' } } },
{ limit: 10, filter: {}, unexpected: true },
]) {
assert.throws(
() => normalizeSecurityAuditQuery(input),
InvalidSecurityAuditQueryError,
);
}
});
@@ -0,0 +1,365 @@
const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const { join } = require('node:path');
const { test } = require('node:test');
const {
InvalidStepRunError,
STEP_RUN_MUTATION_SCHEMA,
STEP_RUN_SCHEMA,
StepRunFenceConflictError,
StepRunMutationConflictError,
StepRunStateConflictError,
createStepRunMutation,
createStepRunRecord,
normalizeListStepRunsQuery,
normalizeListStepRunsResult,
normalizeStepRunMutation,
normalizeStepRunRecord,
resolveStepRunMutation,
transitionStepRunMutation,
transitionStepRunRecord,
} = require('../dist/run/stepRun');
const DIGEST_A = 'a'.repeat(64);
const DIGEST_B = 'b'.repeat(64);
function createInput(overrides = {}) {
return {
id: 'step-run-001',
runId: 'run-001',
stepKey: 'workflow.fetch',
kind: 'tool',
definitionRef: 'tool:demo.compare@1.0.0',
definitionDigest: DIGEST_A,
required: true,
initialStatus: 'pending',
inputRef: 'artifact:step-input-001',
mutationId: 'step-create-001',
createdAtMs: 1_000,
...overrides,
};
}
function context(overrides = {}) {
return {
expectedRunVersion: 4,
expectedRunEventSequence: 7,
eventId: 'event-step-001',
dedupeKey: 'step-create:step-run-001',
actor: { type: 'agent', id: 'agent-001' },
...overrides,
};
}
function transition(current, to, overrides = {}) {
return transitionStepRunRecord(current, {
expectedVersion: current.version,
expectedDigest: current.stepRunDigest,
mutationId: `step-${to}-${current.version + 1}`,
to,
atMs: current.updatedAtMs + 100,
...overrides,
});
}
test('creates one immutable pending or ready StepRun with a canonical digest', () => {
const pending = createStepRunRecord(createInput());
assert.equal(pending.schema, STEP_RUN_SCHEMA);
assert.equal(pending.status, 'pending');
assert.equal(pending.version, 1);
assert.equal(pending.attemptCount, 0);
assert.equal(pending.readyAtMs, null);
assert.match(pending.stepRunDigest, /^[0-9a-f]{64}$/);
assert.equal(Object.isFrozen(pending), true);
assert.deepEqual(normalizeStepRunRecord(pending), pending);
const ready = createStepRunRecord(
createInput({
id: 'step-run-002',
stepKey: 'workflow.ready',
initialStatus: 'ready',
}),
);
assert.equal(ready.readyAtMs, ready.createdAtMs);
});
test('moves a Tool Step through approval, running and success', () => {
const pending = createStepRunRecord(createInput());
const ready = transition(pending, 'ready');
const waiting = transition(ready, 'waiting_approval', {
approvalRequestId: 'approval-step-001',
});
const running = transition(waiting, 'running', {
approvalRequestId: 'approval-step-001',
});
const succeeded = transition(running, 'succeeded', {
outputRef: 'artifact:step-output-001',
});
assert.equal(ready.readyAtMs, 1_100);
assert.equal(waiting.approvalRequestId, 'approval-step-001');
assert.equal(running.attemptCount, 1);
assert.equal(running.startedAtMs, 1_300);
assert.equal(succeeded.status, 'succeeded');
assert.equal(succeeded.outputRef, 'artifact:step-output-001');
assert.equal(succeeded.finishedAtMs, 1_400);
assert.equal(succeeded.version, 5);
});
test('supports a fenced lost-to-ready retry with a bounded attempt count', () => {
const ready = createStepRunRecord(
createInput({ initialStatus: 'ready' }),
);
const first = transition(ready, 'running');
const lost = transition(first, 'lost', {
resultCode: 'worker_lost',
errorSummary: 'Worker lease expired',
});
const retryReady = transition(lost, 'ready');
const second = transition(retryReady, 'running');
assert.equal(lost.finishedAtMs, null);
assert.equal(lost.resultCode, 'worker_lost');
assert.equal(retryReady.resultCode, null);
assert.equal(retryReady.startedAtMs, null);
assert.equal(second.attemptCount, 2);
});
test('refreshes a pre-start ready epoch without forging execution', () => {
const ready = createStepRunRecord(
createInput({ initialStatus: 'ready' }),
);
const refreshed = transition(ready, 'ready');
assert.equal(refreshed.status, 'ready');
assert.equal(refreshed.version, ready.version + 1);
assert.notEqual(refreshed.stepRunDigest, ready.stepRunDigest);
assert.equal(refreshed.readyAtMs, ready.readyAtMs);
assert.equal(refreshed.startedAtMs, null);
assert.equal(refreshed.finishedAtMs, null);
assert.equal(refreshed.attemptCount, 0);
});
test('records a fenced failure before the StepRun crosses its start barrier', () => {
const ready = createStepRunRecord(
createInput({ initialStatus: 'ready' }),
);
const failed = transition(ready, 'failed', {
resultCode: 'executor_start_failed',
errorSummary: 'Executor failed before execution started',
});
assert.equal(failed.status, 'failed');
assert.equal(failed.startedAtMs, null);
assert.equal(failed.finishedAtMs, ready.updatedAtMs + 100);
assert.equal(failed.attemptCount, 0);
assert.equal(failed.resultCode, 'executor_start_failed');
});
test('keeps terminal states immutable and rejects stale fences', () => {
const ready = createStepRunRecord(
createInput({ initialStatus: 'ready' }),
);
const running = transition(ready, 'running');
const failed = transition(running, 'failed', {
resultCode: 'handler_failed',
});
assert.throws(() => transition(failed, 'ready'), StepRunStateConflictError);
assert.throws(
() =>
transitionStepRunRecord(ready, {
expectedVersion: ready.version + 1,
expectedDigest: ready.stepRunDigest,
mutationId: 'stale-step',
to: 'running',
atMs: 2_000,
}),
StepRunFenceConflictError,
);
});
test('enforces approval, result, output and time shapes', () => {
const ready = createStepRunRecord(
createInput({ initialStatus: 'ready' }),
);
assert.throws(
() => transition(ready, 'waiting_approval'),
/approval shape/,
);
assert.throws(
() => transition(ready, 'timed_out'),
/result or approval shape/,
);
assert.throws(
() =>
transition(ready, 'running', {
outputRef: 'artifact:not-yet',
}),
/result or approval shape/,
);
assert.throws(
() =>
transition(ready, 'running', {
atMs: ready.updatedAtMs - 1,
}),
/precedes/,
);
});
test('builds one atomic create mutation for Run, StepRun and RunEvent', () => {
const mutation = createStepRunMutation(createInput(), context());
assert.equal(mutation.schema, STEP_RUN_MUTATION_SCHEMA);
assert.equal(mutation.expectedRunVersion, 4);
assert.equal(mutation.expectedRunEventSequence, 7);
assert.equal(mutation.expectedStepRunVersion, null);
assert.equal(mutation.event.sequence, 8);
assert.equal(mutation.event.type, 'step.created');
assert.equal(mutation.event.stepRunId, mutation.stepRun.id);
assert.equal(
mutation.event.payload.stepRunDigest,
mutation.stepRun.stepRunDigest,
);
assert.match(mutation.mutationDigest, /^[0-9a-f]{64}$/);
assert.deepEqual(normalizeStepRunMutation(mutation), mutation);
});
test('binds a transition mutation to both Run and previous StepRun fences', () => {
const current = createStepRunRecord(createInput());
const mutation = transitionStepRunMutation(
current,
{
expectedVersion: current.version,
expectedDigest: current.stepRunDigest,
mutationId: 'step-ready-002',
to: 'ready',
atMs: 1_100,
},
context({
expectedRunVersion: 5,
expectedRunEventSequence: 8,
eventId: 'event-step-002',
dedupeKey: 'step-ready:step-run-001',
}),
);
assert.equal(mutation.previousStatus, 'pending');
assert.equal(mutation.expectedStepRunVersion, 1);
assert.equal(mutation.expectedStepRunDigest, current.stepRunDigest);
assert.equal(mutation.stepRun.version, 2);
assert.equal(mutation.event.type, 'step.ready');
assert.equal(mutation.event.sequence, 9);
assert.equal(resolveStepRunMutation(current, mutation), 'apply');
assert.equal(
resolveStepRunMutation(mutation.stepRun, mutation),
'existing',
);
});
test('rejects mutation, replay identity, event and record digest tampering', () => {
const mutation = createStepRunMutation(createInput(), context());
assert.equal(resolveStepRunMutation(null, mutation), 'apply');
assert.equal(
resolveStepRunMutation(mutation.stepRun, mutation),
'existing',
);
const reused = createStepRunMutation(
createInput({
id: 'step-run-reused',
stepKey: 'workflow.reused',
}),
context({
eventId: 'event-step-reused',
dedupeKey: 'step-create:step-run-reused',
}),
);
assert.throws(
() => resolveStepRunMutation(mutation.stepRun, reused),
StepRunMutationConflictError,
);
for (const changed of [
{ ...mutation, mutationDigest: DIGEST_B },
{
...mutation,
event: { ...mutation.event, sequence: mutation.event.sequence + 1 },
},
{
...mutation,
stepRun: { ...mutation.stepRun, definitionDigest: DIGEST_B },
},
]) {
assert.throws(
() => normalizeStepRunMutation(changed),
InvalidStepRunError,
);
}
});
test('normalizes bounded keyset pagination and rejects false continuation', () => {
const first = createStepRunRecord(
createInput({ id: 'step-run-001', stepKey: 'a' }),
);
const second = createStepRunRecord(
createInput({
id: 'step-run-002',
stepKey: 'b',
mutationId: 'step-create-002',
}),
);
const query = normalizeListStepRunsQuery({
runId: 'run-001',
limit: 2,
});
assert.deepEqual(
normalizeListStepRunsResult(
{
stepRuns: [first, second],
truncated: true,
next: { stepKey: 'b', id: 'step-run-002' },
},
query,
).next,
{ stepKey: 'b', id: 'step-run-002' },
);
assert.throws(
() =>
normalizeListStepRunsResult(
{
stepRuns: [second, first],
truncated: false,
},
query,
),
/ordering/,
);
assert.throws(
() =>
normalizeListStepRunsResult(
{
stepRuns: [first],
truncated: true,
},
query,
),
/continuation/,
);
});
test('publishes the same StepRun contract through root and subpath without ambient authority', () => {
const root = require('../dist');
const subpath = require('@qinglong/runtime-core/step-run');
assert.equal(root.createStepRunMutation, createStepRunMutation);
assert.equal(subpath.transitionStepRunRecord, transitionStepRunRecord);
const source = readFileSync(
join(__dirname, '..', 'src', 'run', 'stepRun.ts'),
'utf8',
);
for (const authority of [
'node:child_process',
'node:fs',
'node:http',
'node:net',
'node:worker_threads',
]) {
assert.equal(source.includes(`from '${authority}'`), false);
}
});
@@ -0,0 +1,106 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidTaskDefinitionError,
assertTaskDefinitionPageSize,
createTaskDefinitionRecord,
normalizeAppendTaskDefinitionRevisionCommand,
normalizeTaskDefinitionCursor,
normalizeTaskDefinitionRecord,
} = require('../dist/task-definition/taskDefinition');
function command(overrides = {}) {
return {
projectId: 'default',
taskId: 'task-1',
expectedRevision: null,
mutationId: '019f7200-0000-7000-8000-000000000001',
name: 'Example task',
description: 'one immutable revision',
kind: 'script',
spec: {
schema: 'qinglong/script@v1',
config: {
command: ['/usr/local/bin/node', 'script.js'],
retry: { maximumAttempts: 1 },
},
},
labels: { environment: 'test', 'qinglong.io/source': 'manual' },
enabled: true,
occurredAtMs: 100,
...overrides,
};
}
test('normalizes one bounded canonical TaskDefinition revision', () => {
const value = normalizeAppendTaskDefinitionRevisionCommand(command());
assert.deepEqual(Object.keys(value.spec.config), ['command', 'retry']);
assert.deepEqual(Object.keys(value.labels), [
'environment',
'qinglong.io/source',
]);
assert.equal(Object.isFrozen(value.spec.config), true);
const record = createTaskDefinitionRecord(value, 90);
assert.equal(record.revision, 1);
assert.equal(record.contentDigest.length, 64);
assert.deepEqual(normalizeTaskDefinitionRecord(record), record);
});
test('rejects extensible commands and unbounded or non-JSON specs', () => {
assert.throws(
() => normalizeAppendTaskDefinitionRevisionCommand(command({ extra: 1 })),
InvalidTaskDefinitionError,
);
assert.throws(
() =>
normalizeAppendTaskDefinitionRevisionCommand(
command({ spec: { schema: 'unknown', config: {} } }),
),
/spec schema is invalid/,
);
assert.throws(
() =>
normalizeAppendTaskDefinitionRevisionCommand(
command({
spec: { schema: 'qinglong/script@v1', config: { fn() {} } },
}),
),
/non-JSON value/,
);
assert.throws(
() =>
normalizeAppendTaskDefinitionRevisionCommand(
command({
labels: Object.fromEntries(
Array.from({ length: 33 }, (_, index) => [`key-${index}`, 'x']),
),
}),
),
/count budget/,
);
});
test('binds content digest to revision semantics and validates pagination', () => {
const first = createTaskDefinitionRecord(command(), 90);
const second = createTaskDefinitionRecord(
command({
expectedRevision: 1,
mutationId: '019f7200-0000-7000-8000-000000000002',
name: 'Changed task',
occurredAtMs: 110,
}),
90,
);
assert.equal(second.revision, 2);
assert.notEqual(second.contentDigest, first.contentDigest);
assert.throws(
() => normalizeTaskDefinitionRecord({ ...first, enabled: false }),
/content digest did not match/,
);
assert.doesNotThrow(() => assertTaskDefinitionPageSize(256));
assert.throws(() => assertTaskDefinitionPageSize(257), RangeError);
assert.deepEqual(normalizeTaskDefinitionCursor({ taskId: 'task-1' }), {
taskId: 'task-1',
});
});
@@ -0,0 +1,177 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const { createLocalSecretRef } = require('../dist/secret/localSecret');
const {
createTaskDefinitionRecord,
normalizeAppendTaskDefinitionRevisionCommand,
} = require('../dist/task-definition/taskDefinition');
const {
InvalidTaskDefinitionCompilationError,
UnsupportedTaskDefinitionCompilationError,
compileLocalCommandTaskDefinition,
createTaskDefinitionRevisionRef,
parseTaskDefinitionRevisionRef,
} = require('../dist/task-definition/taskDefinitionExecutionCompiler');
const {
TaskSpecSemanticRegistry,
createBuiltInTaskSpecSemanticRegistry,
} = require('../dist/task-definition/taskSpecSemantic');
function command(overrides = {}) {
return {
projectId: 'default',
taskId: 'task-1',
expectedRevision: null,
mutationId: '019f7400-0000-7000-8000-000000000001',
name: 'Compiled command',
kind: 'command',
spec: {
schema: 'qinglong/command@v1',
config: {
command: { kind: 'argv', file: '/bin/echo', args: [''] },
},
},
labels: { source: 'compiler-test' },
enabled: true,
occurredAtMs: 100,
...overrides,
};
}
function semanticRecord(registry, overrides = {}) {
const normalized = normalizeAppendTaskDefinitionRevisionCommand(
command(overrides),
);
const spec = registry.normalize({
projectId: normalized.projectId,
taskId: normalized.taskId,
kind: normalized.kind,
spec: normalized.spec,
});
return createTaskDefinitionRecord({ ...normalized, spec }, 90);
}
test('compiles one canonical command revision into a profile-neutral and local plan', () => {
const registry = createBuiltInTaskSpecSemanticRegistry();
const secretRef = createLocalSecretRef({
projectId: 'default',
name: 'TOKEN',
});
const definition = semanticRecord(registry, {
spec: {
schema: 'qinglong/command@v1',
config: {
command: { kind: 'argv', file: '/bin/echo', args: ['', 'ready'] },
environment: [
{ kind: 'secret', name: 'TOKEN', secretRef },
{ kind: 'public', name: 'MODE', value: 'test' },
],
workingDirectory: '/work',
timeoutMs: 5_000,
},
},
});
const compiled = compileLocalCommandTaskDefinition(definition, registry);
assert.deepEqual(parseTaskDefinitionRevisionRef(compiled.source.taskRevision), {
revision: definition.revision,
contentDigest: definition.contentDigest,
});
assert.deepEqual(JSON.parse(JSON.stringify(compiled.source.environment)), [
{ name: 'MODE', kind: 'public', value: 'test' },
{ name: 'TOKEN', kind: 'secret', secretRef },
]);
assert.deepEqual(compiled.executionRevision.command, {
kind: 'argv',
file: '/bin/echo',
args: ['', 'ready'],
});
assert.equal(
compiled.executionRevision.contextRef,
compiled.contextRecipe.contextRef,
);
assert.equal(compiled.executionRevision.createdAtMs, definition.updatedAtMs);
assert.equal(Object.isFrozen(compiled.source), true);
assert.deepEqual(
compileLocalCommandTaskDefinition(definition, registry),
compiled,
);
});
test('rejects disabled, unsupported, structurally-only and drifted sources', () => {
const registry = createBuiltInTaskSpecSemanticRegistry();
assert.throws(
() =>
compileLocalCommandTaskDefinition(
semanticRecord(registry, { enabled: false }),
registry,
),
/source is disabled/,
);
const script = createTaskDefinitionRecord(
command({
kind: 'script',
spec: { schema: 'qinglong/script@v1', config: {} },
}),
90,
);
assert.throws(
() => compileLocalCommandTaskDefinition(script, registry),
UnsupportedTaskDefinitionCompilationError,
);
const structurallyOnly = createTaskDefinitionRecord(command(), 90);
assert.throws(
() => compileLocalCommandTaskDefinition(structurallyOnly, registry),
/not semantically canonical/,
);
assert.throws(
() =>
compileLocalCommandTaskDefinition(
{ ...semanticRecord(registry), contentDigest: '0'.repeat(64) },
registry,
),
/source record is invalid/,
);
const withoutBuiltIn = new TaskSpecSemanticRegistry([
{
schema: 'example/tool@v1',
kind: 'tool',
normalizeConfig: (config) => config,
},
]);
assert.throws(
() =>
compileLocalCommandTaskDefinition(
semanticRecord(registry),
withoutBuiltIn,
),
UnsupportedTaskDefinitionCompilationError,
);
});
test('uses one canonical digest-bound TaskDefinition revision reference', () => {
const digest = 'a'.repeat(64);
const reference = createTaskDefinitionRevisionRef({
revision: 2_147_483_647,
contentDigest: digest,
});
assert.equal(reference, `qltd:v1:2147483647:${digest}`);
assert.deepEqual(parseTaskDefinitionRevisionRef(reference), {
revision: 2_147_483_647,
contentDigest: digest,
});
for (const invalid of [
`qltd:v1:01:${digest}`,
`qltd:v1:2147483648:${digest}`,
`qltd:v1:1:${'A'.repeat(64)}`,
'revision-1',
]) {
assert.throws(
() => parseTaskDefinitionRevisionRef(invalid),
InvalidTaskDefinitionCompilationError,
);
}
});
@@ -0,0 +1,247 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const { createLocalSecretRef } = require('../dist/secret/localSecret');
const {
BUILT_IN_COMMAND_TASK_SPEC_SCHEMA,
InvalidTaskSpecSemanticError,
TaskSpecSemanticRegistry,
UnsupportedTaskSpecError,
createBuiltInTaskSpecSemanticRegistry,
createTaskSpecSemanticRegistry,
} = require('../dist/task-definition/taskSpecSemantic');
function context(overrides = {}) {
return {
projectId: 'default',
taskId: 'task-1',
kind: 'command',
spec: {
schema: BUILT_IN_COMMAND_TASK_SPEC_SCHEMA,
config: {
command: { kind: 'argv', file: '/bin/echo', args: ['hello'] },
},
},
...overrides,
};
}
test('publishes one immutable built-in schema and canonicalizes command specs', () => {
const registry = createBuiltInTaskSpecSemanticRegistry();
assert.equal(Object.isFrozen(registry), true);
assert.equal('register' in registry, false);
assert.deepEqual(registry.list(), [
{ schema: BUILT_IN_COMMAND_TASK_SPEC_SCHEMA, kind: 'command' },
]);
assert.equal(
registry.supports('command', BUILT_IN_COMMAND_TASK_SPEC_SCHEMA),
true,
);
const secretRef = createLocalSecretRef({
projectId: 'default',
name: 'TOKEN',
});
const normalized = registry.normalize(
context({
spec: {
schema: BUILT_IN_COMMAND_TASK_SPEC_SCHEMA,
config: {
timeoutMs: 5_000,
workingDirectory: '/work',
environment: [
{ kind: 'secret', name: 'TOKEN', secretRef },
{ kind: 'public', name: 'EMPTY', value: '' },
],
command: { kind: 'shell', command: 'echo "$EMPTY"' },
},
},
}),
);
assert.deepEqual(JSON.parse(JSON.stringify(normalized)), {
schema: BUILT_IN_COMMAND_TASK_SPEC_SCHEMA,
config: {
command: {
kind: 'shell',
command: 'echo "$EMPTY"',
shell: '/bin/sh',
},
environment: [
{ name: 'EMPTY', kind: 'public', value: '' },
{ name: 'TOKEN', kind: 'secret', secretRef },
],
timeoutMs: 5_000,
workingDirectory: '/work',
},
});
assert.equal(Object.isFrozen(normalized.config.environment), true);
});
test('fails closed for unknown schemas, kind drift and unsafe command shapes', () => {
const registry = createBuiltInTaskSpecSemanticRegistry();
assert.throws(
() =>
registry.normalize(
context({
kind: 'script',
spec: { schema: 'qinglong/script@v1', config: {} },
}),
),
UnsupportedTaskSpecError,
);
assert.throws(
() => registry.normalize(context({ kind: 'script' })),
/schema does not match TaskDefinition kind/,
);
const invalidConfigs = [
{ command: { kind: 'argv', file: 'bin/echo', args: [] } },
{ command: { kind: 'shell', command: 'true', shell: '/usr/bin/zsh' } },
{
command: { kind: 'argv', file: '/bin/echo', args: [] },
workingDirectory: 'work',
},
{
command: { kind: 'argv', file: '/bin/echo', args: [] },
environment: [{ kind: 'public', name: 'QL3_TOKEN', value: 'x' }],
},
{
command: { kind: 'argv', file: '/bin/echo', args: [] },
environment: [
{ kind: 'public', name: 'TOKEN', value: 'a' },
{ kind: 'public', name: 'TOKEN', value: 'b' },
],
},
{
command: { kind: 'argv', file: '/bin/echo', args: [] },
environment: [
{
kind: 'secret',
name: 'TOKEN',
secretRef: createLocalSecretRef({
projectId: 'other',
name: 'TOKEN',
}),
},
],
},
{ command: { kind: 'argv', file: '/bin/echo', args: [] }, extra: true },
];
for (const config of invalidConfigs) {
assert.throws(
() =>
registry.normalize(
context({
spec: { schema: BUILT_IN_COMMAND_TASK_SPEC_SCHEMA, config },
}),
),
InvalidTaskSpecSemanticError,
);
}
assert.doesNotThrow(() =>
registry.normalize(
context({
spec: {
schema: BUILT_IN_COMMAND_TASK_SPEC_SCHEMA,
config: {
command: { kind: 'argv', file: '/bin/echo', args: [''] },
},
},
}),
),
);
});
test('accepts only an explicit bounded descriptor set and hides validator errors', () => {
const descriptor = {
schema: 'example/tool@v1',
kind: 'tool',
normalizeConfig() {
throw new Error('provider internals');
},
};
assert.throws(
() => new TaskSpecSemanticRegistry([descriptor, descriptor]),
/invalid or duplicated/,
);
const registry = new TaskSpecSemanticRegistry([descriptor]);
assert.throws(
() =>
registry.normalize(
context({
kind: 'tool',
spec: { schema: 'example/tool@v1', config: {} },
}),
),
(error) => {
assert.equal(error.message.includes('provider internals'), false);
return error instanceof InvalidTaskSpecSemanticError;
},
);
const extended = createTaskSpecSemanticRegistry([
{
schema: 'example/command@v1',
kind: 'command',
normalizeConfig: (config) => config,
},
]);
assert.deepEqual(
extended.list().map(({ schema }) => schema),
['example/command@v1', BUILT_IN_COMMAND_TASK_SPEC_SCHEMA],
);
assert.throws(
() =>
createTaskSpecSemanticRegistry([
{
schema: 'qinglong/tool@v1',
kind: 'tool',
normalizeConfig: (config) => config,
},
]),
/reserved qinglong namespace/,
);
});
test('canonicalizes an optional bounded Remote Worker PlacementSpec in command semantics', () => {
const registry = createBuiltInTaskSpecSemanticRegistry();
const normalized = registry.normalize(
context({
spec: {
schema: BUILT_IN_COMMAND_TASK_SPEC_SCHEMA,
config: {
command: { kind: 'argv', file: '/bin/echo', args: ['placed'] },
placement: {
required: {
architectures: ['arm64'],
runtimes: [{ name: 'node', versionRange: '^24.0.0' }],
labels: { region: 'cn-east' },
},
preferred: [{ labels: { tier: 'edge' }, weight: 5 }],
},
},
},
}),
);
assert.deepEqual(JSON.parse(JSON.stringify(normalized.config.placement)), {
required: {
architectures: ['arm64'],
runtimes: [{ name: 'node', versionRange: '^24.0.0' }],
labels: { region: 'cn-east' },
},
preferred: [{ labels: { tier: 'edge' }, weight: 5 }],
});
assert.throws(
() => registry.normalize(context({
spec: {
schema: BUILT_IN_COMMAND_TASK_SPEC_SCHEMA,
config: {
command: { kind: 'argv', file: '/bin/echo', args: [] },
placement: {
required: { runtimes: [{ name: 'node', versionRange: 'not-semver' }] },
},
},
},
})),
InvalidTaskSpecSemanticError,
);
});
@@ -0,0 +1,108 @@
'use strict';
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
TASK_START_SCHEMA,
createTaskStartResponseBody,
normalizeTaskStartCommand,
normalizeTaskStartResult,
parseTaskStartRequestBody,
parseTaskStartResponseBody,
} = require('@qinglong/runtime-core/task-start');
const DIGEST = 'a'.repeat(64);
const EXECUTION_DIGEST = 'b'.repeat(64);
function command(overrides = {}) {
return {
projectId: 'project-1',
taskId: 'task-1',
mutationId: '019f7300-0000-7000-8000-000000000001',
expectedRevision: 3,
expectedContentDigest: DIGEST,
runId: '019f7300-0000-7000-8000-000000000002',
attemptId: '019f7300-0000-7000-8000-000000000003',
createdEventId: '019f7300-0000-7000-8000-000000000004',
queuedEventId: '019f7300-0000-7000-8000-000000000005',
subject: { type: 'user', id: 'user-1' },
policyFence: { projectVersion: 2, bindingVersion: 4 },
...overrides,
};
}
function result(overrides = {}) {
return {
status: 'accepted',
projectId: 'project-1',
taskId: 'task-1',
taskRevision: 3,
taskContentDigest: DIGEST,
runId: '019f7300-0000-7000-8000-000000000002',
attemptId: '019f7300-0000-7000-8000-000000000003',
runStatus: 'queued',
runVersion: 2,
eventSequence: 2,
executorType: 'local_process',
executionRevisionDigest: EXECUTION_DIGEST,
createdAtMs: 1_800_000_000_000,
...overrides,
};
}
test('accepts only the exact digest-fenced Task start wire body', () => {
const body = {
schema: TASK_START_SCHEMA,
mutationId: command().mutationId,
expectedRevision: 3,
expectedContentDigest: DIGEST,
};
assert.equal(TASK_START_SCHEMA, 'qinglong/task-start@v1');
assert.deepEqual(parseTaskStartRequestBody(body), body);
assert.throws(
() => parseTaskStartRequestBody({ ...body, command: '/bin/sh' }),
/shape is invalid/,
);
assert.throws(
() => parseTaskStartRequestBody({ ...body, mutationId: 'MUTATION' }),
/mutationId is invalid/,
);
assert.throws(
() => parseTaskStartRequestBody({ ...body, expectedContentDigest: 'A'.repeat(64) }),
/expectedContentDigest is invalid/,
);
});
test('normalizes complete server-owned identities and authorization fence', () => {
assert.deepEqual(normalizeTaskStartCommand(command()), command());
assert.throws(
() => normalizeTaskStartCommand(command({ policyFence: {
projectVersion: 2,
bindingVersion: null,
} })),
/authorization fence is incomplete/,
);
assert.throws(
() => normalizeTaskStartCommand(command({ runId: 'caller-run-id' })),
/runId is invalid/,
);
});
test('round-trips accepted and existing bounded receipts', () => {
assert.deepEqual(normalizeTaskStartResult(result()), result());
const existing = result({
status: 'existing',
executorType: 'remote_worker',
});
const body = createTaskStartResponseBody(existing);
assert.equal(body.schema, TASK_START_SCHEMA);
assert.deepEqual(parseTaskStartResponseBody(body), body);
assert.throws(
() => normalizeTaskStartResult(result({ runVersion: 3 })),
/result state is invalid/,
);
assert.throws(
() => parseTaskStartResponseBody({ ...body, command: {} }),
/shape is invalid/,
);
});
@@ -0,0 +1,261 @@
const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const { join } = require('node:path');
const { test } = require('node:test');
const {
InvalidToolExecutionEvidenceError,
MAX_TOOL_EXECUTION_EVIDENCE_PAGE_SIZE,
TOOL_EXECUTION_AUDIT_RECEIPT_SCHEMA,
TOOL_EXECUTION_EVIDENCE_BUNDLE_SCHEMA,
TOOL_EXECUTION_START_AUDIT_OPERATION,
TOOL_EXECUTION_TRACE_ANCHOR_SCHEMA,
createToolExecutionEvidenceBundle,
normalizeListToolExecutionEvidenceQuery,
normalizeListToolExecutionEvidenceResult,
normalizeToolExecutionAuditReceipt,
normalizeToolExecutionEvidenceBundle,
normalizeToolExecutionTraceAnchor,
toolExecutionAdmissionEvidence,
toolExecutionAuditRecordDigest,
} = require('../dist/tool-execution/toolExecutionEvidence');
const DIGEST_A = 'a'.repeat(64);
const DIGEST_B = 'b'.repeat(64);
const DIGEST_C = 'c'.repeat(64);
const DIGEST_D = 'd'.repeat(64);
const DIGEST_E = 'e'.repeat(64);
function audit(overrides = {}) {
return {
eventId: '40000000-0000-4000-8000-000000000001',
requestId: 'tool-request-001',
operationId: TOOL_EXECUTION_START_AUDIT_OPERATION,
projectId: 'project-001',
subject: { type: 'agent', id: 'agent-001' },
authenticationId: 'auth-agent-001',
outcome: 'allowed',
reasons: ['tool_execution_start'],
fence: { projectVersion: 3, bindingVersion: 4 },
occurredAtMs: 1_000,
...overrides,
};
}
function input(overrides = {}) {
return {
traceId: '1'.repeat(32),
spanId: '2'.repeat(16),
projectId: 'project-001',
runId: 'run-001',
stepRunId: 'step-run-001',
invocationPlanDigest: DIGEST_A,
bindingDigest: DIGEST_B,
adapterDigest: DIGEST_C,
redactionContractDigest: DIGEST_D,
auditContractDigest: DIGEST_E,
audit: audit(),
createdAtMs: 1_000,
...overrides,
};
}
function copy(value) {
return structuredClone(value);
}
test('creates one immutable low-sensitive Trace and Audit evidence bundle', () => {
const bundle = createToolExecutionEvidenceBundle(input());
assert.equal(bundle.schema, TOOL_EXECUTION_EVIDENCE_BUNDLE_SCHEMA);
assert.equal(bundle.trace.schema, TOOL_EXECUTION_TRACE_ANCHOR_SCHEMA);
assert.equal(bundle.receipt.schema, TOOL_EXECUTION_AUDIT_RECEIPT_SCHEMA);
assert.equal(bundle.trace.parentSpanId, null);
assert.match(bundle.trace.traceDigest, /^[0-9a-f]{64}$/);
assert.match(bundle.receipt.auditRecordDigest, /^[0-9a-f]{64}$/);
assert.match(bundle.receipt.receiptDigest, /^[0-9a-f]{64}$/);
assert.equal(Object.isFrozen(bundle), true);
assert.equal(Object.isFrozen(bundle.trace), true);
assert.equal(Object.isFrozen(bundle.audit), true);
assert.equal(Object.isFrozen(bundle.receipt), true);
assert.deepEqual(normalizeToolExecutionEvidenceBundle(bundle), bundle);
assert.deepEqual(toolExecutionAdmissionEvidence(bundle), {
trace: {
traceId: bundle.trace.traceId,
spanId: bundle.trace.spanId,
digest: bundle.trace.traceDigest,
},
audit: {
eventId: bundle.audit.eventId,
digest: bundle.receipt.receiptDigest,
},
});
});
test('uses canonical domain-separated digests and binds every authority fact', () => {
const first = createToolExecutionEvidenceBundle(input());
const replay = createToolExecutionEvidenceBundle(input());
assert.deepEqual(replay, first);
assert.equal(
toolExecutionAuditRecordDigest(first.audit),
first.receipt.auditRecordDigest,
);
const changed = createToolExecutionEvidenceBundle(
input({
adapterDigest: 'f'.repeat(64),
audit: audit({
eventId: '40000000-0000-4000-8000-000000000002',
}),
}),
);
assert.notEqual(changed.trace.traceDigest, first.trace.traceDigest);
assert.notEqual(changed.receipt.receiptDigest, first.receipt.receiptDigest);
});
test('rejects non-start, denied, unfenced and cross-Project audit records', () => {
for (const invalidAudit of [
audit({ operationId: 'tool.invoke.finish' }),
audit({ outcome: 'denied' }),
audit({ fence: null }),
audit({ projectId: 'project-other' }),
audit({ occurredAtMs: 999 }),
]) {
assert.throws(
() => createToolExecutionEvidenceBundle(input({ audit: invalidAudit })),
InvalidToolExecutionEvidenceError,
);
}
});
test('rejects trace identity, parent loops, unknown fields and digest tampering', () => {
assert.throws(
() => createToolExecutionEvidenceBundle(input({ traceId: '1'.repeat(31) })),
InvalidToolExecutionEvidenceError,
);
assert.throws(
() =>
createToolExecutionEvidenceBundle(
input({ parentSpanId: '2'.repeat(16) }),
),
InvalidToolExecutionEvidenceError,
);
assert.throws(
() => createToolExecutionEvidenceBundle({ ...input(), secret: 'value' }),
InvalidToolExecutionEvidenceError,
);
const bundle = createToolExecutionEvidenceBundle(input());
assert.throws(
() =>
normalizeToolExecutionTraceAnchor({
...copy(bundle.trace),
traceDigest: '0'.repeat(64),
}),
InvalidToolExecutionEvidenceError,
);
assert.throws(
() =>
normalizeToolExecutionAuditReceipt({
...copy(bundle.receipt),
receiptDigest: '0'.repeat(64),
}),
InvalidToolExecutionEvidenceError,
);
});
test('rejects detached Trace, Audit and receipt relationships', () => {
const bundle = createToolExecutionEvidenceBundle(input());
const other = createToolExecutionEvidenceBundle(
input({
traceId: '3'.repeat(32),
spanId: '4'.repeat(16),
stepRunId: 'step-run-002',
audit: audit({
eventId: '40000000-0000-4000-8000-000000000002',
}),
}),
);
assert.throws(
() =>
normalizeToolExecutionEvidenceBundle({
...copy(bundle),
receipt: other.receipt,
}),
InvalidToolExecutionEvidenceError,
);
assert.throws(
() =>
normalizeToolExecutionEvidenceBundle({
...copy(bundle),
audit: other.audit,
}),
InvalidToolExecutionEvidenceError,
);
});
test('normalizes bounded stable evidence pagination', () => {
const first = createToolExecutionEvidenceBundle(input());
const second = createToolExecutionEvidenceBundle(
input({
traceId: '3'.repeat(32),
spanId: '4'.repeat(16),
audit: audit({
eventId: '40000000-0000-4000-8000-000000000002',
occurredAtMs: 1_001,
}),
createdAtMs: 1_001,
}),
);
const query = normalizeListToolExecutionEvidenceQuery({
runId: 'run-001',
limit: 2,
});
assert.deepEqual(
normalizeListToolExecutionEvidenceResult(
{
bundles: [first, second],
truncated: true,
next: {
createdAtMs: second.trace.createdAtMs,
traceId: second.trace.traceId,
spanId: second.trace.spanId,
},
},
query,
).bundles,
[first, second],
);
assert.throws(
() =>
normalizeListToolExecutionEvidenceQuery({
runId: 'run-001',
limit: MAX_TOOL_EXECUTION_EVIDENCE_PAGE_SIZE + 1,
}),
InvalidToolExecutionEvidenceError,
);
assert.throws(
() =>
normalizeListToolExecutionEvidenceResult(
{ bundles: [second, first], truncated: false },
query,
),
InvalidToolExecutionEvidenceError,
);
});
test('publishes the same pure contract through root and explicit subpath', () => {
const root = require('../dist');
const subpath = require('../dist/tool-execution/toolExecutionEvidence');
assert.equal(
root.createToolExecutionEvidenceBundle,
subpath.createToolExecutionEvidenceBundle,
);
const source = readFileSync(
join(__dirname, '../src/tool-execution/toolExecutionEvidence.ts'),
'utf8',
);
assert.doesNotMatch(
source,
/node:(?:fs|child_process|net|http|https)|setInterval|setTimeout|execute|handler/i,
);
});
@@ -0,0 +1,480 @@
const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const { join } = require('node:path');
const { test } = require('node:test');
const {
consumeApprovalRequest,
createApprovalRequest,
decideApprovalRequest,
} = require('../dist/approved-action/approvedAction');
const {
createPluginPackageResourceGenerationFromReferences,
} = require('../dist/plugin-package/pluginPackageResourceGeneration');
const {
createProjectToolDefinitionSnapshot,
projectToolDefinitionRegistry,
} = require('../dist/tool-execution/tool-registry/projectToolDefinitionSnapshot');
const {
createStepRunRecord,
transitionStepRunMutation,
transitionStepRunRecord,
} = require('../dist/run/stepRun');
const {
InvalidToolExecutionStartBarrierError,
TOOL_EXECUTION_START_BARRIER_SCHEMA,
TOOL_EXECUTION_START_COMMAND_SCHEMA,
createToolExecutionStartCommand,
normalizeToolExecutionStartBarrierRecord,
normalizeToolExecutionStartCommand,
toolExecutionStartBarrierRecord,
} = require('../dist/tool-execution/toolExecutionStartBarrier');
const {
TOOL_EXECUTION_START_AUDIT_OPERATION,
createToolExecutionEvidenceBundle,
toolExecutionAdmissionEvidence,
} = require('../dist/tool-execution/toolExecutionEvidence');
const {
TrustedToolHandlerBindingRegistry,
admitTrustedToolExecution,
createTrustedToolHandlerBinding,
createTrustedToolInvocationPlan,
trustedToolContractIdentityDigest,
trustedToolInvocationApprovalBinding,
} = require('../dist/tool-execution/trustedToolInvocation');
const {
prepareToolInvocation,
} = require('../dist/tool-execution/tool-registry/toolRegistry');
const DIGEST_A = 'a'.repeat(64);
const DIGEST_B = 'b'.repeat(64);
const DIGEST_C = 'c'.repeat(64);
const REQUESTER = Object.freeze({ type: 'user', id: 'usr-tool-owner' });
const SYSTEM = Object.freeze({ type: 'system', id: 'tool-dispatcher' });
const FENCE = Object.freeze({ projectVersion: 3, bindingVersion: 7 });
const NOW_MS = 1_400;
function definition() {
return {
name: 'demo.compare',
version: '1.0.0',
description: 'Compare one bounded Run projection',
inputSchema: {
type: 'object',
properties: {
runId: { type: 'string', minLength: 1, maxLength: 64 },
},
required: ['runId'],
additionalProperties: false,
},
outputSchema: {
type: 'object',
properties: {
summary: { type: 'string', maxLength: 1024 },
},
required: ['summary'],
additionalProperties: false,
},
effect: 'read',
risk: 'low',
requiredPermissions: ['run.read'],
timeoutSeconds: 30,
};
}
function snapshot() {
const generation = createPluginPackageResourceGenerationFromReferences({
installationId: 'install-demo',
projectId: 'project-001',
packageName: 'demo',
lockDigest: DIGEST_A,
generation: 1,
previousActiveLockDigest: null,
contentDigest: DIGEST_B,
resources: [],
});
return createProjectToolDefinitionSnapshot({
projectId: 'project-001',
contributions: [
{
generation,
revisionDigest: DIGEST_C,
definitions: [definition()],
},
],
});
}
function principal() {
return {
subject: REQUESTER,
authenticationId: 'auth-tool-1',
authenticatedAtMs: 800,
expiresAtMs: 10_000,
assurance: 'local_console',
};
}
function authorizer(effect = 'allow') {
return {
async authorize() {
return {
effect,
reasons:
effect === 'allow'
? ['role_grant']
: ['agent_action_requires_approval'],
fence: FENCE,
};
},
};
}
async function approvedDispatch(currentPlan) {
const action = trustedToolInvocationApprovalBinding(
currentPlan.plan,
currentPlan.bindings,
);
const request = createApprovalRequest({
id: 'approval-tool-001',
projectId: currentPlan.plan.projectId,
action,
risk: currentPlan.plan.risk,
decisionMode: 'human_confirmation',
requestedBy: REQUESTER,
requestedAtMs: 1_050,
expiresAtMs: 9_000,
requestFence: FENCE,
});
const approved = decideApprovalRequest(request, {
expectedVersion: 1,
decisionId: 'decision-tool-001',
decision: 'approved',
reasonCode: 'reviewed',
principal: principal(),
decidedAtMs: 1_100,
authorizationFence: FENCE,
});
return consumeApprovalRequest(approved, {
expectedVersion: 2,
consumptionId: 'consume-tool-001',
dispatchId: 'dispatch-tool-001',
action,
requestedBy: REQUESTER,
consumedBy: SYSTEM,
consumedAtMs: 1_200,
authorizationFence: FENCE,
}).dispatch;
}
async function fixture(options = {}) {
const currentSnapshot = snapshot();
const binding = createTrustedToolHandlerBinding(currentSnapshot, {
tool: { name: 'demo.compare', version: '1.0.0' },
adapter: { id: 'builtin.demo-compare', version: '1.0.0' },
executionClass: 'builtin_in_process',
profiles: ['edge', 'standalone'],
authorities: ['database.read'],
timeoutSeconds: 20,
redactionContract: {
id: 'redaction.demo-compare',
version: '1.0.0',
},
auditContract: { id: 'audit.tool-call', version: '1.0.0' },
});
const bindings = new TrustedToolHandlerBindingRegistry(currentSnapshot, [
binding,
]);
const approvalRequired = options.approvalRequired === true;
const invocation = await prepareToolInvocation(
projectToolDefinitionRegistry(currentSnapshot),
{
projectId: 'project-001',
principal: principal(),
nowMs: 900,
tool: { name: 'demo.compare', version: '1.0.0' },
input: { runId: 'run-001' },
},
authorizer(approvalRequired ? 'require_approval' : 'allow'),
);
const plan = (
await createTrustedToolInvocationPlan(bindings, invocation, {
actionRef: 'tool-plan:run-001',
inputArtifactId: 'artifact-input-001',
previewArtifactId: 'artifact-preview-001',
artifactKeyId: 'tool-key-test',
artifactKey: Buffer.alloc(32, 7),
artifactNonce: Buffer.alloc(12, 9),
profile: 'edge',
preview: {
title: 'Compare Run',
summary: 'Reads one Run projection',
fields: [{ kind: 'identifier', label: 'Run', value: 'run-001' }],
warnings: [],
},
sealedAtMs: 1_000,
})
).plan;
const ready = createStepRunRecord({
id: 'step-run-001',
runId: 'run-001',
stepKey: 'workflow.compare',
kind: 'tool',
definitionRef: 'tool:demo.compare@1.0.0',
definitionDigest: binding.definitionDigest,
required: true,
initialStatus: 'ready',
inputRef: 'artifact:step-input-001',
mutationId: 'step-create-001',
createdAtMs: 1_000,
});
const planWithBindings = { plan, bindings };
const dispatch = approvalRequired
? await approvedDispatch(planWithBindings)
: undefined;
const previous = approvalRequired
? transitionStepRunRecord(ready, {
expectedVersion: ready.version,
expectedDigest: ready.stepRunDigest,
mutationId: 'step-waiting-002',
to: 'waiting_approval',
atMs: 1_200,
approvalRequestId: dispatch.approvalRequestId,
})
: ready;
const evidence = createToolExecutionEvidenceBundle({
traceId: '1'.repeat(32),
spanId: '2'.repeat(16),
projectId: 'project-001',
runId: 'run-001',
stepRunId: previous.id,
invocationPlanDigest: plan.planDigest,
bindingDigest: binding.bindingDigest,
adapterDigest:
options.adapterDigest ??
trustedToolContractIdentityDigest(binding.adapter),
redactionContractDigest: trustedToolContractIdentityDigest(
binding.redactionContract,
),
auditContractDigest: trustedToolContractIdentityDigest(
binding.auditContract,
),
audit: {
eventId: '40000000-0000-4000-8000-000000000001',
requestId: 'tool-request-001',
operationId: TOOL_EXECUTION_START_AUDIT_OPERATION,
projectId: 'project-001',
subject: REQUESTER,
authenticationId: 'auth-tool-1',
outcome: 'allowed',
reasons: ['tool_execution_start'],
fence: FENCE,
occurredAtMs: NOW_MS,
},
createdAtMs: NOW_MS,
});
const admission = await admitTrustedToolExecution(bindings, plan, {
principal: principal(),
profile: 'edge',
nowMs: NOW_MS,
authorizer: authorizer(),
evidence: {
stepRun: {
id: previous.id,
version: previous.version,
digest: previous.stepRunDigest,
},
...toolExecutionAdmissionEvidence(evidence),
},
...(dispatch ? { dispatch } : {}),
});
const stepRunMutation = transitionStepRunMutation(
previous,
{
expectedVersion: previous.version,
expectedDigest: previous.stepRunDigest,
mutationId: 'step-running-003',
to: 'running',
atMs: NOW_MS,
...(dispatch ? { approvalRequestId: dispatch.approvalRequestId } : {}),
},
{
expectedRunVersion: 5,
expectedRunEventSequence: 8,
eventId: 'event-step-running-001',
dedupeKey: 'step-running:step-run-001',
actor: REQUESTER,
},
);
return { admission, binding, evidence, stepRunMutation };
}
function copy(value) {
return structuredClone(value);
}
test('creates one immutable same-transaction Tool start command and barrier', async () => {
const current = await fixture();
const command = createToolExecutionStartCommand({
startId: 'tool-start-001',
admission: current.admission,
evidence: current.evidence,
stepRunMutation: current.stepRunMutation,
});
const barrier = toolExecutionStartBarrierRecord(command);
assert.equal(command.schema, TOOL_EXECUTION_START_COMMAND_SCHEMA);
assert.equal(barrier.schema, TOOL_EXECUTION_START_BARRIER_SCHEMA);
assert.equal(barrier.projectId, 'project-001');
assert.equal(barrier.stepRunId, 'step-run-001');
assert.equal(barrier.previousStepRunVersion, 1);
assert.equal(barrier.startedStepRunVersion, 2);
assert.equal(barrier.approvalRequestId, null);
assert.equal(barrier.adapterDigest, current.evidence.trace.adapterDigest);
assert.match(command.commandDigest, /^[0-9a-f]{64}$/);
assert.match(barrier.barrierDigest, /^[0-9a-f]{64}$/);
assert.equal(Object.isFrozen(command), true);
assert.deepEqual(normalizeToolExecutionStartCommand(command), command);
assert.deepEqual(normalizeToolExecutionStartBarrierRecord(barrier), barrier);
for (const sensitive of ['input', 'handler', 'execute', 'token', 'secret']) {
assert.equal(sensitive in barrier, false);
}
});
test('binds an approved start to the exact waiting Approval request', async () => {
const current = await fixture({ approvalRequired: true });
const command = createToolExecutionStartCommand({
startId: 'tool-start-approved-001',
admission: current.admission,
evidence: current.evidence,
stepRunMutation: current.stepRunMutation,
});
const barrier = toolExecutionStartBarrierRecord(command);
assert.equal(barrier.approvalRequestId, 'approval-tool-001');
assert.equal(barrier.approvalDispatchId, 'dispatch-tool-001');
assert.equal(command.stepRunMutation.previousStatus, 'waiting_approval');
assert.equal(
command.stepRunMutation.stepRun.approvalRequestId,
barrier.approvalRequestId,
);
});
test('rejects detached contract, StepRun, audit and approval bindings', async () => {
const current = await fixture();
const wrongContract = await fixture({ adapterDigest: DIGEST_A });
assert.notEqual(
DIGEST_A,
trustedToolContractIdentityDigest(wrongContract.binding.adapter),
);
assert.throws(
() =>
createToolExecutionStartCommand({
startId: 'tool-start-wrong-contract',
admission: wrongContract.admission,
evidence: wrongContract.evidence,
stepRunMutation: wrongContract.stepRunMutation,
}),
InvalidToolExecutionStartBarrierError,
);
assert.throws(
() =>
createToolExecutionStartCommand({
startId: 'tool-start-wrong-step',
admission: current.admission,
evidence: current.evidence,
stepRunMutation: {
...copy(current.stepRunMutation),
runId: 'run-other',
},
}),
InvalidToolExecutionStartBarrierError,
);
const approved = await fixture({ approvalRequired: true });
assert.throws(
() =>
createToolExecutionStartCommand({
startId: 'tool-start-wrong-approval',
admission: approved.admission,
evidence: approved.evidence,
stepRunMutation: current.stepRunMutation,
}),
InvalidToolExecutionStartBarrierError,
);
});
test('rejects unknown fields, accessors and digest tampering', async () => {
const current = await fixture();
const command = createToolExecutionStartCommand({
startId: 'tool-start-001',
admission: current.admission,
evidence: current.evidence,
stepRunMutation: current.stepRunMutation,
});
const barrier = toolExecutionStartBarrierRecord(command);
assert.throws(
() =>
normalizeToolExecutionStartCommand({
...copy(command),
commandDigest: DIGEST_A,
}),
InvalidToolExecutionStartBarrierError,
);
assert.throws(
() =>
normalizeToolExecutionStartBarrierRecord({
...copy(barrier),
adapterDigest: DIGEST_A,
}),
InvalidToolExecutionStartBarrierError,
);
assert.throws(
() => normalizeToolExecutionStartCommand({ ...copy(command), extra: 1 }),
InvalidToolExecutionStartBarrierError,
);
const accessor = copy(command);
Object.defineProperty(accessor, 'startId', {
enumerable: true,
get() {
return 'tool-start-accessor';
},
});
assert.throws(
() => normalizeToolExecutionStartCommand(accessor),
InvalidToolExecutionStartBarrierError,
);
});
test('publishes the contract through root and explicit subpath without authority', () => {
const root = require('../dist');
const subpath = require('@qinglong/runtime-core/tool-execution-start-barrier');
assert.equal(
root.createToolExecutionStartCommand,
createToolExecutionStartCommand,
);
assert.equal(
subpath.toolExecutionStartBarrierRecord,
toolExecutionStartBarrierRecord,
);
const source = readFileSync(
join(
__dirname,
'..',
'src',
'tool-execution',
'toolExecutionStartBarrier.ts',
),
'utf8',
);
for (const authority of [
'node:child_process',
'node:fs',
'node:http',
'node:https',
'node:net',
'node:worker_threads',
]) {
assert.equal(source.includes(`from '${authority}'`), false);
}
});
@@ -0,0 +1,163 @@
const assert = require('node:assert/strict');
const { createHash } = require('node:crypto');
const { test } = require('node:test');
const {
InvalidToolInvocationArtifactError,
TOOL_INVOCATION_ARTIFACT_ALGORITHM,
TOOL_INVOCATION_INPUT_ARTIFACT_SCHEMA,
TOOL_INVOCATION_PREVIEW_ARTIFACT_SCHEMA,
ToolInvocationArtifactUnavailableError,
createToolInvocationInputArtifact,
createToolInvocationPreviewArtifact,
normalizeToolInvocationInputArtifact,
normalizeToolInvocationPreviewArtifact,
openToolInvocationInputArtifact,
toolInvocationInputArtifactReference,
toolInvocationPreviewArtifactReference,
} = require('../dist/tool-execution/toolInvocationArtifact');
const {
ToolDefinitionRegistry,
} = require('../dist/tool-execution/tool-registry/toolRegistry');
const KEY = Buffer.alloc(32, 7);
const WRONG_KEY = Buffer.alloc(32, 8);
const NONCE = Buffer.alloc(12, 9);
const ACTION_DIGEST = 'a'.repeat(64);
const REDACTION_DIGEST = 'b'.repeat(64);
function registry() {
return new ToolDefinitionRegistry([
{
name: 'demo.compare',
version: '1.0.0',
description: 'Compare one bounded Run projection',
inputSchema: {
type: 'object',
properties: {
runId: { type: 'string', minLength: 1, maxLength: 64 },
token: { type: 'string', minLength: 1, maxLength: 128 },
},
required: ['runId', 'token'],
additionalProperties: false,
},
effect: 'read',
risk: 'low',
requiredPermissions: ['run.read'],
timeoutSeconds: 30,
},
]);
}
function digest(value) {
return createHash('sha256').update(JSON.stringify(value)).digest('hex');
}
function inputArtifact(overrides = {}) {
const input = { runId: 'run-001', token: 'secret-value' };
return createToolInvocationInputArtifact(
{
artifactId: 'artifact-input-001',
projectId: 'project-001',
actionRef: 'tool-plan:run-001',
requestedBy: { type: 'user', id: 'usr-owner' },
tool: { name: 'demo.compare', version: '1.0.0' },
input,
inputDigest: digest(input),
invocationActionDigest: ACTION_DIGEST,
keyId: 'tool-key-2026-07',
key: KEY,
sealedAtMs: 1_000,
...overrides,
},
() => NONCE,
);
}
test('seals bounded Tool input as an opaque authenticated Artifact', () => {
const artifact = inputArtifact();
assert.equal(artifact.schema, TOOL_INVOCATION_INPUT_ARTIFACT_SCHEMA);
assert.equal(artifact.algorithm, TOOL_INVOCATION_ARTIFACT_ALGORITHM);
assert.equal(JSON.stringify(artifact).includes('secret-value'), false);
assert.deepEqual(normalizeToolInvocationInputArtifact(artifact), artifact);
assert.deepEqual(openToolInvocationInputArtifact(artifact, KEY, registry()), {
runId: 'run-001',
token: 'secret-value',
});
assert.deepEqual(toolInvocationInputArtifactReference(artifact), {
artifactId: artifact.artifactId,
artifactDigest: artifact.artifactDigest,
inputDigest: artifact.inputDigest,
keyId: artifact.keyId,
algorithm: TOOL_INVOCATION_ARTIFACT_ALGORITHM,
plaintextBytes: artifact.plaintextBytes,
});
});
test('fails closed for Artifact drift, the wrong key and schema drift', () => {
const artifact = inputArtifact();
assert.throws(
() =>
normalizeToolInvocationInputArtifact({
...artifact,
ciphertext: `${artifact.ciphertext.slice(0, -1)}A`,
}),
InvalidToolInvocationArtifactError,
);
assert.throws(
() => openToolInvocationInputArtifact(artifact, WRONG_KEY, registry()),
ToolInvocationArtifactUnavailableError,
);
assert.throws(
() =>
inputArtifact({
input: { runId: 'run-001', token: 'secret-value', extra: true },
}),
InvalidToolInvocationArtifactError,
);
});
test('publishes the redacted preview as a separately digest-bound Artifact', () => {
const preview = {
title: 'Compare Run',
summary: 'Reads one Run projection',
fields: [
{ kind: 'identifier', label: 'Run', value: 'run-001' },
{ kind: 'redacted', label: 'Credential', value: null },
],
warnings: [],
};
const artifact = createToolInvocationPreviewArtifact({
artifactId: 'artifact-preview-001',
projectId: 'project-001',
actionRef: 'tool-plan:run-001',
actionDigest: ACTION_DIGEST,
redactionContractDigest: REDACTION_DIGEST,
preview,
sealedAtMs: 1_000,
});
assert.equal(artifact.schema, TOOL_INVOCATION_PREVIEW_ARTIFACT_SCHEMA);
assert.equal(JSON.stringify(artifact).includes('secret-value'), false);
assert.deepEqual(normalizeToolInvocationPreviewArtifact(artifact), artifact);
assert.deepEqual(toolInvocationPreviewArtifactReference(artifact), {
artifactId: artifact.artifactId,
artifactDigest: artifact.artifactDigest,
actionDigest: ACTION_DIGEST,
previewDigest: artifact.previewDigest,
redactionContractDigest: REDACTION_DIGEST,
byteLength: artifact.byteLength,
});
});
test('publishes the contract through root and the explicit Artifact subpath', () => {
const root = require('../dist');
const subpath = require('@qinglong/runtime-core/tool-invocation-artifact');
assert.equal(
root.TOOL_INVOCATION_INPUT_ARTIFACT_SCHEMA,
TOOL_INVOCATION_INPUT_ARTIFACT_SCHEMA,
);
assert.equal(
subpath.TOOL_INVOCATION_PREVIEW_ARTIFACT_SCHEMA,
TOOL_INVOCATION_PREVIEW_ARTIFACT_SCHEMA,
);
});
@@ -0,0 +1,500 @@
const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const { join } = require('node:path');
const { test } = require('node:test');
const {
ProjectPolicyEngine,
} = require('@qinglong/runtime-core/project-policy');
const {
InvalidToolDefinitionError,
InvalidToolJsonValueError,
TOOL_INVOCATION_SCHEMA,
ToolDefinitionRegistry,
ToolPolicySnapshotConflictError,
ToolPolicyUnavailableError,
UnsupportedToolError,
normalizeToolDefinition,
prepareToolInvocation,
} = require('../dist/tool-execution/tool-registry/toolRegistry');
function definition(overrides = {}) {
const value = {
name: 'run.compare',
version: '1.0.0',
description: 'Compare one bounded Run projection',
inputSchema: {
type: 'object',
properties: {
runId: { type: 'string', minLength: 1, maxLength: 64 },
tags: {
type: 'array',
items: { type: 'string', maxLength: 16 },
maxItems: 4,
uniqueItems: true,
},
},
required: ['runId'],
additionalProperties: false,
},
outputSchema: {
type: 'object',
properties: {
summary: { type: 'string', maxLength: 1024 },
},
required: ['summary'],
additionalProperties: false,
},
effect: 'read',
risk: 'low',
requiredPermissions: ['run.read'],
timeoutSeconds: 15,
};
return {
...value,
...overrides,
inputSchema: overrides.inputSchema ?? value.inputSchema,
outputSchema: Object.hasOwn(overrides, 'outputSchema')
? overrides.outputSchema
: value.outputSchema,
};
}
function principal(overrides = {}) {
return {
subject: { type: 'user', id: 'usr-1' },
authenticationId: 'auth-1',
authenticatedAtMs: 900,
expiresAtMs: 2_000,
assurance: 'multi_factor',
...overrides,
};
}
function request(overrides = {}) {
return {
projectId: 'default',
principal: principal(),
nowMs: 1_000,
tool: { name: 'run.compare', version: '1.0.0' },
input: { tags: ['failed', 'recent'], runId: 'run-1' },
...overrides,
};
}
function policyDecision(effect = 'allow', fence = {}) {
return {
effect,
reasons:
effect === 'allow'
? ['role_grant']
: effect === 'deny'
? ['permission_missing']
: ['agent_action_requires_approval'],
fence:
fence === null
? null
: {
projectVersion: 3,
bindingVersion: 7,
...fence,
},
};
}
function authorizer(resolve = () => policyDecision()) {
const calls = [];
return {
calls,
async authorize(currentPrincipal, projectId, permission) {
calls.push({ currentPrincipal, projectId, permission });
return resolve(permission);
},
};
}
test('publishes one immutable registry without runtime registration', () => {
const registry = new ToolDefinitionRegistry([
definition({ version: '2.0.0' }),
definition(),
]);
assert.equal(Object.isFrozen(registry), true);
assert.equal('register' in registry, false);
assert.deepEqual(
registry.list().map(({ name, version }) => ({ name, version })),
[
{ name: 'run.compare', version: '1.0.0' },
{ name: 'run.compare', version: '2.0.0' },
],
);
assert.equal(Object.isFrozen(registry.list()[0].inputSchema), true);
assert.throws(
() => registry.resolve('run.compare', '3.0.0'),
UnsupportedToolError,
);
});
test('publishes the same contract through root and tool-registry subpath', () => {
const root = require('../dist');
const subpath = require('@qinglong/runtime-core/tool-registry');
assert.equal(root.ToolDefinitionRegistry, ToolDefinitionRegistry);
assert.equal(subpath.prepareToolInvocation, prepareToolInvocation);
});
test('normalizes a bounded exact JSON Schema subset', () => {
const normalized = normalizeToolDefinition(definition());
assert.deepEqual(normalized.requiredPermissions, ['run.read']);
assert.deepEqual(
normalizeToolDefinition(
definition({ requiredPermissions: ['package.manage'] }),
).requiredPermissions,
['package.manage'],
);
assert.deepEqual(Object.keys(normalized.inputSchema.properties), [
'runId',
'tags',
]);
assert.deepEqual(normalized.inputSchema.required, ['runId']);
const invalid = [
definition({ extra: true }),
definition({ name: 'RunCompare' }),
definition({ version: 'v1.0.0' }),
definition({ requiredPermissions: ['tool.call:run.get'] }),
definition({ requiredPermissions: ['run.read', 'run.read'] }),
definition({
inputSchema: {
type: 'object',
properties: {},
required: [],
additionalProperties: true,
},
}),
definition({
inputSchema: {
type: 'object',
properties: {
value: { type: 'string' },
},
required: [],
additionalProperties: false,
},
}),
definition({
inputSchema: {
type: 'object',
properties: {},
required: [],
additionalProperties: false,
oneOf: [],
},
}),
];
for (const value of invalid) {
assert.throws(
() => normalizeToolDefinition(value),
InvalidToolDefinitionError,
);
}
});
test('enforces schema depth, node and property budgets', () => {
let schema = { type: 'string', maxLength: 8 };
for (let index = 0; index < 9; index += 1) {
schema = { type: 'array', items: schema, maxItems: 1 };
}
assert.throws(
() =>
normalizeToolDefinition(
definition({
inputSchema: {
type: 'object',
properties: { value: schema },
required: ['value'],
additionalProperties: false,
},
}),
),
/depth exceeded/,
);
const properties = Object.fromEntries(
Array.from({ length: 65 }, (_, index) => [
`field${index}`,
{ type: 'boolean' },
]),
);
assert.throws(
() =>
normalizeToolDefinition(
definition({
inputSchema: {
type: 'object',
properties,
required: [],
additionalProperties: false,
},
}),
),
/property budget exceeded/,
);
});
test('canonicalizes input and output while rejecting drift and bounds', () => {
const registry = new ToolDefinitionRegistry([definition()]);
const input = registry.normalizeInput('run.compare', '1.0.0', {
tags: ['failed', 'recent'],
runId: 'run-1',
});
assert.deepEqual(input, {
runId: 'run-1',
tags: ['failed', 'recent'],
});
assert.equal(Object.isFrozen(input), true);
assert.deepEqual(
registry.normalizeOutput('run.compare', '1.0.0', {
summary: 'changed\nwith context',
}),
{ summary: 'changed\nwith context' },
);
for (const invalid of [
{},
{ runId: 'run-1', extra: true },
{ runId: 'run-1', tags: ['same', 'same'] },
{ runId: 'x'.repeat(65) },
]) {
assert.throws(
() => registry.normalizeInput('run.compare', '1.0.0', invalid),
InvalidToolJsonValueError,
);
}
assert.throws(
() =>
registry.normalizeOutput('run.compare', '1.0.0', {
summary: 1,
}),
InvalidToolJsonValueError,
);
const getterInput = { runId: 'run-1' };
Object.defineProperty(getterInput, 'tags', {
enumerable: true,
get() {
throw new Error('must not execute');
},
});
assert.throws(
() => registry.normalizeInput('run.compare', '1.0.0', getterInput),
/JSON data properties/,
);
const sparse = [];
sparse.length = 1;
assert.throws(
() =>
registry.normalizeInput('run.compare', '1.0.0', {
runId: 'run-1',
tags: sparse,
}),
/dense JSON array/,
);
});
test('requires null output when a Tool has no output schema', () => {
const registry = new ToolDefinitionRegistry([
definition({ outputSchema: undefined }),
]);
assert.equal(registry.normalizeOutput('run.compare', '1.0.0', null), null);
assert.throws(
() => registry.normalizeOutput('run.compare', '1.0.0', {}),
/output must be null/,
);
});
test('prepares one digest-bound invocation from a single policy fence', async () => {
const registry = new ToolDefinitionRegistry([definition()]);
const policy = authorizer();
const plan = await prepareToolInvocation(registry, request(), policy);
assert.equal(plan.status, 'ready');
assert.equal(plan.schema, TOOL_INVOCATION_SCHEMA);
assert.equal(plan.permission, 'tool.call:run.compare');
assert.deepEqual(plan.requiredPermissions, ['run.read']);
assert.deepEqual(plan.fence, {
projectVersion: 3,
bindingVersion: 7,
});
assert.match(plan.inputDigest, /^[0-9a-f]{64}$/);
assert.match(plan.actionDigest, /^[0-9a-f]{64}$/);
assert.equal('execute' in plan, false);
assert.deepEqual(
policy.calls.map(({ permission }) => permission),
['tool.call:run.compare', 'run.read'],
);
const replay = await prepareToolInvocation(
registry,
request({ input: { runId: 'run-1', tags: ['failed', 'recent'] } }),
authorizer(),
);
assert.equal(replay.actionDigest, plan.actionDigest);
});
test('uses the real Project Policy port and requires approval for an Agent Tool call', async () => {
const registry = new ToolDefinitionRegistry([definition()]);
const policy = new ProjectPolicyEngine({
async resolve(projectId, subject) {
return {
project: {
id: projectId,
name: 'Default',
slug: 'default',
status: 'active',
version: 3,
createdAtMs: 1,
updatedAtMs: 2,
},
binding: {
projectId,
subject,
version: 7,
state: 'active',
role: 'operator',
mutationId: 'bind-1',
changedBy: { type: 'user', id: 'owner-1' },
createdAtMs: 2,
},
};
},
async append() {
throw new Error('not used');
},
});
const plan = await prepareToolInvocation(
registry,
request({
principal: principal({
subject: { type: 'agent', id: 'agent-1' },
assurance: 'service',
}),
}),
policy,
);
assert.equal(plan.status, 'approval_required');
assert.equal(plan.permission, 'tool.call:run.compare');
assert.equal('execute' in plan, false);
});
test('short-circuits denial before parsing untrusted Tool input', async () => {
const registry = new ToolDefinitionRegistry([definition()]);
const policy = authorizer(() => policyDecision('deny', null));
const plan = await prepareToolInvocation(
registry,
request({ input: { invalid: true } }),
policy,
);
assert.deepEqual(plan, {
status: 'denied',
tool: { name: 'run.compare', version: '1.0.0' },
permission: 'tool.call:run.compare',
});
assert.equal(policy.calls.length, 1);
});
test('fails closed on unavailable, malformed or mixed policy snapshots', async () => {
const registry = new ToolDefinitionRegistry([definition()]);
await assert.rejects(
prepareToolInvocation(
registry,
request(),
authorizer(() => {
throw new Error('storage internals');
}),
),
ToolPolicyUnavailableError,
);
await assert.rejects(
prepareToolInvocation(
registry,
request(),
authorizer((permission) =>
policyDecision('allow', {
projectVersion: permission === 'run.read' ? 4 : 3,
}),
),
),
ToolPolicySnapshotConflictError,
);
await assert.rejects(
prepareToolInvocation(
registry,
request(),
authorizer(() => ({
effect: 'allow',
reasons: ['driver stack'],
fence: null,
})),
),
ToolPolicyUnavailableError,
);
});
test('rejects expired principals and extensible invocation envelopes', async () => {
const registry = new ToolDefinitionRegistry([definition()]);
await assert.rejects(
prepareToolInvocation(
registry,
request({
principal: principal({ expiresAtMs: 1_000 }),
}),
authorizer(),
),
/principal lifetime is inactive/,
);
await assert.rejects(
prepareToolInvocation(
registry,
{ ...request(), extra: true },
authorizer(),
),
/request shape is invalid/,
);
});
test('enforces whole-envelope byte budgets after schema validation', () => {
const registry = new ToolDefinitionRegistry([
definition({
inputSchema: {
type: 'object',
properties: {
payload: { type: 'string', maxLength: 70_000 },
},
required: ['payload'],
additionalProperties: false,
},
}),
]);
assert.throws(
() =>
registry.normalizeInput('run.compare', '1.0.0', {
payload: 'x'.repeat(66_000),
}),
/byte budget exceeded/,
);
});
test('keeps registry and invocation planning free of execution and ambient authority', () => {
const source = readFileSync(
join(__dirname, '../src/tool-execution/tool-registry/toolRegistry.ts'),
'utf8',
);
for (const authority of [
"from 'node:child_process'",
"from 'node:fs'",
"from 'node:http'",
"from 'node:https'",
'setInterval(',
'setTimeout(',
'dynamic import',
]) {
assert.equal(source.includes(authority), false, authority);
}
});
@@ -0,0 +1,245 @@
'use strict';
const assert = require('node:assert/strict');
const test = require('node:test');
const {
TOOL_RESULT_KEY_CATALOG_SCHEMA,
ToolResultKeyCatalogUnavailableError,
ToolResultKeyLostError,
createToolResultKeyCatalogBootstrapCommand,
createToolResultKeyLostCommand,
createToolResultKeyRestoreCommand,
createToolResultKeyRetirementCommand,
createToolResultKeyRotationCommand,
findToolResultKeyCatalogEntry,
normalizeToolResultKeyCatalogCommand,
normalizeToolResultKeyCatalogRecord,
requireActiveToolResultKey,
requireDecryptableToolResultKey,
toolResultKeyMaterialProof,
} = require('../dist/tool-execution/toolResultKeyCatalog.js');
function committed(command, committedAtMs = 1_000) {
return normalizeToolResultKeyCatalogRecord({
...command.next,
committedAtMs,
});
}
function bootstrap() {
const key = Buffer.alloc(32, 1);
const proof = toolResultKeyMaterialProof('result-key-001', key);
const command = createToolResultKeyCatalogBootstrapCommand({
keyId: 'result-key-001',
materialProof: proof,
mutationId: 'result-key-bootstrap-001',
});
return { key, proof, command, catalog: committed(command) };
}
test('bootstraps one digest-bound active result key without retaining material', () => {
const value = bootstrap();
assert.equal(value.command.next.schema, TOOL_RESULT_KEY_CATALOG_SCHEMA);
assert.equal(value.command.expectedGeneration, 0);
assert.equal(value.command.expectedCatalogDigest, null);
assert.equal(value.catalog.generation, 1);
assert.equal(value.catalog.activeKeyId, 'result-key-001');
assert.equal(
requireActiveToolResultKey(value.catalog).materialProof,
value.proof,
);
assert.equal(
value.key.every((byte) => byte === 1),
true,
);
assert.match(value.proof, /^[0-9a-f]{64}$/);
assert.notEqual(
toolResultKeyMaterialProof('result-key-002', value.key),
value.proof,
);
assert.equal(
JSON.stringify(value.catalog).includes(value.key.toString('base64url')),
false,
);
});
test('rotates with exact generation fencing and preserves historical decryption', () => {
const first = bootstrap();
const secondKey = Buffer.alloc(32, 2);
const rotation = createToolResultKeyRotationCommand(first.catalog, {
keyId: 'result-key-002',
materialProof: toolResultKeyMaterialProof('result-key-002', secondKey),
mutationId: 'result-key-rotate-002',
});
const second = committed(rotation, 2_000);
assert.equal(rotation.expectedGeneration, 1);
assert.equal(rotation.expectedCatalogDigest, first.catalog.catalogDigest);
assert.equal(second.generation, 2);
assert.equal(second.activeKeyId, 'result-key-002');
assert.equal(
findToolResultKeyCatalogEntry(second, 'result-key-001').state,
'decrypt_only',
);
assert.equal(requireActiveToolResultKey(second).keyId, 'result-key-002');
assert.equal(
requireDecryptableToolResultKey(second, 'result-key-001').keyId,
'result-key-001',
);
assert.throws(
() =>
createToolResultKeyRotationCommand(second, {
keyId: 'result-key-001',
materialProof: first.proof,
mutationId: 'result-key-reuse-003',
}),
TypeError,
);
});
test('canonicalizes reverse-lexical key rotation before hashing', () => {
const first = committed(
createToolResultKeyCatalogBootstrapCommand({
keyId: 'result-key-z',
materialProof: toolResultKeyMaterialProof(
'result-key-z',
Buffer.alloc(32, 1),
),
mutationId: 'result-key-bootstrap-z',
}),
1_000,
);
const rotated = createToolResultKeyRotationCommand(first, {
keyId: 'result-key-a',
materialProof: toolResultKeyMaterialProof(
'result-key-a',
Buffer.alloc(32, 2),
),
mutationId: 'result-key-rotate-a',
});
assert.deepEqual(
rotated.next.keys.map((entry) => entry.keyId),
['result-key-a', 'result-key-z'],
);
});
test('requires a rekey receipt before retirement and prunes retired history later', () => {
const first = bootstrap();
const rotated = committed(
createToolResultKeyRotationCommand(first.catalog, {
keyId: 'result-key-002',
materialProof: toolResultKeyMaterialProof(
'result-key-002',
Buffer.alloc(32, 2),
),
mutationId: 'result-key-rotate-002',
}),
);
assert.throws(
() =>
createToolResultKeyRetirementCommand(rotated, {
keyId: 'result-key-002',
retirementReceiptDigest: 'a'.repeat(64),
mutationId: 'result-key-retire-active-003',
}),
TypeError,
);
const retirement = createToolResultKeyRetirementCommand(rotated, {
keyId: 'result-key-001',
retirementReceiptDigest: 'b'.repeat(64),
mutationId: 'result-key-retire-003',
});
const retired = committed(retirement);
assert.equal(
findToolResultKeyCatalogEntry(retired, 'result-key-001').state,
'retired',
);
assert.throws(
() => requireDecryptableToolResultKey(retired, 'result-key-001'),
ToolResultKeyCatalogUnavailableError,
);
const next = committed(
createToolResultKeyRotationCommand(retired, {
keyId: 'result-key-003',
materialProof: toolResultKeyMaterialProof(
'result-key-003',
Buffer.alloc(32, 3),
),
mutationId: 'result-key-rotate-004',
}),
);
assert.equal(findToolResultKeyCatalogEntry(next, 'result-key-001'), null);
assert.equal(
findToolResultKeyCatalogEntry(next, 'result-key-002').state,
'decrypt_only',
);
});
test('marks missing material lost and restores only the exact proof', () => {
const first = bootstrap();
const lost = committed(
createToolResultKeyLostCommand(first.catalog, {
keyId: 'result-key-001',
mutationId: 'result-key-lost-002',
}),
);
assert.equal(lost.activeKeyId, null);
assert.throws(
() => requireActiveToolResultKey(lost),
ToolResultKeyCatalogUnavailableError,
);
assert.throws(
() => requireDecryptableToolResultKey(lost, 'result-key-001'),
ToolResultKeyLostError,
);
assert.throws(
() =>
createToolResultKeyRestoreCommand(lost, {
keyId: 'result-key-001',
materialProof: 'c'.repeat(64),
mutationId: 'result-key-bad-restore-003',
}),
TypeError,
);
const restored = committed(
createToolResultKeyRestoreCommand(lost, {
keyId: 'result-key-001',
materialProof: first.proof,
mutationId: 'result-key-restore-003',
}),
);
assert.equal(restored.activeKeyId, null);
assert.equal(
findToolResultKeyCatalogEntry(restored, 'result-key-001').state,
'decrypt_only',
);
assert.throws(
() => requireActiveToolResultKey(restored),
ToolResultKeyCatalogUnavailableError,
);
});
test('rejects command drift and exposes authority only through its subpath', () => {
const value = bootstrap();
assert.throws(
() =>
normalizeToolResultKeyCatalogCommand({
...value.command,
expectedGeneration: 1,
}),
TypeError,
);
const root = require('../dist');
const authority = require('@qinglong/runtime-core/tool-result-key-catalog');
assert.equal(root.createToolResultKeyCatalogBootstrapCommand, undefined);
assert.equal(
authority.createToolResultKeyCatalogBootstrapCommand,
createToolResultKeyCatalogBootstrapCommand,
);
});
@@ -0,0 +1,445 @@
'use strict';
const assert = require('node:assert/strict');
const { createHash } = require('node:crypto');
const test = require('node:test');
const {
BUILTIN_RUN_READ_TOOL,
BUILTIN_RUN_READ_TOOL_DEFINITION,
} = require('../dist/tool-execution/builtin-run-read/builtInRunReadTool');
const {
TRUSTED_TOOL_EXECUTION_RESULT_SCHEMA,
} = require('../dist/tool-execution/trustedToolExecution');
const {
TOOL_EXECUTION_RESULT_KEY_BINDING_SCHEMA,
createToolExecutionResultArtifact,
normalizeToolExecutionResultKeyBinding,
} = require('../dist/tool-execution/toolExecutionCompletion');
const {
createToolResultKeyCatalogBootstrapCommand,
createToolResultKeyRotationCommand,
normalizeToolResultKeyCatalogRecord,
requireActiveToolResultKey,
toolResultKeyCatalogFence,
toolResultKeyMaterialProof,
} = require('../dist/tool-execution/toolResultKeyCatalog');
const {
TOOL_EXECUTION_RESULT_REKEY_OVERLAY_SCHEMA,
InvalidToolExecutionResultRekeyError,
ToolResultKeyRetirementCoverageBuilder,
ToolExecutionResultRekeyConflictError,
ToolExecutionResultRekeyUnavailableError,
createToolExecutionResultRekeyCommand,
createToolResultKeyRetirementReceipt,
createToolResultKeyRetirementReceiptCommand,
normalizeToolExecutionResultRekeyCommand,
normalizeToolResultKeyRetirementReceiptCommand,
normalizeToolResultKeyRetirementReceipt,
openToolExecutionResultRekeyOverlay,
} = require('../dist/tool-execution/toolResultRekey');
const {
ToolDefinitionRegistry,
} = require('../dist/tool-execution/tool-registry/toolRegistry');
const KEY_A = Buffer.alloc(32, 1);
const KEY_B = Buffer.alloc(32, 2);
const KEY_C = Buffer.alloc(32, 3);
const OUTPUT_DIGEST_DOMAIN = Buffer.from(
'qinglong/trusted-tool-execution-output-digest@v1\0',
'utf8',
);
const RESULT_DIGEST_DOMAIN = Buffer.from(
'qinglong/trusted-tool-execution-result-digest@v1\0',
'utf8',
);
const BINDING_DIGEST_DOMAIN = Buffer.from(
'qinglong/tool-execution-result-key-binding-digest@v1\0',
'utf8',
);
function hash(domain, value) {
return createHash('sha256')
.update(domain)
.update(JSON.stringify(value))
.digest('hex');
}
function registry() {
return new ToolDefinitionRegistry([BUILTIN_RUN_READ_TOOL_DEFINITION]);
}
function output() {
return {
createdAtMs: 1_000,
eventSequence: 3,
executionOrigin: 'manual',
executionOwner: 'runtime',
found: true,
id: 'run-rekey-001',
priority: 10,
queuedAtMs: 1_100,
startedAtMs: 1_200,
status: 'succeeded',
taskId: 'task-rekey-001',
taskRevision: 'task-rekey-001@1',
version: 2,
};
}
function executionResult() {
const value = output();
const unsigned = Object.freeze({
schema: TRUSTED_TOOL_EXECUTION_RESULT_SCHEMA,
startId: 'tool-start-rekey-001',
barrierDigest: 'a'.repeat(64),
adapterDigest: 'b'.repeat(64),
output: value,
outputDigest: hash(OUTPUT_DIGEST_DOMAIN, value),
completedAtMs: 1_500,
});
return Object.freeze({
...unsigned,
resultDigest: hash(RESULT_DIGEST_DOMAIN, unsigned),
});
}
function artifact() {
return createToolExecutionResultArtifact(
{
artifactId: 'artifact-result-rekey-001',
projectId: 'project-rekey-001',
runId: 'run-host-rekey-001',
stepRunId: 'step-run-rekey-001',
tool: BUILTIN_RUN_READ_TOOL,
executionResult: executionResult(),
keyId: 'result-key-a',
key: KEY_A,
},
registry(),
() => Buffer.alloc(12, 4),
);
}
function binding(source) {
const unsigned = Object.freeze({
schema: TOOL_EXECUTION_RESULT_KEY_BINDING_SCHEMA,
startId: source.startId,
artifactId: source.artifactId,
artifactDigest: source.artifactDigest,
catalogGeneration: 1,
catalogDigest: 'c'.repeat(64),
keyId: source.keyId,
materialProof: toolResultKeyMaterialProof(source.keyId, KEY_A),
});
return normalizeToolExecutionResultKeyBinding({
...unsigned,
bindingDigest: hash(BINDING_DIGEST_DOMAIN, unsigned),
});
}
function committed(command, committedAtMs) {
return normalizeToolResultKeyCatalogRecord({
...command.next,
committedAtMs,
});
}
function targetCatalogs() {
const first = committed(
createToolResultKeyCatalogBootstrapCommand({
keyId: 'result-key-b',
materialProof: toolResultKeyMaterialProof('result-key-b', KEY_B),
mutationId: 'result-key-bootstrap-b',
}),
1_600,
);
const second = committed(
createToolResultKeyRotationCommand(first, {
keyId: 'result-key-c',
materialProof: toolResultKeyMaterialProof('result-key-c', KEY_C),
mutationId: 'result-key-rotate-c',
}),
1_800,
);
return { first, second };
}
test('creates an immutable rekey head without rewriting the source Artifact', () => {
const source = artifact();
const sourceJson = JSON.stringify(source);
const sourceBinding = binding(source);
const { first } = targetCatalogs();
const command = createToolExecutionResultRekeyCommand({
artifact: source,
binding: sourceBinding,
previousOverlay: null,
overlayId: 'result-rekey-overlay-001',
mutationId: 'result-rekey-mutation-001',
targetCatalogFence: toolResultKeyCatalogFence(
first,
requireActiveToolResultKey(first),
),
targetKey: KEY_B,
output: output(),
rekeyedAtMs: 1_700,
registry: registry(),
nonceFactory: () => Buffer.alloc(12, 5),
});
assert.equal(command.expectedRevision, 0);
assert.equal(command.expectedOverlayDigest, null);
assert.equal(
command.overlay.schema,
TOOL_EXECUTION_RESULT_REKEY_OVERLAY_SCHEMA,
);
assert.equal(command.overlay.revision, 1);
assert.equal(command.overlay.fromKeyId, 'result-key-a');
assert.equal(command.overlay.targetCatalogFence.keyId, 'result-key-b');
assert.equal(
JSON.stringify(command.overlay).includes('run-rekey-001'),
false,
);
assert.equal(JSON.stringify(source), sourceJson);
assert.deepEqual(
openToolExecutionResultRekeyOverlay(
command.overlay,
KEY_B,
registry(),
source,
),
output(),
);
assert.throws(
() =>
openToolExecutionResultRekeyOverlay(
command.overlay,
KEY_C,
registry(),
source,
),
ToolExecutionResultRekeyUnavailableError,
);
});
test('chains rekey revisions with an exact head fence', () => {
const source = artifact();
const sourceBinding = binding(source);
const { first, second } = targetCatalogs();
const firstCommand = createToolExecutionResultRekeyCommand({
artifact: source,
binding: sourceBinding,
previousOverlay: null,
overlayId: 'result-rekey-overlay-001',
mutationId: 'result-rekey-mutation-001',
targetCatalogFence: toolResultKeyCatalogFence(
first,
requireActiveToolResultKey(first),
),
targetKey: KEY_B,
output: output(),
rekeyedAtMs: 1_700,
registry: registry(),
nonceFactory: () => Buffer.alloc(12, 5),
});
const secondCommand = createToolExecutionResultRekeyCommand({
artifact: source,
binding: sourceBinding,
previousOverlay: firstCommand.overlay,
overlayId: 'result-rekey-overlay-002',
mutationId: 'result-rekey-mutation-002',
targetCatalogFence: toolResultKeyCatalogFence(
second,
requireActiveToolResultKey(second),
),
targetKey: KEY_C,
output: output(),
rekeyedAtMs: 1_900,
registry: registry(),
nonceFactory: () => Buffer.alloc(12, 6),
});
assert.equal(secondCommand.expectedRevision, 1);
assert.equal(
secondCommand.expectedOverlayDigest,
firstCommand.overlay.overlayDigest,
);
assert.equal(secondCommand.overlay.revision, 2);
assert.equal(secondCommand.overlay.fromKeyId, 'result-key-b');
assert.deepEqual(
openToolExecutionResultRekeyOverlay(
secondCommand.overlay,
KEY_C,
registry(),
source,
),
output(),
);
assert.throws(
() =>
normalizeToolExecutionResultRekeyCommand({
...secondCommand,
expectedRevision: 0,
}),
InvalidToolExecutionResultRekeyError,
);
assert.throws(
() =>
createToolExecutionResultRekeyCommand({
artifact: { ...source, artifactId: 'artifact-result-rekey-other' },
binding: sourceBinding,
previousOverlay: firstCommand.overlay,
overlayId: 'result-rekey-overlay-bad',
mutationId: 'result-rekey-mutation-bad',
targetCatalogFence: toolResultKeyCatalogFence(
second,
requireActiveToolResultKey(second),
),
targetKey: KEY_C,
output: output(),
rekeyedAtMs: 1_900,
registry: registry(),
}),
TypeError,
);
assert.throws(
() =>
createToolExecutionResultRekeyCommand({
artifact: source,
binding: { ...sourceBinding, artifactId: 'artifact-result-other' },
previousOverlay: firstCommand.overlay,
overlayId: 'result-rekey-overlay-bad',
mutationId: 'result-rekey-mutation-bad',
targetCatalogFence: toolResultKeyCatalogFence(
second,
requireActiveToolResultKey(second),
),
targetKey: KEY_C,
output: output(),
rekeyedAtMs: 1_900,
registry: registry(),
}),
TypeError,
);
});
test('binds retirement evidence to an exact catalog and zero uncovered heads', () => {
const coverage = new ToolResultKeyRetirementCoverageBuilder({
catalogGeneration: 2,
catalogDigest: 'd'.repeat(64),
keyId: 'result-key-a',
decryptableKeyIds: ['result-key-b'],
});
coverage.add({
artifactId: 'artifact-result-rekey-001',
bindingDigest: 'f'.repeat(64),
bindingKeyId: 'result-key-a',
headOverlayDigest: '1'.repeat(64),
headTargetKeyId: 'result-key-b',
headTargetCatalogGeneration: 2,
headTargetCatalogDigest: 'd'.repeat(64),
});
const coverageResult = coverage.finish();
assert.deepEqual(
{
bindingCount: coverageResult.bindingCount,
overlayHeadCount: coverageResult.overlayHeadCount,
uncoveredBindingCount: coverageResult.uncoveredBindingCount,
uncoveredOverlayHeadCount: coverageResult.uncoveredOverlayHeadCount,
},
{
bindingCount: 1,
overlayHeadCount: 1,
uncoveredBindingCount: 0,
uncoveredOverlayHeadCount: 0,
},
);
const receipt = createToolResultKeyRetirementReceipt({
catalogGeneration: 2,
catalogDigest: 'd'.repeat(64),
keyId: 'result-key-a',
materialProof: toolResultKeyMaterialProof('result-key-a', KEY_A),
mutationId: 'result-key-retirement-receipt-001',
bindingCount: coverageResult.bindingCount,
overlayHeadCount: coverageResult.overlayHeadCount,
coverageDigest: coverageResult.coverageDigest,
createdAtMs: 2_000,
});
assert.equal(receipt.uncoveredBindingCount, 0);
assert.equal(receipt.uncoveredOverlayHeadCount, 0);
assert.throws(
() =>
normalizeToolResultKeyRetirementReceipt({
...receipt,
uncoveredBindingCount: 1,
}),
InvalidToolExecutionResultRekeyError,
);
const command = createToolResultKeyRetirementReceiptCommand({
expectedCatalogGeneration: 2,
expectedCatalogDigest: 'd'.repeat(64),
keyId: 'result-key-a',
mutationId: 'result-key-retirement-receipt-001',
});
assert.throws(
() =>
normalizeToolResultKeyRetirementReceiptCommand({
...command,
expectedCatalogGeneration: 3,
}),
InvalidToolExecutionResultRekeyError,
);
});
test('retirement coverage rejects missing and self-key heads', () => {
const missing = new ToolResultKeyRetirementCoverageBuilder({
catalogGeneration: 2,
catalogDigest: 'd'.repeat(64),
keyId: 'result-key-a',
decryptableKeyIds: ['result-key-b'],
});
missing.add({
artifactId: 'artifact-result-rekey-001',
bindingDigest: 'f'.repeat(64),
bindingKeyId: 'result-key-a',
headOverlayDigest: null,
headTargetKeyId: null,
headTargetCatalogGeneration: null,
headTargetCatalogDigest: null,
});
assert.equal(missing.finish().uncoveredBindingCount, 1);
const self = new ToolResultKeyRetirementCoverageBuilder({
catalogGeneration: 2,
catalogDigest: 'd'.repeat(64),
keyId: 'result-key-a',
decryptableKeyIds: ['result-key-b'],
});
self.add({
artifactId: 'artifact-result-rekey-002',
bindingDigest: '2'.repeat(64),
bindingKeyId: 'result-key-b',
headOverlayDigest: '3'.repeat(64),
headTargetKeyId: 'result-key-a',
headTargetCatalogGeneration: 1,
headTargetCatalogDigest: 'c'.repeat(64),
});
assert.equal(self.finish().uncoveredOverlayHeadCount, 1);
});
test('exposes rekey only from its explicit subpath', () => {
const root = require('../dist');
const authority = require('@qinglong/runtime-core/tool-result-rekey');
assert.equal(root.createToolExecutionResultRekeyCommand, undefined);
assert.equal(
authority.createToolExecutionResultRekeyCommand,
createToolExecutionResultRekeyCommand,
);
assert.equal(
authority.ToolExecutionResultRekeyConflictError,
ToolExecutionResultRekeyConflictError,
);
});
@@ -0,0 +1,162 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidTriggerError,
InvalidTriggerSpecSemanticError,
UnsupportedTriggerSpecError,
createBuiltInTriggerSpecSemanticRegistry,
createTriggerRecord,
createTriggerSpecSemanticRegistry,
normalizeTriggerRecord,
} = require('@qinglong/runtime-core/trigger');
function command(overrides = {}) {
return {
projectId: 'default',
triggerId: 'trigger-1',
expectedRevision: null,
mutationId: '019f7300-0000-7000-8000-000000000001',
taskId: 'task-1',
taskRevision: 3,
taskContentDigest: 'a'.repeat(64),
spec: {
schema: 'qinglong/cron@v1',
config: {
expression: ' 0 2 * * * ',
timezone: 'Etc/UTC',
misfirePolicy: 'skip',
},
},
enabled: true,
occurredAtMs: 200,
...overrides,
};
}
test('normalizes built-in cron semantics and creates a digest-bound record', () => {
const registry = createBuiltInTriggerSpecSemanticRegistry();
const input = command();
const spec = registry.normalize({
projectId: input.projectId,
triggerId: input.triggerId,
taskId: input.taskId,
taskRevision: input.taskRevision,
spec: input.spec,
});
assert.deepEqual({ ...spec.config }, {
expression: '0 2 * * *',
timezone: 'UTC',
misfirePolicy: 'skip',
});
const record = createTriggerRecord({ ...input, spec }, 100);
assert.match(record.contentDigest, /^[0-9a-f]{64}$/);
assert.deepEqual(normalizeTriggerRecord(record), record);
assert.throws(
() => normalizeTriggerRecord({ ...record, enabled: false }),
InvalidTriggerError,
);
});
test('rejects cron macros, implicit timezones and unknown misfire behavior', () => {
const registry = createBuiltInTriggerSpecSemanticRegistry();
const normalize = (config) =>
registry.normalize({
projectId: 'default',
triggerId: 'trigger-1',
taskId: 'task-1',
taskRevision: 1,
spec: { schema: 'qinglong/cron@v1', config },
});
assert.throws(
() =>
normalize({
expression: '@daily',
timezone: 'UTC',
misfirePolicy: 'skip',
}),
InvalidTriggerSpecSemanticError,
);
assert.throws(
() => normalize({ expression: '0 2 * * *', misfirePolicy: 'skip' }),
InvalidTriggerSpecSemanticError,
);
assert.throws(
() =>
normalize({
expression: '0 2 * * *',
timezone: 'UTC',
misfirePolicy: 'replay_all',
}),
InvalidTriggerSpecSemanticError,
);
});
test('keeps extension schemas explicit and the qinglong namespace reserved', () => {
assert.throws(
() =>
createTriggerSpecSemanticRegistry([
{
schema: 'qinglong/event@v1',
normalizeConfig: (config) => config,
},
]),
InvalidTriggerSpecSemanticError,
);
const registry = createTriggerSpecSemanticRegistry([
{
schema: 'example/event@v1',
normalizeConfig(config) {
return Object.freeze({ topic: String(config.topic).toLowerCase() });
},
},
]);
assert.deepEqual(
{
...registry.normalize({
projectId: 'default',
triggerId: 'trigger-1',
taskId: 'task-1',
taskRevision: 1,
spec: { schema: 'example/event@v1', config: { topic: 'BUILD' } },
}).config,
},
{ topic: 'build' },
);
assert.throws(
() =>
createBuiltInTriggerSpecSemanticRegistry().normalize({
projectId: 'default',
triggerId: 'trigger-1',
taskId: 'task-1',
taskRevision: 1,
spec: { schema: 'example/event@v1', config: { topic: 'build' } },
}),
UnsupportedTriggerSpecError,
);
});
test('rejects extensible records, invalid identity and over-budget specs', () => {
const base = command();
assert.throws(
() => createTriggerRecord({ ...base, unexpected: true }, 100),
InvalidTriggerError,
);
assert.throws(
() => createTriggerRecord({ ...base, taskContentDigest: 'A'.repeat(64) }, 100),
InvalidTriggerError,
);
assert.throws(
() =>
createTriggerRecord(
{
...base,
spec: {
schema: 'example/event@v1',
config: { value: 'x'.repeat(16 * 1024) },
},
},
100,
),
InvalidTriggerError,
);
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,609 @@
const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const { join } = require('node:path');
const { test } = require('node:test');
const {
consumeApprovalRequest,
createApprovalRequest,
decideApprovalRequest,
} = require('../dist/approved-action/approvedAction');
const {
createPluginPackageResourceGenerationFromReferences,
} = require('../dist/plugin-package/pluginPackageResourceGeneration');
const {
createProjectToolDefinitionSnapshot,
projectToolDefinitionRegistry,
} = require('../dist/tool-execution/tool-registry/projectToolDefinitionSnapshot');
const {
prepareToolInvocation,
} = require('../dist/tool-execution/tool-registry/toolRegistry');
const {
InvalidTrustedToolInvocationError,
TOOL_INVOKE_ACTION_TYPE,
TRUSTED_TOOL_EXECUTION_ADMISSION_SCHEMA,
TRUSTED_TOOL_HANDLER_BINDING_SCHEMA,
TRUSTED_TOOL_INVOCATION_PLAN_SCHEMA,
TrustedToolExecutionApprovalRequiredError,
TrustedToolExecutionPolicyDeniedError,
TrustedToolExecutionPolicyUnavailableError,
TrustedToolHandlerBindingRegistry,
TrustedToolHandlerUnavailableError,
TrustedToolInvocationBindingConflictError,
admitTrustedToolExecution,
assertTrustedToolApprovedDispatch,
createTrustedToolHandlerBinding,
createTrustedToolInvocationPlan,
normalizeTrustedToolHandlerBinding,
normalizeTrustedToolInvocationPlan,
trustedToolInvocationApprovalBinding,
} = require('../dist/tool-execution/trustedToolInvocation');
const DIGEST_A = 'a'.repeat(64);
const DIGEST_B = 'b'.repeat(64);
const DIGEST_C = 'c'.repeat(64);
const REQUESTER = Object.freeze({ type: 'user', id: 'usr-tool-owner' });
const SYSTEM = Object.freeze({ type: 'system', id: 'tool-dispatcher' });
const FENCE = Object.freeze({ projectVersion: 3, bindingVersion: 7 });
function definition(overrides = {}) {
return {
name: 'demo.compare',
version: '1.0.0',
description: 'Compare one bounded Run projection',
inputSchema: {
type: 'object',
properties: {
runId: { type: 'string', minLength: 1, maxLength: 64 },
token: { type: 'string', minLength: 1, maxLength: 128 },
},
required: ['runId', 'token'],
additionalProperties: false,
},
outputSchema: {
type: 'object',
properties: {
summary: { type: 'string', maxLength: 1024 },
},
required: ['summary'],
additionalProperties: false,
},
effect: 'read',
risk: 'low',
requiredPermissions: ['run.read'],
timeoutSeconds: 30,
...overrides,
};
}
function snapshot(options = {}) {
const generation = createPluginPackageResourceGenerationFromReferences({
installationId: 'install-demo',
projectId: 'project-001',
packageName: 'demo',
lockDigest: options.lockDigest ?? DIGEST_A,
generation: options.generation ?? 1,
previousActiveLockDigest:
options.generation && options.generation > 1 ? DIGEST_A : null,
contentDigest: options.contentDigest ?? DIGEST_B,
resources: [],
});
return createProjectToolDefinitionSnapshot({
projectId: 'project-001',
contributions: [
{
generation,
revisionDigest: options.revisionDigest ?? DIGEST_C,
definitions: [definition(options.definition)],
},
],
});
}
function bindingInput(overrides = {}) {
return {
tool: { name: 'demo.compare', version: '1.0.0' },
adapter: { id: 'builtin.demo-compare', version: '1.0.0' },
executionClass: 'builtin_in_process',
profiles: ['edge', 'standalone'],
authorities: ['database.read'],
timeoutSeconds: 20,
redactionContract: {
id: 'redaction.demo-compare',
version: '1.0.0',
},
auditContract: { id: 'audit.tool-call', version: '1.0.0' },
...overrides,
};
}
function harness(options = {}) {
const currentSnapshot = options.snapshot ?? snapshot();
const binding = createTrustedToolHandlerBinding(
currentSnapshot,
bindingInput(options.binding),
);
return {
snapshot: currentSnapshot,
binding,
bindings: new TrustedToolHandlerBindingRegistry(currentSnapshot, [binding]),
};
}
function principal(overrides = {}) {
return {
subject: REQUESTER,
authenticationId: 'auth-tool-1',
authenticatedAtMs: 800,
expiresAtMs: 10_000,
assurance: 'local_console',
...overrides,
};
}
function decision(effect = 'allow', fence = FENCE) {
return {
effect,
reasons:
effect === 'allow'
? ['role_grant']
: effect === 'deny'
? ['permission_missing']
: ['agent_action_requires_approval'],
fence,
};
}
function authorizer(resolve = () => decision()) {
const calls = [];
return {
calls,
async authorize(currentPrincipal, projectId, permission) {
calls.push({ currentPrincipal, projectId, permission });
return resolve(permission);
},
};
}
async function invocation(currentSnapshot, status = 'ready') {
return prepareToolInvocation(
projectToolDefinitionRegistry(currentSnapshot),
{
projectId: 'project-001',
principal: principal(),
nowMs: 900,
tool: { name: 'demo.compare', version: '1.0.0' },
input: { token: 'secret-value', runId: 'run-001' },
},
authorizer(() =>
decision(status === 'ready' ? 'allow' : 'require_approval'),
),
);
}
function preview(overrides = {}) {
return {
title: 'Compare Run',
summary: 'Reads one Run projection without exposing credentials',
fields: [
{ kind: 'identifier', label: 'Run', value: 'run-001' },
{ kind: 'redacted', label: 'Credential', value: null },
],
warnings: [],
...overrides,
};
}
async function plan(currentHarness, status = 'ready', overrides = {}) {
return createTrustedToolInvocationPlan(
currentHarness.bindings,
await invocation(currentHarness.snapshot, status),
{
actionRef: 'tool-plan:run-001',
inputArtifactId: 'artifact-input-001',
previewArtifactId: 'artifact-preview-001',
artifactKeyId: 'tool-key-test',
artifactKey: Buffer.alloc(32, 7),
artifactNonce: Buffer.alloc(12, 9),
profile: 'edge',
preview: preview(),
sealedAtMs: 1_000,
...overrides,
},
).plan;
}
function evidence(overrides = {}) {
return {
stepRun: {
id: 'step-run-001',
version: 1,
digest: DIGEST_A,
...overrides.stepRun,
},
trace: {
traceId: 'trace-001',
spanId: 'span-001',
digest: DIGEST_B,
...overrides.trace,
},
audit: {
eventId: 'audit-event-001',
digest: DIGEST_C,
...overrides.audit,
},
};
}
async function approvedDispatch(currentHarness, currentPlan) {
const action = trustedToolInvocationApprovalBinding(
currentPlan,
currentHarness.bindings,
);
const request = createApprovalRequest({
id: 'approval-tool-001',
projectId: currentPlan.projectId,
action,
risk: currentPlan.risk,
decisionMode: 'human_confirmation',
requestedBy: currentPlan.requestedBy,
requestedAtMs: 1_100,
expiresAtMs: 9_000,
requestFence: currentPlan.policyFence,
});
const approved = decideApprovalRequest(request, {
expectedVersion: 1,
decisionId: 'decision-tool-001',
decision: 'approved',
reasonCode: 'reviewed',
principal: principal(),
decidedAtMs: 1_200,
authorizationFence: FENCE,
});
return consumeApprovalRequest(approved, {
expectedVersion: 2,
consumptionId: 'consume-tool-001',
dispatchId: 'dispatch-tool-001',
action,
requestedBy: currentPlan.requestedBy,
consumedBy: SYSTEM,
consumedAtMs: 1_300,
authorizationFence: FENCE,
}).dispatch;
}
test('creates an immutable snapshot-specific handler binding without executable code', () => {
const current = harness();
assert.equal(current.binding.schema, TRUSTED_TOOL_HANDLER_BINDING_SCHEMA);
assert.equal(current.binding.snapshotDigest, current.snapshot.snapshotDigest);
assert.equal(
current.binding.definitionDigest,
current.snapshot.definitions[0].definitionDigest,
);
assert.match(current.binding.bindingDigest, /^[0-9a-f]{64}$/);
assert.deepEqual(current.binding.profiles, ['edge', 'standalone']);
assert.deepEqual(current.binding.authorities, ['database.read']);
assert.equal(Object.isFrozen(current.binding), true);
assert.equal('execute' in current.binding, false);
assert.equal('handler' in current.binding, false);
assert.deepEqual(
normalizeTrustedToolHandlerBinding(current.binding),
current.binding,
);
assert.deepEqual(current.bindings.list()[0], current.binding);
assert.equal('register' in current.bindings, false);
});
test('rejects unknown Tools, widened timeouts, duplicate bindings and stale snapshots', () => {
const currentSnapshot = snapshot();
assert.throws(
() =>
createTrustedToolHandlerBinding(
currentSnapshot,
bindingInput({
tool: { name: 'demo.missing', version: '1.0.0' },
}),
),
TrustedToolHandlerUnavailableError,
);
assert.throws(
() =>
createTrustedToolHandlerBinding(
currentSnapshot,
bindingInput({ timeoutSeconds: 31 }),
),
/widens/,
);
const binding = createTrustedToolHandlerBinding(
currentSnapshot,
bindingInput(),
);
assert.throws(
() =>
new TrustedToolHandlerBindingRegistry(currentSnapshot, [
binding,
binding,
]),
/duplicated/,
);
const nextSnapshot = snapshot({
generation: 2,
lockDigest: 'd'.repeat(64),
contentDigest: 'e'.repeat(64),
revisionDigest: 'f'.repeat(64),
});
assert.throws(
() => new TrustedToolHandlerBindingRegistry(nextSnapshot, [binding]),
TrustedToolInvocationBindingConflictError,
);
});
test('enforces Profile availability independently from Tool definitions', () => {
const current = harness();
assert.equal(
current.bindings.resolve('demo.compare', '1.0.0', 'edge').bindingDigest,
current.binding.bindingDigest,
);
assert.throws(
() => current.bindings.resolve('demo.compare', '1.0.0', 'worker'),
TrustedToolHandlerUnavailableError,
);
});
test('seals invocation, binding and safe preview into separate canonical digests', async () => {
const current = harness();
const sealed = await plan(current);
assert.equal(sealed.schema, TRUSTED_TOOL_INVOCATION_PLAN_SCHEMA);
assert.equal(sealed.actionType, TOOL_INVOKE_ACTION_TYPE);
assert.equal(sealed.snapshotDigest, current.snapshot.snapshotDigest);
assert.equal(sealed.binding.bindingDigest, current.binding.bindingDigest);
assert.equal(sealed.timeoutSeconds, 20);
assert.match(sealed.actionDigest, /^[0-9a-f]{64}$/);
assert.match(sealed.previewArtifact.previewDigest, /^[0-9a-f]{64}$/);
assert.match(sealed.planDigest, /^[0-9a-f]{64}$/);
assert.notEqual(sealed.actionDigest, sealed.invocationActionDigest);
assert.equal(JSON.stringify(sealed).includes('secret-value'), false);
assert.equal('input' in sealed, false);
assert.equal('preview' in sealed, false);
assert.equal('execute' in sealed, false);
assert.deepEqual(
normalizeTrustedToolInvocationPlan(sealed, current.bindings),
sealed,
);
const replay = await plan(current);
assert.equal(replay.planDigest, sealed.planDigest);
const changedAdapter = harness({
snapshot: current.snapshot,
binding: {
adapter: { id: 'builtin.demo-compare', version: '1.0.1' },
},
});
const changed = await plan(changedAdapter);
assert.notEqual(changed.actionDigest, sealed.actionDigest);
});
test('rejects unsafe preview shapes and digest drift', async () => {
const current = harness();
await assert.rejects(
async () =>
plan(current, 'ready', {
preview: preview({
fields: [
{ kind: 'redacted', label: 'Credential', value: 'secret-value' },
],
}),
}),
/redaction is invalid/,
);
const sealed = await plan(current);
assert.throws(
() =>
normalizeTrustedToolInvocationPlan(
{
...sealed,
previewArtifact: {
...sealed.previewArtifact,
previewDigest: DIGEST_A,
},
},
current.bindings,
),
InvalidTrustedToolInvocationError,
);
});
test('publishes Approval binding only for approval-required plans', async () => {
const current = harness();
const required = await plan(current, 'approval_required');
assert.deepEqual(
trustedToolInvocationApprovalBinding(required, current.bindings),
{
permission: 'tool.call:demo.compare',
actionType: TOOL_INVOKE_ACTION_TYPE,
actionRef: 'tool-plan:run-001',
actionDigest: required.actionDigest,
previewDigest: required.previewArtifact.previewDigest,
},
);
await assert.rejects(
async () =>
trustedToolInvocationApprovalBinding(
await plan(current),
current.bindings,
),
TrustedToolExecutionApprovalRequiredError,
);
});
test('accepts only an exact consumed Approved Action dispatch', async () => {
const current = harness();
const required = await plan(current, 'approval_required');
const dispatch = await approvedDispatch(current, required);
assert.equal(
assertTrustedToolApprovedDispatch(required, current.bindings, dispatch).id,
dispatch.id,
);
assert.throws(
() =>
assertTrustedToolApprovedDispatch(required, current.bindings, {
...dispatch,
action: { ...dispatch.action, actionRef: 'tool-plan:replaced' },
}),
TrustedToolInvocationBindingConflictError,
);
});
test('admits a ready Tool only after fresh Policy and durable start evidence', async () => {
const current = harness();
const ready = await plan(current);
const policy = authorizer();
const admitted = await admitTrustedToolExecution(current.bindings, ready, {
principal: principal(),
profile: 'edge',
nowMs: 1_400,
authorizer: policy,
evidence: evidence(),
});
assert.equal(admitted.schema, TRUSTED_TOOL_EXECUTION_ADMISSION_SCHEMA);
assert.equal(admitted.planDigest, ready.planDigest);
assert.equal(admitted.approvalDispatchId, null);
assert.deepEqual(admitted.policyFence, FENCE);
assert.equal(admitted.evidence.stepRun.id, 'step-run-001');
assert.match(admitted.admissionDigest, /^[0-9a-f]{64}$/);
assert.equal('input' in admitted, false);
assert.equal('execute' in admitted, false);
assert.deepEqual(
policy.calls.map(({ permission }) => permission),
['tool.call:demo.compare', 'run.read'],
);
});
test('requires exact approval dispatch before admitting an approval plan', async () => {
const current = harness();
const required = await plan(current, 'approval_required');
await assert.rejects(
admitTrustedToolExecution(current.bindings, required, {
principal: principal(),
profile: 'edge',
nowMs: 1_400,
authorizer: authorizer(),
evidence: evidence(),
}),
TrustedToolExecutionApprovalRequiredError,
);
const dispatch = await approvedDispatch(current, required);
const admitted = await admitTrustedToolExecution(current.bindings, required, {
principal: principal(),
profile: 'edge',
nowMs: 1_400,
authorizer: authorizer(),
evidence: evidence(),
dispatch,
});
assert.equal(admitted.approvalDispatchId, dispatch.id);
assert.match(admitted.approvalDispatchDigest, /^[0-9a-f]{64}$/);
});
test('fails closed on current deny, approval escalation, mixed fence and unavailable Policy', async () => {
const current = harness();
const ready = await plan(current);
await assert.rejects(
admitTrustedToolExecution(current.bindings, ready, {
principal: principal(),
profile: 'edge',
nowMs: 1_400,
authorizer: authorizer(() => decision('deny', null)),
evidence: evidence(),
}),
TrustedToolExecutionPolicyDeniedError,
);
await assert.rejects(
admitTrustedToolExecution(current.bindings, ready, {
principal: principal(),
profile: 'edge',
nowMs: 1_400,
authorizer: authorizer(() => decision('require_approval')),
evidence: evidence(),
}),
TrustedToolExecutionApprovalRequiredError,
);
await assert.rejects(
admitTrustedToolExecution(current.bindings, ready, {
principal: principal(),
profile: 'edge',
nowMs: 1_400,
authorizer: authorizer((permission) =>
decision('allow', {
projectVersion: permission === 'run.read' ? 4 : 3,
bindingVersion: 7,
}),
),
evidence: evidence(),
}),
TrustedToolExecutionPolicyUnavailableError,
);
await assert.rejects(
admitTrustedToolExecution(current.bindings, ready, {
principal: principal(),
profile: 'edge',
nowMs: 1_400,
authorizer: {
async authorize() {
throw new Error('database unavailable');
},
},
evidence: evidence(),
}),
TrustedToolExecutionPolicyUnavailableError,
);
});
test('rejects missing StepRun, Trace or Audit evidence and Profile drift', async () => {
const current = harness();
const ready = await plan(current);
await assert.rejects(
admitTrustedToolExecution(current.bindings, ready, {
principal: principal(),
profile: 'edge',
nowMs: 1_400,
authorizer: authorizer(),
evidence: evidence({ stepRun: { version: 0 } }),
}),
InvalidTrustedToolInvocationError,
);
await assert.rejects(
admitTrustedToolExecution(current.bindings, ready, {
principal: principal(),
profile: 'standalone',
nowMs: 1_400,
authorizer: authorizer(),
evidence: evidence(),
}),
TrustedToolInvocationBindingConflictError,
);
});
test('exports the same contract through root and explicit subpath without authority imports', () => {
const root = require('../dist');
const subpath = require('@qinglong/runtime-core/trusted-tool-invocation');
assert.equal(
root.TrustedToolHandlerBindingRegistry,
TrustedToolHandlerBindingRegistry,
);
assert.equal(subpath.admitTrustedToolExecution, admitTrustedToolExecution);
const source = readFileSync(
join(__dirname, '..', 'src', 'tool-execution', 'trustedToolInvocation.ts'),
'utf8',
);
for (const authority of [
'node:child_process',
'node:fs',
'node:http',
'node:https',
'node:net',
'node:worker_threads',
]) {
assert.equal(source.includes(`from '${authority}'`), false);
}
});
@@ -0,0 +1,71 @@
const assert = require('node:assert/strict');
const { createHmac } = require('node:crypto');
const { test } = require('node:test');
const {
normalizeWorkerCredentialRecord,
} = require('@qinglong/runtime-core/worker-credential');
const {
formatWorkerCredentialToken,
workerCredentialSecretDigest,
} = require('@qinglong/runtime-core/worker-credential-token');
const PEPPER = Buffer.alloc(32, 1).toString('base64url');
const SECRET = Buffer.alloc(32, 2).toString('base64url');
function credential(overrides = {}) {
return {
credentialId: 'worker_primary',
version: 2,
state: 'active',
workerId: 'edge-router-1',
secretDigest: 'a'.repeat(64),
createdAtMs: 100,
notBeforeAtMs: 100,
expiresAtMs: 1_000,
...overrides,
};
}
test('normalizes one immutable Worker credential without secret material', () => {
const normalized = normalizeWorkerCredentialRecord(credential());
assert.deepEqual(normalized, credential());
assert.equal(Object.isFrozen(normalized), true);
assert.equal(JSON.stringify(normalized).includes(SECRET), false);
const preapproved = credential({ notBeforeAtMs: 50 });
assert.deepEqual(normalizeWorkerCredentialRecord(preapproved), preapproved);
});
test('derives a Worker-only digest domain and canonical ql3w token', () => {
const expected = createHmac('sha256', Buffer.from(PEPPER, 'base64url'))
.update(Buffer.from('qinglong-worker-credential-v1\0', 'utf8'))
.update('worker_primary', 'utf8')
.update('\0', 'utf8')
.update(Buffer.from(SECRET, 'base64url'))
.digest('hex');
assert.equal(
workerCredentialSecretDigest(PEPPER, 'worker_primary', SECRET),
expected,
);
assert.equal(
formatWorkerCredentialToken('worker_primary', SECRET),
`ql3w_worker_primary_${SECRET}`,
);
});
test('rejects widened records, unsafe identities, weak entropy and lifetimes', () => {
for (const value of [
{ ...credential(), extra: true },
credential({ credentialId: '../worker' }),
credential({ workerId: '../worker' }),
credential({ version: 0 }),
credential({ state: 'disabled' }),
credential({ secretDigest: 'A'.repeat(64) }),
credential({ notBeforeAtMs: -1 }),
credential({ expiresAtMs: 100 }),
]) {
assert.throws(() => normalizeWorkerCredentialRecord(value));
}
assert.throws(() => workerCredentialSecretDigest('weak', 'worker_primary', SECRET));
assert.throws(() => formatWorkerCredentialToken('worker_primary', 'weak'));
});
@@ -0,0 +1,314 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
normalizeAuthenticatedWorkerCredentialIdentity,
normalizeCommitWorkerCredentialDeliveryCommand,
normalizeMarkWorkerCredentialStageDiscardedCommand,
normalizePublishWorkerCredentialDeliveryCommand,
normalizeRevokePreviousWorkerCredentialDeliveryCommand,
normalizeWorkerCredentialDeliveryRecoveryPage,
normalizeWorkerCredentialDeliveryIntent,
normalizeWorkerCredentialDeliveryRecord,
normalizeWorkerCredentialStageDiscardRecord,
normalizeWorkerCredentialStageDiscardRecoveryPage,
workerCredentialDeliveryTokenDigest,
} = require('@qinglong/runtime-core/worker-credential-delivery');
const MUTATION_ID = '123e4567-e89b-42d3-a456-426614174601';
test('derives one bounded domain-separated delivery token digest', () => {
assert.equal(
workerCredentialDeliveryTokenDigest(Buffer.from('ql3w_example_secret')),
'f768816a9182de755f235f0884ac9082bcab9420fcf46e89e3d2f02b5ad21446',
);
assert.throws(() => workerCredentialDeliveryTokenDigest(Buffer.alloc(0)));
assert.throws(() => workerCredentialDeliveryTokenDigest(Buffer.alloc(257)));
});
function credentialCommand(overrides = {}) {
return {
expectedCurrentVersion: 0,
credential: {
credentialId: 'worker_generation_2',
version: 1,
state: 'active',
workerId: 'edge-router-1',
secretDigest: 'a'.repeat(64),
createdAtMs: 1_000,
notBeforeAtMs: 1_000,
expiresAtMs: 2_000,
},
mutation: {
mutationId: MUTATION_ID,
operation: 'issue',
credentialId: 'worker_generation_2',
credentialVersion: 1,
expectedPreviousVersion: 0,
changedBy: { type: 'user', id: 'usr_admin' },
createdAtMs: 1_000,
},
audit: {
eventId: MUTATION_ID,
requestId: 'request-worker-delivery-1',
operationId: 'worker_credential.issue',
projectId: null,
subject: { type: 'user', id: 'usr_admin' },
authenticationId: 'session:admin:1',
outcome: 'allowed',
reasons: ['worker_credential_admin'],
fence: null,
occurredAtMs: 1_000,
},
...overrides,
};
}
function committed(overrides = {}) {
return {
deliveryId: MUTATION_ID,
version: 1,
state: 'credential_committed',
workerId: 'edge-router-1',
credentialId: 'worker_generation_2',
credentialVersion: 1,
previousCredentialId: 'worker_generation_1',
secretDigest: 'a'.repeat(64),
tokenDigest: 'b'.repeat(64),
deploymentTargetDigest: 'c'.repeat(64),
deploymentGeneration: 'secret-generation-2',
stagedAtMs: 1_000,
credentialCommittedAtMs: 1_000,
publishedAtMs: null,
publicationDigest: null,
observedAtMs: null,
observedSessionId: null,
observedSessionVersion: null,
previousRevokedAtMs: null,
...overrides,
};
}
test('normalizes an exact low-sensitive committed delivery fact', () => {
const intent = normalizeWorkerCredentialDeliveryIntent({
deliveryId: MUTATION_ID,
workerId: 'edge-router-1',
credentialId: 'worker_generation_2',
credentialVersion: 1,
previousCredentialId: 'worker_generation_1',
secretDigest: 'a'.repeat(64),
tokenDigest: 'b'.repeat(64),
deploymentTargetDigest: 'c'.repeat(64),
deploymentGeneration: 'secret-generation-2',
stagedAtMs: 1_000,
});
assert.equal(Object.hasOwn(intent, 'state'), false);
assert.equal(Object.hasOwn(intent, 'credentialCommittedAtMs'), false);
const value = normalizeWorkerCredentialDeliveryRecord(committed());
assert.deepEqual(value, committed());
assert.equal(Object.isFrozen(value), true);
const command = normalizeCommitWorkerCredentialDeliveryCommand({
credential: credentialCommand(),
delivery: value,
});
assert.equal(command.delivery.secretDigest, command.credential.credential.secretDigest);
assert.equal(JSON.stringify(command).includes('ql3w_'), false);
});
test('binds orphan discard authorization to one exact staged intent', () => {
const authorized = normalizeWorkerCredentialStageDiscardRecord({
deliveryId: MUTATION_ID,
version: 1,
state: 'discard_authorized',
workerId: 'edge-router-1',
credentialId: 'worker_generation_2',
credentialVersion: 1,
previousCredentialId: 'worker_generation_1',
secretDigest: 'a'.repeat(64),
tokenDigest: 'b'.repeat(64),
deploymentTargetDigest: 'c'.repeat(64),
deploymentGeneration: 'secret-generation-2',
stagedAtMs: 1_000,
authorizedAtMs: 1_100,
discardedAtMs: null,
});
assert.equal(authorized.state, 'discard_authorized');
assert.deepEqual(
normalizeMarkWorkerCredentialStageDiscardedCommand({
deliveryId: MUTATION_ID,
expectedVersion: 1,
}),
{ deliveryId: MUTATION_ID, expectedVersion: 1 },
);
const page = normalizeWorkerCredentialStageDiscardRecoveryPage({
observedAtMs: 1_200,
discards: [authorized],
truncated: true,
nextCursor: MUTATION_ID,
});
assert.equal(page.discards[0].tokenDigest, 'b'.repeat(64));
const discarded = normalizeWorkerCredentialStageDiscardRecord({
...authorized,
version: 2,
state: 'discarded',
discardedAtMs: 1_200,
});
assert.throws(() => normalizeWorkerCredentialStageDiscardRecoveryPage({
observedAtMs: 1_300,
discards: [discarded],
truncated: false,
}));
assert.throws(() => normalizeWorkerCredentialStageDiscardRecord({
...authorized,
tokenDigest: 'd'.repeat(64),
discardedAtMs: 1_200,
}));
});
test('requires monotonic publication, observation and revoke evidence', () => {
const published = normalizeWorkerCredentialDeliveryRecord(committed({
version: 2,
state: 'published',
publishedAtMs: 1_100,
publicationDigest: 'd'.repeat(64),
}));
const observed = normalizeWorkerCredentialDeliveryRecord({
...published,
version: 3,
state: 'observed',
observedAtMs: 1_200,
observedSessionId: '019f7094-a853-72f3-82ab-dfa08e6bd1c1',
observedSessionVersion: 4,
});
const revoked = normalizeWorkerCredentialDeliveryRecord({
...observed,
version: 4,
state: 'previous_revoked',
previousRevokedAtMs: 1_300,
});
assert.equal(revoked.previousCredentialId, 'worker_generation_1');
assert.deepEqual(
normalizePublishWorkerCredentialDeliveryCommand({
deliveryId: MUTATION_ID,
expectedVersion: 1,
publicationDigest: 'd'.repeat(64),
publishedAtMs: 1_100,
}),
{
deliveryId: MUTATION_ID,
expectedVersion: 1,
publicationDigest: 'd'.repeat(64),
publishedAtMs: 1_100,
},
);
});
test('rejects same-ID rotation, widened records and incomplete state evidence', () => {
for (const value of [
committed({ previousCredentialId: 'worker_generation_2' }),
committed({ token: 'ql3w_secret' }),
committed({ version: 2, state: 'published' }),
committed({ stagedAtMs: 1_001 }),
committed({ credentialVersion: 2 }),
committed({ deploymentTargetDigest: 'A'.repeat(64) }),
]) {
assert.throws(() => normalizeWorkerCredentialDeliveryRecord(value));
}
assert.throws(() => normalizeCommitWorkerCredentialDeliveryCommand({
credential: credentialCommand({
mutation: {
...credentialCommand().mutation,
operation: 'rotate',
},
}),
delivery: committed(),
}));
});
test('normalizes only server-authenticated Worker credential identity', () => {
const identity = {
workerId: 'edge-router-1',
credentialId: 'worker_generation_2',
credentialVersion: 1,
};
assert.deepEqual(
normalizeAuthenticatedWorkerCredentialIdentity(identity),
identity,
);
for (const value of [
{ ...identity, credentialVersion: 0 },
{ ...identity, workerId: '../edge-router-1' },
{ ...identity, deliveryId: MUTATION_ID },
]) {
assert.throws(() => normalizeAuthenticatedWorkerCredentialIdentity(value));
}
});
test('binds previous revoke and bounded recovery pages to delivery evidence', () => {
const observed = normalizeWorkerCredentialDeliveryRecord({
...committed(),
version: 3,
state: 'observed',
publishedAtMs: 1_100,
publicationDigest: 'd'.repeat(64),
observedAtMs: 1_200,
observedSessionId: '019f7094-a853-72f3-82ab-dfa08e6bd1c1',
observedSessionVersion: 4,
});
const revoke = credentialCommand({
expectedCurrentVersion: 1,
credential: {
credentialId: 'worker_generation_1',
version: 2,
state: 'revoked',
workerId: 'edge-router-1',
secretDigest: '0'.repeat(64),
createdAtMs: 1_300,
notBeforeAtMs: 1_300,
expiresAtMs: 2_300,
},
mutation: {
...credentialCommand().mutation,
mutationId: '123e4567-e89b-42d3-a456-426614174602',
operation: 'revoke',
credentialId: 'worker_generation_1',
credentialVersion: 2,
expectedPreviousVersion: 1,
createdAtMs: 1_300,
},
audit: {
...credentialCommand().audit,
eventId: '123e4567-e89b-42d3-a456-426614174602',
operationId: 'worker_credential.revoke',
occurredAtMs: 1_300,
},
});
const terminal = normalizeWorkerCredentialDeliveryRecord({
...observed,
version: 4,
state: 'previous_revoked',
previousRevokedAtMs: 1_300,
});
assert.equal(
normalizeRevokePreviousWorkerCredentialDeliveryCommand({
credential: revoke,
delivery: terminal,
}).delivery.state,
'previous_revoked',
);
const page = normalizeWorkerCredentialDeliveryRecoveryPage({
observedAtMs: 1_400,
deliveries: [observed],
truncated: true,
nextCursor: observed.deliveryId,
});
assert.equal(page.nextCursor, MUTATION_ID);
assert.throws(() => normalizeWorkerCredentialDeliveryRecoveryPage({
observedAtMs: 1_400,
deliveries: [terminal],
truncated: false,
}));
assert.throws(() => normalizeRevokePreviousWorkerCredentialDeliveryCommand({
credential: { ...revoke, expectedCurrentVersion: 2 },
delivery: terminal,
}));
});
@@ -0,0 +1,100 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
InvalidWorkerCredentialManagementPlanError,
createWorkerCredentialManagementPlan,
normalizeWorkerCredentialManagementPlan,
} = require('@qinglong/runtime-core/worker-credential-management-plan');
const BASE = Object.freeze({
actionRef: 'worker-credential:worker-a:generation-2',
authorityProjectId: 'cluster-instance-authority',
action: 'rotate',
target: Object.freeze({
deliveryId: '123e4567-e89b-42d3-a456-426614174702',
workerId: 'worker-a',
credentialId: 'credential-b',
previousCredentialId: 'credential-a',
credentialNotBeforeAtMs: 11_000,
credentialExpiresAtMs: 21_000,
deploymentTargetDigest: '1'.repeat(64),
deploymentGeneration: 'generation-2',
}),
requestedBy: Object.freeze({ type: 'user', id: 'operator-a' }),
plannedAtMs: 10_000,
expiresAtMs: 20_000,
});
test('creates one immutable secret-free Worker credential rotation plan', () => {
const plan = createWorkerCredentialManagementPlan(BASE);
assert.deepEqual(normalizeWorkerCredentialManagementPlan(plan), plan);
assert.equal(Object.isFrozen(plan), true);
assert.equal(Object.isFrozen(plan.target), true);
assert.match(plan.planDigest, /^[0-9a-f]{64}$/);
assert.match(plan.previewDigest, /^[0-9a-f]{64}$/);
assert.notEqual(plan.planDigest, plan.previewDigest);
assert.doesNotMatch(JSON.stringify(plan), /token|kubeconfig|secret/i);
});
test('supports first issue only when no previous credential is bound', () => {
const plan = createWorkerCredentialManagementPlan({
...BASE,
action: 'issue',
target: { ...BASE.target, previousCredentialId: null },
});
assert.equal(plan.action, 'issue');
assert.equal(plan.target.previousCredentialId, null);
});
test('rejects action/predecessor mismatch, secret-shaped input and invalid lifetime', () => {
assert.throws(
() => createWorkerCredentialManagementPlan({
...BASE,
action: 'issue',
}),
InvalidWorkerCredentialManagementPlanError,
);
assert.throws(
() => createWorkerCredentialManagementPlan({
...BASE,
target: { ...BASE.target, token: 'must-not-be-stored' },
}),
InvalidWorkerCredentialManagementPlanError,
);
assert.throws(
() => createWorkerCredentialManagementPlan({
...BASE,
expiresAtMs: BASE.plannedAtMs + 15 * 60 * 1000 + 1,
}),
InvalidWorkerCredentialManagementPlanError,
);
});
test('rejects digest drift, weak requester and credential identity reuse', () => {
const plan = createWorkerCredentialManagementPlan(BASE);
assert.throws(
() => normalizeWorkerCredentialManagementPlan({
...plan,
planDigest: 'f'.repeat(64),
}),
InvalidWorkerCredentialManagementPlanError,
);
assert.throws(
() => createWorkerCredentialManagementPlan({
...BASE,
requestedBy: { type: 'system', id: 'controller' },
}),
InvalidWorkerCredentialManagementPlanError,
);
assert.throws(
() => createWorkerCredentialManagementPlan({
...BASE,
target: {
...BASE.target,
previousCredentialId: BASE.target.credentialId,
},
}),
InvalidWorkerCredentialManagementPlanError,
);
});
@@ -0,0 +1,57 @@
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
normalizeSubmitWorkerExecutionAttestationCommand,
normalizeWorkerExecutionAttestation,
} = require('@qinglong/runtime-core/worker-attestation');
function attestation(overrides = {}) {
return {
attestationId: '018f5c64-9b9d-7f1a-8c2d-1234567890ab',
runId: 'run-1',
attemptId: 'attempt-1',
sequence: 1,
state: 'running',
workerId: 'edge-router-1',
workerSessionId: '018f5c64-9b9d-7f1a-8c2d-1234567890ac',
workerGeneration: 2,
leaseTokenDigest: 'a'.repeat(64),
leaseGeneration: 3,
leaseVersion: 4,
offerId: 'offer-1',
callbackSequence: 5,
executorHandle: 'remote:handle-1',
journalRevision: 6,
receivedAtMs: 7,
...overrides,
};
}
test('normalizes an exact immutable Worker execution attestation', () => {
const value = normalizeWorkerExecutionAttestation(attestation());
assert.deepEqual(value, attestation());
assert.equal(Object.isFrozen(value), true);
const { receivedAtMs, ...command } = attestation();
assert.deepEqual(
normalizeSubmitWorkerExecutionAttestationCommand(command),
command,
);
assert.equal(receivedAtMs, 7);
});
test('rejects widened, malformed and under-fenced attestations', () => {
for (const value of [
{ ...attestation(), extra: true },
attestation({ attestationId: 'not-v7' }),
attestation({ sequence: 0 }),
attestation({ state: 'unknown' }),
attestation({ workerSessionId: 'not-v7' }),
attestation({ workerGeneration: 0 }),
attestation({ leaseTokenDigest: 'A'.repeat(64) }),
attestation({ leaseGeneration: 0 }),
attestation({ executorHandle: '' }),
attestation({ journalRevision: 0 }),
]) {
assert.throws(() => normalizeWorkerExecutionAttestation(value));
}
});
@@ -0,0 +1,64 @@
const assert = require('node:assert/strict');
const { createHash } = require('node:crypto');
const { test } = require('node:test');
const {
InvalidWorkerSessionValueError,
assertWorkerSessionRecord,
assertWorkerCapabilitiesSnapshot,
} = require('../dist');
function capabilities() {
const json = '{"architecture":"arm64","executors":["remote-worker"]}';
return {
json,
hash: createHash('sha256').update(json).digest('hex'),
};
}
test('validates one exact bounded Worker Session snapshot', () => {
const snapshot = capabilities();
assert.doesNotThrow(() =>
assertWorkerSessionRecord({
workerId: 'edge-router-1',
sessionId: '018f0000-0000-7000-8000-000000000001',
generation: 1,
status: 'online',
version: 0,
capabilitiesJson: snapshot.json,
capabilitiesHash: snapshot.hash,
maxConcurrentRuns: 2,
availableSlots: 1,
registeredAtMs: 10,
lastHeartbeatAtMs: 11,
leaseExpiresAtMs: 20,
updatedAtMs: 11,
}),
);
});
test('rejects forged capabilities, partial status capacity and invalid time', () => {
const snapshot = capabilities();
assert.throws(
() => assertWorkerCapabilitiesSnapshot(snapshot.json, '0'.repeat(64)),
InvalidWorkerSessionValueError,
);
assert.throws(
() =>
assertWorkerSessionRecord({
workerId: 'edge-router-1',
sessionId: '018f0000-0000-7000-8000-000000000001',
generation: 1,
status: 'draining',
version: 0,
capabilitiesJson: snapshot.json,
capabilitiesHash: snapshot.hash,
maxConcurrentRuns: 1,
availableSlots: 1,
registeredAtMs: 10,
lastHeartbeatAtMs: 11,
leaseExpiresAtMs: 20,
updatedAtMs: 11,
}),
InvalidWorkerSessionValueError,
);
});

Some files were not shown because too many files have changed in this diff Show More