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,267 @@
const assert = require('node:assert/strict');
const { DatabaseSync } = require('node:sqlite');
const { test } = require('node:test');
const {
ToolExecutionEvidenceConflictError,
ToolExecutionEvidenceUnavailableError,
createToolExecutionEvidenceBundle,
} = require('@qinglong/runtime-core/tool-execution-evidence');
const {
createStepRunMutation,
} = require('@qinglong/runtime-core/step-run');
const {
LocalSqliteOperationAuthority,
} = require('../dist/authority/operationAuthority');
const { migrateLocalSqliteDatabase } = require('../dist/migration/migration');
const {
LocalSqliteStepRunRepository,
} = require('../dist/run/stepRunRepository');
const {
LocalSqliteToolExecutionEvidenceRepository,
} = require('../dist/tool-execution/toolExecutionEvidenceRepository');
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);
async function harness() {
const client = new DatabaseSync(':memory:');
client.exec('PRAGMA foreign_keys = ON');
await migrateLocalSqliteDatabase(client);
client
.prepare(
`INSERT INTO "QingLong3Projects" (
id, name, slug, status, version, created_at_ms, updated_at_ms
) VALUES ('project-001', 'Project', 'project-001', 'active', 1, 1, 1)`,
)
.run();
client
.prepare(
`INSERT INTO "Runs" (
id, project_id, task_id, task_revision, trigger_type,
execution_origin, execution_owner, status, version,
event_sequence, priority, created_at_ms
) VALUES (
'run-001', 'project-001', 'task-001', 'revision-001', 'manual',
'manual', 'runtime', 'running', 0, 0, 0, 1
)`,
)
.run();
const authority = new LocalSqliteOperationAuthority(client);
return {
client,
authority,
stepRuns: new LocalSqliteStepRunRepository(authority),
evidence: new LocalSqliteToolExecutionEvidenceRepository(authority),
close: () => authority.close(),
};
}
function stepMutation(index, expectedRunVersion) {
const suffix = String(index).padStart(3, '0');
return createStepRunMutation(
{
id: `step-run-${suffix}`,
runId: 'run-001',
stepKey: `workflow.tool-${suffix}`,
kind: 'tool',
definitionRef: `tool:demo.tool-${suffix}@1.0.0`,
definitionDigest: DIGEST_A,
required: true,
initialStatus: 'ready',
mutationId: `step-create-${suffix}`,
createdAtMs: 900 + index,
},
{
expectedRunVersion,
expectedRunEventSequence: expectedRunVersion,
eventId: `50000000-0000-4000-8000-${suffix.padStart(12, '0')}`,
dedupeKey: `step-create:step-run-${suffix}`,
actor: { type: 'agent', id: 'agent-001' },
},
);
}
function evidence(index, overrides = {}) {
const suffix = String(index).padStart(3, '0');
const createdAtMs = 1_000 + index;
return createToolExecutionEvidenceBundle({
traceId: index.toString(16).padStart(32, '0'),
spanId: (index + 16).toString(16).padStart(16, '0'),
projectId: 'project-001',
runId: 'run-001',
stepRunId: `step-run-${suffix}`,
invocationPlanDigest: DIGEST_A,
bindingDigest: DIGEST_B,
adapterDigest: DIGEST_C,
redactionContractDigest: DIGEST_D,
auditContractDigest: DIGEST_E,
audit: {
eventId: `60000000-0000-4000-8000-${suffix.padStart(12, '0')}`,
requestId: `tool-request-${suffix}`,
operationId: 'tool.invoke.start',
projectId: 'project-001',
subject: { type: 'agent', id: 'agent-001' },
authenticationId: 'auth-agent-001',
outcome: 'allowed',
reasons: ['tool_execution_start'],
fence: { projectVersion: 1, bindingVersion: 1 },
occurredAtMs: createdAtMs,
},
createdAtMs,
...overrides,
});
}
test('atomically prepares and exactly replays durable Trace and Audit evidence', async (t) => {
const value = await harness();
t.after(() => value.close());
await value.stepRuns.apply(stepMutation(1, 0));
const bundle = evidence(1);
assert.deepEqual(await value.evidence.prepare(bundle), {
status: 'created',
bundle,
});
assert.deepEqual(await value.evidence.prepare(bundle), {
status: 'existing',
bundle,
});
assert.deepEqual(
await value.evidence.findByTrace(
bundle.trace.traceId,
bundle.trace.spanId,
),
bundle,
);
assert.deepEqual(
await value.evidence.findByAuditEventId(bundle.audit.eventId),
bundle,
);
assert.deepEqual(
{
...value.client
.prepare(
`SELECT
(SELECT COUNT(*) FROM "ToolExecutionTraceAnchors") AS traces,
(SELECT COUNT(*) FROM "ToolExecutionAuditReceipts") AS receipts,
(SELECT COUNT(*) FROM "QingLong3SecurityAuditEvents"
WHERE operation_id = 'tool.invoke.start') AS audits`,
)
.get(),
},
{ traces: 1, receipts: 1, audits: 1 },
);
});
test('rejects reused Trace or Audit identity with different content', async (t) => {
const value = await harness();
t.after(() => value.close());
await value.stepRuns.apply(stepMutation(1, 0));
const first = evidence(1);
await value.evidence.prepare(first);
const reusedTrace = evidence(1, {
audit: {
...first.audit,
eventId: '60000000-0000-4000-8000-000000000099',
requestId: 'tool-request-reused',
},
});
await assert.rejects(
value.evidence.prepare(reusedTrace),
ToolExecutionEvidenceConflictError,
);
const reusedAudit = evidence(1, {
traceId: 'f'.repeat(32),
spanId: 'e'.repeat(16),
audit: first.audit,
});
await assert.rejects(
value.evidence.prepare(reusedAudit),
ToolExecutionEvidenceConflictError,
);
});
test('requires one ready Tool StepRun in the same Project and rolls back audit', async (t) => {
const value = await harness();
t.after(() => value.close());
await assert.rejects(
value.evidence.prepare(evidence(1)),
ToolExecutionEvidenceConflictError,
);
assert.equal(
value.client
.prepare(
`SELECT COUNT(*) AS count
FROM "QingLong3SecurityAuditEvents"
WHERE operation_id = 'tool.invoke.start'`,
)
.get().count,
0,
);
});
test('lists evidence with stable bounded keyset pagination', async (t) => {
const value = await harness();
t.after(() => value.close());
for (let index = 1; index <= 3; index += 1) {
await value.stepRuns.apply(stepMutation(index, index - 1));
await value.evidence.prepare(evidence(index));
}
const first = await value.evidence.listByRun({
runId: 'run-001',
limit: 2,
});
assert.equal(first.bundles.length, 2);
assert.equal(first.truncated, true);
assert.deepEqual(first.next, {
createdAtMs: first.bundles[1].trace.createdAtMs,
traceId: first.bundles[1].trace.traceId,
spanId: first.bundles[1].trace.spanId,
});
const second = await value.evidence.listByRun({
runId: 'run-001',
limit: 2,
after: first.next,
});
assert.equal(second.bundles.length, 1);
assert.equal(second.truncated, false);
assert.equal(second.next, undefined);
});
test('fails closed when durable JSON no longer matches mirrored columns', async (t) => {
const value = await harness();
t.after(() => value.close());
await value.stepRuns.apply(stepMutation(1, 0));
const bundle = evidence(1);
await value.evidence.prepare(bundle);
value.client.exec('PRAGMA ignore_check_constraints = ON');
value.client
.prepare(
`UPDATE "ToolExecutionTraceAnchors"
SET trace_json = json_set(trace_json, '$.projectId', 'project-other')`,
)
.run();
await assert.rejects(
value.evidence.findByTrace(bundle.trace.traceId, bundle.trace.spanId),
ToolExecutionEvidenceUnavailableError,
);
});
test('publishes evidence authority only through its explicit subpath', () => {
const root = require('@qinglong/local-sqlite');
const runtime = require('@qinglong/local-sqlite/runtime');
const authority = require('@qinglong/local-sqlite/tool-execution-evidence');
assert.equal(root.LocalSqliteToolExecutionEvidenceRepository, undefined);
assert.equal(runtime.LocalSqliteToolExecutionEvidenceRepository, undefined);
assert.equal(
typeof authority.LocalSqliteToolExecutionEvidenceRepository,
'function',
);
});