@stigmer/server 3.40.0 → 3.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. package/dist/authorization/authorizer.d.ts +16 -10
  2. package/dist/authorization/authorizer.d.ts.map +1 -1
  3. package/dist/authorization/authorizer.js +17 -9
  4. package/dist/authorization/authorizer.js.map +1 -1
  5. package/dist/authorization/derived-tuples.d.ts +7 -3
  6. package/dist/authorization/derived-tuples.d.ts.map +1 -1
  7. package/dist/authorization/derived-tuples.js +62 -6
  8. package/dist/authorization/derived-tuples.js.map +1 -1
  9. package/dist/authorization/evaluator.d.ts +11 -7
  10. package/dist/authorization/evaluator.d.ts.map +1 -1
  11. package/dist/authorization/evaluator.js +16 -10
  12. package/dist/authorization/evaluator.js.map +1 -1
  13. package/dist/authorization/list-read-scope.d.ts +4 -0
  14. package/dist/authorization/list-read-scope.d.ts.map +1 -1
  15. package/dist/authorization/list-read-scope.js +1 -0
  16. package/dist/authorization/list-read-scope.js.map +1 -1
  17. package/dist/authorization/model/data/authorization-model.json +830 -67
  18. package/dist/authorization/model/execution-viewer.d.ts.map +1 -1
  19. package/dist/authorization/model/execution-viewer.js +26 -24
  20. package/dist/authorization/model/execution-viewer.js.map +1 -1
  21. package/dist/authorization/model/index.d.ts +4 -1
  22. package/dist/authorization/model/index.d.ts.map +1 -1
  23. package/dist/authorization/model/index.js +4 -1
  24. package/dist/authorization/model/index.js.map +1 -1
  25. package/dist/authorization/model/rewrite.d.ts +5 -3
  26. package/dist/authorization/model/rewrite.d.ts.map +1 -1
  27. package/dist/authorization/organization-directory.d.ts +44 -0
  28. package/dist/authorization/organization-directory.d.ts.map +1 -1
  29. package/dist/authorization/organization-directory.js +1 -0
  30. package/dist/authorization/organization-directory.js.map +1 -1
  31. package/dist/authorization/person.d.ts +14 -1
  32. package/dist/authorization/person.d.ts.map +1 -1
  33. package/dist/authorization/person.js +16 -0
  34. package/dist/authorization/person.js.map +1 -1
  35. package/dist/authorization/policy-check.d.ts +52 -0
  36. package/dist/authorization/policy-check.d.ts.map +1 -0
  37. package/dist/authorization/policy-check.js +35 -0
  38. package/dist/authorization/policy-check.js.map +1 -0
  39. package/dist/authorization/posture.d.ts +30 -4
  40. package/dist/authorization/posture.d.ts.map +1 -1
  41. package/dist/authorization/posture.js +58 -0
  42. package/dist/authorization/posture.js.map +1 -1
  43. package/dist/authorization/resource-creators.d.ts +4 -0
  44. package/dist/authorization/resource-creators.d.ts.map +1 -0
  45. package/dist/authorization/resource-creators.js +44 -0
  46. package/dist/authorization/resource-creators.js.map +1 -0
  47. package/dist/authorization/trusted-local-authorizer.d.ts +9 -0
  48. package/dist/authorization/trusted-local-authorizer.d.ts.map +1 -0
  49. package/dist/authorization/trusted-local-authorizer.js +70 -0
  50. package/dist/authorization/trusted-local-authorizer.js.map +1 -0
  51. package/dist/authorization/tuples.d.ts +12 -0
  52. package/dist/authorization/tuples.d.ts.map +1 -1
  53. package/dist/authorization/tuples.js +3 -0
  54. package/dist/authorization/tuples.js.map +1 -1
  55. package/dist/boot/compose.d.ts.map +1 -1
  56. package/dist/boot/compose.js +133 -43
  57. package/dist/boot/compose.js.map +1 -1
  58. package/dist/boot/config.d.ts +22 -7
  59. package/dist/boot/config.d.ts.map +1 -1
  60. package/dist/boot/config.js +2 -1
  61. package/dist/boot/config.js.map +1 -1
  62. package/dist/boot/inprocess.d.ts.map +1 -1
  63. package/dist/boot/inprocess.js +10 -4
  64. package/dist/boot/inprocess.js.map +1 -1
  65. package/dist/boot/list-indexes.d.ts.map +1 -1
  66. package/dist/boot/list-indexes.js +6 -1
  67. package/dist/boot/list-indexes.js.map +1 -1
  68. package/dist/boot/logger.d.ts +3 -1
  69. package/dist/boot/logger.d.ts.map +1 -1
  70. package/dist/boot/logger.js +3 -1
  71. package/dist/boot/logger.js.map +1 -1
  72. package/dist/boot/oauth-redirect-uri.d.ts +33 -12
  73. package/dist/boot/oauth-redirect-uri.d.ts.map +1 -1
  74. package/dist/boot/oauth-redirect-uri.js +43 -14
  75. package/dist/boot/oauth-redirect-uri.js.map +1 -1
  76. package/dist/boot/skill-transfer-origin.d.ts +46 -14
  77. package/dist/boot/skill-transfer-origin.d.ts.map +1 -1
  78. package/dist/boot/skill-transfer-origin.js +53 -13
  79. package/dist/boot/skill-transfer-origin.js.map +1 -1
  80. package/dist/domain/agentchannel/steps.d.ts +8 -6
  81. package/dist/domain/agentchannel/steps.d.ts.map +1 -1
  82. package/dist/domain/agentchannel/steps.js +9 -7
  83. package/dist/domain/agentchannel/steps.js.map +1 -1
  84. package/dist/domain/agentexecution/controller.d.ts +7 -0
  85. package/dist/domain/agentexecution/controller.d.ts.map +1 -1
  86. package/dist/domain/agentexecution/controller.js +1 -1
  87. package/dist/domain/agentexecution/controller.js.map +1 -1
  88. package/dist/domain/agentexecution/create-steps.d.ts +26 -12
  89. package/dist/domain/agentexecution/create-steps.d.ts.map +1 -1
  90. package/dist/domain/agentexecution/create-steps.js +61 -43
  91. package/dist/domain/agentexecution/create-steps.js.map +1 -1
  92. package/dist/domain/agentexecution/submit-approval.d.ts.map +1 -1
  93. package/dist/domain/agentexecution/submit-approval.js +9 -6
  94. package/dist/domain/agentexecution/submit-approval.js.map +1 -1
  95. package/dist/domain/agentexecution/submit-file-decision.d.ts.map +1 -1
  96. package/dist/domain/agentexecution/submit-file-decision.js +5 -4
  97. package/dist/domain/agentexecution/submit-file-decision.js.map +1 -1
  98. package/dist/domain/agentshare/steps.d.ts +5 -3
  99. package/dist/domain/agentshare/steps.d.ts.map +1 -1
  100. package/dist/domain/agentshare/steps.js +6 -4
  101. package/dist/domain/agentshare/steps.js.map +1 -1
  102. package/dist/domain/apikey/verifier.d.ts +7 -0
  103. package/dist/domain/apikey/verifier.d.ts.map +1 -1
  104. package/dist/domain/apikey/verifier.js +34 -1
  105. package/dist/domain/apikey/verifier.js.map +1 -1
  106. package/dist/domain/channelapp/controller.d.ts +9 -4
  107. package/dist/domain/channelapp/controller.d.ts.map +1 -1
  108. package/dist/domain/channelapp/controller.js +19 -9
  109. package/dist/domain/channelapp/controller.js.map +1 -1
  110. package/dist/domain/executioncontext/steps.d.ts +2 -1
  111. package/dist/domain/executioncontext/steps.d.ts.map +1 -1
  112. package/dist/domain/executioncontext/steps.js +2 -1
  113. package/dist/domain/executioncontext/steps.js.map +1 -1
  114. package/dist/domain/iampolicy/access-lists.d.ts.map +1 -1
  115. package/dist/domain/iampolicy/access-lists.js +57 -2
  116. package/dist/domain/iampolicy/access-lists.js.map +1 -1
  117. package/dist/domain/iampolicy/change.d.ts +53 -0
  118. package/dist/domain/iampolicy/change.d.ts.map +1 -0
  119. package/dist/domain/iampolicy/change.js +44 -0
  120. package/dist/domain/iampolicy/change.js.map +1 -0
  121. package/dist/domain/iampolicy/constants.d.ts +6 -0
  122. package/dist/domain/iampolicy/constants.d.ts.map +1 -1
  123. package/dist/domain/iampolicy/constants.js +6 -0
  124. package/dist/domain/iampolicy/constants.js.map +1 -1
  125. package/dist/domain/iampolicy/controller.d.ts.map +1 -1
  126. package/dist/domain/iampolicy/controller.js +9 -5
  127. package/dist/domain/iampolicy/controller.js.map +1 -1
  128. package/dist/domain/iampolicy/grant-path.d.ts +31 -13
  129. package/dist/domain/iampolicy/grant-path.d.ts.map +1 -1
  130. package/dist/domain/iampolicy/grant-path.js +216 -19
  131. package/dist/domain/iampolicy/grant-path.js.map +1 -1
  132. package/dist/domain/iampolicy/membership.d.ts +11 -3
  133. package/dist/domain/iampolicy/membership.d.ts.map +1 -1
  134. package/dist/domain/iampolicy/membership.js +18 -13
  135. package/dist/domain/iampolicy/membership.js.map +1 -1
  136. package/dist/domain/iampolicy/resource-store.d.ts.map +1 -1
  137. package/dist/domain/iampolicy/resource-store.js +4 -0
  138. package/dist/domain/iampolicy/resource-store.js.map +1 -1
  139. package/dist/domain/iampolicy/role-lifecycle.d.ts.map +1 -1
  140. package/dist/domain/iampolicy/role-lifecycle.js +2 -2
  141. package/dist/domain/iampolicy/role-lifecycle.js.map +1 -1
  142. package/dist/domain/iampolicy/roles.d.ts.map +1 -1
  143. package/dist/domain/iampolicy/roles.js +7 -0
  144. package/dist/domain/iampolicy/roles.js.map +1 -1
  145. package/dist/domain/iampolicy/steps.d.ts +4 -3
  146. package/dist/domain/iampolicy/steps.d.ts.map +1 -1
  147. package/dist/domain/iampolicy/steps.js +7 -7
  148. package/dist/domain/iampolicy/steps.js.map +1 -1
  149. package/dist/domain/iampolicy/store-contract.d.ts.map +1 -1
  150. package/dist/domain/iampolicy/store-contract.js +22 -1
  151. package/dist/domain/iampolicy/store-contract.js.map +1 -1
  152. package/dist/domain/iampolicy/store.d.ts +18 -5
  153. package/dist/domain/iampolicy/store.d.ts.map +1 -1
  154. package/dist/domain/iampolicy/store.js.map +1 -1
  155. package/dist/domain/identityaccount/constants.d.ts +15 -0
  156. package/dist/domain/identityaccount/constants.d.ts.map +1 -1
  157. package/dist/domain/identityaccount/constants.js +17 -0
  158. package/dist/domain/identityaccount/constants.js.map +1 -1
  159. package/dist/domain/identityaccount/controller.d.ts.map +1 -1
  160. package/dist/domain/identityaccount/controller.js +17 -6
  161. package/dist/domain/identityaccount/controller.js.map +1 -1
  162. package/dist/domain/identityaccount/resolve.d.ts +47 -0
  163. package/dist/domain/identityaccount/resolve.d.ts.map +1 -1
  164. package/dist/domain/identityaccount/resolve.js +38 -1
  165. package/dist/domain/identityaccount/resolve.js.map +1 -1
  166. package/dist/domain/identityaccount/resource-store.d.ts.map +1 -1
  167. package/dist/domain/identityaccount/resource-store.js +11 -1
  168. package/dist/domain/identityaccount/resource-store.js.map +1 -1
  169. package/dist/domain/identityaccount/steps.d.ts +2 -1
  170. package/dist/domain/identityaccount/steps.d.ts.map +1 -1
  171. package/dist/domain/identityaccount/steps.js +4 -3
  172. package/dist/domain/identityaccount/steps.js.map +1 -1
  173. package/dist/domain/identityaccount/store-contract.js +2 -2
  174. package/dist/domain/identityaccount/store-contract.js.map +1 -1
  175. package/dist/domain/identityaccount/store.d.ts +6 -1
  176. package/dist/domain/identityaccount/store.d.ts.map +1 -1
  177. package/dist/domain/mcpserver/connect-sandbox.d.ts +67 -0
  178. package/dist/domain/mcpserver/connect-sandbox.d.ts.map +1 -0
  179. package/dist/domain/mcpserver/connect-sandbox.js +64 -0
  180. package/dist/domain/mcpserver/connect-sandbox.js.map +1 -0
  181. package/dist/domain/mcpserver/connect.d.ts +42 -10
  182. package/dist/domain/mcpserver/connect.d.ts.map +1 -1
  183. package/dist/domain/mcpserver/connect.js +147 -40
  184. package/dist/domain/mcpserver/connect.js.map +1 -1
  185. package/dist/domain/mcpserver/controller.js +4 -2
  186. package/dist/domain/mcpserver/controller.js.map +1 -1
  187. package/dist/domain/mcpserver/engine.d.ts +26 -7
  188. package/dist/domain/mcpserver/engine.d.ts.map +1 -1
  189. package/dist/domain/mcpserver/engine.js.map +1 -1
  190. package/dist/domain/mcpserver/start-connect.d.ts +5 -0
  191. package/dist/domain/mcpserver/start-connect.d.ts.map +1 -1
  192. package/dist/domain/mcpserver/start-connect.js +38 -15
  193. package/dist/domain/mcpserver/start-connect.js.map +1 -1
  194. package/dist/domain/memory/controller.js +2 -1
  195. package/dist/domain/memory/controller.js.map +1 -1
  196. package/dist/domain/memory/list-index.d.ts +2 -0
  197. package/dist/domain/memory/list-index.d.ts.map +1 -0
  198. package/dist/domain/memory/list-index.js +31 -0
  199. package/dist/domain/memory/list-index.js.map +1 -0
  200. package/dist/domain/memory/queries.d.ts +10 -0
  201. package/dist/domain/memory/queries.d.ts.map +1 -0
  202. package/dist/domain/memory/queries.js +54 -0
  203. package/dist/domain/memory/queries.js.map +1 -0
  204. package/dist/domain/memory/steps.d.ts +13 -11
  205. package/dist/domain/memory/steps.d.ts.map +1 -1
  206. package/dist/domain/memory/steps.js +26 -57
  207. package/dist/domain/memory/steps.js.map +1 -1
  208. package/dist/domain/organization/steps.d.ts.map +1 -1
  209. package/dist/domain/organization/steps.js +1 -1
  210. package/dist/domain/organization/steps.js.map +1 -1
  211. package/dist/domain/platformclient/mint.d.ts.map +1 -1
  212. package/dist/domain/platformclient/mint.js +2 -2
  213. package/dist/domain/platformclient/mint.js.map +1 -1
  214. package/dist/domain/platformclient/verifier.d.ts.map +1 -1
  215. package/dist/domain/platformclient/verifier.js +6 -3
  216. package/dist/domain/platformclient/verifier.js.map +1 -1
  217. package/dist/domain/plugin/push.d.ts.map +1 -1
  218. package/dist/domain/plugin/push.js +1 -0
  219. package/dist/domain/plugin/push.js.map +1 -1
  220. package/dist/domain/schedule/steps.d.ts +3 -1
  221. package/dist/domain/schedule/steps.d.ts.map +1 -1
  222. package/dist/domain/schedule/steps.js +3 -1
  223. package/dist/domain/schedule/steps.js.map +1 -1
  224. package/dist/domain/skill/push.d.ts.map +1 -1
  225. package/dist/domain/skill/push.js +1 -0
  226. package/dist/domain/skill/push.js.map +1 -1
  227. package/dist/domain/workflow/registry/data/task-kind-registry.json +27 -1
  228. package/dist/domain/workflowexecution/submit-approval.d.ts +5 -2
  229. package/dist/domain/workflowexecution/submit-approval.d.ts.map +1 -1
  230. package/dist/domain/workflowexecution/submit-approval.js +1 -1
  231. package/dist/domain/workflowexecution/submit-approval.js.map +1 -1
  232. package/dist/domain/workflowexecution/submit-file-decision.d.ts +5 -2
  233. package/dist/domain/workflowexecution/submit-file-decision.d.ts.map +1 -1
  234. package/dist/domain/workflowexecution/submit-file-decision.js +1 -1
  235. package/dist/domain/workflowexecution/submit-file-decision.js.map +1 -1
  236. package/dist/domain/workflowexecution/submit-workflow-task-approval.d.ts.map +1 -1
  237. package/dist/domain/workflowexecution/submit-workflow-task-approval.js +12 -1
  238. package/dist/domain/workflowexecution/submit-workflow-task-approval.js.map +1 -1
  239. package/dist/domain/workflowinstance/controller.d.ts +6 -3
  240. package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
  241. package/dist/domain/workflowinstance/controller.js +12 -7
  242. package/dist/domain/workflowinstance/controller.js.map +1 -1
  243. package/dist/domain/workflowinstance/steps.d.ts +31 -0
  244. package/dist/domain/workflowinstance/steps.d.ts.map +1 -1
  245. package/dist/domain/workflowinstance/steps.js +88 -1
  246. package/dist/domain/workflowinstance/steps.js.map +1 -1
  247. package/dist/extensions/composed-services.d.ts +56 -0
  248. package/dist/extensions/composed-services.d.ts.map +1 -0
  249. package/dist/extensions/composed-services.js +2 -0
  250. package/dist/extensions/composed-services.js.map +1 -0
  251. package/dist/extensions/drivers.d.ts +32 -1
  252. package/dist/extensions/drivers.d.ts.map +1 -1
  253. package/dist/extensions/identity.d.ts +4 -1
  254. package/dist/extensions/identity.d.ts.map +1 -1
  255. package/dist/extensions/identity.js +4 -1
  256. package/dist/extensions/identity.js.map +1 -1
  257. package/dist/extensions/registry.d.ts +37 -0
  258. package/dist/extensions/registry.d.ts.map +1 -1
  259. package/dist/extensions/registry.js +50 -0
  260. package/dist/extensions/registry.js.map +1 -1
  261. package/dist/extensions/resource-authorization.d.ts +78 -0
  262. package/dist/extensions/resource-authorization.d.ts.map +1 -1
  263. package/dist/extensions/resource-row-reader.d.ts +43 -0
  264. package/dist/extensions/resource-row-reader.d.ts.map +1 -0
  265. package/dist/extensions/resource-row-reader.js +2 -0
  266. package/dist/extensions/resource-row-reader.js.map +1 -0
  267. package/dist/extensions/visitor-classifier.d.ts +41 -0
  268. package/dist/extensions/visitor-classifier.d.ts.map +1 -0
  269. package/dist/extensions/visitor-classifier.js +2 -0
  270. package/dist/extensions/visitor-classifier.js.map +1 -0
  271. package/dist/identity/oidc-userinfo.d.ts +6 -1
  272. package/dist/identity/oidc-userinfo.d.ts.map +1 -1
  273. package/dist/identity/oidc-userinfo.js.map +1 -1
  274. package/dist/identity/oidc-verifier.d.ts.map +1 -1
  275. package/dist/identity/oidc-verifier.js +37 -8
  276. package/dist/identity/oidc-verifier.js.map +1 -1
  277. package/dist/index.d.ts +14 -6
  278. package/dist/index.d.ts.map +1 -1
  279. package/dist/index.js +25 -9
  280. package/dist/index.js.map +1 -1
  281. package/dist/pipeline/errors.d.ts +8 -0
  282. package/dist/pipeline/errors.d.ts.map +1 -1
  283. package/dist/pipeline/errors.js +25 -16
  284. package/dist/pipeline/errors.js.map +1 -1
  285. package/dist/pipeline/interceptors/auth.d.ts +17 -9
  286. package/dist/pipeline/interceptors/auth.d.ts.map +1 -1
  287. package/dist/pipeline/interceptors/auth.js +17 -9
  288. package/dist/pipeline/interceptors/auth.js.map +1 -1
  289. package/dist/pipeline/steps/authorization-tuples.d.ts +23 -1
  290. package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
  291. package/dist/pipeline/steps/authorization-tuples.js +42 -0
  292. package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
  293. package/dist/pipeline/steps/authorize.d.ts +6 -5
  294. package/dist/pipeline/steps/authorize.d.ts.map +1 -1
  295. package/dist/pipeline/steps/authorize.js +6 -5
  296. package/dist/pipeline/steps/authorize.js.map +1 -1
  297. package/dist/pipeline/steps/defaults.d.ts +12 -0
  298. package/dist/pipeline/steps/defaults.d.ts.map +1 -1
  299. package/dist/pipeline/steps/defaults.js +42 -7
  300. package/dist/pipeline/steps/defaults.js.map +1 -1
  301. package/dist/pipeline/steps/guard-memory-capture.d.ts +13 -15
  302. package/dist/pipeline/steps/guard-memory-capture.d.ts.map +1 -1
  303. package/dist/pipeline/steps/guard-memory-capture.js +2 -3
  304. package/dist/pipeline/steps/guard-memory-capture.js.map +1 -1
  305. package/dist/runnerauth/built-in-runner-credential-provider.d.ts +0 -2
  306. package/dist/runnerauth/built-in-runner-credential-provider.d.ts.map +1 -1
  307. package/dist/runnerauth/built-in-runner-credential-provider.js +8 -17
  308. package/dist/runnerauth/built-in-runner-credential-provider.js.map +1 -1
  309. package/dist/runnerauth/runner-credential-provider.d.ts +17 -7
  310. package/dist/runnerauth/runner-credential-provider.d.ts.map +1 -1
  311. package/dist/runnerauth/runner-credential-provider.js.map +1 -1
  312. package/dist/sandbox/docker.d.ts.map +1 -1
  313. package/dist/sandbox/docker.js +3 -0
  314. package/dist/sandbox/docker.js.map +1 -1
  315. package/dist/sandbox/kubernetes.d.ts.map +1 -1
  316. package/dist/sandbox/kubernetes.js +3 -0
  317. package/dist/sandbox/kubernetes.js.map +1 -1
  318. package/dist/sandbox/local-process.d.ts.map +1 -1
  319. package/dist/sandbox/local-process.js +4 -0
  320. package/dist/sandbox/local-process.js.map +1 -1
  321. package/dist/sandbox/provisioner.d.ts +18 -6
  322. package/dist/sandbox/provisioner.d.ts.map +1 -1
  323. package/dist/sandbox/provisioner.js.map +1 -1
  324. package/dist/temporal/manager.d.ts +5 -0
  325. package/dist/temporal/manager.d.ts.map +1 -1
  326. package/dist/temporal/manager.js +9 -0
  327. package/dist/temporal/manager.js.map +1 -1
  328. package/dist/temporal/mcpserver/engine-client.d.ts +2 -2
  329. package/dist/temporal/mcpserver/engine-client.d.ts.map +1 -1
  330. package/dist/temporal/mcpserver/engine-client.js +6 -4
  331. package/dist/temporal/mcpserver/engine-client.js.map +1 -1
  332. package/dist/temporal/mcpserver/names.d.ts +13 -2
  333. package/dist/temporal/mcpserver/names.d.ts.map +1 -1
  334. package/dist/temporal/mcpserver/names.js +15 -2
  335. package/dist/temporal/mcpserver/names.js.map +1 -1
  336. package/dist/temporal/sdk-logger.d.ts +74 -0
  337. package/dist/temporal/sdk-logger.d.ts.map +1 -0
  338. package/dist/temporal/sdk-logger.js +143 -0
  339. package/dist/temporal/sdk-logger.js.map +1 -0
  340. package/package.json +6 -6
  341. package/src/authorization/README.md +18 -6
  342. package/src/authorization/__tests__/authorizer.test.ts +5 -1
  343. package/src/authorization/__tests__/derived-tuples.test.ts +26 -0
  344. package/src/authorization/__tests__/evaluator.test.ts +4 -0
  345. package/src/authorization/__tests__/list-read-scope.test.ts +11 -5
  346. package/src/authorization/__tests__/store-tests.test.ts +3 -1
  347. package/src/authorization/__tests__/trusted-local-authorizer.test.ts +155 -0
  348. package/src/authorization/__tests__/unit-owned-kinds.test.ts +420 -0
  349. package/src/authorization/__tests__/wire-permissions.test.ts +31 -2
  350. package/src/authorization/authorizer.ts +21 -10
  351. package/src/authorization/derived-tuples.ts +92 -18
  352. package/src/authorization/evaluator.ts +30 -15
  353. package/src/authorization/list-read-scope.ts +4 -0
  354. package/src/authorization/model/__tests__/registry.test.ts +23 -0
  355. package/src/authorization/model/data/authorization-model.json +830 -67
  356. package/src/authorization/model/execution-viewer.ts +32 -27
  357. package/src/authorization/model/index.ts +4 -1
  358. package/src/authorization/model/rewrite.ts +5 -3
  359. package/src/authorization/organization-directory.ts +4 -0
  360. package/src/authorization/person.ts +32 -1
  361. package/src/authorization/policy-check.ts +105 -0
  362. package/src/authorization/posture.ts +45 -4
  363. package/src/authorization/resource-creators.ts +48 -0
  364. package/src/authorization/trusted-local-authorizer.ts +91 -0
  365. package/src/authorization/tuples.ts +17 -0
  366. package/src/boot/__tests__/compose.test.ts +120 -4
  367. package/src/boot/__tests__/list-indexes.test.ts +4 -0
  368. package/src/boot/__tests__/oauth-redirect-uri.test.ts +121 -10
  369. package/src/boot/__tests__/skill-transfer-origin.test.ts +96 -25
  370. package/src/boot/compose.ts +154 -61
  371. package/src/boot/config.ts +28 -12
  372. package/src/boot/inprocess.ts +18 -4
  373. package/src/boot/list-indexes.ts +6 -1
  374. package/src/boot/logger.ts +3 -1
  375. package/src/boot/oauth-redirect-uri.ts +62 -17
  376. package/src/boot/skill-transfer-origin.ts +71 -16
  377. package/src/domain/agent/__tests__/agent.test.ts +42 -1
  378. package/src/domain/agentchannel/__tests__/agentchannel.test.ts +9 -0
  379. package/src/domain/agentchannel/__tests__/channel-runtime.test.ts +2 -0
  380. package/src/domain/agentchannel/__tests__/create-authorization.test.ts +7 -6
  381. package/src/domain/agentchannel/steps.ts +9 -7
  382. package/src/domain/agentexecution/__tests__/agentexecution.test.ts +148 -56
  383. package/src/domain/agentexecution/__tests__/create-steps.test.ts +175 -12
  384. package/src/domain/agentexecution/__tests__/file-review-seed.ts +91 -0
  385. package/src/domain/agentexecution/controller.ts +8 -0
  386. package/src/domain/agentexecution/create-steps.ts +74 -44
  387. package/src/domain/agentexecution/submit-approval.ts +9 -6
  388. package/src/domain/agentexecution/submit-file-decision.ts +5 -4
  389. package/src/domain/agentinstance/__tests__/agentinstance.test.ts +2 -0
  390. package/src/domain/agentshare/__tests__/agentshare.test.ts +17 -0
  391. package/src/domain/agentshare/__tests__/create-authorization.test.ts +5 -4
  392. package/src/domain/agentshare/steps.ts +6 -4
  393. package/src/domain/apikey/__tests__/verifier.test.ts +73 -1
  394. package/src/domain/apikey/verifier.ts +45 -1
  395. package/src/domain/artifact/__tests__/artifact.test.ts +13 -24
  396. package/src/domain/channelapp/__tests__/channelapp.test.ts +7 -0
  397. package/src/domain/channelapp/controller.ts +35 -12
  398. package/src/domain/environment/__tests__/environment.test.ts +13 -0
  399. package/src/domain/executioncontext/__tests__/executioncontext.test.ts +2 -0
  400. package/src/domain/executioncontext/steps.ts +2 -1
  401. package/src/domain/iampolicy/__tests__/access-lists.test.ts +79 -0
  402. package/src/domain/iampolicy/__tests__/change.test.ts +63 -0
  403. package/src/domain/iampolicy/__tests__/controller.test.ts +39 -3
  404. package/src/domain/iampolicy/__tests__/grant-path.test.ts +595 -27
  405. package/src/domain/iampolicy/__tests__/iampolicy.test.ts +33 -2
  406. package/src/domain/iampolicy/__tests__/membership.test.ts +47 -5
  407. package/src/domain/iampolicy/__tests__/resource-store.test.ts +1 -0
  408. package/src/domain/iampolicy/__tests__/role-lifecycle.test.ts +41 -8
  409. package/src/domain/iampolicy/__tests__/roles.test.ts +3 -2
  410. package/src/domain/iampolicy/__tests__/steps.test.ts +75 -6
  411. package/src/domain/iampolicy/__tests__/support.ts +68 -4
  412. package/src/domain/iampolicy/access-lists.ts +70 -2
  413. package/src/domain/iampolicy/change.ts +109 -0
  414. package/src/domain/iampolicy/constants.ts +8 -0
  415. package/src/domain/iampolicy/controller.ts +17 -3
  416. package/src/domain/iampolicy/grant-path.ts +349 -31
  417. package/src/domain/iampolicy/membership.ts +32 -12
  418. package/src/domain/iampolicy/resource-store.ts +4 -0
  419. package/src/domain/iampolicy/role-lifecycle.ts +2 -0
  420. package/src/domain/iampolicy/roles.ts +8 -0
  421. package/src/domain/iampolicy/steps.ts +15 -5
  422. package/src/domain/iampolicy/store-contract.ts +37 -1
  423. package/src/domain/iampolicy/store.ts +19 -5
  424. package/src/domain/identityaccount/__tests__/resolve.test.ts +246 -2
  425. package/src/domain/identityaccount/__tests__/resource-store.test.ts +1 -1
  426. package/src/domain/identityaccount/constants.ts +20 -0
  427. package/src/domain/identityaccount/controller.ts +20 -5
  428. package/src/domain/identityaccount/resolve.ts +80 -1
  429. package/src/domain/identityaccount/resource-store.ts +14 -1
  430. package/src/domain/identityaccount/steps.ts +4 -3
  431. package/src/domain/identityaccount/store-contract.ts +4 -4
  432. package/src/domain/identityaccount/store.ts +6 -1
  433. package/src/domain/mcpserver/__tests__/connect-authorization.test.ts +1 -0
  434. package/src/domain/mcpserver/__tests__/connect.test.ts +358 -15
  435. package/src/domain/mcpserver/__tests__/mcpserver.test.ts +2 -0
  436. package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +2 -0
  437. package/src/domain/mcpserver/__tests__/store-faults.test.ts +2 -0
  438. package/src/domain/mcpserver/connect-sandbox.ts +135 -0
  439. package/src/domain/mcpserver/connect.ts +226 -56
  440. package/src/domain/mcpserver/controller.ts +8 -2
  441. package/src/domain/mcpserver/engine.ts +24 -6
  442. package/src/domain/mcpserver/start-connect.ts +49 -10
  443. package/src/domain/memory/__tests__/memory.test.ts +92 -22
  444. package/src/domain/memory/__tests__/queries.test.ts +173 -0
  445. package/src/domain/memory/controller.ts +2 -1
  446. package/src/domain/memory/list-index.ts +32 -0
  447. package/src/domain/memory/queries.ts +72 -0
  448. package/src/domain/memory/steps.ts +26 -63
  449. package/src/domain/oauthapp/__tests__/oauthapp.test.ts +14 -0
  450. package/src/domain/organization/__tests__/support.ts +41 -0
  451. package/src/domain/organization/steps.ts +1 -0
  452. package/src/domain/platformclient/mint.ts +6 -2
  453. package/src/domain/platformclient/verifier.ts +6 -3
  454. package/src/domain/plugin/__tests__/plugin.test.ts +11 -24
  455. package/src/domain/plugin/push.ts +1 -0
  456. package/src/domain/schedule/__tests__/schedule.composed.test.ts +2 -0
  457. package/src/domain/schedule/steps.ts +3 -1
  458. package/src/domain/session/__tests__/session.test.ts +2 -0
  459. package/src/domain/skill/__tests__/skill.test.ts +7 -25
  460. package/src/domain/skill/push.ts +1 -0
  461. package/src/domain/workflow/__tests__/workflow.test.ts +2 -0
  462. package/src/domain/workflow/registry/data/task-kind-registry.json +27 -1
  463. package/src/domain/workflowexecution/__tests__/forward-attribution-composed.test.ts +270 -0
  464. package/src/domain/workflowexecution/__tests__/submit-workflow-task-approval.test.ts +196 -0
  465. package/src/domain/workflowexecution/__tests__/workflowexecution.test.ts +3 -57
  466. package/src/domain/workflowexecution/submit-approval.ts +9 -2
  467. package/src/domain/workflowexecution/submit-file-decision.ts +6 -1
  468. package/src/domain/workflowexecution/submit-workflow-task-approval.ts +23 -5
  469. package/src/domain/workflowinstance/controller.ts +27 -9
  470. package/src/domain/workflowinstance/steps.ts +123 -1
  471. package/src/extensions/__tests__/apikey-before-sign-in-composed.test.ts +172 -0
  472. package/src/extensions/__tests__/built-in-authorization-composed.test.ts +80 -1
  473. package/src/extensions/__tests__/composed-services-composed.test.ts +236 -0
  474. package/src/extensions/__tests__/extension-composition.test.ts +229 -16
  475. package/src/extensions/__tests__/identity-account-composed.test.ts +84 -4
  476. package/src/extensions/__tests__/list-read-scope-composed.test.ts +41 -1
  477. package/src/extensions/__tests__/registry.test.ts +147 -1
  478. package/src/extensions/__tests__/secret-cleanup-composed.test.ts +2 -0
  479. package/src/extensions/__tests__/visitor-classifier-points.test.ts +42 -0
  480. package/src/extensions/composed-services.ts +61 -0
  481. package/src/extensions/drivers.ts +33 -1
  482. package/src/extensions/identity.ts +4 -1
  483. package/src/extensions/registry.ts +105 -0
  484. package/src/extensions/resource-authorization.ts +87 -0
  485. package/src/extensions/resource-row-reader.ts +43 -0
  486. package/src/extensions/visitor-classifier.ts +41 -0
  487. package/src/identity/__tests__/oidc-verifier.test.ts +38 -12
  488. package/src/identity/oidc-userinfo.ts +6 -1
  489. package/src/identity/oidc-verifier.ts +42 -8
  490. package/src/index.ts +61 -6
  491. package/src/pipeline/__tests__/steps.test.ts +31 -4
  492. package/src/pipeline/errors.ts +30 -16
  493. package/src/pipeline/interceptors/auth.ts +17 -9
  494. package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +20 -0
  495. package/src/pipeline/steps/__tests__/guard-memory-capture.test.ts +72 -15
  496. package/src/pipeline/steps/authorization-tuples.ts +54 -0
  497. package/src/pipeline/steps/authorize.ts +6 -5
  498. package/src/pipeline/steps/defaults.ts +52 -7
  499. package/src/pipeline/steps/guard-memory-capture.ts +15 -20
  500. package/src/runnerauth/__tests__/built-in-runner-credential-provider.test.ts +1 -1
  501. package/src/runnerauth/__tests__/runner-subject-composed.test.ts +13 -0
  502. package/src/runnerauth/bound-execution.ts +2 -2
  503. package/src/runnerauth/built-in-runner-credential-provider.ts +8 -21
  504. package/src/runnerauth/runner-credential-provider.ts +17 -7
  505. package/src/sandbox/__tests__/docker.integration.test.ts +4 -0
  506. package/src/sandbox/__tests__/kubernetes.test.ts +18 -1
  507. package/src/sandbox/__tests__/local-process.integration.test.ts +4 -0
  508. package/src/sandbox/__tests__/provisioner.test.ts +1 -0
  509. package/src/sandbox/docker.ts +3 -0
  510. package/src/sandbox/kubernetes.ts +3 -0
  511. package/src/sandbox/local-process.ts +4 -0
  512. package/src/sandbox/provisioner.ts +18 -6
  513. package/src/store/postgres/__tests__/support.ts +11 -2
  514. package/src/temporal/README.md +1 -0
  515. package/src/temporal/__tests__/manager.test.ts +56 -4
  516. package/src/temporal/__tests__/sdk-log-workflows.ts +26 -0
  517. package/src/temporal/__tests__/sdk-logger.e2e.test.ts +150 -0
  518. package/src/temporal/__tests__/sdk-logger.test.ts +238 -0
  519. package/src/temporal/manager.ts +9 -0
  520. package/src/temporal/mcpserver/engine-client.ts +8 -3
  521. package/src/temporal/mcpserver/names.ts +16 -2
  522. package/src/temporal/sdk-logger.ts +173 -0
  523. package/dist/authorization/lane-admission.d.ts +0 -50
  524. package/dist/authorization/lane-admission.d.ts.map +0 -1
  525. package/dist/authorization/lane-admission.js +0 -13
  526. package/dist/authorization/lane-admission.js.map +0 -1
  527. package/src/authorization/__tests__/lane-admission.test.ts +0 -115
  528. package/src/authorization/lane-admission.ts +0 -73
