mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
feat(ql3): add strong cluster run management
This commit is contained in:
+9
-1
@@ -108,7 +108,7 @@ test('serializes first observation, exact replay and append-only rotation', asyn
|
||||
assert.equal(value.releases(), 3);
|
||||
});
|
||||
|
||||
test('isolates Plugin, Worker, automation and Approval generations by authority key', async () => {
|
||||
test('isolates Plugin, Worker, automation, Approval and Run generations by authority key', async () => {
|
||||
const value = fixture('worker-credential-management');
|
||||
await value.repository.observe(
|
||||
snapshot(1, { audience: 'qinglong3-worker-credential-management' }),
|
||||
@@ -131,6 +131,14 @@ test('isolates Plugin, Worker, automation and Approval generations by authority
|
||||
approval.queries.find(({ text }) => text.startsWith('INSERT')).values[0],
|
||||
'approval-management',
|
||||
);
|
||||
const run = fixture('run-management');
|
||||
await run.repository.observe(
|
||||
snapshot(1, { audience: 'qinglong3-run-management' }),
|
||||
);
|
||||
assert.equal(
|
||||
run.queries.find(({ text }) => text.startsWith('INSERT')).values[0],
|
||||
'run-management',
|
||||
);
|
||||
assert.throws(
|
||||
() => fixture('worker-credential-executor'),
|
||||
TypeError,
|
||||
|
||||
@@ -104,6 +104,7 @@ test('enforces role-specific bounded pool sizes', () => {
|
||||
'ai-credential-tester',
|
||||
'automation-manager',
|
||||
'approval-manager',
|
||||
'run-manager',
|
||||
'worker-credential-manager',
|
||||
'worker-credential-executor',
|
||||
]) {
|
||||
|
||||
@@ -104,6 +104,7 @@ test('defines the immutable PostgreSQL capability and Run core stream', async ()
|
||||
'pg-0053-plugin-package-workflow-run-list-index',
|
||||
'pg-0054-approval-management-boundary',
|
||||
'pg-0055-run-attempt-log-retention',
|
||||
'pg-0056-run-management-boundary',
|
||||
],
|
||||
);
|
||||
for (const migration of postgresqlMainMigrationStream.migrations) {
|
||||
@@ -514,6 +515,11 @@ test('freezes every published PostgreSQL migration checksum', () => {
|
||||
checksum:
|
||||
'c775c65ec03ae3a1606f899064d2d38fa63fd136ce52cbd1b1172c3a51e6bf30',
|
||||
},
|
||||
{
|
||||
id: 'pg-0056-run-management-boundary',
|
||||
checksum:
|
||||
'7aa2b2ade67cdfa6839d4af02209906646a68adfd6c12c4dddeb854021da72b8',
|
||||
},
|
||||
];
|
||||
assert.deepEqual(
|
||||
postgresqlMainMigrationStream.migrations.map(({ id, checksum }) => ({
|
||||
@@ -1904,3 +1910,30 @@ test('advances capability v54 with durable Cluster log retention authority', asy
|
||||
/migration_id = 'pg-0054-approval-management-boundary'/,
|
||||
);
|
||||
});
|
||||
|
||||
test('advances capability v55 with isolated strong Run management authority', async () => {
|
||||
const migration = migrationById('pg-0056-run-management-boundary');
|
||||
const statements = [];
|
||||
await migration.up({
|
||||
async query(statement) {
|
||||
statements.push(statement);
|
||||
return { rows: [] };
|
||||
},
|
||||
});
|
||||
const sql = statements.join('\n');
|
||||
assert.match(sql, /ql3_run_manager/);
|
||||
assert.match(sql, /lock_run_management_policy_fence/);
|
||||
assert.match(
|
||||
sql,
|
||||
/GRANT SELECT, INSERT ON "ql3"\."runs", "ql3"\."run_attempts", "ql3"\."run_events", "ql3"\."security_audit_events" TO ql3_run_manager/,
|
||||
);
|
||||
assert.doesNotMatch(sql, /GRANT UPDATE ON "ql3"\."runs"/);
|
||||
assert.match(sql, /'run-management'/);
|
||||
assert.match(sql, /contract_version = 55/);
|
||||
assert.match(sql, /"run_management_boundary":1/);
|
||||
assert.match(sql, /contract_version = 54/);
|
||||
assert.match(
|
||||
sql,
|
||||
/migration_id = 'pg-0055-run-attempt-log-retention'/,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ const {
|
||||
PostgresSchemaReadinessError,
|
||||
assertPostgresAdminSchemaReady,
|
||||
assertPostgresApprovalManagerSchemaReady,
|
||||
assertPostgresRunManagerSchemaReady,
|
||||
assertPostgresAutomationManagerSchemaReady,
|
||||
assertPostgresPackageExecutorSchemaReady,
|
||||
assertPostgresPackageManagerSchemaReady,
|
||||
@@ -474,6 +475,37 @@ function approvalManagerPrivileges() {
|
||||
}));
|
||||
}
|
||||
|
||||
function runManagerPrivileges() {
|
||||
const readable = new Set([
|
||||
'schema_migrations',
|
||||
'schema_capabilities',
|
||||
'projects',
|
||||
'project_role_bindings',
|
||||
'task_definitions',
|
||||
'task_definition_revisions',
|
||||
'task_execution_revisions',
|
||||
'runs',
|
||||
'run_attempts',
|
||||
'run_events',
|
||||
'security_audit_events',
|
||||
'plugin_package_identity_keyset_ledger',
|
||||
]);
|
||||
return postgresqlControlSchemaContract.tables.map(({ name: tableName }) => ({
|
||||
tableName,
|
||||
selectAllowed: readable.has(tableName),
|
||||
insertAllowed: [
|
||||
'runs',
|
||||
'run_attempts',
|
||||
'run_events',
|
||||
'security_audit_events',
|
||||
'plugin_package_identity_keyset_ledger',
|
||||
].includes(tableName),
|
||||
updateAllowed: tableName === 'plugin_package_identity_keyset_ledger',
|
||||
deleteAllowed: false,
|
||||
isOwner: false,
|
||||
}));
|
||||
}
|
||||
|
||||
function workerCredentialPrivileges(kind) {
|
||||
const manager = kind === 'manager';
|
||||
const readable = new Set([
|
||||
@@ -634,6 +666,8 @@ function queryable(overrides = {}) {
|
||||
executeAllowed:
|
||||
overrides.functionMode === 'manager'
|
||||
? functionName === 'lock_approval_policy_fence'
|
||||
: overrides.functionMode === 'run-manager'
|
||||
? functionName === 'lock_run_management_policy_fence'
|
||||
: overrides.functionMode === 'executor'
|
||||
? [
|
||||
'commit_plugin_package_lifecycle',
|
||||
@@ -651,6 +685,7 @@ function queryable(overrides = {}) {
|
||||
'plugin_package_workflow_task_attempt_snapshot',
|
||||
'plugin_package_run_start_allowed',
|
||||
'plugin_package_tool_start_allowed',
|
||||
'lock_run_management_policy_fence',
|
||||
].includes(functionName),
|
||||
isOwner: false,
|
||||
})),
|
||||
@@ -696,7 +731,7 @@ test('accepts the exact PostgreSQL control schema and least-privilege runtime ro
|
||||
serverMajor: 16,
|
||||
currentUser: 'ql3_runtime',
|
||||
contractName: 'control-core',
|
||||
contractVersion: 54,
|
||||
contractVersion: 55,
|
||||
migrationIds: [
|
||||
'pg-0001-schema-capability',
|
||||
'pg-0002-run-core',
|
||||
@@ -753,6 +788,7 @@ test('accepts the exact PostgreSQL control schema and least-privilege runtime ro
|
||||
'pg-0053-plugin-package-workflow-run-list-index',
|
||||
'pg-0054-approval-management-boundary',
|
||||
'pg-0055-run-attempt-log-retention',
|
||||
'pg-0056-run-management-boundary',
|
||||
],
|
||||
});
|
||||
});
|
||||
@@ -783,10 +819,10 @@ test('accepts the exact schema and isolated least-privilege admin role', async (
|
||||
}),
|
||||
);
|
||||
assert.equal(report.currentUser, 'ql3_admin');
|
||||
assert.equal(report.contractVersion, 54);
|
||||
assert.equal(report.contractVersion, 55);
|
||||
assert.equal(
|
||||
report.migrationIds.at(-1),
|
||||
'pg-0055-run-attempt-log-retention',
|
||||
'pg-0056-run-management-boundary',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -799,10 +835,10 @@ test('accepts the isolated least-privilege automation manager role', async () =>
|
||||
}),
|
||||
);
|
||||
assert.equal(report.currentUser, 'ql3_automation_manager');
|
||||
assert.equal(report.contractVersion, 54);
|
||||
assert.equal(report.contractVersion, 55);
|
||||
assert.equal(
|
||||
report.migrationIds.at(-1),
|
||||
'pg-0055-run-attempt-log-retention',
|
||||
'pg-0056-run-management-boundary',
|
||||
);
|
||||
|
||||
const widened = automationManagerPrivileges();
|
||||
@@ -831,10 +867,10 @@ test('accepts the isolated least-privilege human Approval manager role', async (
|
||||
}),
|
||||
);
|
||||
assert.equal(report.currentUser, 'ql3_approval_manager');
|
||||
assert.equal(report.contractVersion, 54);
|
||||
assert.equal(report.contractVersion, 55);
|
||||
assert.equal(
|
||||
report.migrationIds.at(-1),
|
||||
'pg-0055-run-attempt-log-retention',
|
||||
'pg-0056-run-management-boundary',
|
||||
);
|
||||
|
||||
const widened = approvalManagerPrivileges();
|
||||
@@ -856,6 +892,35 @@ test('accepts the isolated least-privilege human Approval manager role', async (
|
||||
);
|
||||
});
|
||||
|
||||
test('accepts the isolated least-privilege Run manager role', async () => {
|
||||
const report = await assertPostgresRunManagerSchemaReady(
|
||||
queryable({
|
||||
currentUser: 'ql3_run_manager',
|
||||
privileges: runManagerPrivileges(),
|
||||
functionMode: 'run-manager',
|
||||
}),
|
||||
);
|
||||
assert.equal(report.currentUser, 'ql3_run_manager');
|
||||
assert.equal(report.contractVersion, 55);
|
||||
assert.equal(report.migrationIds.at(-1), 'pg-0056-run-management-boundary');
|
||||
|
||||
const widened = runManagerPrivileges();
|
||||
widened.find(({ tableName }) => tableName === 'runs').updateAllowed = true;
|
||||
await assert.rejects(
|
||||
assertPostgresRunManagerSchemaReady(
|
||||
queryable({
|
||||
currentUser: 'ql3_run_manager',
|
||||
privileges: widened,
|
||||
functionMode: 'run-manager',
|
||||
}),
|
||||
),
|
||||
(error) =>
|
||||
error instanceof PostgresSchemaReadinessError &&
|
||||
error.code === 'run_manager_role_invalid' &&
|
||||
error.facts.includes('table-privileges:runs'),
|
||||
);
|
||||
});
|
||||
|
||||
test('accepts isolated Package manager and executor roles', async () => {
|
||||
const manager = await assertPostgresPackageManagerSchemaReady(
|
||||
queryable({
|
||||
@@ -941,10 +1006,10 @@ test('accepts the exact schema and isolated Worker ingress role', async () => {
|
||||
}),
|
||||
);
|
||||
assert.equal(report.currentUser, 'ql3_worker_ingress');
|
||||
assert.equal(report.contractVersion, 54);
|
||||
assert.equal(report.contractVersion, 55);
|
||||
assert.equal(
|
||||
report.migrationIds.at(-1),
|
||||
'pg-0055-run-attempt-log-retention',
|
||||
'pg-0056-run-management-boundary',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -138,21 +138,11 @@ function fixture(options = {}) {
|
||||
if (normalized.includes('statement_timestamp()')) {
|
||||
return { rows: [{ nowMs: 1_000_000 }], rowCount: 1 };
|
||||
}
|
||||
if (normalized.includes('FROM "ql3"."projects"')) {
|
||||
const rows = options.projectRows ?? [
|
||||
{ projectStatus: 'active', projectVersion: 2 },
|
||||
];
|
||||
return { rows, rowCount: rows.length };
|
||||
}
|
||||
if (normalized.includes('project_role_bindings')) {
|
||||
const rows = options.bindingRows ?? [
|
||||
{
|
||||
bindingVersion: 3,
|
||||
bindingState: 'active',
|
||||
bindingRole: 'operator',
|
||||
},
|
||||
];
|
||||
return { rows, rowCount: rows.length };
|
||||
if (normalized.includes('lock_run_management_policy_fence')) {
|
||||
return {
|
||||
rows: [{ matches: options.authorizationMatches ?? true }],
|
||||
rowCount: 1,
|
||||
};
|
||||
}
|
||||
if (normalized.includes('idempotency_key = $2')) {
|
||||
const rows = options.replayRows ?? [];
|
||||
@@ -245,7 +235,11 @@ test('atomically appends a linked queued Run, remote Attempt, events and allowed
|
||||
});
|
||||
|
||||
test('returns durable identities for an exact replay without appending again', async () => {
|
||||
const { calls, repository } = fixture({ replayRows: [replayRow()] });
|
||||
const { calls, repository } = fixture({
|
||||
replayRows: [
|
||||
replayRow({ runStatus: 'running', runVersion: 4, eventSequence: 4 }),
|
||||
],
|
||||
});
|
||||
const result = await repository.retryRun(
|
||||
command({
|
||||
runId: '019f9200-0000-4000-8000-000000000102',
|
||||
@@ -257,6 +251,7 @@ test('returns durable identities for an exact replay without appending again', a
|
||||
assert.equal(result.status, 'existing');
|
||||
assert.equal(result.runId, IDS.runId);
|
||||
assert.equal(result.attemptId, IDS.attemptId);
|
||||
assert.equal(result.runStatus, 'queued');
|
||||
assert.equal(
|
||||
calls.some(({ sql }) => sql.startsWith('INSERT INTO')),
|
||||
false,
|
||||
@@ -283,15 +278,11 @@ test('rejects stale authentication and changed authorization inside the transact
|
||||
true,
|
||||
);
|
||||
assert.equal(
|
||||
stale.calls.some(({ sql }) => sql.includes('FROM "ql3"."projects"')),
|
||||
stale.calls.some(({ sql }) => sql.includes('lock_run_management_policy_fence')),
|
||||
false,
|
||||
);
|
||||
|
||||
const changed = fixture({
|
||||
bindingRows: [
|
||||
{ bindingVersion: 4, bindingState: 'active', bindingRole: 'operator' },
|
||||
],
|
||||
});
|
||||
const changed = fixture({ authorizationMatches: false });
|
||||
await assert.rejects(
|
||||
changed.repository.retryRun(command()),
|
||||
(error) =>
|
||||
|
||||
Reference in New Issue
Block a user