@pikku/core 0.12.72 → 0.12.77

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 (848) hide show
  1. package/CHANGELOG.md +1171 -0
  2. package/dist/column-form.d.ts +32 -0
  3. package/dist/column-form.js +42 -0
  4. package/dist/crypto-utils.d.ts +43 -7
  5. package/dist/crypto-utils.js +163 -42
  6. package/dist/data-classification.d.ts +44 -0
  7. package/dist/dev/hot-reload.js +11 -30
  8. package/dist/dev/module-runner.d.ts +3 -7
  9. package/dist/dev/module-runner.js +4 -10
  10. package/dist/dev/reload-meta.d.ts +8 -20
  11. package/dist/dev/reload-meta.js +9 -29
  12. package/dist/errors/error-handler.d.ts +5 -30
  13. package/dist/errors/error-handler.js +16 -32
  14. package/dist/errors/errors.d.ts +32 -151
  15. package/dist/errors/errors.js +55 -157
  16. package/dist/function/abort-scope.d.ts +47 -0
  17. package/dist/function/abort-scope.js +63 -0
  18. package/dist/function/function-runner.js +37 -32
  19. package/dist/function/functions.types.d.ts +57 -136
  20. package/dist/function/functions.types.js +0 -58
  21. package/dist/function/index.d.ts +1 -1
  22. package/dist/function/list.types.d.ts +12 -62
  23. package/dist/function/list.types.js +4 -25
  24. package/dist/handle-error.d.ts +0 -13
  25. package/dist/handle-error.js +0 -18
  26. package/dist/index.d.ts +11 -5
  27. package/dist/index.js +7 -2
  28. package/dist/middleware/auth-apikey.d.ts +3 -18
  29. package/dist/middleware/auth-apikey.js +0 -17
  30. package/dist/middleware/auth-bearer.d.ts +6 -41
  31. package/dist/middleware/auth-bearer.js +5 -41
  32. package/dist/middleware/auth-cookie.d.ts +5 -27
  33. package/dist/middleware/auth-cookie.js +2 -26
  34. package/dist/middleware/cors.d.ts +7 -34
  35. package/dist/middleware/cors.js +7 -34
  36. package/dist/middleware/remote-auth.d.ts +3 -1
  37. package/dist/middleware/remote-auth.js +4 -3
  38. package/dist/middleware/telemetry.d.ts +8 -33
  39. package/dist/middleware/telemetry.js +2 -31
  40. package/dist/middleware-runner.d.ts +4 -55
  41. package/dist/middleware-runner.js +5 -74
  42. package/dist/permissions.d.ts +3 -44
  43. package/dist/permissions.js +19 -71
  44. package/dist/pikku-request.d.ts +0 -6
  45. package/dist/pikku-request.js +0 -6
  46. package/dist/pikku-state.d.ts +0 -26
  47. package/dist/pikku-state.js +2 -30
  48. package/dist/remote.d.ts +3 -5
  49. package/dist/remote.js +9 -8
  50. package/dist/schema.d.ts +5 -39
  51. package/dist/schema.js +5 -39
  52. package/dist/scopes.d.ts +4 -23
  53. package/dist/scopes.js +7 -48
  54. package/dist/secret-value.d.ts +56 -0
  55. package/dist/secret-value.js +46 -0
  56. package/dist/services/ai-agent-runner-service.d.ts +20 -0
  57. package/dist/services/ai-embedding-service.d.ts +2 -25
  58. package/dist/services/audit-service.d.ts +74 -4
  59. package/dist/services/audit-service.js +8 -7
  60. package/dist/services/content-service.d.ts +1 -46
  61. package/dist/services/credential-service.d.ts +3 -40
  62. package/dist/services/credential-wire-service.d.ts +5 -0
  63. package/dist/services/credential-wire-service.js +9 -1
  64. package/dist/services/deployment-service.d.ts +3 -9
  65. package/dist/services/email-service.d.ts +2 -1
  66. package/dist/services/gateway-service.d.ts +0 -15
  67. package/dist/services/http-personas.d.ts +80 -0
  68. package/dist/services/http-personas.js +233 -0
  69. package/dist/services/in-memory-queue-service.d.ts +0 -14
  70. package/dist/services/in-memory-queue-service.js +1 -15
  71. package/dist/services/in-memory-trigger-service.d.ts +0 -18
  72. package/dist/services/in-memory-trigger-service.js +1 -18
  73. package/dist/services/in-memory-workflow-service.d.ts +0 -16
  74. package/dist/services/in-memory-workflow-service.js +4 -33
  75. package/dist/services/index.d.ts +8 -9
  76. package/dist/services/index.js +3 -6
  77. package/dist/services/istanbul-coverage-service.d.ts +1 -5
  78. package/dist/services/istanbul-coverage-service.js +2 -8
  79. package/dist/services/jwt-service.d.ts +1 -16
  80. package/dist/services/local-content-request-handler.d.ts +29 -0
  81. package/dist/services/local-content-request-handler.js +176 -0
  82. package/dist/services/local-content.d.ts +13 -2
  83. package/dist/services/local-content.js +40 -13
  84. package/dist/services/local-gateway-service.d.ts +0 -16
  85. package/dist/services/local-gateway-service.js +2 -17
  86. package/dist/services/local-secrets.d.ts +4 -7
  87. package/dist/services/local-secrets.js +7 -7
  88. package/dist/services/logger-console.d.ts +3 -7
  89. package/dist/services/logger-console.js +3 -7
  90. package/dist/services/logger.d.ts +22 -40
  91. package/dist/services/meta-service.d.ts +23 -26
  92. package/dist/services/meta-service.js +22 -36
  93. package/dist/services/personas-service.d.ts +134 -0
  94. package/dist/services/personas-service.js +40 -0
  95. package/dist/services/pikku-user-id.js +0 -4
  96. package/dist/services/queue-webhook-service.d.ts +2 -36
  97. package/dist/services/queue-webhook-service.js +10 -42
  98. package/dist/services/scheduler-service.d.ts +1 -50
  99. package/dist/services/scheduler-service.js +0 -10
  100. package/dist/services/schema-service.d.ts +1 -24
  101. package/dist/services/scope-service.d.ts +49 -34
  102. package/dist/services/scoped-secret-service.d.ts +4 -7
  103. package/dist/services/scoped-secret-service.js +0 -4
  104. package/dist/services/secret-host-binding.d.ts +8 -0
  105. package/dist/services/secret-host-binding.js +36 -0
  106. package/dist/services/secret-service.d.ts +12 -35
  107. package/dist/services/secretless.d.ts +6 -0
  108. package/dist/services/secretless.js +21 -0
  109. package/dist/services/stub-tracker.d.ts +7 -18
  110. package/dist/services/stub-tracker.js +8 -18
  111. package/dist/services/system-role-guard.d.ts +33 -0
  112. package/dist/services/system-role-guard.js +38 -0
  113. package/dist/services/trigger-service.d.ts +0 -12
  114. package/dist/services/typed-secret-service.d.ts +5 -11
  115. package/dist/services/typed-secret-service.js +1 -7
  116. package/dist/services/v8-coverage-service.d.ts +2 -3
  117. package/dist/services/v8-coverage-service.js +1 -2
  118. package/dist/services/variables-service.d.ts +1 -8
  119. package/dist/services/webhook-service.d.ts +21 -64
  120. package/dist/services/webhook-service.js +6 -20
  121. package/dist/services/workflow-service.d.ts +3 -15
  122. package/dist/testing/service-tests.js +6 -23
  123. package/dist/time-utils.d.ts +0 -16
  124. package/dist/time-utils.js +1 -19
  125. package/dist/types/core.types.d.ts +120 -219
  126. package/dist/types/core.types.js +0 -42
  127. package/dist/types/state.types.d.ts +4 -9
  128. package/dist/utils/hmac.d.ts +4 -10
  129. package/dist/utils/hmac.js +4 -10
  130. package/dist/utils/safe-fetch.d.ts +7 -35
  131. package/dist/utils/safe-fetch.js +13 -53
  132. package/dist/utils.d.ts +1 -6
  133. package/dist/utils.js +6 -15
  134. package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -34
  135. package/dist/wirings/actor-flow/index.d.ts +0 -9
  136. package/dist/wirings/actor-flow/run-conversation.d.ts +5 -5
  137. package/dist/wirings/actor-flow/run-conversation.js +14 -7
  138. package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -5
  139. package/dist/wirings/ai-agent/ai-agent-agui.js +46 -12
  140. package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +7 -0
  141. package/dist/wirings/ai-agent/ai-agent-helpers.js +7 -0
  142. package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +153 -0
  143. package/dist/wirings/ai-agent/ai-agent-interrupt.js +256 -0
  144. package/dist/wirings/ai-agent/ai-agent-memory.js +0 -2
  145. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -9
  146. package/dist/wirings/ai-agent/ai-agent-model-config.js +1 -9
  147. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -99
  148. package/dist/wirings/ai-agent/ai-agent-prepare.js +65 -132
  149. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +2 -1
  150. package/dist/wirings/ai-agent/ai-agent-registry.js +5 -1
  151. package/dist/wirings/ai-agent/ai-agent-runner.js +63 -22
  152. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
  153. package/dist/wirings/ai-agent/ai-agent-stream.js +180 -64
  154. package/dist/wirings/ai-agent/ai-agent.types.d.ts +124 -4
  155. package/dist/wirings/ai-agent/index.d.ts +6 -4
  156. package/dist/wirings/ai-agent/index.js +5 -4
  157. package/dist/wirings/ai-agent/voice-input.d.ts +59 -1
  158. package/dist/wirings/ai-agent/voice-input.js +90 -12
  159. package/dist/wirings/ai-agent/voice-output.d.ts +69 -1
  160. package/dist/wirings/ai-agent/voice-output.js +162 -50
  161. package/dist/wirings/channel/channel-common.d.ts +7 -20
  162. package/dist/wirings/channel/channel-common.js +7 -21
  163. package/dist/wirings/channel/channel-handler.js +25 -6
  164. package/dist/wirings/channel/channel-host-rpc.d.ts +25 -0
  165. package/dist/wirings/channel/channel-host-rpc.js +38 -0
  166. package/dist/wirings/channel/channel-middleware-runner.d.ts +0 -12
  167. package/dist/wirings/channel/channel-middleware-runner.js +0 -12
  168. package/dist/wirings/channel/channel-rpc-registry.d.ts +31 -0
  169. package/dist/wirings/channel/channel-rpc-registry.js +89 -0
  170. package/dist/wirings/channel/channel-rpc-responder.d.ts +15 -0
  171. package/dist/wirings/channel/channel-rpc-responder.js +71 -0
  172. package/dist/wirings/channel/channel-rpc-service.d.ts +40 -0
  173. package/dist/wirings/channel/channel-rpc-service.js +106 -0
  174. package/dist/wirings/channel/channel-rpc-validators.d.ts +14 -0
  175. package/dist/wirings/channel/channel-rpc-validators.js +30 -0
  176. package/dist/wirings/channel/channel-rpc.d.ts +5 -0
  177. package/dist/wirings/channel/channel-rpc.js +5 -0
  178. package/dist/wirings/channel/channel-rpc.types.d.ts +90 -0
  179. package/dist/wirings/channel/channel-rpc.types.js +50 -0
  180. package/dist/wirings/channel/channel-runner.d.ts +0 -4
  181. package/dist/wirings/channel/channel-runner.js +0 -14
  182. package/dist/wirings/channel/channel-store.d.ts +0 -10
  183. package/dist/wirings/channel/channel.types.d.ts +12 -1
  184. package/dist/wirings/channel/define-channel-routes.d.ts +0 -20
  185. package/dist/wirings/channel/define-channel-routes.js +0 -20
  186. package/dist/wirings/channel/eventhub-service.d.ts +0 -18
  187. package/dist/wirings/channel/index.d.ts +4 -1
  188. package/dist/wirings/channel/index.js +2 -0
  189. package/dist/wirings/channel/local/local-channel-runner.js +3 -1
  190. package/dist/wirings/channel/local/local-eventhub-service.d.ts +0 -33
  191. package/dist/wirings/channel/local/local-eventhub-service.js +2 -36
  192. package/dist/wirings/channel/log-channels.d.ts +0 -4
  193. package/dist/wirings/channel/log-channels.js +0 -4
  194. package/dist/wirings/channel/pikku-abstract-channel-handler.js +6 -0
  195. package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -5
  196. package/dist/wirings/cli/channel/cli-approval.d.ts +41 -0
  197. package/dist/wirings/cli/channel/cli-approval.js +81 -0
  198. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +0 -4
  199. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -25
  200. package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +47 -9
  201. package/dist/wirings/cli/channel/cli-raw-channel-runner.js +24 -16
  202. package/dist/wirings/cli/channel/cli-raw-client-runner.d.ts +38 -0
  203. package/dist/wirings/cli/channel/cli-raw-client-runner.js +129 -0
  204. package/dist/wirings/cli/channel/index.d.ts +5 -0
  205. package/dist/wirings/cli/channel/index.js +2 -0
  206. package/dist/wirings/cli/cli-runner.d.ts +20 -20
  207. package/dist/wirings/cli/cli-runner.js +28 -89
  208. package/dist/wirings/cli/cli.types.d.ts +14 -3
  209. package/dist/wirings/cli/command-parser.d.ts +1 -10
  210. package/dist/wirings/cli/command-parser.js +10 -87
  211. package/dist/wirings/cli/define-cli-commands.d.ts +1 -17
  212. package/dist/wirings/cli/define-cli-commands.js +1 -17
  213. package/dist/wirings/credential/credential.types.d.ts +0 -12
  214. package/dist/wirings/credential/define-credential.d.ts +48 -0
  215. package/dist/wirings/credential/define-credential.js +47 -0
  216. package/dist/wirings/credential/index.d.ts +1 -1
  217. package/dist/wirings/credential/index.js +1 -1
  218. package/dist/wirings/credential/validate-credential-definitions.d.ts +2 -4
  219. package/dist/wirings/gateway/gateway-runner.d.ts +1 -20
  220. package/dist/wirings/gateway/gateway-runner.js +8 -105
  221. package/dist/wirings/gateway/gateway.types.d.ts +7 -80
  222. package/dist/wirings/http/http-routes.d.ts +0 -63
  223. package/dist/wirings/http/http-routes.js +0 -63
  224. package/dist/wirings/http/http-runner.d.ts +0 -99
  225. package/dist/wirings/http/http-runner.js +9 -165
  226. package/dist/wirings/http/http.types.d.ts +14 -55
  227. package/dist/wirings/http/log-http-routes.d.ts +0 -4
  228. package/dist/wirings/http/log-http-routes.js +0 -4
  229. package/dist/wirings/http/pikku-fetch-http-request.d.ts +0 -40
  230. package/dist/wirings/http/pikku-fetch-http-request.js +0 -58
  231. package/dist/wirings/http/pikku-fetch-http-response.js +0 -3
  232. package/dist/wirings/http/routers/path-to-regex.js +2 -13
  233. package/dist/wirings/http/web-request.d.ts +0 -8
  234. package/dist/wirings/http/web-request.js +25 -17
  235. package/dist/wirings/mcp/mcp-runner.d.ts +1 -4
  236. package/dist/wirings/mcp/mcp-runner.js +1 -14
  237. package/dist/wirings/mcp/mcp.types.d.ts +2 -35
  238. package/dist/wirings/oauth2/oauth2.types.d.ts +0 -28
  239. package/dist/wirings/oauth2/oauth2.types.js +0 -3
  240. package/dist/wirings/persona/define-personas.d.ts +32 -0
  241. package/dist/wirings/persona/define-personas.js +31 -0
  242. package/dist/wirings/persona/index.d.ts +21 -0
  243. package/dist/wirings/persona/index.js +17 -0
  244. package/dist/wirings/persona/persona-email.d.ts +37 -0
  245. package/dist/wirings/persona/persona-email.js +69 -0
  246. package/dist/wirings/persona/persona-environments.d.ts +45 -0
  247. package/dist/wirings/persona/persona-environments.js +81 -0
  248. package/dist/wirings/persona/persona-mailbox.d.ts +101 -0
  249. package/dist/wirings/persona/persona-mailbox.js +53 -0
  250. package/dist/wirings/persona/persona.types.d.ts +136 -0
  251. package/dist/wirings/persona/persona.types.js +1 -0
  252. package/dist/wirings/persona/validate-personas.d.ts +53 -0
  253. package/dist/wirings/persona/validate-personas.js +94 -0
  254. package/dist/wirings/queue/index.d.ts +3 -0
  255. package/dist/wirings/queue/index.js +2 -3
  256. package/dist/wirings/queue/queue-identity.d.ts +28 -0
  257. package/dist/wirings/queue/queue-identity.js +103 -0
  258. package/dist/wirings/queue/queue-runner.d.ts +0 -19
  259. package/dist/wirings/queue/queue-runner.js +9 -30
  260. package/dist/wirings/queue/queue.types.d.ts +20 -90
  261. package/dist/wirings/queue/register-queue-helper.d.ts +0 -12
  262. package/dist/wirings/queue/register-queue-helper.js +0 -11
  263. package/dist/wirings/queue/signed-queue-service.d.ts +17 -0
  264. package/dist/wirings/queue/signed-queue-service.js +42 -0
  265. package/dist/wirings/queue/validate-worker-config.d.ts +2 -23
  266. package/dist/wirings/queue/validate-worker-config.js +0 -14
  267. package/dist/wirings/role/define-system-role.d.ts +32 -0
  268. package/dist/wirings/role/define-system-role.js +31 -0
  269. package/dist/wirings/role/index.d.ts +3 -0
  270. package/dist/wirings/role/index.js +2 -0
  271. package/dist/wirings/role/role.types.d.ts +43 -0
  272. package/dist/wirings/role/role.types.js +1 -0
  273. package/dist/wirings/role/validate-role-definitions.d.ts +21 -0
  274. package/dist/wirings/role/validate-role-definitions.js +71 -0
  275. package/dist/wirings/rpc/addon-runner.d.ts +0 -19
  276. package/dist/wirings/rpc/addon-runner.js +0 -51
  277. package/dist/wirings/rpc/remote-addon-auth.d.ts +3 -13
  278. package/dist/wirings/rpc/remote-addon-auth.js +7 -11
  279. package/dist/wirings/rpc/rpc-runner.d.ts +11 -18
  280. package/dist/wirings/rpc/rpc-runner.js +88 -105
  281. package/dist/wirings/rpc/rpc-types.d.ts +7 -6
  282. package/dist/wirings/rpc/wire-addon.d.ts +25 -0
  283. package/dist/wirings/rpc/wire-addon.js +62 -0
  284. package/dist/wirings/rpc/wire-remote-addon.d.ts +3 -28
  285. package/dist/wirings/rpc/wire-remote-addon.js +0 -8
  286. package/dist/wirings/scheduler/log-schedulers.d.ts +0 -4
  287. package/dist/wirings/scheduler/log-schedulers.js +0 -4
  288. package/dist/wirings/scheduler/scheduler-runner.d.ts +0 -1
  289. package/dist/wirings/scheduler/scheduler-runner.js +0 -1
  290. package/dist/wirings/scheduler/scheduler.types.d.ts +1 -14
  291. package/dist/wirings/scope/define-scope.d.ts +32 -0
  292. package/dist/wirings/scope/define-scope.js +31 -0
  293. package/dist/wirings/scope/index.d.ts +1 -1
  294. package/dist/wirings/scope/index.js +1 -1
  295. package/dist/wirings/scope/scope.types.d.ts +7 -9
  296. package/dist/wirings/scope/validate-scope-definitions.d.ts +2 -21
  297. package/dist/wirings/scope/validate-scope-definitions.js +3 -21
  298. package/dist/wirings/secret/index.d.ts +1 -1
  299. package/dist/wirings/secret/index.js +1 -1
  300. package/dist/wirings/secret/secret.types.d.ts +19 -15
  301. package/dist/wirings/secret/secret.types.js +1 -1
  302. package/dist/wirings/secret/validate-secret-definitions.d.ts +2 -4
  303. package/dist/wirings/trigger/trigger-runner.d.ts +0 -27
  304. package/dist/wirings/trigger/trigger-runner.js +1 -24
  305. package/dist/wirings/trigger/trigger.types.d.ts +1 -82
  306. package/dist/wirings/trigger/trigger.types.js +0 -34
  307. package/dist/wirings/variable/index.d.ts +1 -1
  308. package/dist/wirings/variable/index.js +1 -1
  309. package/dist/wirings/variable/validate-variable-definitions.d.ts +2 -4
  310. package/dist/wirings/variable/variable.types.d.ts +1 -13
  311. package/dist/wirings/variable/variable.types.js +1 -1
  312. package/dist/wirings/virtual-user/index.d.ts +30 -0
  313. package/dist/wirings/virtual-user/index.js +10 -0
  314. package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +54 -0
  315. package/dist/wirings/virtual-user/prepare-virtual-user-run.js +49 -0
  316. package/dist/wirings/virtual-user/run-virtual-user.d.ts +92 -0
  317. package/dist/wirings/virtual-user/run-virtual-user.js +478 -0
  318. package/dist/wirings/virtual-user/virtual-user-agents.d.ts +38 -0
  319. package/dist/wirings/virtual-user/virtual-user-agents.js +24 -0
  320. package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +92 -0
  321. package/dist/wirings/virtual-user/virtual-user-catalogue.js +134 -0
  322. package/dist/wirings/virtual-user/virtual-user-derive.d.ts +26 -0
  323. package/dist/wirings/virtual-user/virtual-user-derive.js +137 -0
  324. package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +79 -0
  325. package/dist/wirings/virtual-user/virtual-user-dispositions.js +128 -0
  326. package/dist/wirings/virtual-user/virtual-user-intents.d.ts +78 -0
  327. package/dist/wirings/virtual-user/virtual-user-intents.js +142 -0
  328. package/dist/wirings/virtual-user/virtual-user-rng.d.ts +24 -0
  329. package/dist/wirings/virtual-user/virtual-user-rng.js +44 -0
  330. package/dist/wirings/virtual-user/virtual-user-run-store.d.ts +90 -0
  331. package/dist/wirings/virtual-user/virtual-user-run-store.js +1 -0
  332. package/dist/wirings/virtual-user/virtual-user-target.d.ts +21 -0
  333. package/dist/wirings/virtual-user/virtual-user-target.js +34 -0
  334. package/dist/wirings/virtual-user/virtual-user.types.d.ts +199 -0
  335. package/dist/wirings/virtual-user/virtual-user.types.js +8 -0
  336. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +19 -15
  337. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +0 -4
  338. package/dist/wirings/workflow/dsl/workflow-runner.js +0 -4
  339. package/dist/wirings/workflow/feature.d.ts +0 -19
  340. package/dist/wirings/workflow/feature.js +0 -19
  341. package/dist/wirings/workflow/graph/graph-node.d.ts +0 -98
  342. package/dist/wirings/workflow/graph/graph-node.js +0 -34
  343. package/dist/wirings/workflow/graph/graph-runner.js +6 -41
  344. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +0 -4
  345. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -58
  346. package/dist/wirings/workflow/graph/workflow-graph.types.js +0 -6
  347. package/dist/wirings/workflow/index.d.ts +5 -7
  348. package/dist/wirings/workflow/index.js +3 -17
  349. package/dist/wirings/workflow/pikku-scenario-service.d.ts +87 -5
  350. package/dist/wirings/workflow/pikku-scenario-service.js +204 -43
  351. package/dist/wirings/workflow/pikku-workflow-service.d.ts +7 -459
  352. package/dist/wirings/workflow/pikku-workflow-service.js +58 -551
  353. package/dist/wirings/workflow/run-timeline.d.ts +0 -47
  354. package/dist/wirings/workflow/run-timeline.js +0 -22
  355. package/dist/wirings/workflow/scenario-cookie-jar.d.ts +0 -23
  356. package/dist/wirings/workflow/scenario-cookie-jar.js +0 -16
  357. package/dist/wirings/workflow/scenario-poll.d.ts +0 -15
  358. package/dist/wirings/workflow/scenario-poll.js +0 -12
  359. package/dist/wirings/workflow/scenario-prose.d.ts +0 -28
  360. package/dist/wirings/workflow/scenario-prose.js +1 -19
  361. package/dist/wirings/workflow/scenario-step-guards.d.ts +0 -13
  362. package/dist/wirings/workflow/scenario-step-guards.js +1 -14
  363. package/dist/wirings/workflow/scenario-step.types.d.ts +84 -12
  364. package/dist/wirings/workflow/scenario-step.types.js +5 -1
  365. package/dist/wirings/workflow/scenario-surface.d.ts +16 -0
  366. package/dist/wirings/workflow/scenario-surface.js +56 -0
  367. package/dist/wirings/workflow/workflow-invocation-id.d.ts +0 -18
  368. package/dist/wirings/workflow/workflow-invocation-id.js +2 -22
  369. package/dist/wirings/workflow/workflow-queue-workers.d.ts +0 -20
  370. package/dist/wirings/workflow/workflow-queue-workers.js +0 -19
  371. package/dist/wirings/workflow/workflow.types.d.ts +5 -195
  372. package/knowledge/decisions/index.md +19 -0
  373. package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +49 -0
  374. package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md +48 -0
  375. package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +23 -0
  376. package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +24 -0
  377. package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +25 -0
  378. package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +26 -0
  379. package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +33 -0
  380. package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +28 -0
  381. package/knowledge/decisions/internals/ai-agent-agui-bridge-obeys-the-client-ordering-contract.md +29 -0
  382. package/knowledge/decisions/internals/ai-agent-audio-chunks-carry-the-format-the-provider-returned.md +20 -0
  383. package/knowledge/decisions/internals/ai-agent-credential-suspensions-hide-the-tool-result.md +26 -0
  384. package/knowledge/decisions/internals/ai-agent-delegate-and-supervise-hide-different-text.md +26 -0
  385. package/knowledge/decisions/internals/ai-agent-llm-tool-arguments-have-nulls-stripped.md +23 -0
  386. package/knowledge/decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md +25 -0
  387. package/knowledge/decisions/internals/ai-agent-onerror-hooks-cannot-change-the-failure.md +22 -0
  388. package/knowledge/decisions/internals/ai-agent-runner-methods-must-keep-their-receiver.md +22 -0
  389. package/knowledge/decisions/internals/ai-agent-stream-persistence-is-best-effort.md +27 -0
  390. package/knowledge/decisions/internals/ai-agent-sub-agents-inherit-the-parent-context-block.md +26 -0
  391. package/knowledge/decisions/internals/ai-agent-tool-execute-failures-are-logged-unconditionally.md +25 -0
  392. package/knowledge/decisions/internals/ai-agent-voice-input-transcribes-audio-parts-in-place.md +22 -0
  393. package/knowledge/decisions/internals/ai-agent-working-memory-is-persisted-only-when-valid.md +25 -0
  394. package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +30 -0
  395. package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +31 -0
  396. package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +29 -0
  397. package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +28 -0
  398. package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +27 -0
  399. package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +28 -0
  400. package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +34 -0
  401. package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +29 -0
  402. package/knowledge/decisions/internals/core-column-form-is-an-axis-of-its-own.md +84 -0
  403. package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +41 -0
  404. package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +44 -0
  405. package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +39 -0
  406. package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +42 -0
  407. package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +39 -0
  408. package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +43 -0
  409. package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +38 -0
  410. package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +44 -0
  411. package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +27 -0
  412. package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +32 -0
  413. package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +28 -0
  414. package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +31 -0
  415. package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +26 -0
  416. package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +32 -0
  417. package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +28 -0
  418. package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +30 -0
  419. package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +26 -0
  420. package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +28 -0
  421. package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +32 -0
  422. package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +26 -0
  423. package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +25 -0
  424. package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +26 -0
  425. package/knowledge/decisions/internals/index.md +117 -0
  426. package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +25 -0
  427. package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +26 -0
  428. package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +24 -0
  429. package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +53 -0
  430. package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +28 -0
  431. package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +27 -0
  432. package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +31 -0
  433. package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +32 -0
  434. package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +27 -0
  435. package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +26 -0
  436. package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +27 -0
  437. package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +48 -0
  438. package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +30 -0
  439. package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +28 -0
  440. package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +30 -0
  441. package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +29 -0
  442. package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +27 -0
  443. package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +40 -0
  444. package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +26 -0
  445. package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +33 -0
  446. package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +26 -0
  447. package/knowledge/decisions/internals/validate-checks-personas-through-a-shared-module.md +43 -0
  448. package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +26 -0
  449. package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +25 -0
  450. package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +58 -0
  451. package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +34 -0
  452. package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +42 -0
  453. package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +38 -0
  454. package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +29 -0
  455. package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +42 -0
  456. package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +25 -0
  457. package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +29 -0
  458. package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +43 -0
  459. package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +29 -0
  460. package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +42 -0
  461. package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +33 -0
  462. package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +32 -0
  463. package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +31 -0
  464. package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +39 -0
  465. package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +29 -0
  466. package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +33 -0
  467. package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +37 -0
  468. package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +50 -0
  469. package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +43 -0
  470. package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +32 -0
  471. package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +18 -0
  472. package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +34 -0
  473. package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +26 -0
  474. package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +33 -0
  475. package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +27 -0
  476. package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +34 -0
  477. package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +38 -0
  478. package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +30 -0
  479. package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +26 -0
  480. package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md +22 -0
  481. package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +27 -0
  482. package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +27 -0
  483. package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +43 -0
  484. package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +52 -0
  485. package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +46 -0
  486. package/knowledge/decisions/security/ai-agent-approval-forwarding-requires-a-symbol-brand.md +27 -0
  487. package/knowledge/decisions/security/ai-agent-credential-requests-are-symbol-branded.md +37 -0
  488. package/knowledge/decisions/security/ai-agent-gate-requires-a-session-only-when-auth-is-true.md +31 -0
  489. package/knowledge/decisions/security/ai-agent-ownership-failures-never-echo-the-resource.md +23 -0
  490. package/knowledge/decisions/security/ai-agent-resume-re-runs-the-authorization-gate.md +22 -0
  491. package/knowledge/decisions/security/ai-agent-sessionless-deployments-have-no-thread-ownership.md +39 -0
  492. package/knowledge/decisions/security/ai-agent-thread-ownership-composes-the-session-principal.md +30 -0
  493. package/knowledge/decisions/security/ai-agent-tool-filtering-reads-the-live-function-config.md +24 -0
  494. package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +30 -0
  495. package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +49 -0
  496. package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +76 -0
  497. package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +39 -0
  498. package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +37 -0
  499. package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +31 -0
  500. package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +30 -0
  501. package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +40 -0
  502. package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +33 -0
  503. package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +46 -0
  504. package/knowledge/decisions/security/index.md +55 -0
  505. package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +27 -0
  506. package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +40 -0
  507. package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +31 -0
  508. package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +26 -0
  509. package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +69 -0
  510. package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +39 -0
  511. package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +34 -0
  512. package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +49 -0
  513. package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +30 -0
  514. package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +28 -0
  515. package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +34 -0
  516. package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +37 -0
  517. package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +25 -0
  518. package/knowledge/decisions/security/workflow-actor-steps-always-use-the-real-transport.md +34 -0
  519. package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +40 -0
  520. package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +32 -0
  521. package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md +32 -0
  522. package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +31 -0
  523. package/knowledge/index.md +24 -0
  524. package/knowledge/questions/index.md +15 -0
  525. package/package.json +6 -2
  526. package/run-tests.sh +0 -0
  527. package/src/column-form.test.ts +97 -0
  528. package/src/column-form.ts +58 -0
  529. package/src/crypto-utils.test.ts +460 -19
  530. package/src/crypto-utils.ts +306 -59
  531. package/src/data-classification.ts +45 -7
  532. package/src/dev/hot-reload.test.ts +0 -4
  533. package/src/dev/hot-reload.ts +11 -30
  534. package/src/dev/module-runner.ts +7 -32
  535. package/src/dev/reload-meta.ts +9 -29
  536. package/src/errors/error-handler.ts +20 -35
  537. package/src/errors/error.test.ts +30 -1
  538. package/src/errors/errors.ts +73 -157
  539. package/src/function/abort-scope.test.ts +97 -0
  540. package/src/function/abort-scope.ts +80 -0
  541. package/src/function/function-runner.test.ts +0 -7
  542. package/src/function/function-runner.ts +62 -32
  543. package/src/function/functions.types.ts +95 -138
  544. package/src/function/index.ts +1 -0
  545. package/src/function/list.types.test.ts +3 -25
  546. package/src/function/list.types.ts +12 -62
  547. package/src/handle-error.ts +0 -18
  548. package/src/index.ts +84 -3
  549. package/src/middleware/auth-apikey.test.ts +0 -1
  550. package/src/middleware/auth-apikey.ts +0 -17
  551. package/src/middleware/auth-bearer.test.ts +3 -5
  552. package/src/middleware/auth-bearer.ts +5 -41
  553. package/src/middleware/auth-cookie.test.ts +0 -6
  554. package/src/middleware/auth-cookie.ts +2 -26
  555. package/src/middleware/cors.test.ts +34 -0
  556. package/src/middleware/cors.ts +12 -33
  557. package/src/middleware/remote-auth.test.ts +26 -10
  558. package/src/middleware/remote-auth.ts +11 -3
  559. package/src/middleware/telemetry.ts +2 -31
  560. package/src/middleware-runner.test.ts +0 -2
  561. package/src/middleware-runner.ts +5 -74
  562. package/src/permissions.test.ts +30 -0
  563. package/src/permissions.ts +24 -74
  564. package/src/pikku-request.ts +0 -6
  565. package/src/pikku-state.ts +2 -30
  566. package/src/production-barrels-stay-lean.test.ts +110 -0
  567. package/src/remote.test.ts +173 -0
  568. package/src/remote.ts +18 -8
  569. package/src/schema.ts +5 -39
  570. package/src/scopes.ts +7 -48
  571. package/src/secret-value.test.ts +204 -0
  572. package/src/secret-value.ts +111 -0
  573. package/src/services/ai-agent-runner-service.ts +20 -0
  574. package/src/services/ai-embedding-service.ts +3 -25
  575. package/src/services/audit-service.ts +88 -11
  576. package/src/services/content-service.ts +1 -46
  577. package/src/services/credential-service.ts +3 -40
  578. package/src/services/credential-wire-service.test.ts +0 -2
  579. package/src/services/credential-wire-service.ts +9 -1
  580. package/src/services/deployment-service.ts +3 -9
  581. package/src/services/email-service.ts +3 -1
  582. package/src/services/gateway-service.ts +0 -15
  583. package/src/services/{http-scenario-actors-converse.test.ts → http-personas-converse.test.ts} +38 -9
  584. package/src/services/{http-scenario-actors.test.ts → http-personas.test.ts} +39 -22
  585. package/src/services/{http-scenario-actors.ts → http-personas.ts} +85 -45
  586. package/src/services/in-memory-queue-service.ts +1 -15
  587. package/src/services/in-memory-trigger-service.ts +1 -18
  588. package/src/services/in-memory-workflow-service.test.ts +0 -13
  589. package/src/services/in-memory-workflow-service.ts +4 -38
  590. package/src/services/index.ts +23 -18
  591. package/src/services/istanbul-coverage-service.ts +2 -8
  592. package/src/services/jwt-service.ts +1 -16
  593. package/src/services/local-content-request-handler.test.ts +202 -0
  594. package/src/services/local-content-request-handler.ts +267 -0
  595. package/src/services/local-content.test.ts +159 -27
  596. package/src/services/local-content.ts +55 -23
  597. package/src/services/local-gateway-service.ts +2 -17
  598. package/src/services/local-secrets.test.ts +20 -5
  599. package/src/services/local-secrets.ts +15 -11
  600. package/src/services/logger-console.test.ts +0 -1
  601. package/src/services/logger-console.ts +3 -7
  602. package/src/services/logger.ts +31 -46
  603. package/src/services/meta-service.test.ts +1 -5
  604. package/src/services/meta-service.ts +41 -61
  605. package/src/services/{scenario-actors-service.ts → personas-service.ts} +48 -43
  606. package/src/services/pikku-user-id.ts +0 -4
  607. package/src/services/queue-webhook-service.test.ts +2 -1
  608. package/src/services/queue-webhook-service.ts +10 -42
  609. package/src/services/scheduler-service.ts +1 -50
  610. package/src/services/schema-service.ts +1 -24
  611. package/src/services/scope-service.ts +50 -34
  612. package/src/services/scoped-secret-service.ts +4 -7
  613. package/src/services/secret-host-binding.test.ts +138 -0
  614. package/src/services/secret-host-binding.ts +51 -0
  615. package/src/services/secret-service.ts +12 -35
  616. package/src/services/secretless.test.ts +54 -0
  617. package/src/services/secretless.ts +29 -0
  618. package/src/services/stub-tracker.ts +8 -18
  619. package/src/services/system-role-guard.test.ts +93 -0
  620. package/src/services/system-role-guard.ts +71 -0
  621. package/src/services/trigger-service.ts +0 -12
  622. package/src/services/typed-secret-service.ts +12 -14
  623. package/src/services/v8-coverage-service.ts +3 -6
  624. package/src/services/variables-service.ts +1 -8
  625. package/src/services/webhook-service.ts +23 -64
  626. package/src/services/workflow-service.ts +3 -20
  627. package/src/testing/service-tests.ts +6 -32
  628. package/src/time-utils.ts +1 -19
  629. package/src/types/core.types.ts +137 -229
  630. package/src/types/state.types.ts +7 -9
  631. package/src/utils/hmac.ts +4 -10
  632. package/src/utils/safe-fetch.ts +13 -54
  633. package/src/utils.test.ts +11 -2
  634. package/src/utils.ts +6 -15
  635. package/src/wirings/actor-flow/actor-flow.types.ts +1 -34
  636. package/src/wirings/actor-flow/index.ts +0 -9
  637. package/src/wirings/actor-flow/run-conversation.test.ts +11 -6
  638. package/src/wirings/actor-flow/run-conversation.ts +19 -12
  639. package/src/wirings/ai-agent/ai-agent-agui.test.ts +91 -10
  640. package/src/wirings/ai-agent/ai-agent-agui.ts +49 -17
  641. package/src/wirings/ai-agent/ai-agent-helpers.ts +20 -0
  642. package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +842 -0
  643. package/src/wirings/ai-agent/ai-agent-interrupt.ts +399 -0
  644. package/src/wirings/ai-agent/ai-agent-memory.ts +0 -2
  645. package/src/wirings/ai-agent/ai-agent-model-config.ts +1 -9
  646. package/src/wirings/ai-agent/ai-agent-prepare.test.ts +202 -31
  647. package/src/wirings/ai-agent/ai-agent-prepare.ts +89 -139
  648. package/src/wirings/ai-agent/ai-agent-registry.test.ts +191 -6
  649. package/src/wirings/ai-agent/ai-agent-registry.ts +18 -1
  650. package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +0 -2
  651. package/src/wirings/ai-agent/ai-agent-runner.test.ts +11 -9
  652. package/src/wirings/ai-agent/ai-agent-runner.ts +85 -35
  653. package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
  654. package/src/wirings/ai-agent/ai-agent-stream.ts +224 -76
  655. package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
  656. package/src/wirings/ai-agent/ai-agent.types.ts +130 -5
  657. package/src/wirings/ai-agent/index.ts +37 -3
  658. package/src/wirings/ai-agent/voice-input.test.ts +137 -7
  659. package/src/wirings/ai-agent/voice-input.ts +96 -12
  660. package/src/wirings/ai-agent/voice-output.test.ts +512 -0
  661. package/src/wirings/ai-agent/voice-output.ts +243 -56
  662. package/src/wirings/channel/channel-common.ts +15 -20
  663. package/src/wirings/channel/channel-handler.test.ts +50 -0
  664. package/src/wirings/channel/channel-handler.ts +32 -11
  665. package/src/wirings/channel/channel-host-rpc.test.ts +150 -0
  666. package/src/wirings/channel/channel-host-rpc.ts +69 -0
  667. package/src/wirings/channel/channel-middleware-runner.test.ts +0 -1
  668. package/src/wirings/channel/channel-middleware-runner.ts +0 -12
  669. package/src/wirings/channel/channel-rpc-registry.ts +116 -0
  670. package/src/wirings/channel/channel-rpc-responder.ts +117 -0
  671. package/src/wirings/channel/channel-rpc-service.ts +146 -0
  672. package/src/wirings/channel/channel-rpc-validators.ts +65 -0
  673. package/src/wirings/channel/channel-rpc.test.ts +820 -0
  674. package/src/wirings/channel/channel-rpc.ts +5 -0
  675. package/src/wirings/channel/channel-rpc.types.ts +150 -0
  676. package/src/wirings/channel/channel-runner.ts +0 -14
  677. package/src/wirings/channel/channel-store.ts +0 -10
  678. package/src/wirings/channel/channel.types.ts +19 -8
  679. package/src/wirings/channel/define-channel-routes.ts +0 -20
  680. package/src/wirings/channel/eventhub-service.ts +0 -18
  681. package/src/wirings/channel/index.ts +35 -0
  682. package/src/wirings/channel/local/local-channel-handler.ts +3 -1
  683. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -10
  684. package/src/wirings/channel/local/local-channel-runner.ts +3 -1
  685. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -13
  686. package/src/wirings/channel/local/local-eventhub-service.ts +2 -37
  687. package/src/wirings/channel/log-channels.ts +0 -4
  688. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +83 -2
  689. package/src/wirings/channel/pikku-abstract-channel-handler.ts +7 -0
  690. package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -5
  691. package/src/wirings/cli/channel/cli-approval.test.ts +177 -0
  692. package/src/wirings/cli/channel/cli-approval.ts +135 -0
  693. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -26
  694. package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +169 -0
  695. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +59 -16
  696. package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +480 -0
  697. package/src/wirings/cli/channel/cli-raw-client-runner.ts +185 -0
  698. package/src/wirings/cli/channel/index.ts +13 -0
  699. package/src/wirings/cli/cli-runner.test.ts +0 -1
  700. package/src/wirings/cli/cli-runner.ts +46 -88
  701. package/src/wirings/cli/cli.types.ts +14 -3
  702. package/src/wirings/cli/command-parser.test.ts +0 -4
  703. package/src/wirings/cli/command-parser.ts +11 -91
  704. package/src/wirings/cli/define-cli-commands.ts +1 -17
  705. package/src/wirings/credential/credential.types.ts +0 -12
  706. package/src/wirings/credential/{wire-credential.ts → define-credential.ts} +7 -7
  707. package/src/wirings/credential/index.ts +1 -1
  708. package/src/wirings/credential/validate-credential-definitions.ts +2 -4
  709. package/src/wirings/gateway/gateway-runner.test.ts +1 -21
  710. package/src/wirings/gateway/gateway-runner.ts +8 -110
  711. package/src/wirings/gateway/gateway.types.ts +7 -80
  712. package/src/wirings/http/http-routes.test.ts +0 -3
  713. package/src/wirings/http/http-routes.ts +0 -86
  714. package/src/wirings/http/http-runner.test.ts +0 -1
  715. package/src/wirings/http/http-runner.ts +8 -167
  716. package/src/wirings/http/http.types.ts +15 -62
  717. package/src/wirings/http/log-http-routes.ts +0 -4
  718. package/src/wirings/http/pikku-fetch-http-request.test.ts +2 -10
  719. package/src/wirings/http/pikku-fetch-http-request.ts +0 -58
  720. package/src/wirings/http/pikku-fetch-http-response.test.ts +1 -1
  721. package/src/wirings/http/pikku-fetch-http-response.ts +0 -3
  722. package/src/wirings/http/routers/path-to-regex.test.ts +4 -17
  723. package/src/wirings/http/routers/path-to-regex.ts +2 -13
  724. package/src/wirings/http/web-request.test.ts +33 -2
  725. package/src/wirings/http/web-request.ts +30 -17
  726. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -1
  727. package/src/wirings/mcp/mcp-runner.ts +2 -17
  728. package/src/wirings/mcp/mcp.types.ts +7 -42
  729. package/src/wirings/oauth2/oauth2.types.ts +0 -30
  730. package/src/wirings/persona/define-personas.ts +33 -0
  731. package/src/wirings/persona/index.ts +62 -0
  732. package/src/wirings/persona/persona-email.ts +87 -0
  733. package/src/wirings/persona/persona-environments.test.ts +183 -0
  734. package/src/wirings/persona/persona-environments.ts +138 -0
  735. package/src/wirings/persona/persona-mailbox.ts +156 -0
  736. package/src/wirings/persona/persona.test.ts +220 -0
  737. package/src/wirings/persona/persona.types.ts +142 -0
  738. package/src/wirings/persona/validate-personas.ts +133 -0
  739. package/src/wirings/queue/index.ts +13 -3
  740. package/src/wirings/queue/queue-identity.test.ts +454 -0
  741. package/src/wirings/queue/queue-identity.ts +176 -0
  742. package/src/wirings/queue/queue-runner.ts +12 -31
  743. package/src/wirings/queue/queue.types.ts +25 -90
  744. package/src/wirings/queue/register-queue-helper.ts +0 -14
  745. package/src/wirings/queue/signed-queue-service.ts +60 -0
  746. package/src/wirings/queue/validate-worker-config.ts +2 -28
  747. package/src/wirings/role/define-system-role.ts +33 -0
  748. package/src/wirings/role/index.ts +13 -0
  749. package/src/wirings/role/role.test.ts +104 -0
  750. package/src/wirings/role/role.types.ts +47 -0
  751. package/src/wirings/role/validate-role-definitions.ts +93 -0
  752. package/src/wirings/rpc/addon-auth-tags.test.ts +223 -0
  753. package/src/wirings/rpc/addon-runner.ts +0 -56
  754. package/src/wirings/rpc/addon-scopes.test.ts +225 -0
  755. package/src/wirings/rpc/remote-addon-auth.ts +9 -16
  756. package/src/wirings/rpc/rpc-runner.test.ts +192 -6
  757. package/src/wirings/rpc/rpc-runner.ts +145 -127
  758. package/src/wirings/rpc/rpc-types.ts +11 -6
  759. package/src/wirings/rpc/wire-addon.test.ts +43 -1
  760. package/src/wirings/rpc/wire-addon.ts +99 -0
  761. package/src/wirings/rpc/wire-remote-addon.ts +9 -29
  762. package/src/wirings/scheduler/log-schedulers.ts +0 -4
  763. package/src/wirings/scheduler/scheduler-runner.test.ts +1 -8
  764. package/src/wirings/scheduler/scheduler-runner.ts +0 -2
  765. package/src/wirings/scheduler/scheduler.types.ts +1 -14
  766. package/src/wirings/scope/{wire-scope.ts → define-scope.ts} +5 -6
  767. package/src/wirings/scope/index.ts +1 -1
  768. package/src/wirings/scope/scope.test.ts +1 -2
  769. package/src/wirings/scope/scope.types.ts +7 -9
  770. package/src/wirings/scope/validate-scope-definitions.ts +3 -21
  771. package/src/wirings/secret/index.ts +1 -1
  772. package/src/wirings/secret/secret.types.ts +19 -15
  773. package/src/wirings/secret/validate-secret-definitions.ts +2 -4
  774. package/src/wirings/trigger/trigger-runner.ts +1 -27
  775. package/src/wirings/trigger/trigger.types.ts +1 -82
  776. package/src/wirings/variable/index.ts +1 -1
  777. package/src/wirings/variable/validate-variable-definitions.ts +2 -4
  778. package/src/wirings/variable/variable.types.ts +1 -13
  779. package/src/wirings/virtual-user/index.ts +88 -0
  780. package/src/wirings/virtual-user/prepare-virtual-user-run.test.ts +115 -0
  781. package/src/wirings/virtual-user/prepare-virtual-user-run.ts +95 -0
  782. package/src/wirings/virtual-user/run-virtual-user.test.ts +765 -0
  783. package/src/wirings/virtual-user/run-virtual-user.ts +671 -0
  784. package/src/wirings/virtual-user/virtual-user-agents.test.ts +65 -0
  785. package/src/wirings/virtual-user/virtual-user-agents.ts +57 -0
  786. package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +215 -0
  787. package/src/wirings/virtual-user/virtual-user-catalogue.ts +184 -0
  788. package/src/wirings/virtual-user/virtual-user-derive.test.ts +398 -0
  789. package/src/wirings/virtual-user/virtual-user-derive.ts +173 -0
  790. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +63 -0
  791. package/src/wirings/virtual-user/virtual-user-dispositions.ts +213 -0
  792. package/src/wirings/virtual-user/virtual-user-intents.test.ts +208 -0
  793. package/src/wirings/virtual-user/virtual-user-intents.ts +185 -0
  794. package/src/wirings/virtual-user/virtual-user-rng.test.ts +72 -0
  795. package/src/wirings/virtual-user/virtual-user-rng.ts +50 -0
  796. package/src/wirings/virtual-user/virtual-user-run-store.ts +98 -0
  797. package/src/wirings/virtual-user/virtual-user-target.ts +47 -0
  798. package/src/wirings/virtual-user/virtual-user.types.ts +219 -0
  799. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +19 -20
  800. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -4
  801. package/src/wirings/workflow/feature.ts +0 -19
  802. package/src/wirings/workflow/graph/graph-node.ts +0 -136
  803. package/src/wirings/workflow/graph/graph-runner.test.ts +20 -19
  804. package/src/wirings/workflow/graph/graph-runner.ts +6 -41
  805. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -4
  806. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -58
  807. package/src/wirings/workflow/index.ts +10 -44
  808. package/src/wirings/workflow/pikku-scenario-service.ts +235 -61
  809. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -39
  810. package/src/wirings/workflow/pikku-workflow-service.ts +77 -674
  811. package/src/wirings/workflow/run-timeline.test.ts +7 -19
  812. package/src/wirings/workflow/run-timeline.ts +0 -56
  813. package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -1
  814. package/src/wirings/workflow/scenario-cookie-jar.ts +0 -25
  815. package/src/wirings/workflow/scenario-expectations.test.ts +2 -7
  816. package/src/wirings/workflow/scenario-hooks.test.ts +2 -7
  817. package/src/wirings/workflow/scenario-poll.test.ts +0 -2
  818. package/src/wirings/workflow/scenario-poll.ts +0 -15
  819. package/src/wirings/workflow/scenario-prose.test.ts +5 -7
  820. package/src/wirings/workflow/scenario-prose.ts +1 -29
  821. package/src/wirings/workflow/scenario-service.test.ts +2 -10
  822. package/src/wirings/workflow/scenario-step-guards.ts +1 -14
  823. package/src/wirings/workflow/scenario-step.test.ts +163 -19
  824. package/src/wirings/workflow/scenario-step.types.ts +94 -12
  825. package/src/wirings/workflow/scenario-surface.test.ts +146 -0
  826. package/src/wirings/workflow/scenario-surface.ts +71 -0
  827. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +14 -15
  828. package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -4
  829. package/src/wirings/workflow/workflow-inline-authority.test.ts +169 -0
  830. package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -2
  831. package/src/wirings/workflow/workflow-invocation-id.ts +2 -22
  832. package/src/wirings/workflow/workflow-mirror.test.ts +0 -7
  833. package/src/wirings/workflow/workflow-on-error.test.ts +0 -9
  834. package/src/wirings/workflow/workflow-queue-workers.ts +0 -21
  835. package/src/wirings/workflow/workflow-replay-snapshot.test.ts +8 -7
  836. package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -5
  837. package/src/wirings/workflow/workflow-run-context.test.ts +5 -10
  838. package/src/wirings/workflow/workflow-run-polling.test.ts +0 -5
  839. package/src/wirings/workflow/workflow-step-ordinal.test.ts +19 -4
  840. package/src/wirings/workflow/workflow-step-session.test.ts +0 -7
  841. package/src/wirings/workflow/workflow.types.ts +5 -201
  842. package/tsconfig.tsbuildinfo +1 -1
  843. package/tsconfig.type-tests.json +12 -0
  844. package/src/middleware/timeout.ts +0 -22
  845. package/src/pikku-response.ts +0 -5
  846. package/src/wirings/mcp/mcp-endpoint-registry.test.d.ts +0 -1
  847. package/src/wirings/workflow/dsl/index.ts +0 -36
  848. package/src/wirings/workflow/graph/index.ts +0 -15