@@ -115,6 +115,7 @@ import {
115
115
  teamQualifierMessage,
116
116
  teamRoleNotGrantableMessage,
117
117
  } from "./constants.js";
118
+ import type { PolicyChangeCause } from "./change.js";
118
119
  import type { IamPolicyGrantPath } from "./grant-path.js";
119
120
  import type { IamPolicyStore } from "./store.js";
120
121
  import {
@@ -231,22 +232,27 @@ function requireTeamGrant(
231
232
  }
232
233
  }
233
234
 
234
- /** Grant the spec as the chain's caller; the row (fresh or held) is the result. */
235
+ /** Grant the spec as the chain's caller, through the chain's door; the row (fresh or held) is the result. */
235
236
  export function newGrantStep(
236
237
  grantPath: IamPolicyGrantPath,
238
+ cause: PolicyChangeCause,
237
239
  ): PipelineStep<typeof IamPolicySpecSchema> {
238
240
  return {
239
241
  name: "Grant",
240
242
  async execute(
241
243
  ctx: RequestContext<typeof IamPolicySpecSchema>,
242
244
  ): Promise<void> {
243
- const { policy } = await grantPath.grant(ctx.input, ctx.callerIdentity);
245
+ const { policy } = await grantPath.grant(
246
+ ctx.input,
247
+ ctx.callerIdentity,
248
+ cause,
249
+ );
244
250
  ctx.set(POLICY_RESULT_KEY, policy);
245
251
  },
246
252
  };
247
253
  }
