@desplega.ai/agent-swarm 1.164.1 → 1.166.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 +1 -1
- package/dist/acp-adapter-yzfxn8vj.js +23 -0
- package/dist/{actions-hp2h32dx.js → actions-qz3m692w.js} +24 -28
- package/dist/{amp-adapter-zfd7djyx.js → amp-adapter-j1xbmsqz.js} +7 -7
- package/dist/{app-w2d26h4f.js → app-43vrdmv8.js} +9 -10
- package/dist/{assistant-45pc4en7.js → assistant-ertffmka.js} +25 -29
- package/dist/{boot-reembed-k1q2s4fc.js → boot-reembed-998jtpdg.js} +12 -15
- package/dist/{boot-reembed-6rhcpsjf.js → boot-reembed-s7k7c6v2.js} +13 -15
- package/dist/boot-scrub-sweep-nepsk4t1.js +211 -0
- package/dist/{boot-seeds-ex93edx7.js → boot-seeds-vvzs1zhk.js} +12 -12
- package/dist/{claude-adapter-hcxd0szm.js → claude-adapter-2zvmekrp.js} +15 -17
- package/dist/{claude-managed-adapter-fz7xps2r.js → claude-managed-adapter-s49wbk8t.js} +5 -5
- package/dist/{claude-managed-setup-xx6f15h9.js → claude-managed-setup-cvhqq8qn.js} +4 -4
- package/dist/{claude-sdk-session-6nb9raem.js → claude-sdk-session-kkbxtw5q.js} +2624 -2606
- package/dist/{cli-etbrt8x1.js → cli-0nhdwxd5.js} +4 -4
- package/dist/{cli-jeefgppq.js → cli-0qjcsxgz.js} +7 -7
- package/dist/{cli-6behs2bt.js → cli-32bca7nr.js} +1 -1
- package/dist/{cli-gt8v96qx.js → cli-3ddybbbx.js} +4 -4
- package/dist/{acp-adapter-rxvek4ym.js → cli-3qn4r334.js} +317 -35
- package/dist/{cli-1d3w4xm3.js → cli-4r1sjfc4.js} +14 -6
- package/dist/{cli-691f2rxm.js → cli-66zh26sp.js} +68 -16
- package/dist/{cli-et8wdyqh.js → cli-68r1j4sg.js} +9 -9
- package/dist/{cli-xb7kyanp.js → cli-8kgvmkak.js} +3 -3
- package/dist/{cli-fdpkw8vk.js → cli-8t229cmr.js} +8 -8
- package/dist/{cli-gc54qc0p.js → cli-aqcey741.js} +1 -1
- package/dist/{cli-4q4cmr4t.js → cli-cpfmqz3n.js} +8 -8
- package/dist/{cli-a9bw0xxt.js → cli-df56tqdw.js} +997 -408
- package/dist/{cli-n7h1kqpf.js → cli-dmtrxqhg.js} +6 -1
- package/dist/{cli-xfb7333f.js → cli-dw2q9f7g.js} +5 -5
- package/dist/{cli-4drstbb9.js → cli-ecknp7p1.js} +81 -23
- package/dist/{cli-v0pvvhfq.js → cli-efnd2kce.js} +36 -1
- package/dist/{cli-1wetf34q.js → cli-f2n17zhp.js} +1 -1
- package/dist/{cli-2c8eky5y.js → cli-feh3dkah.js} +1 -1
- package/dist/cli-fn697bnt.js +126 -0
- package/dist/{cli-v5pr2fgt.js → cli-gt8azyet.js} +3 -3
- package/dist/{cli-dbszf3rw.js → cli-h3x613ze.js} +4 -4
- package/dist/{cli-nwhb8y2e.js → cli-hf5s9pgf.js} +1 -1
- package/dist/cli-j2jbr8af.js +516 -0
- package/dist/{cli-agjzafns.js → cli-jhm6hzjn.js} +593 -10
- package/dist/{cli-j0tmc908.js → cli-jvj6a0cv.js} +484 -477
- package/dist/{cli-xxz89c2n.js → cli-mb75wpxf.js} +1 -1
- package/dist/{cli-07s39g1n.js → cli-mv2520nm.js} +1 -1
- package/dist/{cli-v90vfwyb.js → cli-mwegs4af.js} +5 -5
- package/dist/{cli-bz1gbac9.js → cli-p4ztb80h.js} +2 -2
- package/dist/{cli-1wd1n2ya.js → cli-rfphkzh5.js} +1 -1
- package/dist/{cli-976r1zqx.js → cli-rggdq8wq.js} +5 -5
- package/dist/{cli-3ajw5v5v.js → cli-rsy933yz.js} +6 -6
- package/dist/{cli-yj790e19.js → cli-tadfgd0t.js} +8 -1
- package/dist/{cli-cn53e7vc.js → cli-ttbsse3f.js} +6 -1
- package/dist/{cli-dyqsrqcf.js → cli-v2a8x45d.js} +4 -4
- package/dist/{cli-wbvnn6tk.js → cli-v6vv7dy8.js} +91 -9
- package/dist/{cli-z2ap2c0c.js → cli-vzc73wet.js} +90 -55
- package/dist/cli-wt7ccy4r.js +2654 -0
- package/dist/{cli-4cn19jvn.js → cli-x7kpr72a.js} +3 -3
- package/dist/{cli-003785v9.js → cli-xvc3q9br.js} +1 -1
- package/dist/{cli-v0e7jpr5.js → cli-xvdgasgy.js} +13 -4
- package/dist/{cli-asqeg4ve.js → cli-y59h2pk9.js} +2 -2
- package/dist/{cli-0wn3ypqv.js → cli-yshaazs1.js} +14121 -3478
- package/dist/{cli-wg8yjqtw.js → cli-ysnyhws9.js} +16 -3
- package/dist/cli-zp67qg5x.js +92 -0
- package/dist/{cli-g3qgrzck.js → cli-zsh093hk.js} +71 -3
- package/dist/{cli-ma3zvh39.js → cli-zy7vwsne.js} +6066 -5829
- package/dist/cli.js +79 -26
- package/dist/{codex-adapter-pcxdn10v.js → codex-adapter-dw1wxqt8.js} +10 -10
- package/dist/{codex-hook-b1fb7c2k.js → codex-hook-d2rkvf39.js} +1 -1
- package/dist/{codex-login-059nm145.js → codex-login-terbdsqq.js} +2 -2
- package/dist/{codex-session-runner-xzwwddp8.js → codex-session-runner-3cgb8y1g.js} +10 -10
- package/dist/{commands-98at8mkn.js → commands-mhxam6z2.js} +9 -9
- package/dist/{cursor-adapter-dkg6qnkp.js → cursor-adapter-2qda3st7.js} +6 -6
- package/dist/{db-01g8wtvw.js → db-sjks418k.js} +11 -9
- package/dist/{devin-adapter-qmttt2fz.js → devin-adapter-bffjj5n4.js} +2 -2
- package/dist/{dispatcher-nn2k1wxd.js → dispatcher-1es759rn.js} +22 -26
- package/dist/{dsh-adapter-w4d4vwdq.js → dsh-adapter-bek4cyw9.js} +6 -6
- package/dist/{e2b-9e4g2hvt.js → e2b-nd50eccg.js} +1 -1
- package/dist/{event-bus-z7v2t26e.js → event-bus-vnfthafg.js} +2 -2
- package/dist/grok-adapter-ar9cw9jg.js +29 -0
- package/dist/{handlers-b0kqsbg8.js → handlers-1gkbhktr.js} +25 -29
- package/dist/{hook-sap7v1aj.js → hook-ds2zxq9v.js} +16 -18
- package/dist/{hook-pz50gqep.js → hook-vxa3tcsy.js} +10 -12
- package/dist/{http-ncr8rmd0.js → http-3h21z9md.js} +679 -227
- package/dist/{index-c4aqcyz1.js → index-9b65j1m5.js} +11 -11
- package/dist/{index-r46s01nq.js → index-bn6cy8ps.js} +22 -26
- package/dist/{index-38kqdt3e.js → index-dkfxpkmm.js} +23 -27
- package/dist/{index-630kj5vd.js → index-f8xnqrye.js} +55 -43
- package/dist/{index-fdk1t4d6.js → index-n0rxa4ca.js} +11962 -9900
- package/dist/{index-9nrj7797.js → index-n99fycq7.js} +22 -26
- package/dist/{keepalive-31613r2h.js → keepalive-3xspa9jw.js} +14 -11
- package/dist/{lead-mx59tr5s.js → lead-6qphc124.js} +43 -43
- package/dist/{maintenance-55ff39ca.js → maintenance-0teem1bb.js} +10 -12
- package/dist/{node-f0ykebbv.js → node-9sg7ajby.js} +25 -7
- package/dist/{oauth-refresh-sweep-anma954w.js → oauth-refresh-sweep-sh9q25xp.js} +13 -10
- package/dist/{onboard-b2fy8ftb.js → onboard-54qmnqxe.js} +4 -3
- package/dist/{opencode-adapter-p1s92tmy.js → opencode-adapter-wjfa2wvd.js} +6 -6
- package/dist/{otel-impl-9brvt7xv.js → otel-impl-ycqzp2a1.js} +2 -2
- package/dist/{pi-mono-adapter-kz4rrwvd.js → pi-mono-adapter-e77e9zst.js} +6 -6
- package/dist/{pricing-refresh-7w8mbmva.js → pricing-refresh-atnkngqs.js} +10 -10
- package/dist/{rbac-roles-ejp7qwvb.js → rbac-roles-9pjphh9q.js} +10 -10
- package/dist/{rbac-roles-nhk4r7bc.js → rbac-roles-j78wdksm.js} +10 -10
- package/dist/{render-v2-2gzt8skq.js → render-v2-pxjs49fx.js} +9 -10
- package/dist/{setup-5et8t412.js → setup-ymej0xtx.js} +2 -2
- package/dist/{work-objects-tb0er7qa.js → work-objects-3nh4ymzb.js} +26 -30
- package/dist/{worker-62cv075d.js → worker-qa9fkz5s.js} +43 -43
- package/dist/{x-vbxb31jr.js → x-ma4gnfgy.js} +2 -2
- package/openapi.json +457 -31
- package/package.json +14 -6
- package/plugin/commands/create-pr.md +7 -1
- package/plugin/pi-skills/create-pr/SKILL.md +7 -1
- package/src/agentmail/app.ts +5 -4
- package/src/be/automation-preflight.ts +11 -9
- package/src/be/boot-scrub-sweep.ts +302 -0
- package/src/be/connector-codes.ts +81 -0
- package/src/be/crypto/key-bootstrap.ts +1 -1
- package/src/be/db/approvals.ts +15 -1
- package/src/be/db/codex-oauth-device-flows.ts +40 -0
- package/src/be/db/config-secrets.ts +31 -0
- package/src/be/db/runtime.ts +4 -0
- package/src/be/db/script-runs.ts +15 -0
- package/src/be/db/tasks/write.ts +1 -1
- package/src/be/db-queries/mcp-oauth.ts +5 -0
- package/src/be/db-queries/oauth.ts +77 -0
- package/src/be/db.ts +162 -59
- package/src/be/events.ts +17 -1
- package/src/be/memory/index-content.ts +2 -2
- package/src/be/memory/providers/sqlite-store.ts +63 -11
- package/src/be/memory/types.ts +14 -0
- package/src/be/migrations/197_connector_codes.sql +23 -0
- package/src/be/migrations/198_permission_audit_guest.sql +33 -0
- package/src/be/migrations/200_backfill_auto_memory_expiry.sql +20 -0
- package/src/be/migrations/201_workflow_replay_columns.sql +10 -0
- package/src/be/migrations/202_codex_oauth_device_flows.sql +24 -0
- package/src/be/model-tier-resolution.ts +2 -1
- package/src/be/model-validation.ts +1 -1
- package/src/be/pricing-normalize.ts +3 -0
- package/src/be/rbac-audit.ts +2 -1
- package/src/be/scripts/db.ts +28 -4
- package/src/be/scripts/source-secrets.ts +37 -0
- package/src/be/scripts/typecheck.ts +23 -2
- package/src/be/scrub-json.ts +32 -0
- package/src/be/sealed-json.ts +59 -0
- package/src/be/secret-registry.ts +131 -0
- package/src/be/seed-pricing.ts +14 -0
- package/src/be/users.ts +7 -1
- package/src/be/workflow-replay.ts +77 -0
- package/src/cli.tsx +7 -0
- package/src/commands/provider-credentials.ts +46 -8
- package/src/commands/runner.ts +2 -10
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/github/app.ts +4 -4
- package/src/heartbeat/heartbeat.ts +20 -8
- package/src/hooks/pr-body-guard.ts +1 -1
- package/src/http/agents.ts +1 -0
- package/src/http/approval-requests.ts +1 -0
- package/src/http/apps.ts +3 -0
- package/src/http/auth.ts +4 -1
- package/src/http/codex-oauth-device.ts +8 -10
- package/src/http/codex-oauth-keep-warm.ts +2 -2
- package/src/http/config-values.ts +59 -0
- package/src/http/config.ts +5 -0
- package/src/http/db-query-bounded.ts +3 -0
- package/src/http/db-query-shared.ts +107 -15
- package/src/http/db-query.ts +10 -2
- package/src/http/extensions.ts +1 -0
- package/src/http/index.ts +23 -6
- package/src/http/integrations.ts +1 -38
- package/src/http/ip-rate-limit.ts +82 -0
- package/src/http/kv.ts +38 -4
- package/src/http/mcp-servers.ts +1 -0
- package/src/http/memory.ts +9 -0
- package/src/http/models-catalog.ts +2 -0
- package/src/http/operator-actor.ts +4 -0
- package/src/http/page-proxy.ts +22 -0
- package/src/http/pages.ts +4 -2
- package/src/http/realtime.ts +1 -1
- package/src/http/request-principal.ts +14 -1
- package/src/http/script-connections.ts +8 -0
- package/src/http/script-runs.ts +12 -4
- package/src/http/scripts.ts +15 -0
- package/src/http/session-cost-recompute.ts +3 -2
- package/src/http/tasks.ts +9 -0
- package/src/http/users.ts +226 -0
- package/src/http/workflows.ts +3 -2
- package/src/http.ts +1 -0
- package/src/integrations/kapso/client.ts +3 -1
- package/src/jira/app.ts +2 -2
- package/src/kv-view.ts +324 -0
- package/src/linear/app.ts +2 -2
- package/src/oauth/mcp-wrapper.ts +1 -1
- package/src/prompts/memories.ts +42 -1
- package/src/providers/acp-adapter.ts +85 -24
- package/src/providers/acp-target-catalog.ts +54 -1
- package/src/providers/acp-targets.ts +358 -4
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/cursor-adapter.ts +1 -1
- package/src/providers/grok-adapter.ts +186 -0
- package/src/providers/index.ts +5 -1
- package/src/providers/pricing-sources.md +6 -0
- package/src/providers/reasoning-effort.ts +17 -1
- package/src/providers/types.ts +2 -1
- package/src/rbac/can.ts +4 -3
- package/src/rbac/legacy-policy.ts +3 -3
- package/src/rbac/types.ts +6 -0
- package/src/script-workflows/supervisor.ts +11 -2
- package/src/scripts-runtime/eval-harness.ts +2 -12
- package/src/scripts-runtime/executors/quickjs-bundle.ts +152 -0
- package/src/scripts-runtime/executors/quickjs-prelude.ts +285 -0
- package/src/scripts-runtime/executors/quickjs-runner.ts +580 -0
- package/src/scripts-runtime/executors/quickjs-worker.ts +81 -0
- package/src/scripts-runtime/executors/quickjs.ts +196 -0
- package/src/scripts-runtime/executors/registry.ts +2 -0
- package/src/scripts-runtime/executors/sourcemap.ts +79 -0
- package/src/scripts-runtime/script-error-hints.ts +14 -0
- package/src/scripts-runtime/swarm-sdk.ts +9 -2
- package/src/scripts-runtime/types/stdlib.d.ts +27 -8
- package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -8
- package/src/server-user.ts +2 -20
- package/src/server.ts +3 -1
- package/src/slack/app.ts +4 -0
- package/src/slack/config.ts +3 -1
- package/src/slack/egress-scrub.ts +87 -0
- package/src/tests/acp-adapter.test.ts +191 -2
- package/src/tests/boot-scrub-sweep.test.ts +390 -0
- package/src/tests/budget-user-scope.test.ts +7 -21
- package/src/tests/check-pr-body.test.ts +149 -6
- package/src/tests/check-text-columns.test.ts +145 -0
- package/src/tests/claude-adapter-binary.test.ts +1 -1
- package/src/tests/claude-sdk-process.fixture.ts +13 -2
- package/src/tests/codex-oauth-device.test.ts +23 -37
- package/src/tests/codex-oauth-keep-warm.test.ts +29 -0
- package/src/tests/console-scrub.test.ts +141 -0
- package/src/tests/credential-check.test.ts +90 -0
- package/src/tests/db-query-denylist.test.ts +202 -0
- package/src/tests/db-task-read-contract.test.ts +1 -0
- package/src/tests/db-task-write-contract.test.ts +1 -0
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/entrypoint-acp-target-binary.test.ts +44 -1
- package/src/tests/events-scrub.test.ts +88 -0
- package/src/tests/explicit-model-validation.test.ts +81 -0
- package/src/tests/extensions-pre-task.test.ts +33 -1
- package/src/tests/fixtures/grok/acp-updates-recorded.jsonl +53 -0
- package/src/tests/fixtures/grok/prompt-response-meta.json +36 -0
- package/src/tests/fixtures/secret-corpus.ts +320 -0
- package/src/tests/grok-adapter.test.ts +647 -0
- package/src/tests/heartbeat-checklist.test.ts +44 -0
- package/src/tests/integration-disable-flags.test.ts +156 -0
- package/src/tests/kv-http.test.ts +34 -0
- package/src/tests/kv-tool.test.ts +274 -1
- package/src/tests/kv-view.test.ts +147 -0
- package/src/tests/mcp-user-route.test.ts +257 -15
- package/src/tests/memory-injection-outcome.test.ts +143 -0
- package/src/tests/model-tier-resolution.test.ts +76 -3
- package/src/tests/page-guest-session.test.ts +424 -0
- package/src/tests/page-proxy.test.ts +1 -1
- package/src/tests/page-viewer-auth.test.ts +22 -1
- package/src/tests/pr-body-leaks.test.ts +157 -2
- package/src/tests/preload.ts +10 -0
- package/src/tests/provider-registration.test.ts +3 -1
- package/src/tests/rbac-audit.test.ts +32 -0
- package/src/tests/rbac-mcp-admission-e2e.test.ts +4 -62
- package/src/tests/script-connections.test.ts +9 -0
- package/src/tests/script-executor-conformance.test.ts +3 -0
- package/src/tests/script-executor-quickjs.test.ts +442 -0
- package/src/tests/script-executor-registry.test.ts +6 -1
- package/src/tests/script-runs-http.test.ts +126 -1
- package/src/tests/script-runs-scrub.test.ts +275 -0
- package/src/tests/scripts-http.test.ts +82 -1
- package/src/tests/scripts-mcp-e2e.test.ts +42 -6
- package/src/tests/scripts-runtime.test.ts +37 -0
- package/src/tests/scrubbed-text-12e.test.ts +289 -0
- package/src/tests/sealed-key-guard.test.ts +166 -0
- package/src/tests/secret-canary-sweep.test.ts +958 -0
- package/src/tests/secret-registry.test.ts +355 -0
- package/src/tests/secret-rules.test.ts +230 -0
- package/src/tests/secret-scrubber.test.ts +317 -1
- package/src/tests/session-costs-golden.test.ts +17 -0
- package/src/tests/slack-egress-scrub.test.ts +216 -0
- package/src/tests/swarm-tool-result-gate.test.ts +143 -30
- package/src/tests/task-tools-ctx.test.ts +3 -0
- package/src/tests/user-token-routes.test.ts +342 -3
- package/src/tests/workflow-replay.test.ts +518 -0
- package/src/tests/workflow-scrub.test.ts +242 -0
- package/src/tests/workflow-system-one-decision-providers.test.ts +737 -0
- package/src/tools/db-query.ts +1 -1
- package/src/tools/inject-learning.ts +1 -1
- package/src/tools/kv/kv-get.ts +136 -6
- package/src/tools/send-task.ts +61 -17
- package/src/tools/utils.ts +186 -43
- package/src/tools/workflows/get-workflow-run.ts +3 -2
- package/src/types.ts +16 -1
- package/src/utils/console-scrub-install.ts +5 -0
- package/src/utils/console-scrub.ts +57 -0
- package/src/utils/credentials.ts +8 -0
- package/src/utils/page-session.ts +6 -2
- package/src/utils/pr-body-leaks.ts +149 -10
- package/src/utils/request-auth-context.ts +2 -0
- package/src/utils/secret-rules.generated.ts +2055 -0
- package/src/utils/secret-scrubber.ts +662 -36
- package/src/workflows/engine.ts +39 -4
- package/src/workflows/executors/notify.ts +6 -1
- package/src/workflows/executors/system-one-decision.ts +31 -12
- package/src/workflows/executors/system-one-openai-wire.ts +168 -0
- package/src/workflows/executors/system-one-providers.ts +112 -11
- package/src/workflows/executors/system-one-wire.ts +79 -0
- package/src/workflows/recovery.ts +10 -1
- package/src/workflows/resume.ts +62 -3
- package/src/workflows/retry-poller.ts +3 -0
- package/templates/ai-toolbox.manifest.json +2 -2
- package/templates/skills/agent-browser/SKILL.md +5 -5
- package/templates/skills/agent-browser/config.json +1 -1
- package/templates/skills/agent-browser/content.md +4 -4
- package/templates/skills/artifacts/content.md +17 -7
- package/templates/skills/jira-interaction/config.json +1 -1
- package/templates/skills/jira-interaction/content.md +56 -205
- package/templates/skills/linear-interaction/config.json +1 -1
- package/templates/skills/linear-interaction/content.md +31 -50
- package/templates/skills/pages/content.md +8 -4
- package/templates/skills/qa/content.md +2 -2
- package/templates/skills/workflow-iterate/content.md +4 -4
- package/tsconfig.json +3 -3
- package/dist/boot-scrub-logs-t8xg7wd7.js +0 -99
- package/dist/cli-0a7r5331.js +0 -168
- package/dist/cli-93rxw9yd.js +0 -951
- package/dist/cli-cvk6yzw5.js +0 -40
- package/dist/cli-dgnj0zcc.js +0 -40
- package/dist/cli-qt5wzq6v.js +0 -256
- package/dist/cli-v7fqehqd.js +0 -9281
- package/dist/cli-vbr859rz.js +0 -572
- package/src/be/boot-scrub-logs.ts +0 -132
|
@@ -105,8 +105,10 @@ describe("findPrBodyLeaks: negative controls", () => {
|
|
|
105
105
|
test("a fenced code example with a fresh UUID taskId", () => {
|
|
106
106
|
const body = `## Proof of work\n\n\`\`\`ts\nconst taskId = "${randomUUID()}";\nawait store({ parentTaskId: "${randomUUID()}" });\n\`\`\`\n`;
|
|
107
107
|
expect(findPrBodyLeaks(body)).toEqual([]);
|
|
108
|
-
// The same line outside the fence is still a ref.
|
|
109
|
-
|
|
108
|
+
// The same line outside the fence is still a ref. The rule needs a letter in
|
|
109
|
+
// the first group, so a random UUID would flake (~2% are all digits there).
|
|
110
|
+
const ref = `${hexWithLetter()}-1111-2222-3333-444444444444`;
|
|
111
|
+
expect(findPrBodyLeaks(`taskId = "${ref}"`)).toEqual(["swarm-task-ref"]);
|
|
110
112
|
});
|
|
111
113
|
|
|
112
114
|
test("a fence does not hide Slack or dashboard links", () => {
|
|
@@ -149,6 +151,159 @@ describe("findPrBodyLeaks: negative controls", () => {
|
|
|
149
151
|
});
|
|
150
152
|
});
|
|
151
153
|
|
|
154
|
+
describe("findPrBodyLeaks: Swarm provenance allowlist", () => {
|
|
155
|
+
const provenance = (...lines: string[]) =>
|
|
156
|
+
`${NORMAL_BODY}\n## Swarm provenance <!-- bot -->\n\n${lines.map((l) => `- ${l}`).join("\n")}\n`;
|
|
157
|
+
|
|
158
|
+
test("task, session, agent-fs and Slack permalinks pass inside the section", () => {
|
|
159
|
+
const body = provenance(
|
|
160
|
+
`Task: ${dashboardLink()} · tree: ${dashboardLink().replace("/tasks/", "/sessions/")}`,
|
|
161
|
+
`Ask: ${slackLink()}?thread_ts=${slackTs()}&cid=${slackId("D")}`,
|
|
162
|
+
`Plan: ${agentFsLink()} (durable: ${agentFsPath()})`,
|
|
163
|
+
`Follow-up of task ${hexWithLetter()}.`,
|
|
164
|
+
);
|
|
165
|
+
expect(findPrBodyLeaks(body)).toEqual([]);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("the same links outside the section still fail", () => {
|
|
169
|
+
const body = `${NORMAL_BODY}\nSee ${slackLink()} and ${dashboardLink()}.\n${provenance()}`;
|
|
170
|
+
// The permalink's embedded channel id also counts outside the section.
|
|
171
|
+
expect(findPrBodyLeaks(body)).toEqual(["slack-id", "slack-link", "swarm-dashboard-link"]);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("bare Slack ids, ts values and private-chat quotes stay blocked inside it", () => {
|
|
175
|
+
expect(findPrBodyLeaks(provenance(`Channel ${slackId("C")}`))).toEqual(["slack-id"]);
|
|
176
|
+
expect(findPrBodyLeaks(provenance(`ts ${slackTs()}`))).toEqual(["slack-ts"]);
|
|
177
|
+
expect(
|
|
178
|
+
findPrBodyLeaks(provenance(`Taras in ${"DM"}: "it would be nice to explain the motivation"`)),
|
|
179
|
+
).toEqual(["private-chat-quote"]);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("the section ends at the next heading, and a fenced heading does not open it", () => {
|
|
183
|
+
const after = `${provenance(`Task: ${dashboardLink()}`)}\n## Notes\n\n${dashboardLink()}\n`;
|
|
184
|
+
expect(findPrBodyLeaks(after)).toEqual(["swarm-dashboard-link"]);
|
|
185
|
+
const fenced = `\`\`\`md\n## Swarm provenance\n\`\`\`\n${slackLink()}\n`;
|
|
186
|
+
expect(findPrBodyLeaks(fenced)).toContain("slack-link");
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test("a heading inside an HTML comment does not open it", () => {
|
|
190
|
+
const body = `<!--\n## Swarm provenance\n-->\n${dashboardLink()}\n`;
|
|
191
|
+
expect(findPrBodyLeaks(body)).toEqual(["swarm-dashboard-link"]);
|
|
192
|
+
const oneLine = `<!-- note -->\n## Swarm provenance\n\n- ${dashboardLink()}\n`;
|
|
193
|
+
expect(findPrBodyLeaks(oneLine)).toEqual([]);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("a shorter fence does not close a longer one", () => {
|
|
197
|
+
const body = `\`\`\`\`md\n\`\`\`\n## Swarm provenance\n\`\`\`\`\n${dashboardLink()}\n`;
|
|
198
|
+
expect(findPrBodyLeaks(body)).toEqual(["swarm-dashboard-link"]);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test("tildes do not close a backtick fence", () => {
|
|
202
|
+
const body = `\`\`\`\n~~~\n## Swarm provenance\n\`\`\`\n${dashboardLink()}\n`;
|
|
203
|
+
expect(findPrBodyLeaks(body)).toEqual(["swarm-dashboard-link"]);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("a fence line with an info string does not close it", () => {
|
|
207
|
+
const body = `\`\`\`\n\`\`\`md\n## Swarm provenance\n\`\`\`\n${dashboardLink()}\n`;
|
|
208
|
+
expect(findPrBodyLeaks(body)).toEqual(["swarm-dashboard-link"]);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("a longer closing fence closes it, so a later section opens", () => {
|
|
212
|
+
const body = `\`\`\`\ncode\n\`\`\`\`\`\n## Swarm provenance\n\n- ${dashboardLink()}\n`;
|
|
213
|
+
expect(findPrBodyLeaks(body)).toEqual([]);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// CommonMark 0.31.2 §4.5: a fence line is indented at most 3 columns, and a
|
|
217
|
+
// tab expands to the next multiple of 4, so a deeper "closer" is fence content.
|
|
218
|
+
test("a closer indented 4 spaces does not close the fence", () => {
|
|
219
|
+
const body = `\`\`\`\n \`\`\`\n## Swarm provenance\n\`\`\`\n${dashboardLink()}\n`;
|
|
220
|
+
expect(findPrBodyLeaks(body)).toEqual(["swarm-dashboard-link"]);
|
|
221
|
+
expect(checkPrBodyLeaks(body)).toEqual(["internal identifier in body: swarm-dashboard-link"]);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("a closer with a leading tab does not close the fence", () => {
|
|
225
|
+
const body = `\`\`\`\n\t\`\`\`\n## Swarm provenance\n\`\`\`\n${dashboardLink()}\n`;
|
|
226
|
+
expect(findPrBodyLeaks(body)).toEqual(["swarm-dashboard-link"]);
|
|
227
|
+
expect(checkPrBodyLeaks(body)).toEqual(["internal identifier in body: swarm-dashboard-link"]);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// CommonMark §2.1 whitespace is ASCII space and tab only; JS trim() and \s
|
|
231
|
+
// also strip U+00A0, which GitHub renders as text.
|
|
232
|
+
test("a closer followed by a no-break space does not close the fence", () => {
|
|
233
|
+
const body = `\`\`\`\n\`\`\` \n## Swarm provenance\n\`\`\`\n${dashboardLink()}\n`;
|
|
234
|
+
expect(findPrBodyLeaks(body)).toEqual(["swarm-dashboard-link"]);
|
|
235
|
+
expect(checkPrBodyLeaks(body)).toEqual(["internal identifier in body: swarm-dashboard-link"]);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test("a closer followed by ASCII spaces or a tab still closes the fence", () => {
|
|
239
|
+
for (const tail of [" ", "\t", " \t "]) {
|
|
240
|
+
const body = `\`\`\`\ncode\n\`\`\`${tail}\n## Swarm provenance\n\n- ${dashboardLink()}\n`;
|
|
241
|
+
expect(findPrBodyLeaks(body)).toEqual([]);
|
|
242
|
+
expect(checkPrBodyLeaks(body)).toEqual([]);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("a heading needs ASCII whitespace after the hashes to open the section", () => {
|
|
247
|
+
const nbsp = `## Swarm provenance\n\n- ${dashboardLink()}\n`;
|
|
248
|
+
expect(findPrBodyLeaks(nbsp)).toEqual(["swarm-dashboard-link"]);
|
|
249
|
+
expect(checkPrBodyLeaks(nbsp)).toEqual(["internal identifier in body: swarm-dashboard-link"]);
|
|
250
|
+
const glued = `## Swarm provenance#\n\n- ${dashboardLink()}\n`;
|
|
251
|
+
expect(findPrBodyLeaks(glued)).toEqual(["swarm-dashboard-link"]);
|
|
252
|
+
const closed = `##\tSwarm provenance ##\t\n\n- ${dashboardLink()}\n`;
|
|
253
|
+
expect(findPrBodyLeaks(closed)).toEqual([]);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
test("a non-breaking space in the heading text is part of the name", () => {
|
|
257
|
+
for (const heading of ["## Swarm provenance ", "## Swarm provenance"]) {
|
|
258
|
+
const body = `${heading}\n\n- ${dashboardLink()}\n`;
|
|
259
|
+
expect(findPrBodyLeaks(body)).toEqual(["swarm-dashboard-link"]);
|
|
260
|
+
expect(checkPrBodyLeaks(body)).toEqual(["internal identifier in body: swarm-dashboard-link"]);
|
|
261
|
+
}
|
|
262
|
+
const spaced = `## Swarm \t provenance \t\n\n- ${dashboardLink()}\n`;
|
|
263
|
+
expect(findPrBodyLeaks(spaced)).toEqual([]);
|
|
264
|
+
const commented = `## Swarm provenance <!-- bot --> \n\n- ${dashboardLink()}\n`;
|
|
265
|
+
expect(findPrBodyLeaks(commented)).toEqual([]);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test("a closer indented 3 spaces still closes the fence", () => {
|
|
269
|
+
const body = `\`\`\`\ncode\n \`\`\`\n## Swarm provenance\n\n- ${dashboardLink()}\n`;
|
|
270
|
+
expect(findPrBodyLeaks(body)).toEqual([]);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test("an opener indented 4 spaces is not a fence, for sections or prose", () => {
|
|
274
|
+
const ref = `${hexWithLetter()}-1111-2222-3333-444444444444`;
|
|
275
|
+
expect(findPrBodyLeaks(` \`\`\`\ntaskId = "${ref}"\n\`\`\`\n`)).toEqual(["swarm-task-ref"]);
|
|
276
|
+
const body = ` \`\`\`\n## Swarm provenance\n\n- ${dashboardLink()}\n`;
|
|
277
|
+
expect(findPrBodyLeaks(body)).toEqual([]);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test("a fence closed less indented than its opener cannot open the section", () => {
|
|
281
|
+
// In a list item the closer ends the item and opens a new fence, which hides the heading.
|
|
282
|
+
const body = `- y\n \`\`\`\n\`\`\`\n## Swarm provenance\n\`\`\`\n${dashboardLink()}\n`;
|
|
283
|
+
expect(findPrBodyLeaks(body)).toEqual(["swarm-dashboard-link"]);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
test("an indented heading cannot open the section", () => {
|
|
287
|
+
// A list item fence indented 4 columns hides it on GitHub.
|
|
288
|
+
const body = `- y\n \`\`\`\n ## Swarm provenance\n \`\`\`\n${dashboardLink()}\n`;
|
|
289
|
+
expect(findPrBodyLeaks(body)).toEqual(["swarm-dashboard-link"]);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test("an indented, setext, or commented-out heading still ends the section", () => {
|
|
293
|
+
const section = provenance(`Task: ${dashboardLink()}`);
|
|
294
|
+
for (const end of [" ## Notes", "- ## Notes", "\nNotes\n---", " <!--\n## Notes\n-->"]) {
|
|
295
|
+
expect(findPrBodyLeaks(`${section}\n${end}\n\n${dashboardLink()}\n`)).toEqual([
|
|
296
|
+
"swarm-dashboard-link",
|
|
297
|
+
]);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
test("the heading matches case-insensitively with a trailing marker", () => {
|
|
302
|
+
const body = `## swarm PROVENANCE <!-- bot -->\n\n- ${dashboardLink()}\n`;
|
|
303
|
+
expect(findPrBodyLeaks(body)).toEqual([]);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
|
|
152
307
|
describe("check-pr-body leak gating", () => {
|
|
153
308
|
test("only bot authors, or a local run without an author, get the leak check", () => {
|
|
154
309
|
expect(shouldCheckLeaks(undefined)).toBe(true);
|
package/src/tests/preload.ts
CHANGED
|
@@ -30,6 +30,16 @@ startHangWatchdog();
|
|
|
30
30
|
// drain set API_DRAIN_MAX_MS for their own server.
|
|
31
31
|
process.env.API_DRAIN_MAX_MS = "0";
|
|
32
32
|
|
|
33
|
+
// Credential and provider-routing tests assume no Anthropic credentials, as
|
|
34
|
+
// on CI. A developer shell (or a repo .env, which Bun loads before this file)
|
|
35
|
+
// often sets them, for example a Claude Code session behind a proxy. Then
|
|
36
|
+
// ~17 tests fail locally and the pre-push hook blocks the push. Remove them
|
|
37
|
+
// here; spawned servers inherit the cleaned env, and suites that need a
|
|
38
|
+
// value set their own.
|
|
39
|
+
for (const key of ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_BASE_URL"]) {
|
|
40
|
+
delete process.env[key];
|
|
41
|
+
}
|
|
42
|
+
|
|
33
43
|
// @hono/node-server (pulled in transitively by @modelcontextprotocol/sdk's
|
|
34
44
|
// streamableHttp transport) replaces globalThis.Response/Request with its own
|
|
35
45
|
// lightweight Node-adapter classes the first time getRequestListener() runs.
|
|
@@ -61,6 +61,7 @@ const modelsDevFixture = {
|
|
|
61
61
|
anthropic: { models: { "claude-test": { cost: { input: 1, output: 2 } } } },
|
|
62
62
|
openai: { models: { "gpt-test": { cost: { input: 1, output: 2 } } } },
|
|
63
63
|
openrouter: { models: { "test/model": { cost: { input: 1, output: 2 } } } },
|
|
64
|
+
xai: { models: { "grok-test": { cost: { input: 1, output: 2 } } } },
|
|
64
65
|
};
|
|
65
66
|
|
|
66
67
|
interface TouchPoint {
|
|
@@ -233,6 +234,7 @@ const BOOTSTRAP: Record<ProviderName, { expect: string } | { exempt: string }> =
|
|
|
233
234
|
dsh: { expect: "Warning: dsh provider has no credentials yet" },
|
|
234
235
|
amp: { expect: "Warning: amp provider has no credentials yet" },
|
|
235
236
|
cursor: { expect: "Warning: cursor provider has no credentials yet" },
|
|
237
|
+
grok: { expect: "Warning: grok provider has no credentials yet" },
|
|
236
238
|
pi: { expect: "Warning: pi provider has no credentials yet" },
|
|
237
239
|
opencode: { expect: "Warning: opencode provider has no credentials yet" },
|
|
238
240
|
"claude-managed": { expect: "Warning: claude-managed provider missing:" },
|
|
@@ -282,7 +284,7 @@ function extractMarkedBlock(name: string): string {
|
|
|
282
284
|
/** Resolvable no-op stubs for every binary the verify chain may look up. */
|
|
283
285
|
function makeBinaryStubDir(): string {
|
|
284
286
|
const dir = mkdtempSync(join(tmpdir(), "provider-registration-bin-"));
|
|
285
|
-
for (const name of ["claude", "codex", "opencode", "dsh", "amp"]) {
|
|
287
|
+
for (const name of ["claude", "codex", "opencode", "dsh", "amp", "grok"]) {
|
|
286
288
|
const file = join(dir, name);
|
|
287
289
|
writeFileSync(file, "#!/bin/sh\nexit 0\n");
|
|
288
290
|
chmodSync(file, 0o755);
|
|
@@ -168,6 +168,38 @@ describe("buffer + flush persistence", () => {
|
|
|
168
168
|
expect(denyRow?.reason).toBeTruthy();
|
|
169
169
|
});
|
|
170
170
|
|
|
171
|
+
test("persists a mixed batch with a guest denial and an operator decision", async () => {
|
|
172
|
+
setAuditSink(enqueueAuditRow);
|
|
173
|
+
|
|
174
|
+
const operator = can({
|
|
175
|
+
principal: { kind: "operator" },
|
|
176
|
+
verb: "models.catalog.write",
|
|
177
|
+
source: "http",
|
|
178
|
+
});
|
|
179
|
+
const guest = can({
|
|
180
|
+
principal: { kind: "guest" },
|
|
181
|
+
verb: "models.catalog.write",
|
|
182
|
+
source: "http",
|
|
183
|
+
});
|
|
184
|
+
expect(operator.allow).toBe(true);
|
|
185
|
+
expect(guest.allow).toBe(false);
|
|
186
|
+
|
|
187
|
+
await flushAuditBuffer();
|
|
188
|
+
|
|
189
|
+
const rows = await selectAuditRows();
|
|
190
|
+
expect(rows.length).toBe(2);
|
|
191
|
+
expect(rows.find((r) => r.principalType === "operator")).toMatchObject({
|
|
192
|
+
principalId: null,
|
|
193
|
+
verb: "models.catalog.write",
|
|
194
|
+
decision: "allow",
|
|
195
|
+
});
|
|
196
|
+
expect(rows.find((r) => r.principalType === "guest")).toMatchObject({
|
|
197
|
+
principalId: null,
|
|
198
|
+
verb: "models.catalog.write",
|
|
199
|
+
decision: "deny",
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
171
203
|
test("auto-flushes at the 200-row threshold without the interval writer", async () => {
|
|
172
204
|
for (let i = 0; i < 200; i++) {
|
|
173
205
|
enqueueAuditRow(
|
|
@@ -155,13 +155,6 @@ async function createPendingTask(base: string, token: string): Promise<string> {
|
|
|
155
155
|
return res.body.id as string;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
function taskIdFrom(result: ToolCallResult): string {
|
|
159
|
-
expect(result.isError).not.toBe(true);
|
|
160
|
-
const task = result.structuredContent?.task as { id?: unknown } | undefined;
|
|
161
|
-
expect(typeof task?.id).toBe("string");
|
|
162
|
-
return task.id as string;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
158
|
function expectToolSuccess(result: ToolCallResult): void {
|
|
166
159
|
expect(result.isError).not.toBe(true);
|
|
167
160
|
expect(result.structuredContent?.success).toBe(true);
|
|
@@ -179,24 +172,11 @@ function expectSoftForbidden(result: ToolCallResult, verb: string): void {
|
|
|
179
172
|
);
|
|
180
173
|
}
|
|
181
174
|
|
|
182
|
-
async function createUnassignedViaMcp(
|
|
183
|
-
base: string,
|
|
184
|
-
token: string,
|
|
185
|
-
sessionId: string,
|
|
186
|
-
): Promise<string> {
|
|
187
|
-
const created = await mcpUserCall(base, token, sessionId, "send-task", {
|
|
188
|
-
task: `unassigned task ${crypto.randomUUID()}`,
|
|
189
|
-
});
|
|
190
|
-
expectToolSuccess(created);
|
|
191
|
-
return taskIdFrom(created);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
175
|
async function exerciseAllowedUserTools(
|
|
195
176
|
base: string,
|
|
196
177
|
token: string,
|
|
197
178
|
sessionId: string,
|
|
198
179
|
pendingTaskId: string,
|
|
199
|
-
unassignedTaskId: string,
|
|
200
180
|
): Promise<void> {
|
|
201
181
|
const created = await mcpUserCall(base, token, sessionId, "send-task", {
|
|
202
182
|
task: `allowed send-task ${crypto.randomUUID()}`,
|
|
@@ -217,12 +197,6 @@ async function exerciseAllowedUserTools(
|
|
|
217
197
|
reason: "rbac mcp-user e2e",
|
|
218
198
|
});
|
|
219
199
|
expectToolSuccess(cancelled);
|
|
220
|
-
|
|
221
|
-
const moved = await mcpUserCall(base, token, sessionId, "task-action", {
|
|
222
|
-
action: "to_backlog",
|
|
223
|
-
taskId: unassignedTaskId,
|
|
224
|
-
});
|
|
225
|
-
expectToolSuccess(moved);
|
|
226
200
|
}
|
|
227
201
|
|
|
228
202
|
describe("RBAC admission over /mcp-user", () => {
|
|
@@ -248,25 +222,13 @@ describe("RBAC admission over /mcp-user", () => {
|
|
|
248
222
|
const admin = await createUserToken(server.base, "MCP Admin");
|
|
249
223
|
const adminSid = await mcpUserInit(server.base, admin.token);
|
|
250
224
|
const adminPendingTaskId = await createPendingTask(server.base, admin.token);
|
|
251
|
-
const adminUnassignedTaskId = await createUnassignedViaMcp(server.base, admin.token, adminSid);
|
|
252
225
|
|
|
253
|
-
await exerciseAllowedUserTools(
|
|
254
|
-
server.base,
|
|
255
|
-
admin.token,
|
|
256
|
-
adminSid,
|
|
257
|
-
adminPendingTaskId,
|
|
258
|
-
adminUnassignedTaskId,
|
|
259
|
-
);
|
|
226
|
+
await exerciseAllowedUserTools(server.base, admin.token, adminSid, adminPendingTaskId);
|
|
260
227
|
expect(countAuditRows(enabledDbPath)).toBe(0);
|
|
261
228
|
|
|
262
229
|
const requester = await createUserToken(server.base, "MCP Requester");
|
|
263
230
|
const requesterSid = await mcpUserInit(server.base, requester.token);
|
|
264
231
|
const requesterPendingTaskId = await createPendingTask(server.base, requester.token);
|
|
265
|
-
const requesterUnassignedTaskId = await createUnassignedViaMcp(
|
|
266
|
-
server.base,
|
|
267
|
-
requester.token,
|
|
268
|
-
requesterSid,
|
|
269
|
-
);
|
|
270
232
|
rewriteUserRoles(enabledDbPath, requester.userId, [REQUESTER_ROLE_ID]);
|
|
271
233
|
|
|
272
234
|
await exerciseAllowedUserTools(
|
|
@@ -274,13 +236,11 @@ describe("RBAC admission over /mcp-user", () => {
|
|
|
274
236
|
requester.token,
|
|
275
237
|
requesterSid,
|
|
276
238
|
requesterPendingTaskId,
|
|
277
|
-
requesterUnassignedTaskId,
|
|
278
239
|
);
|
|
279
240
|
|
|
280
241
|
const empty = await createUserToken(server.base, "MCP Empty Grant");
|
|
281
242
|
const emptySid = await mcpUserInit(server.base, empty.token);
|
|
282
243
|
const emptyPendingTaskId = await createPendingTask(server.base, empty.token);
|
|
283
|
-
const emptyUnassignedTaskId = await createUnassignedViaMcp(server.base, empty.token, emptySid);
|
|
284
244
|
rewriteUserRoles(enabledDbPath, empty.userId, []);
|
|
285
245
|
|
|
286
246
|
expectSoftForbidden(
|
|
@@ -295,13 +255,6 @@ describe("RBAC admission over /mcp-user", () => {
|
|
|
295
255
|
}),
|
|
296
256
|
"task.cancel.own",
|
|
297
257
|
);
|
|
298
|
-
expectSoftForbidden(
|
|
299
|
-
await mcpUserCall(server.base, empty.token, emptySid, "task-action", {
|
|
300
|
-
action: "to_backlog",
|
|
301
|
-
taskId: emptyUnassignedTaskId,
|
|
302
|
-
}),
|
|
303
|
-
"task.action.own",
|
|
304
|
-
);
|
|
305
258
|
expectReadableToolResult(
|
|
306
259
|
await mcpUserCall(server.base, empty.token, emptySid, "get-tasks", { limit: 10 }),
|
|
307
260
|
);
|
|
@@ -323,7 +276,7 @@ describe("RBAC admission over /mcp-user", () => {
|
|
|
323
276
|
row.verb === "task.create.own" &&
|
|
324
277
|
row.decision === "allow",
|
|
325
278
|
) &&
|
|
326
|
-
["task.create.own", "task.cancel.own"
|
|
279
|
+
["task.create.own", "task.cancel.own"].every((verb) =>
|
|
327
280
|
auditRows.some(
|
|
328
281
|
(row) =>
|
|
329
282
|
row.principalId === empty.userId && row.decision === "deny" && row.verb === verb,
|
|
@@ -346,7 +299,7 @@ describe("RBAC admission over /mcp-user", () => {
|
|
|
346
299
|
mcpRows
|
|
347
300
|
.filter((row) => row.principalId === empty.userId && row.decision === "deny")
|
|
348
301
|
.map((row) => row.verb),
|
|
349
|
-
).toEqual(["task.create.own", "task.cancel.own"
|
|
302
|
+
).toEqual(["task.create.own", "task.cancel.own"]);
|
|
350
303
|
|
|
351
304
|
await server.stop();
|
|
352
305
|
server = undefined;
|
|
@@ -362,19 +315,8 @@ describe("RBAC admission over /mcp-user", () => {
|
|
|
362
315
|
const flagOffSid = await mcpUserInit(server.base, flagOff.token);
|
|
363
316
|
rewriteUserRoles(disabledDbPath, flagOff.userId, []);
|
|
364
317
|
const flagOffPendingTaskId = await createPendingTask(server.base, flagOff.token);
|
|
365
|
-
const flagOffUnassignedTaskId = await createUnassignedViaMcp(
|
|
366
|
-
server.base,
|
|
367
|
-
flagOff.token,
|
|
368
|
-
flagOffSid,
|
|
369
|
-
);
|
|
370
318
|
|
|
371
|
-
await exerciseAllowedUserTools(
|
|
372
|
-
server.base,
|
|
373
|
-
flagOff.token,
|
|
374
|
-
flagOffSid,
|
|
375
|
-
flagOffPendingTaskId,
|
|
376
|
-
flagOffUnassignedTaskId,
|
|
377
|
-
);
|
|
319
|
+
await exerciseAllowedUserTools(server.base, flagOff.token, flagOffSid, flagOffPendingTaskId);
|
|
378
320
|
expect(countAuditRows(disabledDbPath)).toBe(0);
|
|
379
321
|
});
|
|
380
322
|
});
|
|
@@ -606,6 +606,15 @@ describe("script connections", () => {
|
|
|
606
606
|
markMigrationApplied(database, "195_approval_request_approvals.sql");
|
|
607
607
|
// 196 alters skills, which this migration-112-only fixture does not create.
|
|
608
608
|
markMigrationApplied(database, "196_skill_invocations.sql");
|
|
609
|
+
// 198 rebuilds permission_audit, which this migration-112-only fixture does not create.
|
|
610
|
+
markMigrationApplied(database, "198_permission_audit_guest.sql");
|
|
611
|
+
// 200 backfills agent_memory, which this migration-112-only fixture does not create.
|
|
612
|
+
markMigrationApplied(database, "200_backfill_auto_memory_expiry.sql");
|
|
613
|
+
// 201 alters workflow_runs and workflow_run_steps, which this
|
|
614
|
+
// migration-112-only fixture does not create.
|
|
615
|
+
markMigrationApplied(database, "201_workflow_replay_columns.sql");
|
|
616
|
+
// 202 moves rows out of kv_entries, which this migration-112-only fixture does not create.
|
|
617
|
+
markMigrationApplied(database, "202_codex_oauth_device_flows.sql");
|
|
609
618
|
|
|
610
619
|
const id = crypto.randomUUID();
|
|
611
620
|
const now = new Date().toISOString();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
import { classifyExit, NativeScriptExecutor } from "../scripts-runtime/executors/native";
|
|
3
|
+
import { QuickJSScriptExecutor } from "../scripts-runtime/executors/quickjs";
|
|
3
4
|
import type {
|
|
4
5
|
ExecutorInput,
|
|
5
6
|
ExecutorOutput,
|
|
@@ -128,6 +129,8 @@ function conformance(name: string, makeExecutor: () => ScriptExecutor, spawns: b
|
|
|
128
129
|
|
|
129
130
|
conformance("native", () => new NativeScriptExecutor(), true);
|
|
130
131
|
conformance("fake", () => new FakeScriptExecutor(), false);
|
|
132
|
+
// Worker threads and WASM, no Bun.spawn: runs even when the spawn probe fails.
|
|
133
|
+
conformance("quickjs", () => new QuickJSScriptExecutor(), false);
|
|
131
134
|
|
|
132
135
|
describe("native-only executor behavior", () => {
|
|
133
136
|
test.skipIf(SKIP_SANDBOX_SPAWN_TESTS)("timeout maps to timeout", async () => {
|