@@ -0,0 +1,55 @@
1
+ ---
2
+ type: overview
3
+ title: Security decisions
4
+ description: Who may do what in core — gates, defaults, and the failures they are chosen to cause
5
+ ---
6
+
7
+ # Security decisions
8
+
9
+ A rule about who may do what, and which way it fails when it is unsure.
10
+
11
+ <!-- pikku:knowledge-index -->
12
+ - [A dropped audit write is always logged](a-dropped-audit-write-is-always-logged.md) — The no-op audit service falls back to the singleton logger when the wire carries none, so an unconfigured audit call is never silent
13
+ - [An actor's missing approval decision defaults to denied](actor-flow-missing-approval-decisions-default-to-denied.md) — Every pending tool call gets an explicit decision; an id the persona LLM omitted is denied, so a dropped field can never read as consent
14
+ - [Actor sign-in is proven by Set-Cookie, not a non-empty jar](actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md) — HttpScenarioActor tracks its own signedIn flag and requires the sign-in response itself to set a cookie, because a populated jar proves nothing
15
+ - [Actor sign-in only works for actor-flagged users](actor-sign-in-only-works-for-actor-flagged-users.md) — The scenario actor secret mints sessions for user rows flagged actor and nothing else, so holding it never impersonates a real user
16
+ - [Addon auth and tags only tighten, and resolve where the function runs](addon-auth-and-tags-only-tighten.md) — wireAddon auth and tags are applied in runPikkuFunc like scopes, but auth:false is ignored and tags resolve against the consuming app's tag groups rather than the addon package's
17
+ - [Addon auth and tag gates apply wherever the function runs, including inside the addon](addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md) — wireAddon's auth and tags moved from the namespaced RPC boundary into runPikkuFunc, so they also apply to direct wirings and to bare intra-addon calls
18
+ - [Addon scopes are resolved where the function runs](addon-scopes-are-resolved-where-the-function-runs.md) — wireAddon scopes are merged inside runPikkuFunc rather than at namespace resolution, because most wirings reach an addon function without ever resolving a namespace
19
+ - [Only a Symbol-branded framework result can request tool approval](ai-agent-approval-forwarding-requires-a-symbol-brand.md) — Approval markers are trusted from the APPROVAL_REQUIRED Symbol on a forwardsApproval tool, never from a JSON key an LLM could emit
20
+ - [Credential requests are trusted only when Symbol-branded](ai-agent-credential-requests-are-symbol-branded.md) — The string key is a wire field; the Symbol is the capability, and only core can mint it
21
+ - [An agent requires a session only when auth is true, but always enforces scopes and permissions](ai-agent-gate-requires-a-session-only-when-auth-is-true.md) — Agents follow pikkuSessionlessFunc semantics so crons and queue workers can run them; scopes are an AND gate checked before any permission I/O
22
+ - [An agent ownership failure never echoes the resource it refused](ai-agent-ownership-failures-never-echo-the-resource.md) — assertResourceOwner throws a bare ForbiddenError so the error cannot be used as an existence oracle, at the cost of thinner debugging output
23
+ - [Resuming a suspended agent run re-runs the agent's authorization gate](ai-agent-resume-re-runs-the-authorization-gate.md) — Ownership of the run is not enough — a grant revoked while the run was suspended must block the approval
24
+ - [Agent thread ownership fails closed when there is no principal](ai-agent-sessionless-deployments-have-no-thread-ownership.md) — A sessionless caller gets an ephemeral owner and reaches no stored thread, rather than reaching all of them
25
+ - [An agent thread key is always prefixed with the trusted principal](ai-agent-thread-ownership-composes-the-session-principal.md) — Ownership keys are composed as principal:resourceId, so a client id can sub-divide its own boundary but never widen it
26
+ - [Agent tool permission filtering reads the live function config, not the metadata](ai-agent-tool-filtering-reads-the-live-function-config.md) — The pikkuAuth brand survives only on live permission objects, so a metadata-driven check would silently admit every gated tool
27
+ - [An empty owners constraint matches nothing](an-empty-owners-constraint-matches-nothing.md) — owners is an authorization boundary, so every storage backend must treat [] as no rows rather than no filter
28
+ - [An exposed function with no gate is reported at codegen, not at boot](an-exposed-ungated-function-is-a-codegen-warning.md) — The check runs in the inspector where function meta and every wireAddon declaration are both in hand, because neither source alone can tell a gated function from an ungated one
29
+ - [The console addon's privileged functions gate themselves](console-addon-privileged-functions-gate-themselves.md) — Thread listing is owner-scoped unless the caller holds admin, and addon installation requires an admin session, rather than trusting the host to register a global permission
30
+ - [Core's SSRF guard matches host literals because edge runtimes have no DNS](core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md) — safeFetch rejects internal address literals and re-validates every redirect hop; it cannot stop DNS rebinding
31
+ - [Core secrets are encrypted with a per-secret DEK wrapped by a KEK](core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md) — Envelope encryption keeps ciphertext untouched during key rotation, at the cost of storing two blobs per secret
32
+ - [Gateway handlers run through the function runner gate](gateway-handlers-run-through-the-function-runner-gate.md) — A gateway's handler is registered as a real pikku function and invoked via runPikkuFunc, because calling it directly skips auth, scopes and permissions
33
+ - [Gateway middleware sessions must be bridged onto the wire](gateway-middleware-sessions-must-be-bridged-onto-the-wire.md) — Gateway middleware calling wire.setSession writes to a session service the handler's invocation never reads, so the session is copied onto wire.session before the gate runs
34
+ - [Global permissions and function permissions are independent gates](global-permissions-and-function-permissions-are-independent-gates.md) — Globals AND together and can only narrow access; a function's own group ORs internally and is never satisfied by a global
35
+ - [HTTP error detail is withheld from clients in production](http-error-detail-is-withheld-from-clients-in-production.md) — 5xx bodies carry only a trace id in production; exposeErrors can widen that in development but never in production
36
+ - [HTTP request bodies are bounded before they are buffered](http-request-bodies-are-bounded-before-they-are-buffered.md) — Content-Length is rejected up front and the stream is measured as it arrives, because that header is optional and attacker-controlled
37
+ - [MCP internal error details are double-gated on production](mcp-internal-error-details-are-double-gated-on-production.md) — exposeErrors is checked again against isProduction() at throw time so an explicit true cannot leak stack traces from a production build
38
+ - [Passphrases are stretched, key material is expanded](passphrases-are-stretched-key-material-is-expanded.md) — PBKDF2 guards low-entropy human input; HKDF derives from high-entropy secrets, and the two are never swapped
39
+ - [Auth filtering requires live permission functions, never their metadata](permission-auth-filtering-requires-live-permission-functions.md) — checkAuthPermissions collects pikkuAuth-branded predicates off the real config; passing metadata would let every gated tool through
40
+ - [Pikku carries actor scopes as data and the app grants them](pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md) — scopes and roles on a ScenarioActorConfig are transported, never applied — the app's own seed reads them back and performs the grant
41
+ - [Queue job identities are signed at enqueue](queue-job-identities-are-signed-at-enqueue.md) — A job's pikkuUserId is an HMAC claim bound to the queue and payload; an unverifiable claim is dropped, never trusted
42
+ - [Queue jobs carry the producer's pikku user id](queue-jobs-carry-the-producers-pikku-user-id.md) — A job's pikkuUserId is trusted as identity by the worker, so enqueue rights are effectively act-as-user rights
43
+ - [Remote addon tokens are client credentials, not mesh trust](remote-addon-tokens-are-client-credentials-not-mesh-trust.md) — wireRemoteAddon authenticates as a client to a hosted library and fails closed on an empty token; it never uses PIKKU_REMOTE_SECRET
44
+ - [A scaffolded surface is authenticated unless the config opts out in writing](scaffold-features-are-authenticated-unless-opted-out.md) — scaffold.<feature> became boolean | { auth, path }, where true means authenticated — going public requires typing { auth: false }, and the legacy 'auth' | 'no-auth' strings are refused rather than coerced
45
+ - [Scenario-step functions are never externally invocable over RPC](scenario-step-functions-are-never-externally-invocable.md) — rpcExposed requires expose and rejects scenarioStep, so test steps stay reachable only from inside a scenario run
46
+ - [Scope resolution happens at the session boundary and scope sync never deletes](scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md) — ScopeService is called when a session is built, never by the function runner, and syncScopes only ever adds — revoking is an explicit operation
47
+ - [Self-authentication is declared, not detected](self-authentication-is-declared-not-detected.md) — A function that authorizes callers in its own body says so with selfAuthenticated; codegen never tries to infer it
48
+ - [Signed content URLs bind the request path and verify fail-closed](signed-content-urls-bind-the-request-path.md) — A signature that only carries timestamps authorizes every asset, and a verifier with no key must refuse rather than allow
49
+ - [Webhook bodies are signed before they are enqueued](webhook-bodies-are-signed-before-they-are-enqueued.md) — QueueWebhookService computes the HMAC at enqueue time so the signing key never travels in the queue payload
50
+ - [A scenario actor step always goes over the real transport and never through internal dispatch](workflow-actor-steps-always-use-the-real-transport.md) — Internal dispatch would bypass auth middleware and permissions, turning a scenario into a green health check that proves nothing
51
+ - [An approval decision is stored raw and validated on replay, and an invalid one closes the gate rather than failing the run](workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md) — The schema only exists inside the workflow body, and letting an external payload fail the run would let any caller kill a workflow
52
+ - [A queued workflow step rehydrates its session from the persisted run wire](workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md) — The queue job payload is just `{ runId }`, so without threading `pikkuUserId` an authed step sees no session and throws
53
+ - [Scenario sessions are isolated per actor and reset between scenarios](workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md) — One jar per actor keeps two personas from sharing a session; a browser reset keeps one scenario from leaving the next signed in as somebody else
54
+ - [A scenario step is never registered as a callable RPC and never dispatched on the queue](workflow-scenario-steps-are-never-network-invocable.md) — A step drives a browser and holds an actor's session, so exposing it as an RPC would put that reach on the network
55
+ <!-- /pikku:knowledge-index -->
@@ -0,0 +1,27 @@
1
+ ---
2
+ type: decision
3
+ title: MCP internal error details are double-gated on production
4
+ description: exposeErrors is checked again against isProduction() at throw time so an explicit true cannot leak stack traces from a production build
5
+ tags: mcp
6
+ ---
7
+
8
+ # MCP internal error details are double-gated on production
9
+
10
+ `RunMCPEndpointParams.exposeErrors` in
11
+ `packages/core/src/wirings/mcp/mcp-runner.ts` defaults to `!isProduction()`, and
12
+ `runMCPPikkuFunc` checks `exposeErrors && !isProduction()` *again* when building
13
+ the `-32603` internal-error response that carries `{ message, stack }`. The
14
+ second check looks redundant against the default — it is not. The default only
15
+ applies when the caller omits the option; a caller that passes
16
+ `exposeErrors: true` explicitly would otherwise put the raw exception message and
17
+ stack trace into a JSON-RPC response served from production.
18
+
19
+ Internal errors reaching that branch are by definition unmapped — no `mcpCode` —
20
+ so their message is whatever the underlying failure produced: a database error, a
21
+ file path, a credential in a connection string. MCP responses go to a model
22
+ client, so anything in `data` is exfiltrated into a transcript.
23
+
24
+ **What this rules out:** collapsing `exposeErrors && !isProduction()` to
25
+ `exposeErrors` on the grounds that the default already handles production, and
26
+ adding any other MCP error path that serializes `e.message` or `e.stack` without
27
+ its own `isProduction()` guard.
@@ -0,0 +1,40 @@
1
+ ---
2
+ type: decision
3
+ title: Passphrases are stretched, key material is expanded
4
+ description: PBKDF2 guards low-entropy human input; HKDF derives from high-entropy secrets, and the two are never swapped
5
+ tags: crypto
6
+ ---
7
+
8
+ # Passphrases are stretched, key material is expanded
9
+
10
+ `packages/core/src/crypto-utils.ts` carries two derivation paths that look
11
+ alike and are not interchangeable.
12
+
13
+ `encryptJSON` / `decryptJSON` take a **passphrase** and run PBKDF2-HMAC-SHA256
14
+ at 600,000 iterations over a per-message random salt. They protect data at rest
15
+ — the secret and credential services — where the KEK may be something a human
16
+ chose, so the work factor is the only thing standing between a leaked ciphertext
17
+ and a dictionary.
18
+
19
+ `encryptWithKeyMaterial` / `decryptWithKeyMaterial` take **high-entropy key
20
+ material** and use HKDF-SHA256, which is effectively free. They protect the
21
+ remote-RPC session envelope, whose secret is a generated deployment value. HKDF
22
+ offers no brute-force resistance at all, which is why the minimum length is
23
+ enforced fail-closed at both ends: the entropy has to live in the secret,
24
+ because nothing else supplies it.
25
+
26
+ The split exists because the cost profiles are opposites. Stretching on a
27
+ per-request path cost ~269ms per remote hop and would have consumed most of a
28
+ Cloudflare Workers CPU budget; expanding a human passphrase would leave it
29
+ one cheap hash from being guessed. Both blobs use the same
30
+ `[salt:16][iv:12][ct+tag]` layout, so they are indistinguishable on the wire but
31
+ cryptographically disjoint — feeding one to the other's verifier rejects.
32
+
33
+ The `info` parameter namespaces each use of the same key material, so a key
34
+ derived for one purpose cannot decrypt another's payload.
35
+
36
+ **What this rules out:** using `encryptJSON` on any per-request path; using the
37
+ key-material functions for anything a human types; sharing one derived key
38
+ across two purposes by passing the same `info`; and lowering the minimum length
39
+ to accommodate an existing short secret. See
40
+ [[the-kek-salt-is-scoped-to-the-key-version]].
@@ -0,0 +1,31 @@
1
+ ---
2
+ type: decision
3
+ title: Auth filtering requires live permission functions, never their metadata
4
+ description: checkAuthPermissions collects pikkuAuth-branded predicates off the real config; passing metadata would let every gated tool through
5
+ tags: permissions
6
+ ---
7
+
8
+ # Auth filtering requires live permission functions, never their metadata
9
+
10
+ `checkAuthPermissions` in `packages/core/src/permissions.ts` answers "may this
11
+ session see this function/agent at all", for listing and tool-filtering. It
12
+ collects only predicates branded `__pikkuAuth` — from the globals and from the
13
+ supplied group — and ignores data-dependent permissions, which cannot be
14
+ evaluated without request data at filter time. If no auth predicates exist at
15
+ all, the answer is `true`: nothing is gating visibility.
16
+
17
+ `funcPermissions` must therefore be the **live** `CorePermissionGroup` taken from
18
+ the function or agent config, not the metadata form. The `__pikkuAuth` brand only
19
+ survives on the actual predicate objects, and the by-name registry that metadata
20
+ entries would resolve against is never populated. Passing metadata compiles
21
+ cleanly, collects nothing, hits the `authPerms.length === 0` branch and returns
22
+ `true` — every gated tool becomes visible to every session, silently and with no
23
+ error anywhere.
24
+
25
+ Note also that the collected predicates are ORed: any one passing auth predicate
26
+ grants visibility. This is a visibility filter only; `runPermissions` still runs
27
+ the full gate on invocation.
28
+
29
+ **What this rules out:** feeding this function anything derived from function
30
+ metadata or a serialized permission description, and treating a `true` result as
31
+ authorization to invoke rather than permission to list.
@@ -0,0 +1,26 @@
1
+ ---
2
+ type: decision
3
+ title: Pikku carries actor scopes as data and the app grants them
4
+ description: scopes and roles on a ScenarioActorConfig are transported, never applied — the app's own seed reads them back and performs the grant
5
+ tags: services
6
+ ---
7
+
8
+ # Pikku carries actor scopes as data and the app grants them
9
+
10
+ `ScenarioActorConfig.scopes` and `.roles`
11
+ (`packages/core/src/services/scenario-actors-service.ts`) come from
12
+ `pikku.config.json` and are carried through to `scenarioActorConfigs`. Nothing in
13
+ core reads them to grant anything. The app's seed reads them back off that config
14
+ and performs the grants itself.
15
+
16
+ Core cannot do the granting: which scope store exists, whether roles have been
17
+ created, and what a role means are all the application's own. Worse, a framework
18
+ that granted scopes would be a framework that can escalate an actor's privileges
19
+ from a config file — the one place where a scenario author would least expect a
20
+ security decision to take effect. Keeping the fields inert makes the grant an act
21
+ the app performs deliberately, in code it owns, against a store it wired.
22
+
23
+ **What this rules out:** teaching `createHttpScenarioActors` (or any core service)
24
+ to call `ScopeService.addScopeToUser` / `addUserToRole` from these fields, and
25
+ treating a scope listed on an actor config as evidence that the actor holds it.
26
+ If a scenario fails on a missing scope, the fix is in the app's seed, not here.
@@ -0,0 +1,69 @@
1
+ ---
2
+ type: decision
3
+ title: Queue job identities are signed at enqueue
4
+ description: A job's pikkuUserId is an HMAC claim bound to the queue and payload; an unverifiable claim is dropped, never trusted
5
+ tags: queue, crypto, security
6
+ ---
7
+
8
+ # Queue job identities are signed at enqueue
9
+
10
+ `QueueJob.pikkuUserId` used to be a bare string that `runQueueJob`
11
+ (`packages/core/src/wirings/queue/queue-runner.ts`) copied onto the wire, where
12
+ `defaultPikkuUserIdResolver` resolved it and `resolveSession` loaded that user's
13
+ session out of the `sessionStore`. Anyone able to write to the queue backend —
14
+ a `LPUSH` against Redis, a `SendMessage` against SQS — could name any user and
15
+ the worker would run as them.
16
+
17
+ The field now carries a signed claim instead:
18
+
19
+ ```
20
+ pq1.<base64url({"u":<pikkuUserId>,"q":<queueName>,"j":<jobId>?})>.<base64url(HMAC-SHA256)>
21
+ ```
22
+
23
+ The HMAC covers `pq1.<encoded claim>.<canonical JSON of the job payload>`, so a
24
+ signature cannot be lifted onto a different queue, a different payload, or —
25
+ when the producer knew the job id — a different job. `jobId` is optional
26
+ because most adapters (SQS, Cloudflare Queues, Azure Storage Queues) mint the id
27
+ after `add` returns and never see the producer's; binding the payload is what
28
+ holds in every adapter. Canonicalization sorts keys after a JSON round trip, so
29
+ transport reserialization cannot change the digest.
30
+
31
+ The key is expanded with HKDF from `PIKKU_QUEUE_IDENTITY_SECRET`, read through
32
+ the `SecretService`, under the `pikku:queue-identity` info namespace — the same
33
+ deployment secret therefore cannot produce a key that opens the remote-RPC
34
+ envelope. `signWithKeyMaterial` / `verifyWithKeyMaterial` in
35
+ `packages/core/src/crypto-utils.ts` are WebCrypto-only because that file is in
36
+ the Cloudflare Workers build; the `node:crypto` helpers behind
37
+ `WebhookService.sign` are not reachable from it.
38
+
39
+ Verification lives in `runQueueJob`, the single funnel every adapter calls.
40
+ `SignedQueueService` wraps any `QueueService` to sign on the way out.
41
+
42
+ Failure directions are deliberately asymmetric:
43
+
44
+ - **No secret configured**: the claim is dropped, the job still runs with no
45
+ `pikkuUserId`, and one warning is logged per process. Hard-failing would break
46
+ every deployment on upgrade, and per-job logging is an attacker-triggerable
47
+ flood.
48
+ - **Secret configured, claim does not verify**: the identity is dropped and the
49
+ rejection is logged per job — it sits alongside the per-job logs `runQueueJob`
50
+ already writes, so it adds no flood an attacker did not already have.
51
+ - **Secret too short**: signing throws `WeakKeyMaterialError` at enqueue, so the
52
+ misconfiguration surfaces on the producer, while the worker drops the identity
53
+ rather than failing the job.
54
+
55
+ The threat model is a **compromised or shared queue backend**, nothing more. The
56
+ application process must hold the signing secret in order to sign, so an
57
+ attacker who has code execution inside the app can mint any claim it likes. This
58
+ defends the queue as a transport, not the app as a host. It also does not stop
59
+ replay of a byte-identical job, which is indistinguishable from the redelivery
60
+ every queue already performs; revocation is by rotating the secret.
61
+
62
+ **What this rules out:** treating `JobOptions.pikkuUserId` as trusted anywhere
63
+ downstream of the queue; letting a client-supplied value flow into it without an
64
+ authorization check first (signing proves the producer held the secret, not that
65
+ the producer was entitled to name that user); adding a `node:crypto` import to
66
+ `crypto-utils.ts`; reusing `pikku:queue-identity` as the info string for any
67
+ other purpose; and claiming this mitigates application compromise. See
68
+ [[queue-jobs-carry-the-producers-pikku-user-id]] and
69
+ [[passphrases-are-stretched-key-material-is-expanded]].
@@ -0,0 +1,39 @@
1
+ ---
2
+ type: decision
3
+ title: Queue jobs carry the producer's pikku user id
4
+ description: A job's pikkuUserId is trusted as identity by the worker, so enqueue rights are effectively act-as-user rights
5
+ tags: queue
6
+ ---
7
+
8
+ # Queue jobs carry the producer's pikku user id
9
+
10
+ `JobOptions.pikkuUserId` (`packages/core/src/wirings/queue/queue.types.ts`) is
11
+ set by whoever enqueues the job. The adapter surfaces it as
12
+ `QueueJob.pikkuUserId`, `runQueueJob` in
13
+ `packages/core/src/wirings/queue/queue-runner.ts` copies it onto the wire as
14
+ `PikkuQueue.pikkuUserId`, and `resolveSession` in
15
+ `packages/core/src/function/function-runner.ts` then resolves it through
16
+ `defaultPikkuUserIdResolver` and loads that user's session out of the
17
+ `sessionStore`. The worker function runs with that session.
18
+
19
+ The claim is now HMAC-signed at enqueue and verified in `runQueueJob` — see
20
+ [[queue-job-identities-are-signed-at-enqueue]], which supersedes the "any
21
+ producer may name any user" reading below. Everything here still holds for the
22
+ *authorization* question: signing proves the producer held the deployment
23
+ secret, not that it was entitled to name that user.
24
+
25
+ There is no re-authentication at the worker boundary — the queue payload *is* the
26
+ credential. Workers run with `auth: false`, so nothing downstream re-checks that
27
+ the producer was entitled to name that user. This is deliberate: the whole point
28
+ is to let a background job resolve the same per-user credentials the original
29
+ request had, without persisting a token in the queue. The cost is that write
30
+ access to the queue is equivalent to being able to act as any user whose session
31
+ is in the store.
32
+
33
+ **What this rules out:** exposing job enqueue to untrusted callers, or letting a
34
+ client-supplied field flow into `JobOptions.pikkuUserId` without an authorization
35
+ check first. It also rules out treating the queue as an authorization boundary —
36
+ do not add a "the worker validated the producer's rights" assumption anywhere
37
+ downstream, and do not drop the id from the wire on the theory that workers are
38
+ unauthenticated anyway. Dropping an id that fails *signature* verification is a
39
+ different matter and is what the worker now does.
@@ -0,0 +1,34 @@
1
+ ---
2
+ type: decision
3
+ title: Remote addon tokens are client credentials, not mesh trust
4
+ description: wireRemoteAddon authenticates as a client to a hosted library and fails closed on an empty token; it never uses PIKKU_REMOTE_SECRET
5
+ tags: rpc
6
+ ---
7
+
8
+ # Remote addon tokens are client credentials, not mesh trust
9
+
10
+ `resolveRemoteAddonToken` in
11
+ `packages/core/src/wirings/rpc/remote-addon-auth.ts` resolves the bearer token a
12
+ `wireRemoteAddon` consumer sends to the host. This is a **client** authenticating
13
+ to a hosted library — it is not pikku's trusted machine-to-machine mesh, which
14
+ uses `PIKKU_REMOTE_SECRET`. Conflating the two would hand a third-party addon
15
+ host a credential that grants mesh-level trust inside the consumer's own
16
+ deployment.
17
+
18
+ The consumer binds the addon's declared auth requirement to one of three local
19
+ sources: `credentialId`, a per-user credential read through `wire.getCredential`
20
+ and therefore scoped to `pikkuUserId`; `secretId`, a platform key from the
21
+ secrets service; or `resolve`, a custom escape hatch. The resolved token is never
22
+ logged or traced. Binding a `credentialId` without a wire that supports
23
+ credentials throws rather than falling back to a shared secret.
24
+
25
+ Resolution fails closed. `null` is returned only when no auth is bound at all,
26
+ which is the addon declaring its remote surface public. Once auth *is* bound, a
27
+ resolved value of `null`, `undefined` or `''` raises `RemoteAddonAuthError` (401)
28
+ instead of dispatching an unauthenticated request that the host might accept as
29
+ anonymous.
30
+
31
+ **What this rules out:** defaulting to `PIKKU_REMOTE_SECRET` or any ambient
32
+ credential when the bound source comes up empty, treating an empty token as
33
+ "public", and adding the token to log lines, trace headers or error messages for
34
+ debugging.
@@ -0,0 +1,49 @@
1
+ ---
2
+ type: decision
3
+ title: A scaffolded surface is authenticated unless the config opts out in writing
4
+ description: scaffold.<feature> became boolean | { auth, path }, where true means authenticated — going public requires typing { auth: false }, and the legacy 'auth' | 'no-auth' strings are refused rather than coerced
5
+ tags: config, authorization, codegen, scaffold
6
+ ---
7
+
8
+ # A scaffolded surface is authenticated unless the config opts out in writing
9
+
10
+ `scaffold.<feature>` was `'auth' | 'no-auth' | false`. Two things were wrong
11
+ with it, and they compounded.
12
+
13
+ The auth dimension asked the wrong question of some features and the right one
14
+ of others. For `rpc` it is a blanket "no anonymous RPC in this app", set on a
15
+ dispatcher that cannot know what it dispatches to — wrong the moment one
16
+ legitimately public sessionless function exists. For `userAdmin` it was
17
+ redundant: the generated functions are `pikkuFunc` with `scopes:
18
+ ['admin:users:list']`, gated twice over already. But for `agent`, `workflow`,
19
+ `events` and `scenarios` it was the *only* gate, because those generate real
20
+ endpoints the app never authors and has nowhere else to declare a gate for.
21
+ A uniform collapse to boolean would have silently opened four surfaces.
22
+
23
+ And the value read like a preference. `"rpc": "no-auth"` looks like a
24
+ starter-file setting; it was a live authorization decision, three directories
25
+ from the functions it governed. That is the shape the console incident took.
26
+
27
+ The type is now `boolean | { auth?: boolean; path?: string }`. `true` means
28
+ enabled **and authenticated**; a surface becomes public only by writing
29
+ `{ auth: false }`. Omitting a field can then never open anything — the failure
30
+ mode of a forgotten flag is a locked door. Features with no auth dimension
31
+ (`webhook`, `remoteRpc`, whose generator hardcodes `auth: false`) simply ignore
32
+ it.
33
+
34
+ The object form is also what makes the legacy strings safe to remove. An
35
+ earlier design used `string` for the output path, under which `"no-auth"` would
36
+ have parsed as *a file named `no-auth`* — every unmigrated config silently
37
+ producing nonsense instead of failing. With `boolean | object`, a string is
38
+ never valid, so `resolveScaffoldFeature` refuses `'auth'` and `'no-auth'` by
39
+ name and prints the replacement. Coercing them was rejected outright: the value
40
+ it would coerce to is the one that caused the incident.
41
+
42
+ Reading happens once, in `pikku-cli-config.ts`, so a legacy value fails at load
43
+ with the migration named rather than downstream where it has already become
44
+ something plausible.
45
+
46
+ **What this rules out:** a bare `true` that means "public"; inferring a
47
+ feature's auth posture from its default; using `string` for the output path
48
+ while the legacy string values still exist in the wild; and collapsing the auth
49
+ dimension uniformly across features that do not all have one.
@@ -0,0 +1,30 @@
1
+ ---
2
+ type: decision
3
+ title: Scenario-step functions are never externally invocable over RPC
4
+ description: rpcExposed requires expose and rejects scenarioStep, so test steps stay reachable only from inside a scenario run
5
+ tags: rpc
6
+ ---
7
+
8
+ # Scenario-step functions are never externally invocable over RPC
9
+
10
+ `ContextAwareRPCService.rpcExposed` in
11
+ `packages/core/src/wirings/rpc/rpc-runner.ts` is the entry point for RPCs that
12
+ arrive from outside the process. It resolves the function's meta and throws
13
+ `RPCNotFoundError` unless `functionMeta.expose` is set **and**
14
+ `functionMeta.scenarioStep` is falsy — the same 404 an unknown name gets, so the
15
+ existence of a hidden function is not disclosed.
16
+
17
+ A scenario step is a piece of a test scenario: it may drive a browser, assert
18
+ against fixtures, or reach for privileged setup helpers. Steps are dispatched by
19
+ name from inside a scenario run through the internal `rpc` path, which does not
20
+ consult `expose`. If a step were also reachable from the outside, any caller who
21
+ guessed its name would get an unauthenticated handle on test tooling in whatever
22
+ environment the scenario code shipped to.
23
+
24
+ The two conditions are independent and both required: `expose` opts a function
25
+ into the external surface, `scenarioStep` opts it back out regardless.
26
+
27
+ **What this rules out:** collapsing the check to `!functionMeta.expose`,
28
+ returning a distinct "forbidden" error that confirms the name exists, and routing
29
+ external traffic through `rpc` instead of `rpcExposed` for convenience — `rpc`
30
+ performs no exposure check at all.
@@ -0,0 +1,28 @@
1
+ ---
2
+ type: decision
3
+ title: Scope resolution happens at the session boundary and scope sync never deletes
4
+ description: ScopeService is called when a session is built, never by the function runner, and syncScopes only ever adds — revoking is an explicit operation
5
+ tags: services
6
+ ---
7
+
8
+ # Scope resolution happens at the session boundary and scope sync never deletes
9
+
10
+ Implementations of `ScopeService` (`packages/core/src/services/scope-service.ts`)
11
+ are called at the session boundary — better-auth's `mapSession`, for instance —
12
+ and never by the function runner. The runner reads `session.scopes` and performs
13
+ no I/O of its own, which is what keeps it viable on Workers and Lambda. Because
14
+ the session is rebuilt per request, a scope change takes effect on the next call:
15
+ nothing is cached and there is nothing to invalidate.
16
+
17
+ `syncScopes` is additive and never deletes. Scopes are declared in code, so a
18
+ declaration removed in a deploy would otherwise revoke a live grant the moment
19
+ the new build boots — silently, mid-rollout, for everyone holding it. Instead the
20
+ row stays and goes inert: `listScopes` reports it as `declared: false`, no
21
+ function can require it, `findStaleScopes` surfaces it for `pikku scopes audit`,
22
+ and `pikku scopes prune` is the explicit act that removes it.
23
+
24
+ **What this rules out:** having the function runner resolve scopes per call (it
25
+ would put a store round-trip in every request path and break the Workers/Lambda
26
+ story), caching resolved scopes anywhere, and making `syncScopes` reconcile —
27
+ diffing declared against stored and deleting the difference. A deploy must never
28
+ be able to revoke a grant as a side effect.
@@ -0,0 +1,34 @@
1
+ ---
2
+ type: decision
3
+ title: Self-authentication is declared, not detected
4
+ description: A function that authorizes callers in its own body says so with selfAuthenticated; codegen never tries to infer it
5
+ tags: permissions, codegen
6
+ ---
7
+
8
+ # Self-authentication is declared, not detected
9
+
10
+ Some functions are genuinely closed while carrying no session, scope or
11
+ permission: a webhook receiver that verifies a signature, a handler that
12
+ redeems a signed invite, an exchange endpoint that validates a token before it
13
+ does anything. Nothing in meta distinguishes those from a function nobody
14
+ remembered to gate, so `validateExposedFunctionsGated` (PKU574) would warn about
15
+ them on every build.
16
+
17
+ The fix is a declaration — `selfAuthenticated: true` on the function config —
18
+ not analysis of the body. Detection would have to recognise an open-ended set of
19
+ authorization idioms, and it fails in the expensive direction: a body that
20
+ *looks* like it checks something silences the warning for a function that
21
+ checks nothing. A declaration cannot be wrong by accident. Someone typed it,
22
+ it is greppable, and it survives into meta where an audit reads it as what it
23
+ is — a claim by a named author, not an inference.
24
+
25
+ It carries no runtime effect and grants nothing. Its entire job is to move a
26
+ gate that codegen cannot see into a place where a human can, and to keep PKU574
27
+ worth reading: a warning that is usually wrong stops being read, which costs
28
+ more than the warning ever saved.
29
+
30
+ **What this rules out:** inferring self-authentication from the function body or
31
+ from what it imports; giving `selfAuthenticated` any runtime meaning (it must
32
+ never be a way to skip a check the runtime would otherwise run); and dropping
33
+ the PKU574 warning instead, which was the alternative that would have left every
34
+ genuinely ungated function silent too.
@@ -0,0 +1,37 @@
1
+ ---
2
+ type: decision
3
+ title: Signed content URLs bind the request path and verify fail-closed
4
+ description: A signature that only carries timestamps authorizes every asset, and a verifier with no key must refuse rather than allow
5
+ tags: content
6
+ ---
7
+
8
+ # Signed content URLs bind the request path and verify fail-closed
9
+
10
+ `LocalContent` signs a payload containing the decoded request path, and the
11
+ verifier in `pikku-node-http-server.ts` compares it against the path actually
12
+ requested. `LocalContent` requires a `JWTService` and throws without one; a
13
+ verifier with no key available rejects with 403 rather than allowing the
14
+ request, logging once per process so an attacker-triggerable path cannot flood.
15
+
16
+ A signature over `{signedAt, expiresAt, notBefore}` alone proves only *when* a
17
+ URL was issued, never *what* it was issued for. Any valid token was a skeleton
18
+ key: swap the pathname from a public thumbnail to a private document and the
19
+ signature still verifies. Timestamps bound the window; only the path binds the
20
+ asset.
21
+
22
+ The path is the representation both signing entry points can produce and the
23
+ verifier can reconstruct — it sees a request line, and cannot recover the
24
+ bucket/key split from it. `signedContentPath` normalizes both sides identically
25
+ (pathname only, origin and query dropped, `decodeURIComponent` falling back to
26
+ the raw pathname on a malformed escape) so a difference in encoding cannot
27
+ become a difference in verdict.
28
+
29
+ `pikku serve` and `pikku dev` mint an ephemeral per-process signing key, so
30
+ local content serving works with no configuration without shipping a fail-open
31
+ path. URLs signed by one dev-server process are meaningless to the next, which
32
+ is the correct lifetime for a dev secret.
33
+
34
+ **What this rules out:** signing a URL without binding it to what it grants;
35
+ returning "valid" from a verifier that could not check anything; normalizing the
36
+ path differently on the two sides; and constructing `LocalContent` without a
37
+ JWT service.
@@ -0,0 +1,25 @@
1
+ ---
2
+ type: decision
3
+ title: Webhook bodies are signed before they are enqueued
4
+ description: QueueWebhookService computes the HMAC at enqueue time so the signing key never travels in the queue payload
5
+ tags: services
6
+ ---
7
+
8
+ # Webhook bodies are signed before they are enqueued
9
+
10
+ `QueueWebhookService.prepareDelivery`
11
+ (`packages/core/src/services/queue-webhook-service.ts`) serialises the payload,
12
+ resolves the signing secret, computes the signature and writes it into the job's
13
+ `headers` — all before `queueService.add` is called. The worker,
14
+ `pikkuWebhookWorkerFunc`, POSTs headers it was handed and never sees a secret.
15
+
16
+ Signing in the worker instead would mean the key has to reach the worker, and the
17
+ only channel between the two is the queue payload: an SQS body, a Redis value, a
18
+ `jsonb` column, all of which are at rest, replicated, and visible to anyone who
19
+ can read the queue. The signature is not sensitive; the key is.
20
+
21
+ **What this rules out:** moving signing into the worker so it can re-sign on
22
+ retry, and putting `secret` (or a resolved key of any kind) onto `WebhookJobData`.
23
+ Note the related consequence: because the signature is fixed at enqueue time, a
24
+ key rotated between enqueue and delivery does not change an in-flight job's
25
+ signature — that is intended, not a bug to fix by carrying the key.
@@ -0,0 +1,34 @@
1
+ ---
2
+ type: decision
3
+ title: A scenario actor step always goes over the real transport and never through internal dispatch
4
+ description: Internal dispatch would bypass auth middleware and permissions, turning a scenario into a green health check that proves nothing
5
+ tags: workflow
6
+ ---
7
+
8
+ # A scenario actor step always goes over the real transport and never through internal dispatch
9
+
10
+ When a workflow step carries `options.actor`, `rpcStep` in
11
+ `pikku-workflow-service.ts` calls `actor.invoke(rpcName, data)` — the actor's
12
+ authenticated client, over the real network transport — and never falls back to
13
+ internal dispatch. Internal dispatch skips auth middleware and permission
14
+ checks, so a scenario that "passed" that way would prove only that the function
15
+ body runs, not that the persona is allowed to run it. That is a green health
16
+ check for a system that may be wide open.
17
+
18
+ For the same reason, actor steps never queue: `rpcStep` short-circuits
19
+ `dispatchStep` to `false` whenever `options.actor` is set. An actor step is an
20
+ outbound HTTP call made by the runner itself, and the actor's session lives in
21
+ this process — a queued worker in another process would have no session to make
22
+ it with. The step is still recorded durably like any RPC step, so replay and
23
+ reporting are unaffected.
24
+
25
+ Actor identity is process-local by nature. `PikkuScenarioService.runActors` maps
26
+ run id to live authenticated clients (cookie jars), and those ride that map
27
+ only, never the persisted run wire — a serialized session on a durable run row
28
+ would be a credential at rest.
29
+
30
+ **What this rules out:** adding an "internal dispatch is faster" fast path for
31
+ actor steps, routing an actor step through the queue, serializing actor sessions
32
+ onto the run wire, or letting `actor.invoke` degrade to `rpcWithWire` when the
33
+ transport is unavailable. Each turns an end-to-end authorization test into one
34
+ that cannot fail.
@@ -0,0 +1,40 @@
1
+ ---
2
+ type: decision
3
+ title: An approval decision is stored raw and validated on replay, and an invalid one closes the gate rather than failing the run
4
+ description: The schema only exists inside the workflow body, and letting an external payload fail the run would let any caller kill a workflow
5
+ tags: workflow
6
+ ---
7
+
8
+ # An approval decision is stored raw and validated on replay, and an invalid one closes the gate rather than failing the run
9
+
10
+ `approveStep` in `pikku-workflow-service.ts` is called from outside the workflow
11
+ — an HTTP route, an RPC — where the approval's schema value is not in scope. It
12
+ therefore stores the decision payload raw in run state and does nothing else.
13
+ Validation happens on replay inside `approvalStep`, in the workflow body, which
14
+ is the only place the schema exists.
15
+
16
+ When validation fails, the bad decision is dropped, the issues are recorded on
17
+ the gate's state record, and a `WorkflowSuspendedException` re-closes the gate.
18
+ The failure stays legible to whoever tries next, and — the security point —
19
+ failing the run instead would let any caller kill a workflow with a malformed
20
+ payload. A later valid decision still lands normally.
21
+
22
+ `WorkflowApprovalOptions.schema` is a VALUE, not a type generic, for the same
23
+ reason: the payload arrives from an untrusted caller over the approve wire, and
24
+ a generic is erased at compile time, so it would validate nothing. Any
25
+ standard-schema library (zod, valibot, arktype) satisfies it. The contract is
26
+ the `~standard` spec and nothing more: `@pikku/core` deliberately carries no
27
+ zod dependency, which is why `pikku-workflow-service.test.ts` hand-rolls a
28
+ minimal `StandardSchemaV1` rather than importing a validation library.
29
+
30
+ A decision arriving for a gate that has already resolved is rejected with
31
+ `WorkflowApprovalResolvedError` (409) rather than accepted and dropped. The gate
32
+ caches its outcome as the step result and never re-reads run state, so a
33
+ decision recorded after resolution could not take effect — most obviously when
34
+ it loses the race with expiry — and the approver has to be told their decision
35
+ did not land.
36
+
37
+ **What this rules out:** validating in `approveStep` (the schema is not there),
38
+ failing the run on an invalid payload, turning `schema` into a type parameter,
39
+ accepting a decision on a resolved gate, or making a resolved gate re-read run
40
+ state so a late decision "wins".