248
254
 
249
- /** Revoke the spec's row; absent, the default instance is the result (Java's idempotent delete). */
255
+ /** Revoke the spec's row as the chain's caller; absent, the default instance is the result (Java's idempotent delete). */
250
256
  export function newRevokeStep(
251
257
  grantPath: IamPolicyGrantPath,
252
258
  ): PipelineStep<typeof IamPolicySpecSchema> {
@@ -255,7 +261,10 @@ export function newRevokeStep(
255
261
  async execute(
256
262
  ctx: RequestContext<typeof IamPolicySpecSchema>,
257
263
  ): Promise<void> {
258
- const revoked = await grantPath.revokeBySpec(ctx.input);
264
+ const revoked = await grantPath.revokeBySpec(
265
+ ctx.input,
266
+ ctx.callerIdentity,
267
+ );
259
268
  ctx.set(POLICY_RESULT_KEY, revoked ?? create(IamPolicySchema));
260
269
  },
261
270
  };
@@ -273,6 +282,7 @@ export function newRevokeOrgAccessStep(
273
282
  return grantPath.revokeOrgAccess(
274
283
  ctx.input.identityAccountId,
275
284
  ctx.input.organizationId,
285
+ ctx.callerIdentity,
276
286
  );
277
287
  },
278
288
  };
