@desplega.ai/agent-swarm 1.165.0 → 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.
Files changed (188) hide show
  1. package/dist/{acp-adapter-w6zws6me.js → acp-adapter-yzfxn8vj.js} +4 -4
  2. package/dist/{actions-jna0b3wm.js → actions-qz3m692w.js} +20 -24
  3. package/dist/{amp-adapter-0eve81pz.js → amp-adapter-j1xbmsqz.js} +4 -4
  4. package/dist/{app-75hm5cfa.js → app-43vrdmv8.js} +6 -7
  5. package/dist/{assistant-yzd51j33.js → assistant-ertffmka.js} +21 -25
  6. package/dist/{boot-reembed-z158xq32.js → boot-reembed-998jtpdg.js} +9 -12
  7. package/dist/{boot-reembed-2ex2mcsh.js → boot-reembed-s7k7c6v2.js} +10 -12
  8. package/dist/boot-scrub-sweep-nepsk4t1.js +211 -0
  9. package/dist/{boot-seeds-2bmnh18p.js → boot-seeds-vvzs1zhk.js} +8 -8
  10. package/dist/{claude-adapter-jbj1mycz.js → claude-adapter-2zvmekrp.js} +9 -11
  11. package/dist/{claude-managed-adapter-17ggz09t.js → claude-managed-adapter-s49wbk8t.js} +3 -3
  12. package/dist/{claude-managed-setup-ptm1nzm2.js → claude-managed-setup-cvhqq8qn.js} +4 -4
  13. package/dist/{claude-sdk-session-9re1g7r2.js → claude-sdk-session-kkbxtw5q.js} +2618 -2600
  14. package/dist/{cli-k6xx3pve.js → cli-0nhdwxd5.js} +4 -4
  15. package/dist/{cli-n9ehc28t.js → cli-0qjcsxgz.js} +4 -4
  16. package/dist/{cli-zn2v3t8v.js → cli-3ddybbbx.js} +1 -1
  17. package/dist/{cli-5anb0ev3.js → cli-3qn4r334.js} +71 -14
  18. package/dist/{cli-1kzfvd1z.js → cli-4r1sjfc4.js} +9 -5
  19. package/dist/{cli-ba66wyhy.js → cli-66zh26sp.js} +6 -6
  20. package/dist/{cli-9xb89xca.js → cli-68r1j4sg.js} +6 -6
  21. package/dist/{cli-xnzrzets.js → cli-8kgvmkak.js} +2 -2
  22. package/dist/{cli-28smfvbn.js → cli-8t229cmr.js} +5 -5
  23. package/dist/{cli-9866bd07.js → cli-aqcey741.js} +1 -1
  24. package/dist/{cli-90v942q1.js → cli-cpfmqz3n.js} +8 -8
  25. package/dist/{cli-50eg13rj.js → cli-df56tqdw.js} +459 -282
  26. package/dist/{cli-8gpbwy09.js → cli-dw2q9f7g.js} +5 -5
  27. package/dist/{cli-0n4fasz0.js → cli-ecknp7p1.js} +15 -15
  28. package/dist/{cli-xb3c6aat.js → cli-f2n17zhp.js} +1 -1
  29. package/dist/{cli-ftry7975.js → cli-feh3dkah.js} +1 -1
  30. package/dist/{cli-amwhs8h2.js → cli-fn697bnt.js} +2 -2
  31. package/dist/{cli-prt9emct.js → cli-gt8azyet.js} +3 -3
  32. package/dist/{cli-59jn5twa.js → cli-h3x613ze.js} +2 -2
  33. package/dist/{cli-mmzwwptd.js → cli-hf5s9pgf.js} +1 -1
  34. package/dist/cli-j2jbr8af.js +516 -0
  35. package/dist/{cli-wfajtmf7.js → cli-jhm6hzjn.js} +593 -10
  36. package/dist/{cli-xtgtyafv.js → cli-jvj6a0cv.js} +190 -439
  37. package/dist/{cli-hpryr6em.js → cli-mb75wpxf.js} +1 -1
  38. package/dist/{cli-420bdgw0.js → cli-mv2520nm.js} +1 -1
  39. package/dist/{cli-pjxnr1jn.js → cli-mwegs4af.js} +3 -3
  40. package/dist/{cli-5b2fjjzh.js → cli-p4ztb80h.js} +2 -2
  41. package/dist/{cli-e7t4snpa.js → cli-rggdq8wq.js} +4 -4
  42. package/dist/{cli-bdv39kgj.js → cli-rsy933yz.js} +5 -5
  43. package/dist/{cli-gh5yqzpe.js → cli-v2a8x45d.js} +2 -2
  44. package/dist/{cli-bns5c8k9.js → cli-vzc73wet.js} +43 -47
  45. package/dist/cli-wt7ccy4r.js +2654 -0
  46. package/dist/{cli-j0pdrmwg.js → cli-x7kpr72a.js} +3 -3
  47. package/dist/{cli-x7afk5wm.js → cli-xvc3q9br.js} +1 -1
  48. package/dist/{cli-9s3h836g.js → cli-xvdgasgy.js} +1 -1
  49. package/dist/{cli-zvckv750.js → cli-y59h2pk9.js} +2 -2
  50. package/dist/{cli-qdv8kgz7.js → cli-yshaazs1.js} +13884 -3241
  51. package/dist/{cli-nfygw434.js → cli-ysnyhws9.js} +2 -2
  52. package/dist/{cli-fw6vdcq5.js → cli-zp67qg5x.js} +34 -1
  53. package/dist/{cli-ma3zvh39.js → cli-zy7vwsne.js} +6066 -5829
  54. package/dist/cli.js +24 -20
  55. package/dist/{codex-adapter-3qnxshje.js → codex-adapter-dw1wxqt8.js} +7 -7
  56. package/dist/{codex-login-brkxhhdg.js → codex-login-terbdsqq.js} +2 -2
  57. package/dist/{codex-session-runner-612wnapp.js → codex-session-runner-3cgb8y1g.js} +7 -7
  58. package/dist/{commands-2ybfcxkj.js → commands-mhxam6z2.js} +6 -6
  59. package/dist/{cursor-adapter-p3jgdehv.js → cursor-adapter-2qda3st7.js} +3 -3
  60. package/dist/{db-f4ans0jj.js → db-sjks418k.js} +8 -6
  61. package/dist/{devin-adapter-dhzt01ff.js → devin-adapter-bffjj5n4.js} +2 -2
  62. package/dist/{dispatcher-pk182apd.js → dispatcher-1es759rn.js} +18 -22
  63. package/dist/{dsh-adapter-7twaeps1.js → dsh-adapter-bek4cyw9.js} +3 -3
  64. package/dist/{e2b-y8t3jzyz.js → e2b-nd50eccg.js} +1 -1
  65. package/dist/{event-bus-w7ac4n3c.js → event-bus-vnfthafg.js} +2 -2
  66. package/dist/{grok-adapter-yt9pab3k.js → grok-adapter-ar9cw9jg.js} +5 -5
  67. package/dist/{handlers-g2wnr4t9.js → handlers-1gkbhktr.js} +21 -25
  68. package/dist/{hook-f7jt9vnm.js → hook-ds2zxq9v.js} +14 -16
  69. package/dist/{hook-bbdpnkb4.js → hook-vxa3tcsy.js} +8 -10
  70. package/dist/{http-w40q4w94.js → http-3h21z9md.js} +247 -164
  71. package/dist/{index-056j5kzn.js → index-9b65j1m5.js} +8 -8
  72. package/dist/{index-9bfssf54.js → index-bn6cy8ps.js} +18 -22
  73. package/dist/{index-cj1r9q83.js → index-dkfxpkmm.js} +19 -23
  74. package/dist/{index-7n70jwbb.js → index-f8xnqrye.js} +19 -21
  75. package/dist/{index-fdk1t4d6.js → index-n0rxa4ca.js} +11962 -9900
  76. package/dist/{index-k8xc083e.js → index-n99fycq7.js} +18 -22
  77. package/dist/{keepalive-1tj10tf4.js → keepalive-3xspa9jw.js} +11 -8
  78. package/dist/{lead-st0bg7v4.js → lead-6qphc124.js} +34 -38
  79. package/dist/{maintenance-nz71zats.js → maintenance-0teem1bb.js} +7 -9
  80. package/dist/{node-f0ykebbv.js → node-9sg7ajby.js} +25 -7
  81. package/dist/{oauth-refresh-sweep-aefzwvvq.js → oauth-refresh-sweep-sh9q25xp.js} +10 -7
  82. package/dist/{onboard-kgpr9mbn.js → onboard-54qmnqxe.js} +2 -2
  83. package/dist/{opencode-adapter-0c8e70dk.js → opencode-adapter-wjfa2wvd.js} +2 -2
  84. package/dist/{otel-impl-x8zp4y5a.js → otel-impl-ycqzp2a1.js} +2 -2
  85. package/dist/{pi-mono-adapter-t280ah5c.js → pi-mono-adapter-e77e9zst.js} +4 -4
  86. package/dist/{pricing-refresh-9e0q7cwk.js → pricing-refresh-atnkngqs.js} +7 -7
  87. package/dist/{rbac-roles-kcp6zge2.js → rbac-roles-9pjphh9q.js} +6 -6
  88. package/dist/{rbac-roles-790j3ga8.js → rbac-roles-j78wdksm.js} +6 -6
  89. package/dist/{render-v2-tch4nefj.js → render-v2-pxjs49fx.js} +6 -7
  90. package/dist/{setup-rcm303ns.js → setup-ymej0xtx.js} +2 -2
  91. package/dist/{work-objects-ctg7t70w.js → work-objects-3nh4ymzb.js} +22 -26
  92. package/dist/{worker-5dp0xm55.js → worker-qa9fkz5s.js} +34 -38
  93. package/dist/{x-v3yw66zs.js → x-ma4gnfgy.js} +2 -2
  94. package/openapi.json +5 -2
  95. package/package.json +9 -5
  96. package/src/be/automation-preflight.ts +9 -4
  97. package/src/be/boot-scrub-sweep.ts +302 -0
  98. package/src/be/crypto/key-bootstrap.ts +1 -1
  99. package/src/be/db/approvals.ts +15 -1
  100. package/src/be/db/codex-oauth-device-flows.ts +40 -0
  101. package/src/be/db/config-secrets.ts +31 -0
  102. package/src/be/db/runtime.ts +4 -0
  103. package/src/be/db/script-runs.ts +15 -0
  104. package/src/be/db/tasks/write.ts +1 -1
  105. package/src/be/db-queries/mcp-oauth.ts +5 -0
  106. package/src/be/db-queries/oauth.ts +77 -0
  107. package/src/be/db.ts +162 -59
  108. package/src/be/events.ts +17 -1
  109. package/src/be/memory/index-content.ts +2 -2
  110. package/src/be/memory/providers/sqlite-store.ts +63 -11
  111. package/src/be/memory/types.ts +14 -0
  112. package/src/be/migrations/201_workflow_replay_columns.sql +10 -0
  113. package/src/be/migrations/202_codex_oauth_device_flows.sql +24 -0
  114. package/src/be/scripts/db.ts +28 -4
  115. package/src/be/scripts/source-secrets.ts +37 -0
  116. package/src/be/scrub-json.ts +32 -0
  117. package/src/be/sealed-json.ts +59 -0
  118. package/src/be/secret-registry.ts +131 -0
  119. package/src/be/workflow-replay.ts +77 -0
  120. package/src/http/codex-oauth-device.ts +8 -10
  121. package/src/http/db-query-bounded.ts +3 -0
  122. package/src/http/db-query-shared.ts +107 -15
  123. package/src/http/db-query.ts +10 -2
  124. package/src/http/index.ts +23 -6
  125. package/src/http/script-runs.ts +9 -1
  126. package/src/http/scripts.ts +15 -0
  127. package/src/http/workflows.ts +3 -2
  128. package/src/oauth/mcp-wrapper.ts +1 -1
  129. package/src/providers/acp-adapter.ts +25 -11
  130. package/src/providers/acp-target-catalog.ts +35 -1
  131. package/src/providers/acp-targets.ts +69 -3
  132. package/src/providers/amp-adapter.ts +1 -1
  133. package/src/providers/cursor-adapter.ts +1 -1
  134. package/src/script-workflows/supervisor.ts +11 -2
  135. package/src/scripts-runtime/eval-harness.ts +2 -12
  136. package/src/scripts-runtime/executors/quickjs-bundle.ts +152 -0
  137. package/src/scripts-runtime/executors/quickjs-prelude.ts +285 -0
  138. package/src/scripts-runtime/executors/quickjs-runner.ts +580 -0
  139. package/src/scripts-runtime/executors/quickjs-worker.ts +81 -0
  140. package/src/scripts-runtime/executors/quickjs.ts +196 -0
  141. package/src/scripts-runtime/executors/registry.ts +2 -0
  142. package/src/scripts-runtime/executors/sourcemap.ts +79 -0
  143. package/src/scripts-runtime/script-error-hints.ts +14 -0
  144. package/src/server.ts +3 -1
  145. package/src/tests/acp-adapter.test.ts +127 -2
  146. package/src/tests/boot-scrub-sweep.test.ts +390 -0
  147. package/src/tests/check-text-columns.test.ts +145 -0
  148. package/src/tests/claude-sdk-process.fixture.ts +13 -2
  149. package/src/tests/codex-oauth-device.test.ts +23 -37
  150. package/src/tests/db-query-denylist.test.ts +202 -0
  151. package/src/tests/db-task-read-contract.test.ts +1 -0
  152. package/src/tests/db-task-write-contract.test.ts +1 -0
  153. package/src/tests/entrypoint-acp-target-binary.test.ts +31 -1
  154. package/src/tests/events-scrub.test.ts +88 -0
  155. package/src/tests/fixtures/secret-corpus.ts +320 -0
  156. package/src/tests/script-connections.test.ts +5 -0
  157. package/src/tests/script-executor-conformance.test.ts +3 -0
  158. package/src/tests/script-executor-quickjs.test.ts +442 -0
  159. package/src/tests/script-executor-registry.test.ts +6 -1
  160. package/src/tests/script-runs-http.test.ts +88 -1
  161. package/src/tests/script-runs-scrub.test.ts +275 -0
  162. package/src/tests/scripts-http.test.ts +82 -1
  163. package/src/tests/scrubbed-text-12e.test.ts +289 -0
  164. package/src/tests/sealed-key-guard.test.ts +166 -0
  165. package/src/tests/secret-canary-sweep.test.ts +958 -0
  166. package/src/tests/secret-registry.test.ts +355 -0
  167. package/src/tests/secret-rules.test.ts +230 -0
  168. package/src/tests/secret-scrubber.test.ts +3 -2
  169. package/src/tests/workflow-replay.test.ts +518 -0
  170. package/src/tests/workflow-scrub.test.ts +242 -0
  171. package/src/tools/db-query.ts +1 -1
  172. package/src/tools/inject-learning.ts +1 -1
  173. package/src/tools/workflows/get-workflow-run.ts +3 -2
  174. package/src/types.ts +1 -1
  175. package/src/utils/secret-rules.generated.ts +2055 -0
  176. package/src/utils/secret-scrubber.ts +363 -29
  177. package/src/workflows/engine.ts +39 -4
  178. package/src/workflows/recovery.ts +10 -1
  179. package/src/workflows/resume.ts +62 -3
  180. package/src/workflows/retry-poller.ts +3 -0
  181. package/dist/boot-scrub-logs-246yn076.js +0 -99
  182. package/dist/cli-3a4m1aws.js +0 -572
  183. package/dist/cli-a87b04k8.js +0 -951
  184. package/dist/cli-cvk6yzw5.js +0 -40
  185. package/dist/cli-h1spv8v4.js +0 -427
  186. package/dist/cli-jqt9hrnz.js +0 -168
  187. package/dist/cli-yhmwmv0g.js +0 -9281
  188. package/src/be/boot-scrub-logs.ts +0 -132
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Scrubber corpus: credential shapes that must redact, and real-looking
3
+ * non-secrets that must survive untouched.
4
+ *
5
+ * Positives are built at runtime from random bytes, never written as
6
+ * literals, so repo secret scanners and GitHub push protection never flag
7
+ * this file. Negatives are deterministic (hash-derived where they need to look
8
+ * random) so a false positive reproduces on every run.
9
+ */
10
+ import { createHash, randomBytes } from "node:crypto";
11
+
12
+ const ALNUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
13
+ const UPPER_ALNUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
14
+ const LOWER_ALNUM = "abcdefghijklmnopqrstuvwxyz0123456789";
15
+ const LOWER = "abcdefghijklmnopqrstuvwxyz";
16
+ const LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
17
+ const HEX = "0123456789abcdef";
18
+ const DIGITS = "0123456789";
19
+ const URLSAFE = `${ALNUM}_-`;
20
+
21
+ /** `len` random chars from `alphabet`. */
22
+ function rand(alphabet: string, len: number): string {
23
+ const bytes = randomBytes(len);
24
+ let out = "";
25
+ for (let i = 0; i < len; i++) out += alphabet[(bytes[i] as number) % alphabet.length];
26
+ return out;
27
+ }
28
+
29
+ const join = (...parts: string[]) => parts.join("");
30
+
31
+ export interface CorpusPositive {
32
+ /** Shape name, for test titles. */
33
+ name: string;
34
+ /** The credential itself; it must not survive `scrubSecrets`. */
35
+ secret: string;
36
+ /** The credential in context, as it would reach a log. */
37
+ text: string;
38
+ /** Set when pass 5 (gitleaks) is the pass that must catch it. */
39
+ gitleaksRule?: string;
40
+ }
41
+
42
+ function positive(
43
+ name: string,
44
+ secret: string,
45
+ opts: { context?: (secret: string) => string; gitleaksRule?: string } = {},
46
+ ): CorpusPositive {
47
+ const context = opts.context ?? ((s: string) => `the response included ${s} in its body`);
48
+ return { name, secret, text: context(secret), gitleaksRule: opts.gitleaksRule };
49
+ }
50
+
51
+ /**
52
+ * The vendor shapes an audit probe found unredacted after the structural
53
+ * passes, plus the providers this repo integrates with.
54
+ */
55
+ export function buildPositives(): CorpusPositive[] {
56
+ return [
57
+ // Audit probe shapes.
58
+ positive("stripe secret key", join("sk", "_live_", rand(ALNUM, 24)), {
59
+ gitleaksRule: "stripe-access-token",
60
+ }),
61
+ positive("stripe restricted key", join("rk", "_live_", rand(ALNUM, 24)), {
62
+ gitleaksRule: "stripe-access-token",
63
+ }),
64
+ positive("sendgrid", join("SG", ".", rand(URLSAFE, 22), ".", rand(URLSAFE, 43)), {
65
+ gitleaksRule: "sendgrid-api-token",
66
+ }),
67
+ positive("hugging face", join("hf", "_", rand(LOWER, 34)), {
68
+ gitleaksRule: "huggingface-access-token",
69
+ }),
70
+ positive(
71
+ "resend",
72
+ join("re", "_", rand(DIGITS, 2), rand(UPPER_ALNUM, 6), "_", rand(ALNUM, 24)),
73
+ ),
74
+ positive("google oauth access token", join("ya29", ".", rand(URLSAFE, 120))),
75
+ positive("google refresh token", join("1/", "/0", rand(URLSAFE, 100))),
76
+ positive(
77
+ "discord webhook",
78
+ join("https://discord.com/api/", "webhooks/", rand(DIGITS, 18), "/", rand(URLSAFE, 68)),
79
+ ),
80
+ positive(
81
+ "slack webhook",
82
+ join("https://hooks.", "slack.com/services/", rand(UPPER_ALNUM, 44)),
83
+ { gitleaksRule: "slack-webhook-url" },
84
+ ),
85
+ positive(
86
+ "telegram bot token",
87
+ join(rand("123456789", 1), rand(DIGITS, 9), ":", "AA", rand(URLSAFE, 33)),
88
+ ),
89
+ positive(
90
+ "telegram bot token by keyword",
91
+ join(rand("123456789", 1), rand(DIGITS, 9), ":", "A", rand(LOWER_ALNUM, 34)),
92
+ { context: (s) => `telegram bot: ${s}`, gitleaksRule: "telegram-bot-api-token" },
93
+ ),
94
+ positive("xai", join("xai", "-", rand(ALNUM, 80))),
95
+
96
+ // Providers we integrate with.
97
+ positive("github classic pat", join("ghp", "_", rand(ALNUM, 36))),
98
+ positive("github fine-grained pat", join("github", "_pat_", rand(ALNUM, 82))),
99
+ positive("github oauth", join("gho", "_", rand(ALNUM, 36))),
100
+ positive("gitlab pat", join("glpat", "-", rand(ALNUM, 20))),
101
+ positive(
102
+ "slack bot token",
103
+ join("xoxb", "-", rand(DIGITS, 12), "-", rand(DIGITS, 12), "-", rand(ALNUM, 24)),
104
+ ),
105
+ positive(
106
+ "slack app token",
107
+ join("xapp", "-1-", rand(UPPER_ALNUM, 11), "-", rand(DIGITS, 13), "-", rand(HEX, 64)),
108
+ ),
109
+ positive("linear api key", join("lin", "_api_", rand(ALNUM, 40))),
110
+ positive("anthropic api key", join("sk-ant", "-api03-", rand(URLSAFE, 93), "AA")),
111
+ positive(
112
+ "openai project key",
113
+ join("sk-proj", "-", rand(URLSAFE, 58), "T3Blbk", "FJ", rand(URLSAFE, 58)),
114
+ ),
115
+ positive("aws access key id", join("AKIA", rand("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", 16))),
116
+ positive("google api key", join("AIza", rand(URLSAFE, 35))),
117
+ positive("npm token", join("npm", "_", rand(ALNUM, 36))),
118
+ positive("atlassian api token", join("ATATT3", rand(URLSAFE, 186))),
119
+ positive("notion", join("ntn", "_", rand(DIGITS, 11), rand(ALNUM, 35)), {
120
+ gitleaksRule: "notion-api-token",
121
+ }),
122
+ positive("fly.io", join("fo1", "_", rand(URLSAFE, 43)), { gitleaksRule: "flyio-access-token" }),
123
+ positive("doppler", join("dp", ".pt.", rand(ALNUM, 43)), { gitleaksRule: "doppler-api-token" }),
124
+ positive("grafana service account", join("glsa", "_", rand(ALNUM, 32), "_", rand(HEX, 8)), {
125
+ gitleaksRule: "grafana-service-account-token",
126
+ }),
127
+ positive("postman", join("PMAK", "-", rand(HEX, 24), "-", rand(HEX, 34)), {
128
+ gitleaksRule: "postman-api-token",
129
+ }),
130
+ positive("shopify", join("shpat", "_", rand(HEX, 32)), {
131
+ gitleaksRule: "shopify-access-token",
132
+ }),
133
+ positive("digitalocean", join("dop", "_v1_", rand(HEX, 64)), {
134
+ gitleaksRule: "digitalocean-pat",
135
+ }),
136
+ positive("databricks", join("dapi", rand(HEX, 32)), { gitleaksRule: "databricks-api-token" }),
137
+ positive("pypi", join("pypi", "-AgEIcHlwaS5vcmc", rand(URLSAFE, 70)), {
138
+ gitleaksRule: "pypi-upload-token",
139
+ }),
140
+ positive("sentry user token", join("sntryu", "_", rand(HEX, 64)), {
141
+ gitleaksRule: "sentry-user-token",
142
+ }),
143
+ positive("heroku", join("HRKU", "-AA", rand(URLSAFE, 58)), {
144
+ gitleaksRule: "heroku-api-key-v2",
145
+ }),
146
+ positive("twilio", join("SK", rand(HEX, 32)), { gitleaksRule: "twilio-api-key" }),
147
+ positive("mailgun", join("key", "-", rand(HEX, 32)), {
148
+ context: (s) => `mailgun: ${s}`,
149
+ gitleaksRule: "mailgun-private-api-token",
150
+ }),
151
+ positive("new relic", join("NRAK", "-", rand(UPPER_ALNUM, 27)), {
152
+ context: (s) => `newrelic = ${s}`,
153
+ gitleaksRule: "new-relic-user-api-key",
154
+ }),
155
+ positive("vault service token", join("hvs", ".", rand(ALNUM, 96)), {
156
+ gitleaksRule: "vault-service-token",
157
+ }),
158
+ // gitleaks' `s\.[A-Za-z]{24}` allowlist used to fire inside a token whose
159
+ // first 24 characters after "hvs." are all letters (~1.5% of real tokens).
160
+ positive(
161
+ "vault service token, letters-only head",
162
+ join("hvs", ".", rand(LETTERS, 24), rand(ALNUM, 72)),
163
+ {
164
+ gitleaksRule: "vault-service-token",
165
+ },
166
+ ),
167
+ positive("sourcegraph", join("sgp", "_", rand(HEX, 40)), {
168
+ gitleaksRule: "sourcegraph-access-token",
169
+ }),
170
+ positive("sourcegraph instance", join("sgp", "_", rand(HEX, 16), "_", rand(HEX, 40)), {
171
+ gitleaksRule: "sourcegraph-access-token",
172
+ }),
173
+ ];
174
+ }
175
+
176
+ const sha1 = (seed: string) => createHash("sha1").update(seed).digest("hex");
177
+ const sha256 = (seed: string) => createHash("sha256").update(seed).digest("hex");
178
+ const uuid = (seed: string) => {
179
+ const h = sha256(seed);
180
+ return `${h.slice(0, 8)}-${h.slice(8, 12)}-4${h.slice(13, 16)}-a${h.slice(17, 20)}-${h.slice(20, 32)}`;
181
+ };
182
+ const b64 = (seed: string, bytes: number) => {
183
+ let buf = Buffer.alloc(0);
184
+ for (let i = 0; buf.length < bytes; i++) {
185
+ buf = Buffer.concat([buf, createHash("sha256").update(`${seed}:${i}`).digest()]);
186
+ }
187
+ return buf.subarray(0, bytes).toString("base64");
188
+ };
189
+
190
+ /** Real-looking strings an agent log carries that are not credentials. */
191
+ export function buildNegatives(): string[] {
192
+ const out: string[] = [];
193
+ for (let i = 0; i < 10; i++) {
194
+ out.push(`commit ${sha1(`commit-${i}`)}`);
195
+ out.push(`task ${uuid(`task-${i}`)} completed`);
196
+ }
197
+ for (let i = 0; i < 5; i++) {
198
+ out.push(`git checkout ${sha1(`short-${i}`).slice(0, 7)}`);
199
+ out.push(`image sha256:${sha256(`image-${i}`)}`);
200
+ out.push(`{"id":"${uuid(`json-${i}`)}","parentTaskId":"${uuid(`parent-${i}`)}"}`);
201
+ }
202
+ // Provider keywords in prose next to commit SHAs, digests and UUIDs. The
203
+ // keyword gate only needs the word somewhere in the text, so a rule with a
204
+ // bare hex or UUID branch would redact these.
205
+ for (const [i, kw] of [
206
+ "sourcegraph",
207
+ "heroku",
208
+ "twilio",
209
+ "mailgun",
210
+ "databricks",
211
+ "sentry",
212
+ "datadog",
213
+ "github",
214
+ "gitlab",
215
+ "linear",
216
+ "okta",
217
+ "azure",
218
+ ].entries()) {
219
+ out.push(
220
+ `${kw} searched commit ${sha1(`kw-commit-${i}`)} for references`,
221
+ `${kw} deploy ${uuid(`kw-deploy-${i}`)} finished`,
222
+ `${kw} run ${sha256(`kw-run-${i}`)} passed`,
223
+ `${kw} request id ${sha256(`kw-req-${i}`).slice(0, 32)}`,
224
+ );
225
+ }
226
+ out.push(
227
+ `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA${b64("png", 600)}`,
228
+ `data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ${b64("jpeg", 900)}`,
229
+ `"thumbnail": "${b64("thumb", 300)}"`,
230
+ "claude-opus-5-5",
231
+ "claude-sonnet-5-5",
232
+ "claude-haiku-4-5-20251001",
233
+ "google/gemini-3-flash-preview",
234
+ "anthropic/claude-sonnet-4.5",
235
+ "openai/gpt-5.1-codex-mini",
236
+ "meta-llama/llama-3.3-70b-instruct",
237
+ "v1.4.0",
238
+ "1.62.3-beta.2+build.4711",
239
+ "^5.9.2",
240
+ "bun 1.4.0 (linux-x64)",
241
+ "https://github.com/desplega-ai/agent-swarm/pull/1918",
242
+ "https://github.com/desplega-ai/agent-swarm/actions/runs/18234567890/job/52012345678",
243
+ "https://docs.stripe.com/keys#obtain-api-keys",
244
+ "https://huggingface.co/meta-llama/Llama-3.3-70B-Instruct/resolve/main/config.json",
245
+ "https://api.telegram.org/bot<token>/getMe",
246
+ "https://hooks.slack.com/services/",
247
+ "https://www.npmjs.com/package/@modelcontextprotocol/sdk?activeTab=versions",
248
+ "http://localhost:3013/api/tasks?status=in_progress&limit=50",
249
+ "postgres://localhost:5432/agent_swarm",
250
+ "/workspace/personal/worktrees/agent-swarm-gitleaks-rules/src/utils/secret-scrubber.ts",
251
+ "src/utils/secret-rules.generated.ts:120:5",
252
+ "2026-10-07T00:36:49.123Z",
253
+ "Wed Oct 7 02:36:49 CEST 2026",
254
+ "NODE_ENV=production",
255
+ "LOG_LEVEL=debug",
256
+ "PORT=3013",
257
+ "MCP_BASE_URL=http://localhost:3013",
258
+ "HARNESS_PROVIDER=claude",
259
+ "export PATH=/usr/local/bin:$PATH",
260
+ "the monkey keyed the lock and they left",
261
+ "okta: enabled for SSO, see the okta admin page",
262
+ "jira: DES-1234 moved to In Review",
263
+ "the sumo wrestler won 3 bouts",
264
+ "telegram channel @desplega_updates has 120 members",
265
+ "heroku: deployed my-app-123 to the eu region",
266
+ "cohere: model command-r-plus-08-2024",
267
+ "slack: posted to #swarm-dev-2",
268
+ "github: desplega-ai/agent-swarm#1918",
269
+ "const keys = Object.keys(this.state.items);",
270
+ "s.length > 0 && s.startsWith('x')",
271
+ "pat.name === 'default'",
272
+ "pip install scikit-learn==1.5.2",
273
+ "sk-learn is not a package name",
274
+ "ask the risky task skill",
275
+ "api-docs and api-reference live under docs-site/",
276
+ "rk_tests_helper.ts",
277
+ "re_validate_payload_and_retry_failed_steps",
278
+ "ya29 is a prefix, not a token",
279
+ "1//0 is not a refresh token",
280
+ "xai-grok-4",
281
+ "the api key is stored in swarm_config, not in env",
282
+ "Authorization header omitted",
283
+ "Bearer token rotation runs nightly",
284
+ "password reset email sent to user@example.com",
285
+ "token count: 128000",
286
+ "secret scanning is enabled on the repo",
287
+ "SKU-2024-ABCDEF-001",
288
+ "AKIA is the prefix of an AWS access key id",
289
+ "AIza is the prefix of a Google API key",
290
+ "ghp_ prefix marks a classic GitHub PAT",
291
+ "C0AR967K0KZ",
292
+ "U0ALZGQCF96",
293
+ "1759797409.123456",
294
+ "*/15 * * * *",
295
+ "192.168.1.10:8080",
296
+ "#3b82f6",
297
+ "rgba(59, 130, 246, 0.5)",
298
+ "@modelcontextprotocol/sdk@1.20.1",
299
+ "node_modules/.bin/biome check --write",
300
+ "refs/heads/feat/scrubber-gitleaks-rules",
301
+ "Merge pull request #1912 from desplega-ai/fix/tasks-scrub",
302
+ "error: ENOENT: no such file or directory, open '/tmp/x.json'",
303
+ "TypeError: Cannot read properties of undefined (reading 'id')",
304
+ '{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"done"}]}}',
305
+ "WARN [heartbeat] task stalled for 300000ms, requeueing",
306
+ "ran 1681 tests across 412 files in 93.4s",
307
+ "SELECT id, name FROM agents WHERE status = 'idle' LIMIT 10",
308
+ "base64: SGVsbG8sIHdvcmxkIQ==",
309
+ "eyes on the prize",
310
+ "they keyed in the hex 0x7f454c46",
311
+ "s.a.r.l. is a company form",
312
+ "hvs is not a vault token without a dot",
313
+ "dapi is short for data api",
314
+ "PMAK stands for Postman API key",
315
+ "ntn_ prefix belongs to Notion",
316
+ "fo1_ prefix belongs to Fly.io",
317
+ "the stripe dashboard shows sk_live_ keys masked",
318
+ );
319
+ return out;
320
+ }
@@ -610,6 +610,11 @@ describe("script connections", () => {
610
610
  markMigrationApplied(database, "198_permission_audit_guest.sql");
611
611
  // 200 backfills agent_memory, which this migration-112-only fixture does not create.
612
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");
613
618
 
614
619
  const id = crypto.randomUUID();
615
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 () => {