merge: integrate AgentBus account workers

This commit is contained in:
inman committed 2026-09-02 15:15:01 +08:00
commit b5f58477d9
30 files changed
+1054 -257

No files matched your search

@@ -55,6 +55,32 @@ test('business authorization migration adds a fail-closed per-user allowlist for
assert.doesNotMatch(sql, /INSERT INTO user_business_route_authorizations[\s\S]+SELECT[\s\S]+FROM users/i);
});
test('AgentBus account-worker migration adds fail-closed channel, task, browser, and ERP identity ownership', async () => {
const sql = await source('../migrations/018_agentbus_account_workers.sql');
assert.match(sql, /ADD COLUMN IF NOT EXISTS erp_account text/);
assert.match(sql, /users_org_erp_account_unique_idx/);
assert.match(sql, /ADD COLUMN IF NOT EXISTS owner_user_id uuid/);
assert.match(sql, /FOREIGN KEY \(organization_id, owner_user_id\)[\s\S]+REFERENCES users \(organization_id, id\)/);
assert.match(sql, /user_channels_owner_unique_idx/);
assert.match(sql, /ADD COLUMN IF NOT EXISTS assigned_user_id uuid/);
assert.match(sql, /FOREIGN KEY \(organization_id, assigned_user_id\)[\s\S]+REFERENCES users \(organization_id, id\)/);
assert.match(sql, /source = 'manual'[\s\S]+created_by IS NOT NULL/);
assert.match(sql, /erp_account_verified boolean NOT NULL DEFAULT false/);
assert.match(sql, /browser_connections_active_user_unique_idx/);
assert.match(sql, /status = 'superseded'/);
assert.match(sql, /owner_user_id IS NULL[\s\S]+enabled = true/);
});
test('AgentBus channel keys and owners are unique so one inbound identity cannot fan out to multiple employees', async () => {
const channels = await source('../src/agentbus-channels.ts');
assert.match(channels, /requireAssignableOwner/);
assert.match(channels, /requireUniqueAgentBusKey/);
assert.match(channels, /pg_advisory_xact_lock/);
assert.match(channels, /sha256Text\(agentbusKey\)/);
assert.match(channels, /channel_key_conflict/);
assert.match(channels, /channel_owner_conflict/);
});
test('account lifecycle is administrator-gated and protects passwords, sessions, and the last administrator', async () => {
const [auth, server] = await Promise.all([
source('../src/auth.ts'),
@@ -71,6 +97,9 @@ test('account lifecycle is administrator-gated and protects passwords, sessions,
assert.doesNotMatch(auth, /password\.length < 12|12—512/);
assert.match(auth, /account\.password_reset/);
assert.match(auth, /account\.password_changed/);
assert.match(auth, /function validateAccountRouting/);
assert.match(auth, /admin_erp_account_forbidden/);
assert.match(auth, /erp_account_conflict/);
assert.match(server, /app\.get\('\/api\/accounts'[\s\S]+requireAdminSession\(request\)/);
assert.match(server, /app\.post\('\/api\/accounts'[\s\S]+requireAdminMutationSession\(request\)/);
assert.match(server, /app\.get\('\/api\/audit'[\s\S]+requireAdminSession\(request\)/);
@@ -183,7 +212,7 @@ test('ordinary task access is enforced across reads, mutations, artifacts, event
source('../src/task-service.ts'),
source('../src/server.ts')
]);
assert.match(tasks, /created_by = \$4 AND source = 'manual'/);
assert.match(tasks, /assigned_user_id = \$4/);
assert.match(tasks, /private async lockTaskForAccess/);
for (const mutation of ['reparseTaskWithAi', 'confirmTask', 'claimForBrowser', 'recordExecutionResult', 'cancelTask']) {
const start = tasks.indexOf(`async ${mutation}(`);
@@ -191,11 +220,19 @@ test('ordinary task access is enforced across reads, mutations, artifacts, event
const body = tasks.slice(start, start + 20_000);
assert.match(body, /lockTaskForAccess\(/, `${mutation} uses the task access lock`);
}
assert.match(tasks, /async getTaskArtifact[\s\S]+created_by = \$4 AND source = 'manual'/);
assert.match(tasks, /async eventsSince[\s\S]+t\.created_by = \$4 AND t\.source = 'manual'/);
assert.match(tasks, /async getTaskArtifact[\s\S]+assigned_user_id = \$4/);
assert.match(tasks, /async eventsSince[\s\S]+t\.assigned_user_id = \$4/);
assert.match(tasks, /async getTaskInputHistory[\s\S]+actor_user_id/);
assert.match(tasks, /WHERE organization_id = \$1 AND user_id = \$2 AND connection_id = \$3/);
assert.match(tasks, /connection\.organization_id = \$1[\s\S]+connection\.user_id = \$2[\s\S]+connection\.connection_id = \$3/);
assert.match(tasks, /WHERE browser_connections\.user_id = EXCLUDED\.user_id/);
assert.match(tasks, /browser_worker_conflict/);
assert.match(tasks, /identity_mismatch/);
assert.match(tasks, /erp_account_mismatch/);
assert.match(tasks, /task_execution_assignee_mismatch/);
assert.match(tasks, /assignee: publicActor\(row\.assignee_id, row\.assignee_username\)/);
const confirmation = tasks.slice(tasks.indexOf('async confirmTask('), tasks.indexOf('async claimForBrowser('));
assert.match(confirmation, /assigned_user_id/);
assert.match(confirmation, /task_execution_assignee_mismatch/);
assert.match(tasks, /i\.actor_user_id IS NOT DISTINCT FROM \$3::uuid/);
assert.match(tasks, /private async lockIdempotencyKey/);
assert.match(tasks, /pg_advisory_xact_lock/);
@@ -215,6 +252,8 @@ test('operator UI exposes role-aware accounts, executive drill-through, original
assert.match(index, /href="\/operations-dashboard"/);
assert.match(index, /id="passwordChangeForm"/);
assert.match(index, /id="accountForm"/);
assert.match(index, /id="accountErpAccount"/);
assert.match(index, /id="channelOwnerUserId"/);
assert.doesNotMatch(index, /accountMustChangePassword|首次登录必须修改密码|minlength="12"|12—512/);
assert.match(index, /id="accountAuthorizationPanel"/);
assert.match(index, /id="accountAuthorizationTypes"/);
@@ -240,6 +279,11 @@ test('operator UI exposes role-aware accounts, executive drill-through, original
assert.match(app, /\/api\/tasks\/\$\{encodeURIComponent\(taskId\)\}\/input-history/);
assert.match(app, /创建人与原始输入审计/);
assert.match(app, /function renderAccountAuthorizationPanel/);
assert.match(app, /function renderChannelOwnerOptions/);
assert.match(app, /function taskAssignedToCurrentAccount/);
assert.match(app, /expected_erp_account/);
assert.match(app, /executable_by=me/);
assert.match(app, /const candidates = Array\.isArray\(result\.tasks\) \? result\.tasks : \[\]/);
assert.match(app, /\/business-authorizations/);
assert.match(app, /当前默认不能执行任何业务/);
assert.match(app, /function canViewOperationsDashboard/);