@@ -286,7 +296,7 @@ export function newCleanupResourceStep(
286
296
  name: "CleanupResource",
287
297
  execute(ctx: RequestContext<typeof ApiResourceRefSchema>): Promise<void> {
288
298
  const ref: ApiResourceRef = ctx.input;
289
- return grantPath.cleanupResource(ref);
299
+ return grantPath.cleanupResource(ref, ctx.callerIdentity);
290
300
  },
291
301
  };
292
302
  }
@@ -18,7 +18,10 @@
18
18
  *
19
19
  * The corners A12 taught are cases from the start, not later additions:
20
20
  * every relation on a pair; distinct principals, not rows; the scope-tuple
21
- * exclusions verbatim; unknown-id delete a no-op; a held id refused.
21
+ * exclusions verbatim; unknown-id delete a no-op; a held id refused. A
22
+ * change record changes nothing about the row; what a store that keeps a
23
+ * history writes with it is that store's own test, since the port lets an
24
+ * implementation keep none.
22
25
  *
23
26
  * What the kit deliberately does not carry: open source's derived-id
24
27
  * refusal and its primary-key read, the cloud's column layout and SQLSTATE
@@ -51,6 +54,7 @@ import type {
51
54
  PortContractDeclaration,
52
55
  PortContractFixture,
53
56
  } from "../../store/port-contract.js";
