@desplega.ai/agent-swarm 1.112.0 → 1.114.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/{actions-eckb4g8r.js → actions-bm8vdxys.js} +7 -8
- package/dist/{app-b05sgm02.js → app-bhwdxmvp.js} +5 -5
- package/dist/{assistant-7255sbyw.js → assistant-15mp2apr.js} +18 -17
- package/dist/{boot-reembed-y1bt3ttn.js → boot-reembed-awr2179r.js} +6 -6
- package/dist/{boot-reembed-yv7awg4y.js → boot-reembed-b9sbk87z.js} +5 -5
- package/dist/{boot-scrub-logs-ddyaeqar.js → boot-scrub-logs-c1zsaw9m.js} +4 -4
- package/dist/{claude-adapter-mma9a1yr.js → claude-adapter-2k45y7p7.js} +2 -2
- package/dist/{claude-managed-adapter-pv2nbqy4.js → claude-managed-adapter-kysmkz89.js} +2 -2
- package/dist/cli-0kgcv878.js +344 -0
- package/dist/cli-0pygq9r1.js +429 -0
- package/dist/{cli-7xkwgkrs.js → cli-113wmegp.js} +90 -3
- package/dist/{cli-7ga43spr.js → cli-1yjrbg1f.js} +1 -1
- package/dist/{cli-56s4ehzw.js → cli-2t4e4ayk.js} +1 -1
- package/dist/{cli-0c3n0eba.js → cli-312v3c41.js} +1 -1
- package/dist/{cli-ceewqajw.js → cli-46b6kc7f.js} +5 -5
- package/dist/cli-49j095n9.js +393 -0
- package/dist/{cli-h9jx5mag.js → cli-5afkmcfj.js} +10 -7
- package/dist/{cli-76d1vtvq.js → cli-5ktc9fd4.js} +1 -1
- package/dist/cli-7rgh0w0k.js +262 -0
- package/dist/{cli-9cy6nc5m.js → cli-8fjwym53.js} +1 -1
- package/dist/{cli-tg0f2wmz.js → cli-a6tzw6vq.js} +175 -28
- package/dist/{cli-q21d49ac.js → cli-bw80ck94.js} +1 -1
- package/dist/{cli-709t753c.js → cli-byjcad11.js} +2 -2
- package/dist/{cli-15598a4k.js → cli-e2xbxmhd.js} +1808 -302
- package/dist/{cli-6wscj9z0.js → cli-e7306swv.js} +14 -14
- package/dist/{cli-8f0dwca2.js → cli-f5pzfvwb.js} +6 -5
- package/dist/{cli-s9pj3c7z.js → cli-f9n2jg31.js} +2 -2
- package/dist/{cli-dcfyyh3t.js → cli-ftyf58xj.js} +2 -2
- package/dist/{cli-hm27prrc.js → cli-hq39e630.js} +5 -5
- package/dist/{cli-a5e8n5hg.js → cli-hvg05qwm.js} +1 -1
- package/dist/cli-jkhwmmgg.js +136 -0
- package/dist/{cli-951w7c79.js → cli-jzwtn8rm.js} +136 -21
- package/dist/{cli-rp8pca98.js → cli-k6h2zkw3.js} +1 -1
- package/dist/{cli-3r5y6ayj.js → cli-pnfyyp6h.js} +1240 -335
- package/dist/{cli-94vzr3nq.js → cli-q1z5d5ss.js} +13 -7
- package/dist/{cli-pt7c7qxz.js → cli-q4e2x252.js} +3 -3
- package/dist/{cli-tch0ypp6.js → cli-r3mtrrzp.js} +16 -16
- package/dist/{cli-ywez6yps.js → cli-sq7f72d6.js} +1 -1
- package/dist/{cli-r1btc895.js → cli-w3nq88yc.js} +2 -2
- package/dist/{cli-30d2ct3k.js → cli-w4wk3kx6.js} +12 -7
- package/dist/{cli-anrj584m.js → cli-xz9aq0rf.js} +1 -1
- package/dist/{cli-tp7e60s3.js → cli-zmmp2r79.js} +22 -9
- package/dist/cli.js +35 -17
- package/dist/{codex-adapter-5cmy858w.js → codex-adapter-4z8m9mb5.js} +9 -9
- package/dist/{codex-session-runner-46q8mrba.js → codex-session-runner-rbct46dg.js} +9 -9
- package/dist/{commands-14g7taf4.js → commands-zk4d6esf.js} +4 -4
- package/dist/{db-3tge4jrn.js → db-stn16jp2.js} +4 -4
- package/dist/{handlers-sy64egg6.js → handlers-gshprvpf.js} +16 -30
- package/dist/{hook-rnkzw8vp.js → hook-amzx9tap.js} +7 -7
- package/dist/{http-xx9xptcs.js → http-6g0hfzax.js} +1977 -786
- package/dist/{index-wz1ea15p.js → index-2dgfj9av.js} +3 -3
- package/dist/{index-ha8e9xn2.js → index-df8fmphk.js} +55 -17
- package/dist/{index-zfx5p959.js → index-f03rnnrs.js} +13 -10
- package/dist/{index-3wr6v2mm.js → index-jbm7qcqk.js} +12 -9
- package/dist/{index-ykvs43z4.js → index-t2snazez.js} +4 -4
- package/dist/{index-brma88d4.js → index-ty42rxw9.js} +14 -11
- package/dist/{keepalive-rbz05zad.js → keepalive-pm6g2wpw.js} +7 -6
- package/dist/{lead-s790v7r0.js → lead-h79fzpzw.js} +33 -29
- package/dist/{maintenance-420rmadb.js → maintenance-433zndy1.js} +6 -6
- package/dist/{mistral-conversations-26yrnbf1.js → mistral-conversations-7gqnz2wt.js} +7 -7
- package/dist/oauth-refresh-sweep-mjsbmsk2.js +114 -0
- package/dist/{onboard-jgqamqnw.js → onboard-vdr9hc3f.js} +2 -2
- package/dist/{otel-zjd9zaxs.js → otel-g299k41b.js} +2 -2
- package/dist/{otel-impl-ch3n3783.js → otel-impl-yswd0fty.js} +1 -1
- package/dist/{pi-mono-adapter-kxjxpfgy.js → pi-mono-adapter-vbrvg1p8.js} +16 -108
- package/dist/{pricing-refresh-rmtrby6h.js → pricing-refresh-2kk2ap9b.js} +6 -6
- package/dist/rbac-roles-2wgh9b5t.js +276 -0
- package/dist/rbac-roles-xdc5208b.js +28 -0
- package/dist/{seed-pricing-1szjzfj1.js → seed-pricing-m9h69d2t.js} +5 -5
- package/dist/{setup-8jfzkyzv.js → setup-eynkvafa.js} +2 -2
- package/dist/{worker-40vq0pm8.js → worker-136q8dc2.js} +33 -29
- package/openapi.json +1634 -20
- package/package.json +6 -5
- package/src/agentmail/handlers.ts +16 -6
- package/src/agentmail/templates.ts +25 -5
- package/src/be/audit-user.ts +28 -4
- package/src/be/db-queries/oauth.ts +42 -0
- package/src/be/db.ts +104 -11
- package/src/be/identity.ts +79 -0
- package/src/be/mcp-proxy.ts +132 -0
- package/src/be/memory/providers/sqlite-store.ts +5 -1
- package/src/be/migrations/108_rbac_permission_audit.sql +26 -0
- package/src/be/migrations/109_rbac_roles.sql +79 -0
- package/src/be/migrations/111_oauth_credential_bindings.sql +6 -0
- package/src/be/migrations/112_script_connections_graphql.sql +96 -0
- package/src/be/oauth-credential-bindings.ts +35 -0
- package/src/be/oauth-refresh-sweep.ts +159 -0
- package/src/be/rbac-audit.ts +246 -0
- package/src/be/rbac-roles.ts +417 -0
- package/src/be/script-connections.ts +456 -37
- package/src/be/script-credential-broker.ts +29 -3
- package/src/be/scripts/typecheck.ts +40 -7
- package/src/be/users.ts +24 -0
- package/src/cli.tsx +17 -0
- package/src/github/handlers.ts +10 -9
- package/src/github/templates.ts +45 -9
- package/src/gitlab/handlers.ts +20 -8
- package/src/gitlab/templates.ts +18 -6
- package/src/http/all-routes.ts +61 -0
- package/src/http/approval-requests.ts +12 -0
- package/src/http/config.ts +98 -9
- package/src/http/core.ts +30 -3
- package/src/http/favorites.ts +5 -0
- package/src/http/fs.ts +27 -7
- package/src/http/index.ts +50 -0
- package/src/http/kv.ts +21 -4
- package/src/http/mcp-oauth.ts +2 -0
- package/src/http/mcp-servers.ts +6 -3
- package/src/http/oauth-generic.ts +105 -0
- package/src/http/poll.ts +13 -1
- package/src/http/route-def.ts +9 -0
- package/src/http/schedules.ts +56 -22
- package/src/http/script-connection-proxy.ts +116 -0
- package/src/http/script-connections.ts +1657 -0
- package/src/http/scripts.ts +54 -7
- package/src/http/tasks.ts +16 -14
- package/src/http/workflows.ts +13 -2
- package/src/http/x.ts +6 -2
- package/src/integrations/kapso/inbound.ts +23 -6
- package/src/jira/sync.ts +111 -17
- package/src/jira/templates.ts +10 -2
- package/src/mcp-client/http-client.ts +194 -0
- package/src/oauth/app-validation.ts +16 -0
- package/src/oauth/ensure-token.ts +69 -14
- package/src/oauth/mcp-wrapper.ts +15 -0
- package/src/oauth/wrapper.ts +48 -20
- package/src/prompts/base-prompt.ts +7 -6
- package/src/prompts/session-templates.ts +38 -11
- package/src/providers/pi-mono-mcp-client.ts +2 -133
- package/src/rbac/admission.ts +44 -0
- package/src/rbac/can.ts +44 -0
- package/src/rbac/index.ts +15 -0
- package/src/rbac/legacy-policy.ts +188 -0
- package/src/rbac/permissions.ts +194 -0
- package/src/rbac/types.ts +45 -0
- package/src/scheduler/scheduler.ts +9 -1
- package/src/scripts-runtime/api-client.ts +70 -14
- package/src/scripts-runtime/api-types.ts +38 -6
- package/src/scripts-runtime/credential-broker/default-bindings.ts +1 -0
- package/src/scripts-runtime/credential-broker/types.ts +8 -0
- package/src/scripts-runtime/ctx.ts +11 -1
- package/src/scripts-runtime/eval-harness.ts +5 -1
- package/src/scripts-runtime/executors/types.ts +2 -1
- package/src/scripts-runtime/loader.ts +3 -1
- package/src/scripts-runtime/mcp-client.ts +87 -0
- package/src/scripts-runtime/sdk-allowlist.ts +2 -0
- package/src/scripts-runtime/swarm-sdk.ts +81 -0
- package/src/scripts-runtime/types/stdlib.d.ts +24 -2
- package/src/scripts-runtime/types/swarm-sdk.d.ts +26 -2
- package/src/server.ts +14 -0
- package/src/slack/assistant.ts +14 -6
- package/src/slack/enrich.ts +17 -0
- package/src/slack/handlers.ts +8 -22
- package/src/slack/thread-buffer.ts +6 -3
- package/src/stdio.ts +43 -0
- package/src/tests/agentmail-handlers.test.ts +32 -3
- package/src/tests/approval-requests.test.ts +61 -0
- package/src/tests/audit-user.test.ts +47 -1
- package/src/tests/base-prompt.test.ts +7 -4
- package/src/tests/credential-broker.test.ts +5 -2
- package/src/tests/delete-page-tool.test.ts +197 -0
- package/src/tests/github-handlers.test.ts +28 -2
- package/src/tests/gitlab-handlers.test.ts +125 -0
- package/src/tests/harness-provider-resolution.test.ts +5 -0
- package/src/tests/http-api-integration.test.ts +8 -1
- package/src/tests/identity.test.ts +117 -0
- package/src/tests/jira-sync.test.ts +99 -1
- package/src/tests/kapso-inbound.test.ts +7 -0
- package/src/tests/mcp-tools-user.test.ts +60 -6
- package/src/tests/oauth-credential-bindings.test.ts +490 -0
- package/src/tests/oauth-refresh-sweep.test.ts +160 -0
- package/src/tests/prompt-template-remaining.test.ts +2 -2
- package/src/tests/prompt-template-session.test.ts +21 -8
- package/src/tests/rbac-admission-e2e.test.ts +241 -0
- package/src/tests/rbac-admission.test.ts +433 -0
- package/src/tests/rbac-audit.test.ts +345 -0
- package/src/tests/rbac-charact-http.test.ts +272 -0
- package/src/tests/rbac-charact-misc-tools.test.ts +428 -0
- package/src/tests/rbac-charact-skills.test.ts +492 -0
- package/src/tests/rbac-charact-slack.test.ts +283 -0
- package/src/tests/rbac-e2e-helpers.ts +308 -0
- package/src/tests/rbac-engine.test.ts +474 -0
- package/src/tests/rbac-lifecycle-e2e.test.ts +262 -0
- package/src/tests/rbac-roles.test.ts +326 -0
- package/src/tests/rbac-wire-e2e.test.ts +574 -0
- package/src/tests/schedule-http-triage-tools.test.ts +121 -0
- package/src/tests/schedule-target-type.test.ts +50 -0
- package/src/tests/scheduled-tasks.test.ts +74 -0
- package/src/tests/script-connections-http.test.ts +1158 -0
- package/src/tests/script-connections-mcp.test.ts +894 -0
- package/src/tests/script-connections.test.ts +727 -5
- package/src/tests/scripts-external-api.test.ts +49 -1
- package/src/tests/scripts-http.test.ts +56 -7
- package/src/tests/scripts-runtime-secret-egress.test.ts +1 -0
- package/src/tests/scripts-runtime.test.ts +104 -0
- package/src/tests/slack-identity-resolution.test.ts +37 -3
- package/src/tests/slack-thread-buffer.test.ts +28 -0
- package/src/tests/swarm-config-reserved-keys.test.ts +17 -0
- package/src/tests/tool-annotations.test.ts +2 -0
- package/src/tests/update-schedule-mcp-tool.test.ts +57 -0
- package/src/tests/user-token-rest-auth.test.ts +30 -1
- package/src/tests/workflow-http-v2.test.ts +80 -0
- package/src/tests/workflow-swarm-script.test.ts +44 -0
- package/src/tests/workflow-triggers-v2.test.ts +300 -1
- package/src/tools/cancel-task.ts +13 -3
- package/src/tools/context-diff.ts +12 -1
- package/src/tools/context-history.ts +12 -1
- package/src/tools/credential-bindings/tool.ts +289 -19
- package/src/tools/delete-channel.ts +12 -1
- package/src/tools/delete-page.ts +145 -0
- package/src/tools/get-task-details.ts +1 -1
- package/src/tools/inject-learning.ts +12 -1
- package/src/tools/kv/kv-delete.ts +3 -18
- package/src/tools/kv/kv-incr.ts +3 -18
- package/src/tools/kv/kv-set.ts +3 -20
- package/src/tools/kv/kv-write-auth.ts +40 -0
- package/src/tools/manage-user.ts +12 -1
- package/src/tools/mcp-servers/mcp-server-create.ts +12 -1
- package/src/tools/mcp-servers/mcp-server-delete.ts +19 -5
- package/src/tools/mcp-servers/mcp-server-install.ts +12 -1
- package/src/tools/mcp-servers/mcp-server-uninstall.ts +12 -1
- package/src/tools/mcp-servers/mcp-server-update.ts +12 -1
- package/src/tools/memory-delete.ts +12 -4
- package/src/tools/register-kapso-number.ts +23 -2
- package/src/tools/request-human-input.ts +2 -0
- package/src/tools/resolve-user.ts +77 -27
- package/src/tools/schedules/create-schedule.ts +4 -3
- package/src/tools/schedules/index.ts +1 -0
- package/src/tools/schedules/list-schedules.ts +36 -2
- package/src/tools/schedules/patch-schedule.ts +405 -0
- package/src/tools/schedules/update-schedule.ts +2 -2
- package/src/tools/script-connections/tool.ts +287 -32
- package/src/tools/skills/skill-create.ts +12 -1
- package/src/tools/skills/skill-delete.ts +12 -1
- package/src/tools/skills/skill-install-remote.ts +12 -1
- package/src/tools/skills/skill-install.ts +12 -1
- package/src/tools/skills/skill-uninstall.ts +12 -1
- package/src/tools/skills/skill-update.ts +25 -2
- package/src/tools/slack-delete.ts +8 -1
- package/src/tools/slack-post.ts +8 -1
- package/src/tools/slack-read.ts +8 -1
- package/src/tools/slack-start-thread.ts +8 -1
- package/src/tools/slack-update.ts +8 -1
- package/src/tools/slack-upload-file.ts +8 -1
- package/src/tools/swarm-config/delete-config.ts +28 -1
- package/src/tools/swarm-config/get-config.ts +32 -5
- package/src/tools/swarm-config/list-config.ts +31 -5
- package/src/tools/swarm-config/set-config.ts +38 -1
- package/src/tools/task-action.ts +1 -1
- package/src/tools/task-tool-ctx.ts +19 -3
- package/src/tools/templates.ts +5 -1
- package/src/tools/tool-config.ts +4 -2
- package/src/tools/update-profile.ts +8 -1
- package/src/tools/workflows/create-workflow.ts +8 -1
- package/src/tools/workflows/list-workflows.ts +14 -2
- package/src/tools/workflows/update-workflow.ts +11 -2
- package/src/types.ts +63 -6
- package/src/utils/scoped-resource.ts +25 -0
- package/src/workflows/executors/human-in-the-loop.ts +1 -0
- package/src/workflows/executors/swarm-script.ts +7 -1
- package/src/workflows/triggers.ts +146 -18
- package/templates/skills/swarm-scripts/SKILL.md +4 -9
- package/templates/skills/swarm-scripts/content.md +45 -9
- package/dist/cli-52tbq17n.js +0 -771
- package/dist/cli-9p0qhead.js +0 -43
- package/dist/{anthropic-messages-8nc6r2dw.js → anthropic-messages-kq3pjhbp.js} +6 -6
- package/dist/{azure-openai-responses-6yfzw3qw.js → azure-openai-responses-gm1ejtmn.js} +7 -7
- package/dist/{cli-vbraamxr.js → cli-6b4wwmm8.js} +9 -9
- package/dist/{cli-2fc97xm5.js → cli-ggy8c7tk.js} +3 -3
- package/dist/{cli-2r7s8jhp.js → cli-sznberje.js} +3 -3
- package/dist/{google-generative-ai-vfq6ymz9.js → google-generative-ai-hyrra2jm.js} +3 -3
- package/dist/{google-vertex-mj5y5rfj.js → google-vertex-8bs2pzgn.js} +3 -3
- package/dist/{openai-codex-responses-8h6kvfv8.js → openai-codex-responses-3nkvje79.js} +4 -4
- package/dist/{openai-completions-x6kjnqjd.js → openai-completions-0asftkwg.js} +11 -11
- package/dist/{openai-responses-7jwyz3ds.js → openai-responses-pmatek45.js} +10 -10
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PermissionVerbSchema
|
|
3
|
+
} from "./cli-0kgcv878.js";
|
|
4
|
+
import {
|
|
5
|
+
getDb,
|
|
6
|
+
init_db
|
|
7
|
+
} from "./cli-jzwtn8rm.js";
|
|
8
|
+
|
|
9
|
+
// src/be/rbac-roles.ts
|
|
10
|
+
init_db();
|
|
11
|
+
var DEFAULT_ROLE_ID = "rbac-role-admin";
|
|
12
|
+
var BUILTIN_ROLES = [
|
|
13
|
+
{
|
|
14
|
+
id: DEFAULT_ROLE_ID,
|
|
15
|
+
name: "admin",
|
|
16
|
+
description: "Full access including verb-less routes (legacy-equivalent default).",
|
|
17
|
+
isBuiltin: true,
|
|
18
|
+
grantsAll: true,
|
|
19
|
+
verbs: []
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "rbac-role-requester",
|
|
23
|
+
name: "requester",
|
|
24
|
+
description: "Own-task lifecycle: what legacy policy grants user principals.",
|
|
25
|
+
isBuiltin: true,
|
|
26
|
+
grantsAll: false,
|
|
27
|
+
verbs: ["task.read.own", "task.cancel.own", "task.action.own", "task.fs.mutate"]
|
|
28
|
+
}
|
|
29
|
+
];
|
|
30
|
+
var CREATE_USER_DEFAULT_ROLE_TRIGGER_SQL = `
|
|
31
|
+
CREATE TRIGGER IF NOT EXISTS trg_users_default_role
|
|
32
|
+
AFTER INSERT ON users
|
|
33
|
+
BEGIN
|
|
34
|
+
INSERT OR IGNORE INTO principal_roles (principalType, principalId, roleId)
|
|
35
|
+
SELECT 'user', NEW.id, 'rbac-role-admin'
|
|
36
|
+
WHERE EXISTS (SELECT 1 FROM roles WHERE id = 'rbac-role-admin');
|
|
37
|
+
END;
|
|
38
|
+
`;
|
|
39
|
+
function roleRowToUserRole(row) {
|
|
40
|
+
return {
|
|
41
|
+
id: row.id,
|
|
42
|
+
name: row.name,
|
|
43
|
+
description: row.description,
|
|
44
|
+
isBuiltin: row.isBuiltin === 1,
|
|
45
|
+
grantsAll: row.grantsAll === 1,
|
|
46
|
+
createdAt: row.createdAt
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function requireRoleId(roleName) {
|
|
50
|
+
const row = getDb().prepare("SELECT id FROM roles WHERE name = ?").get(roleName);
|
|
51
|
+
if (!row) {
|
|
52
|
+
throw new Error(`Unknown RBAC role: ${roleName}`);
|
|
53
|
+
}
|
|
54
|
+
return row.id;
|
|
55
|
+
}
|
|
56
|
+
function validateBuiltinVerb(roleName, verb) {
|
|
57
|
+
const parsed = PermissionVerbSchema.safeParse(verb);
|
|
58
|
+
if (!parsed.success) {
|
|
59
|
+
throw new Error(`Invalid RBAC permission verb "${verb}" in built-in role "${roleName}"`);
|
|
60
|
+
}
|
|
61
|
+
return parsed.data;
|
|
62
|
+
}
|
|
63
|
+
function validatedBuiltinVerbSets() {
|
|
64
|
+
const byRoleId = new Map;
|
|
65
|
+
for (const role of BUILTIN_ROLES) {
|
|
66
|
+
const verbs = new Set;
|
|
67
|
+
for (const verb of role.verbs) {
|
|
68
|
+
verbs.add(validateBuiltinVerb(role.name, verb));
|
|
69
|
+
}
|
|
70
|
+
byRoleId.set(role.id, verbs);
|
|
71
|
+
}
|
|
72
|
+
return byRoleId;
|
|
73
|
+
}
|
|
74
|
+
var loggedInvalidGrantVerbs = new Set;
|
|
75
|
+
function parseDatabaseGrantVerb(roleId, verb) {
|
|
76
|
+
const parsed = PermissionVerbSchema.safeParse(verb);
|
|
77
|
+
if (parsed.success) {
|
|
78
|
+
return parsed.data;
|
|
79
|
+
}
|
|
80
|
+
const logKey = `${roleId}:${verb}`;
|
|
81
|
+
if (!loggedInvalidGrantVerbs.has(logKey)) {
|
|
82
|
+
loggedInvalidGrantVerbs.add(logKey);
|
|
83
|
+
console.error(`[rbac] Ignoring invalid role_permissions verb "${verb}" for roleId="${roleId}". ` + "Invalid RBAC verbs grant nothing; remove or repair the row.");
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
function getUserGrant(userId) {
|
|
88
|
+
const rows = getDb().prepare(`SELECT r.id AS roleId, r.grantsAll, rp.verb
|
|
89
|
+
FROM principal_roles pr
|
|
90
|
+
JOIN roles r ON r.id = pr.roleId
|
|
91
|
+
LEFT JOIN role_permissions rp ON rp.roleId = r.id
|
|
92
|
+
WHERE pr.principalType = 'user' AND pr.principalId = ?
|
|
93
|
+
ORDER BY r.grantsAll DESC`).all(userId);
|
|
94
|
+
if (rows.length === 0) {
|
|
95
|
+
return { grantsAll: false, verbs: new Set };
|
|
96
|
+
}
|
|
97
|
+
const verbs = new Set;
|
|
98
|
+
for (const row of rows) {
|
|
99
|
+
if (row.grantsAll === 1) {
|
|
100
|
+
return { grantsAll: true, verbs: new Set };
|
|
101
|
+
}
|
|
102
|
+
if (row.verb) {
|
|
103
|
+
const verb = parseDatabaseGrantVerb(row.roleId, row.verb);
|
|
104
|
+
if (verb) {
|
|
105
|
+
verbs.add(verb);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return { grantsAll: false, verbs };
|
|
110
|
+
}
|
|
111
|
+
function attachRole(userId, roleName) {
|
|
112
|
+
const db = getDb();
|
|
113
|
+
db.transaction(() => {
|
|
114
|
+
const roleId = requireRoleId(roleName);
|
|
115
|
+
db.prepare(`INSERT OR IGNORE INTO principal_roles (principalType, principalId, roleId)
|
|
116
|
+
VALUES ('user', ?, ?)`).run(userId, roleId);
|
|
117
|
+
})();
|
|
118
|
+
}
|
|
119
|
+
function detachRole(userId, roleName) {
|
|
120
|
+
const db = getDb();
|
|
121
|
+
db.transaction(() => {
|
|
122
|
+
const roleId = requireRoleId(roleName);
|
|
123
|
+
db.prepare(`DELETE FROM principal_roles
|
|
124
|
+
WHERE principalType = 'user' AND principalId = ? AND roleId = ?`).run(userId, roleId);
|
|
125
|
+
})();
|
|
126
|
+
}
|
|
127
|
+
function listUserRoles(userId) {
|
|
128
|
+
return getDb().prepare(`SELECT r.id, r.name, r.description, r.isBuiltin, r.grantsAll, r.createdAt
|
|
129
|
+
FROM principal_roles pr
|
|
130
|
+
JOIN roles r ON r.id = pr.roleId
|
|
131
|
+
WHERE pr.principalType = 'user' AND pr.principalId = ?
|
|
132
|
+
ORDER BY r.name`).all(userId).map(roleRowToUserRole);
|
|
133
|
+
}
|
|
134
|
+
function ensureRbacSeedsSynced(opts) {
|
|
135
|
+
const db = getDb();
|
|
136
|
+
const desiredVerbsByRoleId = validatedBuiltinVerbSets();
|
|
137
|
+
const insertRole = db.prepare(`INSERT OR IGNORE INTO roles (id, name, description, isBuiltin, grantsAll)
|
|
138
|
+
VALUES (?, ?, ?, 1, ?)`);
|
|
139
|
+
const updateRole = db.prepare(`UPDATE roles
|
|
140
|
+
SET name = ?, description = ?, isBuiltin = 1, grantsAll = ?, lastUpdatedAt = CURRENT_TIMESTAMP
|
|
141
|
+
WHERE id = ?
|
|
142
|
+
AND (
|
|
143
|
+
name <> ?
|
|
144
|
+
OR COALESCE(description, '') <> COALESCE(?, '')
|
|
145
|
+
OR isBuiltin <> 1
|
|
146
|
+
OR grantsAll <> ?
|
|
147
|
+
)`);
|
|
148
|
+
const selectRoleById = db.prepare("SELECT id, name FROM roles WHERE id = ?");
|
|
149
|
+
const selectRoleByName = db.prepare("SELECT id, name FROM roles WHERE name = ?");
|
|
150
|
+
const selectRolePermissions = db.prepare("SELECT verb FROM role_permissions WHERE roleId = ?");
|
|
151
|
+
const deleteRolePermission = db.prepare("DELETE FROM role_permissions WHERE roleId = ? AND verb = ?");
|
|
152
|
+
const insertRolePermission = db.prepare("INSERT OR IGNORE INTO role_permissions (roleId, verb) VALUES (?, ?)");
|
|
153
|
+
const backfillDefaultRoleForZeroRoleUsers = db.prepare(`INSERT OR IGNORE INTO principal_roles (principalType, principalId, roleId)
|
|
154
|
+
SELECT 'user', u.id, ?
|
|
155
|
+
FROM users u
|
|
156
|
+
WHERE NOT EXISTS (
|
|
157
|
+
SELECT 1
|
|
158
|
+
FROM principal_roles pr
|
|
159
|
+
WHERE pr.principalType = 'user'
|
|
160
|
+
AND pr.principalId = u.id
|
|
161
|
+
)`);
|
|
162
|
+
const stats = {
|
|
163
|
+
rolesInserted: 0,
|
|
164
|
+
rolesUpdated: 0,
|
|
165
|
+
permissionsInserted: 0,
|
|
166
|
+
permissionsDeleted: 0,
|
|
167
|
+
usersBackfilled: 0
|
|
168
|
+
};
|
|
169
|
+
db.transaction(() => {
|
|
170
|
+
for (const role of BUILTIN_ROLES) {
|
|
171
|
+
const grantsAll = role.grantsAll ? 1 : 0;
|
|
172
|
+
const insertResult = insertRole.run(role.id, role.name, role.description, grantsAll);
|
|
173
|
+
stats.rolesInserted += insertResult.changes;
|
|
174
|
+
if (insertResult.changes === 0) {
|
|
175
|
+
const updateResult = updateRole.run(role.name, role.description, grantsAll, role.id, role.name, role.description, grantsAll);
|
|
176
|
+
stats.rolesUpdated += updateResult.changes;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
for (const role of BUILTIN_ROLES) {
|
|
180
|
+
const row = selectRoleById.get(role.id);
|
|
181
|
+
if (row) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const colliding = selectRoleByName.get(role.name);
|
|
185
|
+
if (colliding) {
|
|
186
|
+
throw new Error(`RBAC built-in role "${role.name}" (${role.id}) is missing because role ` + `"${colliding.name}" (${colliding.id}) already uses that name. ` + "Rename or remove the conflicting role, then rerun `rbac bootstrap`.");
|
|
187
|
+
}
|
|
188
|
+
throw new Error(`RBAC built-in role "${role.name}" (${role.id}) is missing after seed sync. ` + "Rerun `rbac bootstrap`; if it still fails, inspect the roles table.");
|
|
189
|
+
}
|
|
190
|
+
for (const role of BUILTIN_ROLES) {
|
|
191
|
+
const desiredVerbs = desiredVerbsByRoleId.get(role.id) ?? new Set;
|
|
192
|
+
const existingRows = selectRolePermissions.all(role.id);
|
|
193
|
+
for (const row of existingRows) {
|
|
194
|
+
if (!desiredVerbs.has(row.verb)) {
|
|
195
|
+
stats.permissionsDeleted += deleteRolePermission.run(role.id, row.verb).changes;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
for (const verb of desiredVerbs) {
|
|
199
|
+
stats.permissionsInserted += insertRolePermission.run(role.id, verb).changes;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
db.run(CREATE_USER_DEFAULT_ROLE_TRIGGER_SQL);
|
|
203
|
+
stats.usersBackfilled += backfillDefaultRoleForZeroRoleUsers.run(DEFAULT_ROLE_ID).changes;
|
|
204
|
+
})();
|
|
205
|
+
if (!opts?.quiet) {
|
|
206
|
+
console.log(`[rbac] seed sync: roles inserted=${stats.rolesInserted}, updated=${stats.rolesUpdated}; permissions inserted=${stats.permissionsInserted}, deleted=${stats.permissionsDeleted}; trigger=ensured; users backfilled=${stats.usersBackfilled}`);
|
|
207
|
+
}
|
|
208
|
+
return stats;
|
|
209
|
+
}
|
|
210
|
+
function describeRbacFlag() {
|
|
211
|
+
const raw = process.env.RBAC_ENABLED;
|
|
212
|
+
if (raw === undefined)
|
|
213
|
+
return "unset (off)";
|
|
214
|
+
return `${raw} (${raw === "true" ? "on" : "off"})`;
|
|
215
|
+
}
|
|
216
|
+
function printRolesTable(rows) {
|
|
217
|
+
const tableRows = rows.map((row) => [
|
|
218
|
+
row.name,
|
|
219
|
+
row.isBuiltin === 1 ? "yes" : "no",
|
|
220
|
+
row.grantsAll === 1 ? "yes" : "no",
|
|
221
|
+
String(row.verbCount),
|
|
222
|
+
String(row.attachedUserCount)
|
|
223
|
+
]);
|
|
224
|
+
const headers = ["name", "builtin", "grantsAll", "verbs", "attachedUsers"];
|
|
225
|
+
const widths = headers.map((header, column) => Math.max(header.length, ...tableRows.map((row) => row[column]?.length ?? 0)));
|
|
226
|
+
const format = (row) => row.map((cell, column) => cell.padEnd(widths[column] ?? cell.length)).join(" ");
|
|
227
|
+
console.log("Roles:");
|
|
228
|
+
console.log(format(headers));
|
|
229
|
+
console.log(format(widths.map((width) => "-".repeat(width))));
|
|
230
|
+
for (const row of tableRows) {
|
|
231
|
+
console.log(format(row));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function getRbacRoleSummary() {
|
|
235
|
+
return getDb().prepare(`SELECT
|
|
236
|
+
r.name,
|
|
237
|
+
r.isBuiltin,
|
|
238
|
+
r.grantsAll,
|
|
239
|
+
COUNT(DISTINCT rp.verb) AS verbCount,
|
|
240
|
+
COUNT(DISTINCT CASE WHEN pr.principalType = 'user' THEN pr.principalId END)
|
|
241
|
+
AS attachedUserCount
|
|
242
|
+
FROM roles r
|
|
243
|
+
LEFT JOIN role_permissions rp ON rp.roleId = r.id
|
|
244
|
+
LEFT JOIN principal_roles pr ON pr.roleId = r.id
|
|
245
|
+
GROUP BY r.id, r.name, r.isBuiltin, r.grantsAll
|
|
246
|
+
ORDER BY r.isBuiltin DESC, r.name`).all();
|
|
247
|
+
}
|
|
248
|
+
async function runRbacCliCommand(args) {
|
|
249
|
+
const subcommand = args[0];
|
|
250
|
+
if (args.length !== 1 || subcommand !== "bootstrap") {
|
|
251
|
+
throw new Error(`Unknown RBAC command: ${args.join(" ") || "(none)"}`);
|
|
252
|
+
}
|
|
253
|
+
const stats = ensureRbacSeedsSynced({ quiet: true });
|
|
254
|
+
const roles = getRbacRoleSummary();
|
|
255
|
+
console.log("RBAC bootstrap complete");
|
|
256
|
+
console.log(`RBAC_ENABLED: ${describeRbacFlag()}`);
|
|
257
|
+
console.log(`Users backfilled this run: ${stats.usersBackfilled}`);
|
|
258
|
+
console.log("");
|
|
259
|
+
printRolesTable(roles);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export { DEFAULT_ROLE_ID, BUILTIN_ROLES, getUserGrant, attachRole, detachRole, listUserRoles, ensureRbacSeedsSynced, runRbacCliCommand };
|
|
@@ -6,14 +6,23 @@ import {
|
|
|
6
6
|
DEFAULT_CREDENTIAL_BINDINGS,
|
|
7
7
|
SwarmConfigCredentialBindingStore,
|
|
8
8
|
getScript,
|
|
9
|
+
getScriptApiConnectionDescriptors,
|
|
10
|
+
getScriptMcpConnectionDescriptors,
|
|
9
11
|
getScriptVersion,
|
|
10
12
|
listRelationalCredentialBindings,
|
|
11
13
|
validateScriptImports
|
|
12
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-pnfyyp6h.js";
|
|
15
|
+
import {
|
|
16
|
+
ensureTokenOrThrow,
|
|
17
|
+
getOAuthApp,
|
|
18
|
+
getOAuthTokens,
|
|
19
|
+
isTokenExpiringSoon,
|
|
20
|
+
oauthAppRowToProviderConfig
|
|
21
|
+
} from "./cli-49j095n9.js";
|
|
13
22
|
import {
|
|
14
23
|
withSiblingAwareness,
|
|
15
24
|
workflowContextKey
|
|
16
|
-
} from "./cli-
|
|
25
|
+
} from "./cli-312v3c41.js";
|
|
17
26
|
import {
|
|
18
27
|
getAppUrl
|
|
19
28
|
} from "./cli-dh55d5fg.js";
|
|
@@ -62,13 +71,13 @@ import {
|
|
|
62
71
|
telemetry,
|
|
63
72
|
updateWorkflowRun,
|
|
64
73
|
updateWorkflowRunStep
|
|
65
|
-
} from "./cli-
|
|
74
|
+
} from "./cli-jzwtn8rm.js";
|
|
66
75
|
import {
|
|
67
76
|
init_zod
|
|
68
|
-
} from "./cli-
|
|
77
|
+
} from "./cli-bw80ck94.js";
|
|
69
78
|
import {
|
|
70
79
|
exports_external
|
|
71
|
-
} from "./cli-
|
|
80
|
+
} from "./cli-xz9aq0rf.js";
|
|
72
81
|
import {
|
|
73
82
|
init_secret_scrubber,
|
|
74
83
|
isSensitiveKey,
|
|
@@ -2083,6 +2092,51 @@ function resolveHmacSecret(raw) {
|
|
|
2083
2092
|
}
|
|
2084
2093
|
return raw;
|
|
2085
2094
|
}
|
|
2095
|
+
function verifyWebhookRequest(trigger, rawBody, headers) {
|
|
2096
|
+
if (!trigger.hmacSecret) {
|
|
2097
|
+
if (trigger.verification) {
|
|
2098
|
+
throw new WebhookError("Webhook trigger has `verification` configured but no `hmacSecret`; refusing to accept unverified requests", 500);
|
|
2099
|
+
}
|
|
2100
|
+
return;
|
|
2101
|
+
}
|
|
2102
|
+
const secret = resolveHmacSecret(trigger.hmacSecret);
|
|
2103
|
+
const verification = trigger.verification;
|
|
2104
|
+
if (!verification) {
|
|
2105
|
+
const hmacHeader = trigger.hmacHeader || DEFAULT_HMAC_HEADER;
|
|
2106
|
+
const signature2 = resolveSignature(headers, hmacHeader);
|
|
2107
|
+
if (!signature2) {
|
|
2108
|
+
throw new WebhookError("Missing signature", 401);
|
|
2109
|
+
}
|
|
2110
|
+
if (!verifyHmacSignature(secret, rawBody, signature2)) {
|
|
2111
|
+
throw new WebhookError("Invalid signature", 401);
|
|
2112
|
+
}
|
|
2113
|
+
return;
|
|
2114
|
+
}
|
|
2115
|
+
const header = verification.header || DEFAULT_HMAC_HEADER;
|
|
2116
|
+
const signature = getHeader(headers, header);
|
|
2117
|
+
if (!signature) {
|
|
2118
|
+
throw new WebhookError("Missing signature", 401);
|
|
2119
|
+
}
|
|
2120
|
+
let isValid = false;
|
|
2121
|
+
switch (verification.format) {
|
|
2122
|
+
case "hmac-sha256":
|
|
2123
|
+
isValid = verifyHmacSignature(secret, rawBody, signature);
|
|
2124
|
+
break;
|
|
2125
|
+
case "timestamped-hmac-sha256":
|
|
2126
|
+
isValid = verifyTimestampedHmacSignature(secret, rawBody, signature, {
|
|
2127
|
+
timestampKey: verification.timestampKey,
|
|
2128
|
+
signatureKey: verification.signatureKey,
|
|
2129
|
+
toleranceSeconds: verification.toleranceSeconds
|
|
2130
|
+
});
|
|
2131
|
+
break;
|
|
2132
|
+
case "token-equality":
|
|
2133
|
+
isValid = verifyTokenEquality(secret, signature);
|
|
2134
|
+
break;
|
|
2135
|
+
}
|
|
2136
|
+
if (!isValid) {
|
|
2137
|
+
throw new WebhookError("Invalid signature", 401);
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2086
2140
|
async function handleWebhookTrigger(workflowId, payload, headers, registry) {
|
|
2087
2141
|
const workflow = getWorkflow(workflowId);
|
|
2088
2142
|
if (!workflow) {
|
|
@@ -2092,17 +2146,8 @@ async function handleWebhookTrigger(workflowId, payload, headers, registry) {
|
|
|
2092
2146
|
throw new WebhookError("Workflow is disabled", 400);
|
|
2093
2147
|
}
|
|
2094
2148
|
const webhookTrigger = workflow.triggers.find((t) => t.type === "webhook");
|
|
2095
|
-
if (webhookTrigger && webhookTrigger.type === "webhook" && webhookTrigger.hmacSecret) {
|
|
2096
|
-
|
|
2097
|
-
const signature = resolveSignature(headers, hmacHeader);
|
|
2098
|
-
if (!signature) {
|
|
2099
|
-
throw new WebhookError("Missing signature", 401);
|
|
2100
|
-
}
|
|
2101
|
-
const secret = resolveHmacSecret(webhookTrigger.hmacSecret);
|
|
2102
|
-
const isValid = verifyHmacSignature(secret, typeof payload === "string" ? payload : JSON.stringify(payload), signature);
|
|
2103
|
-
if (!isValid) {
|
|
2104
|
-
throw new WebhookError("Invalid signature", 401);
|
|
2105
|
-
}
|
|
2149
|
+
if (webhookTrigger && webhookTrigger.type === "webhook" && (webhookTrigger.hmacSecret || webhookTrigger.verification)) {
|
|
2150
|
+
verifyWebhookRequest(webhookTrigger, typeof payload === "string" ? payload : JSON.stringify(payload), headers);
|
|
2106
2151
|
}
|
|
2107
2152
|
const triggerData = parseTriggerPayload(payload);
|
|
2108
2153
|
const runId = await startWorkflowExecution(workflow, triggerData, registry, {
|
|
@@ -2149,6 +2194,57 @@ function verifyHmacSignature(secret, body, providedSignature) {
|
|
|
2149
2194
|
return false;
|
|
2150
2195
|
}
|
|
2151
2196
|
}
|
|
2197
|
+
function verifyTimestampedHmacSignature(secret, body, headerValue, opts = {}, nowMs = Date.now()) {
|
|
2198
|
+
const timestampKey = opts.timestampKey ?? "t";
|
|
2199
|
+
const signatureKey = opts.signatureKey ?? "v1";
|
|
2200
|
+
const toleranceSeconds = opts.toleranceSeconds ?? 300;
|
|
2201
|
+
const parsed = parseSignatureHeader(headerValue);
|
|
2202
|
+
const timestampValue = parsed.get(timestampKey)?.[0];
|
|
2203
|
+
const signatures = parsed.get(signatureKey) ?? [];
|
|
2204
|
+
if (!timestampValue || signatures.length === 0 || !/^\d+$/.test(timestampValue)) {
|
|
2205
|
+
return false;
|
|
2206
|
+
}
|
|
2207
|
+
const timestampSeconds = Number(timestampValue);
|
|
2208
|
+
if (!Number.isSafeInteger(timestampSeconds)) {
|
|
2209
|
+
return false;
|
|
2210
|
+
}
|
|
2211
|
+
const ageSeconds = Math.abs(nowMs / 1000 - timestampSeconds);
|
|
2212
|
+
if (ageSeconds > toleranceSeconds) {
|
|
2213
|
+
return false;
|
|
2214
|
+
}
|
|
2215
|
+
const hmac = crypto2.createHmac("sha256", secret);
|
|
2216
|
+
hmac.update(`${timestampValue}.${body}`);
|
|
2217
|
+
const expectedHex = hmac.digest("hex");
|
|
2218
|
+
const expected = Buffer.from(expectedHex, "hex");
|
|
2219
|
+
return signatures.some((signature) => timingSafeEqualHex(signature, expected));
|
|
2220
|
+
}
|
|
2221
|
+
function verifyTokenEquality(secret, providedToken) {
|
|
2222
|
+
const secretDigest = crypto2.createHash("sha256").update(secret).digest();
|
|
2223
|
+
const providedDigest = crypto2.createHash("sha256").update(providedToken).digest();
|
|
2224
|
+
return crypto2.timingSafeEqual(providedDigest, secretDigest);
|
|
2225
|
+
}
|
|
2226
|
+
function parseSignatureHeader(headerValue) {
|
|
2227
|
+
const parsed = new Map;
|
|
2228
|
+
for (const part of headerValue.split(",")) {
|
|
2229
|
+
const trimmed = part.trim();
|
|
2230
|
+
const separatorIndex = trimmed.indexOf("=");
|
|
2231
|
+
if (separatorIndex <= 0)
|
|
2232
|
+
continue;
|
|
2233
|
+
const key = trimmed.slice(0, separatorIndex).trim();
|
|
2234
|
+
const value = trimmed.slice(separatorIndex + 1).trim();
|
|
2235
|
+
const values = parsed.get(key) ?? [];
|
|
2236
|
+
values.push(value);
|
|
2237
|
+
parsed.set(key, values);
|
|
2238
|
+
}
|
|
2239
|
+
return parsed;
|
|
2240
|
+
}
|
|
2241
|
+
function timingSafeEqualHex(providedHex, expected) {
|
|
2242
|
+
try {
|
|
2243
|
+
return crypto2.timingSafeEqual(Buffer.from(providedHex, "hex"), expected);
|
|
2244
|
+
} catch {
|
|
2245
|
+
return false;
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2152
2248
|
|
|
2153
2249
|
class WebhookError extends Error {
|
|
2154
2250
|
statusCode;
|
|
@@ -2487,7 +2583,8 @@ class HumanInTheLoopExecutor extends BaseExecutor {
|
|
|
2487
2583
|
workflowRunId: meta.runId,
|
|
2488
2584
|
workflowRunStepId: meta.stepId,
|
|
2489
2585
|
timeoutSeconds: config.timeout?.seconds,
|
|
2490
|
-
notificationChannels: config.notifications
|
|
2586
|
+
notificationChannels: config.notifications,
|
|
2587
|
+
createdBy: meta.requestedByUserId
|
|
2491
2588
|
});
|
|
2492
2589
|
if (config.notifications?.length) {
|
|
2493
2590
|
this.dispatchNotifications(requestId, config, db).catch((err) => {
|
|
@@ -2515,7 +2612,7 @@ class HumanInTheLoopExecutor extends BaseExecutor {
|
|
|
2515
2612
|
}
|
|
2516
2613
|
if (notification.channel === "slack") {
|
|
2517
2614
|
try {
|
|
2518
|
-
const { getSlackApp } = await import("./app-
|
|
2615
|
+
const { getSlackApp } = await import("./app-bhwdxmvp.js");
|
|
2519
2616
|
const slackApp = getSlackApp();
|
|
2520
2617
|
if (!slackApp) {
|
|
2521
2618
|
console.warn("[HITL] Slack not initialized — cannot send notification");
|
|
@@ -2629,7 +2726,7 @@ class NotifyExecutor extends BaseExecutor {
|
|
|
2629
2726
|
}
|
|
2630
2727
|
}
|
|
2631
2728
|
case "slack": {
|
|
2632
|
-
const { getSlackApp } = await import("./app-
|
|
2729
|
+
const { getSlackApp } = await import("./app-bhwdxmvp.js");
|
|
2633
2730
|
const app = getSlackApp();
|
|
2634
2731
|
if (!app) {
|
|
2635
2732
|
return {
|
|
@@ -2752,14 +2849,14 @@ var RawLlmOutputSchema = exports_external.object({
|
|
|
2752
2849
|
async function executeRawLlm(config) {
|
|
2753
2850
|
const modelName = config.model ?? "google/gemini-3-flash-preview";
|
|
2754
2851
|
try {
|
|
2755
|
-
const { createOpenAI } = await import("./index-
|
|
2852
|
+
const { createOpenAI } = await import("./index-2dgfj9av.js");
|
|
2756
2853
|
const openrouter = createOpenAI({
|
|
2757
2854
|
baseURL: "https://openrouter.ai/api/v1",
|
|
2758
2855
|
apiKey: process.env.OPENROUTER_API_KEY
|
|
2759
2856
|
});
|
|
2760
2857
|
const model = openrouter(modelName);
|
|
2761
2858
|
if (config.schema) {
|
|
2762
|
-
const { generateObject, jsonSchema } = await import("./index-
|
|
2859
|
+
const { generateObject, jsonSchema } = await import("./index-t2snazez.js");
|
|
2763
2860
|
const { object } = await generateObject({
|
|
2764
2861
|
model,
|
|
2765
2862
|
schema: jsonSchema(config.schema),
|
|
@@ -2773,7 +2870,7 @@ async function executeRawLlm(config) {
|
|
|
2773
2870
|
output: { result: object, model: modelName }
|
|
2774
2871
|
};
|
|
2775
2872
|
}
|
|
2776
|
-
const { generateText } = await import("./index-
|
|
2873
|
+
const { generateText } = await import("./index-t2snazez.js");
|
|
2777
2874
|
const { text } = await generateText({
|
|
2778
2875
|
model,
|
|
2779
2876
|
prompt: config.prompt
|
|
@@ -2926,6 +3023,33 @@ init_zod();
|
|
|
2926
3023
|
// src/be/script-credential-broker.ts
|
|
2927
3024
|
init_secret_scrubber();
|
|
2928
3025
|
init_db();
|
|
3026
|
+
|
|
3027
|
+
// src/be/oauth-credential-bindings.ts
|
|
3028
|
+
var OAUTH_BINDING_REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
3029
|
+
function getOAuthProviderConfig(provider) {
|
|
3030
|
+
const app = getOAuthApp(provider);
|
|
3031
|
+
return app ? oauthAppRowToProviderConfig(app) : null;
|
|
3032
|
+
}
|
|
3033
|
+
function getOAuthBindingTokenStatus(provider) {
|
|
3034
|
+
if (!getOAuthApp(provider))
|
|
3035
|
+
return "missing";
|
|
3036
|
+
if (!getOAuthTokens(provider))
|
|
3037
|
+
return "missing";
|
|
3038
|
+
return isTokenExpiringSoon(provider, OAUTH_BINDING_REFRESH_BUFFER_MS) ? "expiring" : "ok";
|
|
3039
|
+
}
|
|
3040
|
+
async function resolveOAuthBindingToken(provider) {
|
|
3041
|
+
if (!getOAuthApp(provider))
|
|
3042
|
+
return;
|
|
3043
|
+
const initialTokens = getOAuthTokens(provider);
|
|
3044
|
+
if (!initialTokens)
|
|
3045
|
+
return;
|
|
3046
|
+
if (isTokenExpiringSoon(provider, OAUTH_BINDING_REFRESH_BUFFER_MS)) {
|
|
3047
|
+
await ensureTokenOrThrow(provider, OAUTH_BINDING_REFRESH_BUFFER_MS);
|
|
3048
|
+
}
|
|
3049
|
+
return getOAuthTokens(provider)?.accessToken;
|
|
3050
|
+
}
|
|
3051
|
+
|
|
3052
|
+
// src/be/script-credential-broker.ts
|
|
2929
3053
|
class RelationalCredentialBindingStore extends SwarmConfigCredentialBindingStore {
|
|
2930
3054
|
listActiveBindings(context) {
|
|
2931
3055
|
const relational = listRelationalCredentialBindings(context);
|
|
@@ -2934,9 +3058,29 @@ class RelationalCredentialBindingStore extends SwarmConfigCredentialBindingStore
|
|
|
2934
3058
|
return super.listActiveBindings(context);
|
|
2935
3059
|
}
|
|
2936
3060
|
}
|
|
2937
|
-
function buildScriptCredentialBindings(input) {
|
|
3061
|
+
async function buildScriptCredentialBindings(input) {
|
|
2938
3062
|
const resolvedConfigs = getResolvedConfig(input.agentId, input.repoId);
|
|
2939
3063
|
const configMap = new Map(resolvedConfigs.map((config) => [config.key, config.value]));
|
|
3064
|
+
const relationalBindings = listRelationalCredentialBindings(input);
|
|
3065
|
+
for (const binding of relationalBindings) {
|
|
3066
|
+
if (binding.authKind !== "oauth")
|
|
3067
|
+
continue;
|
|
3068
|
+
configMap.set(binding.configKey, "");
|
|
3069
|
+
if (!binding.oauthProvider)
|
|
3070
|
+
continue;
|
|
3071
|
+
let accessToken;
|
|
3072
|
+
try {
|
|
3073
|
+
accessToken = await resolveOAuthBindingToken(binding.oauthProvider);
|
|
3074
|
+
} catch (err) {
|
|
3075
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3076
|
+
console.warn(`[script-credential-broker] skipping OAuth binding ${binding.configKey}: token refresh for provider ${binding.oauthProvider} failed: ${scrubSecrets(message)}`);
|
|
3077
|
+
continue;
|
|
3078
|
+
}
|
|
3079
|
+
if (!accessToken)
|
|
3080
|
+
continue;
|
|
3081
|
+
configMap.set(binding.configKey, accessToken);
|
|
3082
|
+
registerVolatileSecret(accessToken, binding.configKey);
|
|
3083
|
+
}
|
|
2940
3084
|
const broker = new CredentialBroker(new RelationalCredentialBindingStore((filters) => getSwarmConfigs(filters)), (configKey) => configMap.get(configKey) ?? process.env[configKey], DEFAULT_CREDENTIAL_BINDINGS);
|
|
2941
3085
|
const bindings = broker.resolveBindings({ agentId: input.agentId, repoId: input.repoId });
|
|
2942
3086
|
for (const binding of bindings) {
|
|
@@ -3211,7 +3355,8 @@ function buildConfigPayload(input) {
|
|
|
3211
3355
|
},
|
|
3212
3356
|
user: input.userConfig ?? {},
|
|
3213
3357
|
egressSecrets: input.egressSecrets ?? buildEgressSecrets(),
|
|
3214
|
-
apiConnections: input.apiConnections ?? []
|
|
3358
|
+
apiConnections: input.apiConnections ?? [],
|
|
3359
|
+
mcpConnections: input.mcpConnections ?? []
|
|
3215
3360
|
};
|
|
3216
3361
|
}
|
|
3217
3362
|
async function runScript(input) {
|
|
@@ -3307,7 +3452,9 @@ class SwarmScriptExecutor extends BaseExecutor {
|
|
|
3307
3452
|
args: config.args,
|
|
3308
3453
|
fsMode: "none",
|
|
3309
3454
|
agentId: agentId ?? "workflow",
|
|
3310
|
-
egressSecrets: buildScriptCredentialBindings({ agentId: agentId ?? undefined }),
|
|
3455
|
+
egressSecrets: await buildScriptCredentialBindings({ agentId: agentId ?? undefined }),
|
|
3456
|
+
apiConnections: getScriptApiConnectionDescriptors({ agentId: agentId ?? undefined }),
|
|
3457
|
+
mcpConnections: getScriptMcpConnectionDescriptors({ agentId: agentId ?? undefined }),
|
|
3311
3458
|
timeoutMs: config.timeoutMs
|
|
3312
3459
|
});
|
|
3313
3460
|
const workflowOutput = {
|
|
@@ -3462,8 +3609,8 @@ class ValidateExecutor extends BaseExecutor {
|
|
|
3462
3609
|
const interpolatedPrompt = this.deps.interpolate(prompt, context);
|
|
3463
3610
|
const outputStr = typeof targetOutput === "string" ? targetOutput : JSON.stringify(targetOutput);
|
|
3464
3611
|
try {
|
|
3465
|
-
const { createOpenAI } = await import("./index-
|
|
3466
|
-
const { generateObject, jsonSchema } = await import("./index-
|
|
3612
|
+
const { createOpenAI } = await import("./index-2dgfj9av.js");
|
|
3613
|
+
const { generateObject, jsonSchema } = await import("./index-t2snazez.js");
|
|
3467
3614
|
const openrouter = createOpenAI({
|
|
3468
3615
|
baseURL: "https://openrouter.ai/api/v1",
|
|
3469
3616
|
apiKey: process.env.OPENROUTER_API_KEY
|
|
@@ -3665,4 +3812,4 @@ function initWorkflows() {
|
|
|
3665
3812
|
initWaitBusSubscriptions(_registry);
|
|
3666
3813
|
}
|
|
3667
3814
|
|
|
3668
|
-
export { buildScriptCredentialBindings, runScript, generateEdges, findEntryNodes, getSuccessors, validateDefinition, applyDefinitionPatch, validateJsonSchema, TriggerSchemaError, startWorkflowExecution, setupWorkflowResumeListener, retryFailedRun, cancelWorkflowRun, resumeWaitState, initWaitBusSubscriptions, subscribeWaitToBus, recoverIncompleteRuns, startRetryPoller, stopRetryPoller, validateTemplateVariables, instantiateTemplate, handleWebhookTrigger, handleScheduleTrigger, verifyHmacSignature, WebhookError, snapshotWorkflow, startWaitPoller, stopWaitPoller, RawLlmConfigSchema, executeRawLlm, getExecutorRegistry, initWorkflows };
|
|
3815
|
+
export { getOAuthProviderConfig, getOAuthBindingTokenStatus, buildScriptCredentialBindings, runScript, generateEdges, findEntryNodes, getSuccessors, validateDefinition, applyDefinitionPatch, validateJsonSchema, TriggerSchemaError, startWorkflowExecution, setupWorkflowResumeListener, retryFailedRun, cancelWorkflowRun, resumeWaitState, initWaitBusSubscriptions, subscribeWaitToBus, recoverIncompleteRuns, startRetryPoller, stopRetryPoller, validateTemplateVariables, instantiateTemplate, handleWebhookTrigger, handleScheduleTrigger, verifyHmacSignature, WebhookError, snapshotWorkflow, startWaitPoller, stopWaitPoller, RawLlmConfigSchema, executeRawLlm, getExecutorRegistry, initWorkflows };
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getDb,
|
|
7
7
|
init_db,
|
|
8
8
|
isSqliteVecAvailable
|
|
9
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-jzwtn8rm.js";
|
|
10
10
|
import {
|
|
11
11
|
__esm,
|
|
12
12
|
__export,
|
|
@@ -6740,7 +6740,7 @@ class SqliteMemoryStore {
|
|
|
6740
6740
|
}
|
|
6741
6741
|
}
|
|
6742
6742
|
deleteFtsRows(ids) {
|
|
6743
|
-
if (ids.length === 0 || !this.
|
|
6743
|
+
if (ids.length === 0 || !this.getFtsTableSchema())
|
|
6744
6744
|
return;
|
|
6745
6745
|
const db = getDb();
|
|
6746
6746
|
const placeholders = ids.map(() => "?").join(",");
|