57
+ import type { PolicyChangeRecord } from "./change.js";
54
58
  import {
55
59
  IAM_POLICY_API_VERSION,
56
60
  IAM_POLICY_KIND,
@@ -378,6 +382,38 @@ const CASES: ReadonlyArray<PortContractDeclaration<IamPolicyStore>> = [
378
382
  );
379
383
  },
380
384
  ],
385
+ [
386
+ "a change record changes nothing about the row: save and deleteById behave as without one",
387
+ async ({ store }) => {
388
+ const record: PolicyChangeRecord = {
389
+ actor: { id: BOB, callerClass: "user" },
390
+ cause: "grant",
391
+ organizationId: "acme",
392
+ };
393
+ const policy = policyRow(orgRole(ALICE, "admin", "acme"));
394
+ await store.save(policy, record);
395
+ const found = await store.findById(idOf(policy));
396
+ assert.ok(
397
+ found !== undefined && equals(IamPolicySchema, found, policy),
398
+ "a policy saved with a record must read back exactly as saved",
399
+ );
400
+ await assert.rejects(
401
+ store.save(policyRow(orgRole(ALICE, "admin", "acme"), BOB), record),
402
+ DuplicatePolicyError,
403
+ "a held id with a record must still raise DuplicatePolicyError",
404
+ );
405
+ await store.deleteById(idOf(policy), { ...record, cause: "revoke" });
406
+ assert.equal(
407
+ await store.findById(idOf(policy)),
408
+ undefined,
409
+ "a policy deleted with a record must be gone",
410
+ );
411
+ await assert.doesNotReject(
412
+ store.deleteById(idOf(policy), { ...record, cause: "revoke" }),
413
+ "deleting an id that is not held, with a record, must resolve",
414
+ );
415
+ },
416
+ ],
381
417
  [
382
418
  "deleteById of an unknown id resolves",
383
419
  async ({ store }) => {
@@ -38,10 +38,24 @@
38
38
  * editions' filters read alike);
39
39
  * - a typed not-found reads as `undefined`; any other storage failure
40
40
  * propagates as the infrastructure fault it is (the ratified
41
- * store-fault mapping — an outage must never read as "no grant").
41
+ * store-fault mapping — an outage must never read as "no grant");
42
+ * - a change record (change.ts) never changes what happens to the row:
43
+ * `save` and `deleteById` behave identically with and without one.
44
+ *
45
+ * The change record. The grant path hands one to `save` and `deleteById`
46
+ * for every access row it writes or deletes. An implementation that keeps
47
+ * a permission history writes exactly one entry for it in the SAME atomic
48
+ * unit as the row change, and none when the row did not change: a held id
49
+ * raises DuplicatePolicyError before anything is written, and deleting an
50
+ * id that is not held records nothing. History equals the row changes
51
+ * exactly, with nothing to filter or heal. An implementation may keep no
52
+ * history and ignore the record; open source's adapter does. A driver
53
+ * written against the one-argument methods still satisfies this interface.
42
54
  */
43
55
  import type { IamPolicy } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/api_pb";
44
56
 
57
+ import type { PolicyChangeRecord } from "./change.js";
58
+
45
59
  /**
46
60
  * Raised by `save` when the id is already held, so the grant path runs its
47
61
  * race arm (re-read the winner by triple; answer it as the duplicate).
@@ -56,10 +70,10 @@ export class DuplicatePolicyError extends Error {
56
70
  }
57
71
 
58
72
  export interface IamPolicyStore {
59
- /** Insert; a held id raises DuplicatePolicyError. */
60
- save(policy: IamPolicy): Promise<void>;
61
- /** Removes the row; no error when it does not exist. */
62
- deleteById(id: string): Promise<void>;
73
+ /** Insert; a held id raises DuplicatePolicyError. `record`: the change to keep, when the row grants access. */
74
+ save(policy: IamPolicy, record?: PolicyChangeRecord): Promise<void>;
75
+ /** Removes the row; no error when it does not exist. `record`: as for `save`, kept only when a row was removed. */
76
+ deleteById(id: string, record?: PolicyChangeRecord): Promise<void>;
63
77
  findById(id: string): Promise<IamPolicy | undefined>;
64
78
  /** Every row naming the principal — the cleanup's principal-side arm. */
65
79
  findByPrincipal(
@@ -30,6 +30,35 @@
30
30
  * - a caller whose credential names no subject (an opaque token) is
31
31
  * `undefined` with NO second read — the store is never asked about "";
32
32
  * - an idp-shaped caller with no account is `undefined`.
33
+ *
34
+ * And the question the API-key verifier asks of a stamp that resolved to
35
+ * nobody, `isPreSignInOperatorStamp` (stigmer/stigmer#1169): does it name
36
+ * the operator of the server's life before sign-in was turned on? Written
37
+ * failing before the export exists.
38
+ *
39
+ * - the `"system"` placeholder does, with no read (it is only ever the
40
+ * unconfigured laptop's operator);
41
+ * - an email with a `local|<email>` account in the store does;
42
+ * - an email with no such account does not (an issuer subject that
43
+ * happens to look like an email);
44
+ * - an account-id stamp and the empty stamp do not, with no read, so the
45
+ * common key costs the verifier nothing;
46
+ * - a store fault propagates as the same error.
47
+ *
48
+ * And provisionMyAccount's admission, `mayProvisionDirectAccount`: did the
49
+ * platform's own sign-in vouch for this caller? Over a store whose direct
50
+ * read answers no federated and no platform-client row, as the port says:
51
+ *
52
+ * - the trusted-local operator (no issuer, no token) is admitted;
53
+ * - an idp-shaped `user` caller (no account, identity = subject) is;
54
+ * - a caller that is already its subject's direct account is;
55
+ * - a caller whose account is a federated one is not, whether or not a
56
+ * platform person holds the direct account of the subject its token
57
+ * names: that subject is the provider's to choose;
58
+ * - a platform client's user is not, nor a system lane's token (its
59
+ * identity is its lane account, whose id no direct row carries as a
60
+ * subject), nor any caller that is not of class `user`, nor a
61
+ * credential naming no subject.
33
62
  */
34
63
  import { create } from "@bufbuild/protobuf";
35
64
  import { ConnectError } from "@connectrpc/connect";
@@ -40,8 +69,13 @@ import { IdentityAccountProvisioningMode } from "@stigmer/protos/ai/stigmer/iam/
40
69
 
41
70
  import type { CallerIdentity } from "../../../extensions/identity.js";
42
71
  import { accountIdFor, localIdpIdFor } from "../constants.js";
43
- import { accountForCaller, identityIdForSubject } from "../resolve.js";
44
- import type { AccountsBySubject } from "../resolve.js";
72
+ import {
73
+ accountForCaller,
74
+ identityIdForSubject,
75
+ isPreSignInOperatorStamp,
76
+ mayProvisionDirectAccount,
77
+ } from "../resolve.js";
78
+ import type { AccountsByCaller, AccountsBySubject } from "../resolve.js";
45
79
  import { fakeIdentityAccountStore } from "./support.js";
46
80
 
47
81
  function seeded(sub: string, id: string = accountIdFor(sub)) {
@@ -223,3 +257,213 @@ describe("accountForCaller — the account a caller stands for", () => {
223
257
  expect(account).toBeUndefined();
224
258
  });
225
259
  });
260
+
261
+ describe("isPreSignInOperatorStamp — a stamp from before sign-in was turned on (stigmer/stigmer#1169)", () => {
262
+ it('the "system" placeholder is the unconfigured laptop\'s operator, with no read', async () => {
263
+ const accounts = fakeIdentityAccountStore();
264
+ const bySubject = vi.spyOn(accounts, "findDirectByIdpId");
265
+
266
+ expect(await isPreSignInOperatorStamp(accounts, "system")).toBe(true);
267
+ expect(bySubject).not.toHaveBeenCalled();
268
+ });
269
+
270
+ it("an email with a local|<email> account is the configured operator's", async () => {
271
+ const accounts = seeded(localIdpIdFor("operator@example.com"));
272
+ const bySubject = vi.spyOn(accounts, "findDirectByIdpId");
273
+
274
+ expect(
275
+ await isPreSignInOperatorStamp(accounts, "operator@example.com"),
276
+ ).toBe(true);
277
+ expect(bySubject).toHaveBeenCalledTimes(1);
278
+ expect(bySubject).toHaveBeenCalledWith(
279
+ localIdpIdFor("operator@example.com"),
280
+ );
281
+ });
282
+
283
+ it("an email with no local|<email> account is not — an issuer subject may look like one", async () => {
284
+ const accounts = seeded(localIdpIdFor("operator@example.com"));
285
+
286
+ expect(
287
+ await isPreSignInOperatorStamp(accounts, "someone@example.com"),
288
+ ).toBe(false);
289
+ });
290
+
291
+ it("an account-id stamp and the empty stamp are not, and the store is never asked", async () => {
292
+ const accounts = seeded(localIdpIdFor("operator@example.com"));
293
+ const bySubject = vi.spyOn(accounts, "findDirectByIdpId");
294
+
295
+ expect(
296
+ await isPreSignInOperatorStamp(
297
+ accounts,
298
+ accountIdFor(localIdpIdFor("operator@example.com")),
299
+ ),
300
+ ).toBe(false);
301
+ expect(await isPreSignInOperatorStamp(accounts, "")).toBe(false);
302
+ expect(bySubject).not.toHaveBeenCalled();
303
+ });
304
+
305
+ it("a store fault propagates as the same error", async () => {
306
+ const fault = new Error("store is on fire");
307
+ const broken: AccountsBySubject = {
308
+ findDirectByIdpId: () => Promise.reject(fault),
309
+ };
310
+ await expect(
311
+ isPreSignInOperatorStamp(broken, "operator@example.com"),
312
+ ).rejects.toBe(fault);
313
+ });
314
+ });
315
+
316
+ describe("mayProvisionDirectAccount — provisionMyAccount's admission", () => {
317
+ const PERSON = "auth0|platform-person";
318
+
319
+ function row(
320
+ id: string,
321
+ idpId: string,
322
+ mode: IdentityAccountProvisioningMode,
323
+ ) {
324
+ return create(IdentityAccountSchema, {
325
+ metadata: { id },
326
+ spec: { idpId, provisioningMode: mode },
327
+ });
328
+ }
329
+
330
+ /** The port's semantics: the direct read answers no federated and no platform-client row. */
331
+ function accountsOf(...rows: ReturnType<typeof row>[]): AccountsByCaller {
332
+ return {
333
+ findById: (id) =>
334
+ Promise.resolve(rows.find((r) => r.metadata?.id === id)),
335
+ findDirectByIdpId: (idpId) =>
336
+ Promise.resolve(
337
+ rows.find(
338
+ (r) =>
339
+ r.spec?.idpId === idpId &&
340
+ r.spec.provisioningMode !==
341
+ IdentityAccountProvisioningMode.federated &&
342
+ r.spec.provisioningMode !==
343
+ IdentityAccountProvisioningMode.platform_client,
344
+ ),
345
+ ),
346
+ };
347
+ }
348
+
349
+ const direct = row(
350
+ accountIdFor(PERSON),
351
+ PERSON,
352
+ IdentityAccountProvisioningMode.direct,
353
+ );
354
+ const federated = row(
355
+ "ida_federated",
356
+ PERSON,
357
+ IdentityAccountProvisioningMode.federated,
358
+ );
359
+ const endUser = row(
360
+ accountIdFor("stgm_pc|acme|user-7"),
361
+ "stgm_pc|acme|user-7",
362
+ IdentityAccountProvisioningMode.platform_client,
363
+ );
364
+ const lane = row(
365
+ "ida_guestlane",
366
+ "stgm_guest|acme",
367
+ IdentityAccountProvisioningMode.identity_account_provisioning_mode_unspecified,
368
+ );
369
+ const token = (sub: string) => ({
370
+ issuer: "https://issuer.test",
371
+ rawToken: tokenFor(sub),
372
+ });
373
+
374
+ it.each([
375
+ [
376
+ "the trusted-local operator",
377
+ accountsOf(),
378
+ caller({ identityId: "operator@example.com" }),
379
+ localIdpIdFor("operator@example.com"),
380
+ ],
381
+ [
382
+ "an idp-shaped person before their first provisioning",
383
+ accountsOf(),
384
+ caller({ identityId: PERSON, ...token(PERSON) }),
385
+ PERSON,
386
+ ],
387
+ [
388
+ "a person who is already their subject's direct account",
389
+ accountsOf(direct),
390
+ caller({ identityId: direct.metadata!.id, ...token(PERSON) }),
391
+ PERSON,
392
+ ],
393
+ ])("admits %s", async (_name, accounts, who, subject) => {
394
+ expect(await mayProvisionDirectAccount(accounts, who, subject)).toBe(true);
395
+ });
396
+
397
+ it.each([
398
+ [
399
+ "a federated account whose provider minted a platform person's subject",
400
+ accountsOf(direct, federated),
401
+ caller({ identityId: federated.metadata!.id, ...token(PERSON) }),
402
+ PERSON,
403
+ ],
404
+ [
405
+ "a federated account whose subject no platform person holds",
406
+ accountsOf(federated),
407
+ caller({ identityId: federated.metadata!.id, ...token(PERSON) }),
408
+ PERSON,
409
+ ],
410
+ [
411
+ "a platform client's user",
412
+ accountsOf(endUser),
413
+ caller({
414
+ identityId: endUser.metadata!.id,
415
+ ...token("stgm_pc|acme|user-7"),
416
+ }),
417
+ "stgm_pc|acme|user-7",
418
+ ],
419
+ [
420
+ "a system lane's token, whose subject is its lane account's id",
421
+ accountsOf(lane),
422
+ caller({
423
+ identityId: lane.metadata!.id,
424
+ callerClass: "user",
425
+ ...token(lane.metadata!.id),
426
+ }),
427
+ lane.metadata!.id,
428
+ ],
429
+ [
430
+ "a caller of another class, idp-shaped",
431
+ accountsOf(),
432
+ caller({
433
+ identityId: "stgm_channel|acme",
434
+ callerClass: "channel",
435
+ ...token("stgm_channel|acme"),
436
+ }),
437
+ "stgm_channel|acme",
438
+ ],
439
+ [
440
+ "an identity that is neither its subject nor an account",
441
+ accountsOf(),
442
+ caller({ identityId: "someone-else", ...token(PERSON) }),
443
+ PERSON,
444
+ ],
445
+ [
446
+ "a credential naming no subject",
447
+ accountsOf(),
448
+ caller({ identityId: "", ...token("") }),
449
+ "",
450
+ ],
451
+ ])("refuses %s", async (_name, accounts, who, subject) => {
452
+ expect(await mayProvisionDirectAccount(accounts, who, subject)).toBe(false);
453
+ });
454
+
455
+ it("a store fault propagates as the same error", async () => {
456
+ const fault = new Error("store is on fire");
457
+ const broken: AccountsByCaller = {
458
+ findById: () => Promise.reject(fault),
459
+ findDirectByIdpId: () => Promise.reject(fault),
460
+ };
461
+ await expect(
462
+ mayProvisionDirectAccount(
463
+ broken,
464
+ caller({ identityId: PERSON, ...token(PERSON) }),
465
+ PERSON,
466
+ ),
467
+ ).rejects.toBe(fault);
468
+ });
469
+ });
@@ -53,7 +53,7 @@ const CONTRACT_CASE_NAMES = [
53
53
  "findByIds answers the present ones in request order and skips the unknown",
54
54
  "a disconnected store is an infrastructure fault, never 'not found'",
55
55
  "two concurrent saves of one subject end in fulfilments and DuplicateAccountErrors only, and the winner is readable by subject",
56
- "findDirectByIdpId and findDirectByEmail never answer a federated account, while findByIdpId (any mode) does",
56
+ "no subject lookup answers a federated account: its subject is its identity provider's",
57
57
  "findDirectByIdpId and findDirectByEmail never answer a platform-client account, while findByIdpId (any mode) does",
58
58
  "findByIds answers one row per distinct id, in first-occurrence order; an empty request answers an empty list",
59
59
  "update of an unknown id is a no-op: no row appears",
@@ -49,6 +49,16 @@ export function accountIdFor(idpId: string): string {
49
49
  return derivedId(ACCOUNT_ID_PREFIX, idpId);
50
50
  }
51
51
 
52
+ /**
53
+ * Whether `id` has an account id's shape, `ida_<...>`: a derived id and a
54
+ * minted one share it (see the header). A shape test, not an existence
55
+ * check. Its one use is to skip a read that could only miss, since no
56
+ * account carries an account id as its subject (resolve.ts).
57
+ */
58
+ export function isAccountIdShaped(id: string): boolean {
59
+ return id.startsWith(`${ACCOUNT_ID_PREFIX}_`);
60
+ }
61
+
52
62
  /**
53
63
  * The subject namespace of the trusted-local posture. An OIDC subject is
54
64
  * `<connection>|<id>` by Auth0 convention; `local|` claims the same shape
@@ -142,6 +152,16 @@ export const ACCOUNT_NOT_FOUND_FOR_CALLER_MESSAGE =
142
152
  export const NO_IDP_ID_MESSAGE =
143
153
  "Cannot provision account: no IDP ID in authentication context";
144
154
 
155
+ /**
156
+ * provisionMyAccount for a caller the platform's own sign-in did not vouch
157
+ * for (PERMISSION_DENIED): a person of an organization's identity provider,
158
+ * a platform client's user, a system lane's token, or any caller that is
159
+ * not a person. Names no account: the refusal answers before the store is
160
+ * asked about the credential's subject.
161
+ */
162
+ export const NOT_A_DIRECT_SIGN_IN_MESSAGE =
163
+ "Cannot provision account: this RPC provisions a person signing in through this platform's own sign-in, and another lane vouched for this credential";
164
+
145
165
  /** provisionMyAccount when the issuer's userinfo cannot be read (UNAVAILABLE); the cause follows. */
146
166
  export const USERINFO_UNAVAILABLE_PREFIX =
147
167
  "Failed to fetch user profile from identity provider: ";
@@ -31,7 +31,9 @@
31
31
  * unprovisioned), getByEmail and getByIdpId (lookup FIRST, then
32
32
  * authorizeDirect on the FOUND id — the cloud's order; the annotation's
33
33
  * `field_path = "value"` would otherwise hand the Authorizer an email as a
34
- * resource id), getActorInfo, and provisionMyAccount (the provisioner,
34
+ * resource id), getActorInfo, and provisionMyAccount (PERMISSION_DENIED
35
+ * first for a caller the platform's own sign-in did not vouch for,
36
+ * resolve.ts `mayProvisionDirectAccount`; then the provisioner,
35
37
  * then — on the call that CREATED the row — the core AccountCreatedHook
36
38
  * (open source's membership rules, 20260913.01 slice 4), then the composed
37
39
  * post-persist gates; UNAUTHENTICATED with the cloud's copy for a
@@ -101,6 +103,7 @@ import {
101
103
  ACCOUNT_NOT_FOUND_FOR_CALLER_MESSAGE,
102
104
  CREATE_IS_INTERNAL_MESSAGE,
103
105
  NO_IDP_ID_MESSAGE,
106
+ NOT_A_DIRECT_SIGN_IN_MESSAGE,
104
107
  USERINFO_UNAVAILABLE_PREFIX,
105
108
  federationUnimplementedMessage,
106
109
  idpIdOf,
@@ -113,7 +116,7 @@ import type {
113
116
  DirectAccountProvisioner,
114
117
  } from "./provisioning.js";
115
118
  import { UserInfoFetchError } from "./provisioning.js";
116
- import { accountForCaller } from "./resolve.js";
119
+ import { accountForCaller, mayProvisionDirectAccount } from "./resolve.js";
117
120
  import {
118
121
  accountNotFoundError,
119
122
  newAssignBackendFieldsStep,
@@ -509,7 +512,7 @@ async function getByEmail(
509
512
  );
510
513
  }
511
514
 
512
- /** getByIdpId — any provisioning mode; lookup first, authorize on the FOUND id. */
515
+ /** getByIdpId — any provisioning mode but federated (a federated subject is its provider's: getByExternalSub); lookup first, authorize on the FOUND id. */
513
516
  async function getByIdpId(
514
517
  deps: IdentityAccountControllerDeps,
515
518
  idpId: IdpId,
@@ -548,8 +551,10 @@ async function lookupThenAuthorize(
548
551
  // ---------------------------------------------------------------------------
549
552
 
550
553
  /**
551
- * provisionMyAccount — the subject from the caller's credential, the
552
- * provisioner's flow, then two post-persist consumers with the caller
554
+ * provisionMyAccount — the subject from the caller's credential, admitted
555
+ * only for a caller the platform's own sign-in vouched for
556
+ * (`mayProvisionDirectAccount`), the provisioner's flow, then two
557
+ * post-persist consumers with the caller
553
558
  * RE-STAMPED as the account: the position-1 identity was idp-shaped
554
559
  * because no row existed when the verifier ran, and anything that
555
560
  * attributes ownership must name the account, never a principal no later
@@ -582,6 +587,16 @@ async function provisionMyAccount(
582
587
  if (idpId === "") {
583
588
  throw new ConnectError(NO_IDP_ID_MESSAGE, Code.Unauthenticated);
584
589
  }
590
+ // Before any read of the subject: a credential another lane vouched for
591
+ // names a subject that lane chose, and the direct account under it is a
592
+ // platform person's to hold, never that lane's to provision or read.
593
+ const admitted = await read(
594
+ () => mayProvisionDirectAccount(deps.accounts, caller, idpId),
595
+ "failed to resolve the caller's account",
596
+ );
597
+ if (!admitted) {
598
+ throw new ConnectError(NOT_A_DIRECT_SIGN_IN_MESSAGE, Code.PermissionDenied);
599
+ }
585
600
  let account: IdentityAccount;
586
601
  let created: boolean;
587
602
  try {
@@ -54,11 +54,45 @@
54
54
  * what "nobody" means (the fire caller's deterministic refusal, the
55
55
  * verifier's liveness sentence), so this function answers `undefined`
56
56
  * and never throws for it. The empty stamp is `undefined` with no read.
57
+ *
58
+ * The fourth reading asks of a stamp that named nobody whether it is the
59
+ * operator's from before sign-in was turned on:
60
+ * `isPreSignInOperatorStamp` (stigmer/stigmer#1169). Under the
61
+ * trusted-local posture every write is stamped with the operator's email,
62
+ * or with the "system" placeholder when no email is configured, and the
63
+ * operator's account carries the subject `local|<that stamp>`. After
64
+ * sign-in the operator signs in as a different account, one derived from
65
+ * the issuer's subject, which by construction never collides with a
66
+ * `local|` one (constants.ts). So such a stamp names a principal no
67
+ * signed-in person is. The API-key verifier asks this so it can refuse
68
+ * such a key by name instead of admitting a bare email. The answer is yes
69
+ * for "system" with no read, and for any other stamp when the store holds
70
+ * `local|<stamp>`, which is one direct-subject read. An account-id stamp
71
+ * and the empty stamp answer no with no read: the common key costs its
72
+ * verifier nothing.
73
+ *
74
+ * The fifth reading asks of a caller whether the platform's own sign-in
75
+ * vouched for it: `mayProvisionDirectAccount`, provisionMyAccount's
76
+ * admission. That RPC provisions the DIRECT account of the credential's
77
+ * subject, and a subject names a direct account only when the lane that
78
+ * admitted the caller is one of the platform's own. Every such lane
79
+ * resolves its caller through `identityIdForSubject` and stamps the `user`
80
+ * class, so its caller is either idp-shaped (no account, and the identity
81
+ * is the subject itself) or the direct account of that subject. Anything
82
+ * else was vouched for by another lane: an organization's identity
83
+ * provider stamps its own federated account, a platform client's user
84
+ * token its own account, a system lane its lane account or raw lane
85
+ * subject. Their `sub` is theirs to choose, so provisioning by it would
86
+ * hand them a platform person's row, or create one under the subject with
87
+ * a profile fetched from their own issuer. The trusted-local operator, who
88
+ * carries no issuer and no token, is the posture's own and is admitted.
89
+ * Two primary-key reads; faults propagate as they are.
57
90
  */
58
91
  import type { IdentityAccount } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/api_pb";
59
92
 
60
93
  import type { CallerIdentity } from "../../extensions/identity.js";
61
- import { idpIdOf } from "./constants.js";
94
+ import { SYSTEM_OPERATOR_IDENTITY_ID } from "../../pipeline/interceptors/auth.js";
95
+ import { idpIdOf, isAccountIdShaped, localIdpIdFor } from "./constants.js";
62
96
  import type { IdentityAccountStore } from "./store.js";
63
97
 
64
98
  /** The one read a verifier needs from the domain: the direct account for a subject. */
@@ -124,3 +158,48 @@ export async function accountForStamp(
124
158
  (await accounts.findDirectByIdpId(stamp))
125
159
  );
126
160
  }
161
+
162
+ /**
163
+ * Whether a creator stamp is the operator's from before sign-in was turned
164
+ * on: the "system" placeholder, or an email whose `local|<email>` account
165
+ * the store holds. Faults propagate as they are.
166
+ */
167
+ export async function isPreSignInOperatorStamp(
168
+ accounts: AccountsBySubject,
169
+ stamp: string,
170
+ ): Promise<boolean> {
171
+ if (stamp === SYSTEM_OPERATOR_IDENTITY_ID) {
172
+ return true;
173
+ }
174
+ if (stamp === "" || isAccountIdShaped(stamp)) {
175
+ return false;
176
+ }
177
+ return (await accounts.findDirectByIdpId(localIdpIdFor(stamp))) !== undefined;
178
+ }
179
+
180
+ /**
181
+ * Whether provisionMyAccount may provision the direct account of
182
+ * `subject` (the caller's `idpIdOf`) for `caller`: the trusted-local
183
+ * operator; or a `user`-class caller that is idp-shaped (no account under
184
+ * its identity, which is the subject itself) or is already that subject's
185
+ * direct account. Faults propagate as they are.
186
+ */
187
+ export async function mayProvisionDirectAccount(
188
+ accounts: AccountsByCaller,
189
+ caller: CallerIdentity,
190
+ subject: string,
191
+ ): Promise<boolean> {
192
+ if (caller.issuer === "" && caller.rawToken === "") {
193
+ return true;
194
+ }
195
+ if (caller.callerClass !== "user" || subject === "") {
196
+ return false;
197
+ }
198
+ const standing = await accounts.findById(caller.identityId);
199
+ if (standing === undefined) {
200
+ return caller.identityId === subject;
201
+ }
202
+ const standingId = standing.metadata?.id ?? "";
203
+ const direct = await accounts.findDirectByIdpId(subject);
204
+ return standingId !== "" && direct?.metadata?.id === standingId;
205
+ }
@@ -103,7 +103,12 @@ export function newResourceIdentityAccountStore(
103
103
 
104
104
  findById: readById,
105
105
 
106
- findByIdpId: readBySubject,
106
+ async findByIdpId(idpId): Promise<IdentityAccount | undefined> {
107
+ const account = await readBySubject(idpId);
108
+ return account !== undefined && !isFederated(account)
109
+ ? account
110
+ : undefined;
111
+ },
107
112
 
108
113
  async findDirectByIdpId(idpId): Promise<IdentityAccount | undefined> {
109
114
  const account = await readBySubject(idpId);
@@ -151,6 +156,14 @@ export function newResourceIdentityAccountStore(
151
156
  * asserted, so no direct lookup — a verifier's subject resolve, getByEmail —
152
157
  * may answer it.
153
158
  */
159
+ /** A row an identity provider vouches for: its subject is the provider's, reached only by the natural key. */
160
+ function isFederated(account: IdentityAccount): boolean {
161
+ return (
162
+ account.spec?.identityProviderRef !== undefined ||
163
+ account.spec?.provisioningMode === IdentityAccountProvisioningMode.federated
164
+ );
165
+ }
166
+
154
167
  function isDirect(account: IdentityAccount): boolean {
155
168
  const mode = account.spec?.provisioningMode;
156
169
  return (