@stigmer/server 3.40.1 → 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 (527) 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 +132 -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 +4 -3
  107. package/dist/domain/channelapp/controller.d.ts.map +1 -1
  108. package/dist/domain/channelapp/controller.js.map +1 -1
  109. package/dist/domain/executioncontext/steps.d.ts +2 -1
  110. package/dist/domain/executioncontext/steps.d.ts.map +1 -1
  111. package/dist/domain/executioncontext/steps.js +2 -1
  112. package/dist/domain/executioncontext/steps.js.map +1 -1
  113. package/dist/domain/iampolicy/access-lists.d.ts.map +1 -1
  114. package/dist/domain/iampolicy/access-lists.js +57 -2
  115. package/dist/domain/iampolicy/access-lists.js.map +1 -1
  116. package/dist/domain/iampolicy/change.d.ts +53 -0
  117. package/dist/domain/iampolicy/change.d.ts.map +1 -0
  118. package/dist/domain/iampolicy/change.js +44 -0
  119. package/dist/domain/iampolicy/change.js.map +1 -0
  120. package/dist/domain/iampolicy/constants.d.ts +6 -0
  121. package/dist/domain/iampolicy/constants.d.ts.map +1 -1
  122. package/dist/domain/iampolicy/constants.js +6 -0
  123. package/dist/domain/iampolicy/constants.js.map +1 -1
  124. package/dist/domain/iampolicy/controller.d.ts.map +1 -1
  125. package/dist/domain/iampolicy/controller.js +9 -5
  126. package/dist/domain/iampolicy/controller.js.map +1 -1
  127. package/dist/domain/iampolicy/grant-path.d.ts +31 -13
  128. package/dist/domain/iampolicy/grant-path.d.ts.map +1 -1
  129. package/dist/domain/iampolicy/grant-path.js +216 -19
  130. package/dist/domain/iampolicy/grant-path.js.map +1 -1
  131. package/dist/domain/iampolicy/membership.d.ts +11 -3
  132. package/dist/domain/iampolicy/membership.d.ts.map +1 -1
  133. package/dist/domain/iampolicy/membership.js +18 -13
  134. package/dist/domain/iampolicy/membership.js.map +1 -1
  135. package/dist/domain/iampolicy/resource-store.d.ts.map +1 -1
  136. package/dist/domain/iampolicy/resource-store.js +4 -0
  137. package/dist/domain/iampolicy/resource-store.js.map +1 -1
  138. package/dist/domain/iampolicy/role-lifecycle.d.ts.map +1 -1
  139. package/dist/domain/iampolicy/role-lifecycle.js +2 -2
  140. package/dist/domain/iampolicy/role-lifecycle.js.map +1 -1
  141. package/dist/domain/iampolicy/roles.d.ts.map +1 -1
  142. package/dist/domain/iampolicy/roles.js +7 -0
  143. package/dist/domain/iampolicy/roles.js.map +1 -1
  144. package/dist/domain/iampolicy/steps.d.ts +4 -3
  145. package/dist/domain/iampolicy/steps.d.ts.map +1 -1
  146. package/dist/domain/iampolicy/steps.js +7 -7
  147. package/dist/domain/iampolicy/steps.js.map +1 -1
  148. package/dist/domain/iampolicy/store-contract.d.ts.map +1 -1
  149. package/dist/domain/iampolicy/store-contract.js +22 -1
  150. package/dist/domain/iampolicy/store-contract.js.map +1 -1
  151. package/dist/domain/iampolicy/store.d.ts +18 -5
  152. package/dist/domain/iampolicy/store.d.ts.map +1 -1
  153. package/dist/domain/iampolicy/store.js.map +1 -1
  154. package/dist/domain/identityaccount/constants.d.ts +15 -0
  155. package/dist/domain/identityaccount/constants.d.ts.map +1 -1
  156. package/dist/domain/identityaccount/constants.js +17 -0
  157. package/dist/domain/identityaccount/constants.js.map +1 -1
  158. package/dist/domain/identityaccount/controller.d.ts.map +1 -1
  159. package/dist/domain/identityaccount/controller.js +17 -6
  160. package/dist/domain/identityaccount/controller.js.map +1 -1
  161. package/dist/domain/identityaccount/resolve.d.ts +47 -0
  162. package/dist/domain/identityaccount/resolve.d.ts.map +1 -1
  163. package/dist/domain/identityaccount/resolve.js +38 -1
  164. package/dist/domain/identityaccount/resolve.js.map +1 -1
  165. package/dist/domain/identityaccount/resource-store.d.ts.map +1 -1
  166. package/dist/domain/identityaccount/resource-store.js +11 -1
  167. package/dist/domain/identityaccount/resource-store.js.map +1 -1
  168. package/dist/domain/identityaccount/steps.d.ts +2 -1
  169. package/dist/domain/identityaccount/steps.d.ts.map +1 -1
  170. package/dist/domain/identityaccount/steps.js +4 -3
  171. package/dist/domain/identityaccount/steps.js.map +1 -1
  172. package/dist/domain/identityaccount/store-contract.js +2 -2
  173. package/dist/domain/identityaccount/store-contract.js.map +1 -1
  174. package/dist/domain/identityaccount/store.d.ts +6 -1
  175. package/dist/domain/identityaccount/store.d.ts.map +1 -1
  176. package/dist/domain/mcpserver/connect-sandbox.d.ts +67 -0
  177. package/dist/domain/mcpserver/connect-sandbox.d.ts.map +1 -0
  178. package/dist/domain/mcpserver/connect-sandbox.js +64 -0
  179. package/dist/domain/mcpserver/connect-sandbox.js.map +1 -0
  180. package/dist/domain/mcpserver/connect.d.ts +42 -10
  181. package/dist/domain/mcpserver/connect.d.ts.map +1 -1
  182. package/dist/domain/mcpserver/connect.js +147 -40
  183. package/dist/domain/mcpserver/connect.js.map +1 -1
  184. package/dist/domain/mcpserver/controller.js +4 -2
  185. package/dist/domain/mcpserver/controller.js.map +1 -1
  186. package/dist/domain/mcpserver/engine.d.ts +26 -7
  187. package/dist/domain/mcpserver/engine.d.ts.map +1 -1
  188. package/dist/domain/mcpserver/engine.js.map +1 -1
  189. package/dist/domain/mcpserver/start-connect.d.ts +5 -0
  190. package/dist/domain/mcpserver/start-connect.d.ts.map +1 -1
  191. package/dist/domain/mcpserver/start-connect.js +38 -15
  192. package/dist/domain/mcpserver/start-connect.js.map +1 -1
  193. package/dist/domain/memory/controller.js +2 -1
  194. package/dist/domain/memory/controller.js.map +1 -1
  195. package/dist/domain/memory/list-index.d.ts +2 -0
  196. package/dist/domain/memory/list-index.d.ts.map +1 -0
  197. package/dist/domain/memory/list-index.js +31 -0
  198. package/dist/domain/memory/list-index.js.map +1 -0
  199. package/dist/domain/memory/queries.d.ts +10 -0
  200. package/dist/domain/memory/queries.d.ts.map +1 -0
  201. package/dist/domain/memory/queries.js +54 -0
  202. package/dist/domain/memory/queries.js.map +1 -0
  203. package/dist/domain/memory/steps.d.ts +13 -11
  204. package/dist/domain/memory/steps.d.ts.map +1 -1
  205. package/dist/domain/memory/steps.js +26 -57
  206. package/dist/domain/memory/steps.js.map +1 -1
  207. package/dist/domain/organization/steps.d.ts.map +1 -1
  208. package/dist/domain/organization/steps.js +1 -1
  209. package/dist/domain/organization/steps.js.map +1 -1
  210. package/dist/domain/platformclient/mint.d.ts.map +1 -1
  211. package/dist/domain/platformclient/mint.js +2 -2
  212. package/dist/domain/platformclient/mint.js.map +1 -1
  213. package/dist/domain/platformclient/verifier.d.ts.map +1 -1
  214. package/dist/domain/platformclient/verifier.js +6 -3
  215. package/dist/domain/platformclient/verifier.js.map +1 -1
  216. package/dist/domain/plugin/push.d.ts.map +1 -1
  217. package/dist/domain/plugin/push.js +1 -0
  218. package/dist/domain/plugin/push.js.map +1 -1
  219. package/dist/domain/schedule/steps.d.ts +3 -1
  220. package/dist/domain/schedule/steps.d.ts.map +1 -1
  221. package/dist/domain/schedule/steps.js +3 -1
  222. package/dist/domain/schedule/steps.js.map +1 -1
  223. package/dist/domain/skill/push.d.ts.map +1 -1
  224. package/dist/domain/skill/push.js +1 -0
  225. package/dist/domain/skill/push.js.map +1 -1
  226. package/dist/domain/workflow/registry/data/task-kind-registry.json +27 -1
  227. package/dist/domain/workflowexecution/submit-approval.d.ts +5 -2
  228. package/dist/domain/workflowexecution/submit-approval.d.ts.map +1 -1
  229. package/dist/domain/workflowexecution/submit-approval.js +1 -1
  230. package/dist/domain/workflowexecution/submit-approval.js.map +1 -1
  231. package/dist/domain/workflowexecution/submit-file-decision.d.ts +5 -2
  232. package/dist/domain/workflowexecution/submit-file-decision.d.ts.map +1 -1
  233. package/dist/domain/workflowexecution/submit-file-decision.js +1 -1
  234. package/dist/domain/workflowexecution/submit-file-decision.js.map +1 -1
  235. package/dist/domain/workflowexecution/submit-workflow-task-approval.d.ts.map +1 -1
  236. package/dist/domain/workflowexecution/submit-workflow-task-approval.js +12 -1
  237. package/dist/domain/workflowexecution/submit-workflow-task-approval.js.map +1 -1
  238. package/dist/domain/workflowinstance/controller.d.ts +6 -3
  239. package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
  240. package/dist/domain/workflowinstance/controller.js +12 -7
  241. package/dist/domain/workflowinstance/controller.js.map +1 -1
  242. package/dist/domain/workflowinstance/steps.d.ts +31 -0
  243. package/dist/domain/workflowinstance/steps.d.ts.map +1 -1
  244. package/dist/domain/workflowinstance/steps.js +88 -1
  245. package/dist/domain/workflowinstance/steps.js.map +1 -1
  246. package/dist/extensions/composed-services.d.ts +56 -0
  247. package/dist/extensions/composed-services.d.ts.map +1 -0
  248. package/dist/extensions/composed-services.js +2 -0
  249. package/dist/extensions/composed-services.js.map +1 -0
  250. package/dist/extensions/drivers.d.ts +32 -1
  251. package/dist/extensions/drivers.d.ts.map +1 -1
  252. package/dist/extensions/identity.d.ts +4 -1
  253. package/dist/extensions/identity.d.ts.map +1 -1
  254. package/dist/extensions/identity.js +4 -1
  255. package/dist/extensions/identity.js.map +1 -1
  256. package/dist/extensions/registry.d.ts +37 -0
  257. package/dist/extensions/registry.d.ts.map +1 -1
  258. package/dist/extensions/registry.js +50 -0
  259. package/dist/extensions/registry.js.map +1 -1
  260. package/dist/extensions/resource-authorization.d.ts +78 -0
  261. package/dist/extensions/resource-authorization.d.ts.map +1 -1
  262. package/dist/extensions/resource-row-reader.d.ts +43 -0
  263. package/dist/extensions/resource-row-reader.d.ts.map +1 -0
  264. package/dist/extensions/resource-row-reader.js +2 -0
  265. package/dist/extensions/resource-row-reader.js.map +1 -0
  266. package/dist/extensions/visitor-classifier.d.ts +41 -0
  267. package/dist/extensions/visitor-classifier.d.ts.map +1 -0
  268. package/dist/extensions/visitor-classifier.js +2 -0
  269. package/dist/extensions/visitor-classifier.js.map +1 -0
  270. package/dist/identity/oidc-userinfo.d.ts +6 -1
  271. package/dist/identity/oidc-userinfo.d.ts.map +1 -1
  272. package/dist/identity/oidc-userinfo.js.map +1 -1
  273. package/dist/identity/oidc-verifier.d.ts.map +1 -1
  274. package/dist/identity/oidc-verifier.js +37 -8
  275. package/dist/identity/oidc-verifier.js.map +1 -1
  276. package/dist/index.d.ts +14 -6
  277. package/dist/index.d.ts.map +1 -1
  278. package/dist/index.js +25 -9
  279. package/dist/index.js.map +1 -1
  280. package/dist/pipeline/errors.d.ts +8 -0
  281. package/dist/pipeline/errors.d.ts.map +1 -1
  282. package/dist/pipeline/errors.js +25 -16
  283. package/dist/pipeline/errors.js.map +1 -1
  284. package/dist/pipeline/interceptors/auth.d.ts +17 -9
  285. package/dist/pipeline/interceptors/auth.d.ts.map +1 -1
  286. package/dist/pipeline/interceptors/auth.js +17 -9
  287. package/dist/pipeline/interceptors/auth.js.map +1 -1
  288. package/dist/pipeline/steps/authorization-tuples.d.ts +23 -1
  289. package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
  290. package/dist/pipeline/steps/authorization-tuples.js +42 -0
  291. package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
  292. package/dist/pipeline/steps/authorize.d.ts +6 -5
  293. package/dist/pipeline/steps/authorize.d.ts.map +1 -1
  294. package/dist/pipeline/steps/authorize.js +6 -5
  295. package/dist/pipeline/steps/authorize.js.map +1 -1
  296. package/dist/pipeline/steps/defaults.d.ts +12 -0
  297. package/dist/pipeline/steps/defaults.d.ts.map +1 -1
  298. package/dist/pipeline/steps/defaults.js +42 -7
  299. package/dist/pipeline/steps/defaults.js.map +1 -1
  300. package/dist/pipeline/steps/guard-memory-capture.d.ts +13 -15
  301. package/dist/pipeline/steps/guard-memory-capture.d.ts.map +1 -1
  302. package/dist/pipeline/steps/guard-memory-capture.js +2 -3
  303. package/dist/pipeline/steps/guard-memory-capture.js.map +1 -1
  304. package/dist/runnerauth/built-in-runner-credential-provider.d.ts +0 -2
  305. package/dist/runnerauth/built-in-runner-credential-provider.d.ts.map +1 -1
  306. package/dist/runnerauth/built-in-runner-credential-provider.js +8 -17
  307. package/dist/runnerauth/built-in-runner-credential-provider.js.map +1 -1
  308. package/dist/runnerauth/runner-credential-provider.d.ts +17 -7
  309. package/dist/runnerauth/runner-credential-provider.d.ts.map +1 -1
  310. package/dist/runnerauth/runner-credential-provider.js.map +1 -1
  311. package/dist/sandbox/docker.d.ts.map +1 -1
  312. package/dist/sandbox/docker.js +3 -0
  313. package/dist/sandbox/docker.js.map +1 -1
  314. package/dist/sandbox/kubernetes.d.ts.map +1 -1
  315. package/dist/sandbox/kubernetes.js +3 -0
  316. package/dist/sandbox/kubernetes.js.map +1 -1
  317. package/dist/sandbox/local-process.d.ts.map +1 -1
  318. package/dist/sandbox/local-process.js +4 -0
  319. package/dist/sandbox/local-process.js.map +1 -1
  320. package/dist/sandbox/provisioner.d.ts +18 -6
  321. package/dist/sandbox/provisioner.d.ts.map +1 -1
  322. package/dist/sandbox/provisioner.js.map +1 -1
  323. package/dist/temporal/manager.d.ts +5 -0
  324. package/dist/temporal/manager.d.ts.map +1 -1
  325. package/dist/temporal/manager.js +9 -0
  326. package/dist/temporal/manager.js.map +1 -1
  327. package/dist/temporal/mcpserver/engine-client.d.ts +2 -2
  328. package/dist/temporal/mcpserver/engine-client.d.ts.map +1 -1
  329. package/dist/temporal/mcpserver/engine-client.js +6 -4
  330. package/dist/temporal/mcpserver/engine-client.js.map +1 -1
  331. package/dist/temporal/mcpserver/names.d.ts +13 -2
  332. package/dist/temporal/mcpserver/names.d.ts.map +1 -1
  333. package/dist/temporal/mcpserver/names.js +15 -2
  334. package/dist/temporal/mcpserver/names.js.map +1 -1
  335. package/dist/temporal/sdk-logger.d.ts +74 -0
  336. package/dist/temporal/sdk-logger.d.ts.map +1 -0
  337. package/dist/temporal/sdk-logger.js +143 -0
  338. package/dist/temporal/sdk-logger.js.map +1 -0
  339. package/package.json +6 -6
  340. package/src/authorization/README.md +18 -6
  341. package/src/authorization/__tests__/authorizer.test.ts +5 -1
  342. package/src/authorization/__tests__/derived-tuples.test.ts +26 -0
  343. package/src/authorization/__tests__/evaluator.test.ts +4 -0
  344. package/src/authorization/__tests__/list-read-scope.test.ts +11 -5
  345. package/src/authorization/__tests__/store-tests.test.ts +3 -1
  346. package/src/authorization/__tests__/trusted-local-authorizer.test.ts +155 -0
  347. package/src/authorization/__tests__/unit-owned-kinds.test.ts +420 -0
  348. package/src/authorization/__tests__/wire-permissions.test.ts +31 -2
  349. package/src/authorization/authorizer.ts +21 -10
  350. package/src/authorization/derived-tuples.ts +92 -18
  351. package/src/authorization/evaluator.ts +30 -15
  352. package/src/authorization/list-read-scope.ts +4 -0
  353. package/src/authorization/model/__tests__/registry.test.ts +23 -0
  354. package/src/authorization/model/data/authorization-model.json +830 -67
  355. package/src/authorization/model/execution-viewer.ts +32 -27
  356. package/src/authorization/model/index.ts +4 -1
  357. package/src/authorization/model/rewrite.ts +5 -3
  358. package/src/authorization/organization-directory.ts +4 -0
  359. package/src/authorization/person.ts +32 -1
  360. package/src/authorization/policy-check.ts +105 -0
  361. package/src/authorization/posture.ts +45 -4
  362. package/src/authorization/resource-creators.ts +48 -0
  363. package/src/authorization/trusted-local-authorizer.ts +91 -0
  364. package/src/authorization/tuples.ts +17 -0
  365. package/src/boot/__tests__/compose.test.ts +120 -4
  366. package/src/boot/__tests__/list-indexes.test.ts +4 -0
  367. package/src/boot/__tests__/oauth-redirect-uri.test.ts +121 -10
  368. package/src/boot/__tests__/skill-transfer-origin.test.ts +96 -25
  369. package/src/boot/compose.ts +153 -61
  370. package/src/boot/config.ts +28 -12
  371. package/src/boot/inprocess.ts +18 -4
  372. package/src/boot/list-indexes.ts +6 -1
  373. package/src/boot/logger.ts +3 -1
  374. package/src/boot/oauth-redirect-uri.ts +62 -17
  375. package/src/boot/skill-transfer-origin.ts +71 -16
  376. package/src/domain/agent/__tests__/agent.test.ts +42 -1
  377. package/src/domain/agentchannel/__tests__/agentchannel.test.ts +9 -0
  378. package/src/domain/agentchannel/__tests__/channel-runtime.test.ts +2 -0
  379. package/src/domain/agentchannel/__tests__/create-authorization.test.ts +7 -6
  380. package/src/domain/agentchannel/steps.ts +9 -7
  381. package/src/domain/agentexecution/__tests__/agentexecution.test.ts +148 -56
  382. package/src/domain/agentexecution/__tests__/create-steps.test.ts +175 -12
  383. package/src/domain/agentexecution/__tests__/file-review-seed.ts +91 -0
  384. package/src/domain/agentexecution/controller.ts +8 -0
  385. package/src/domain/agentexecution/create-steps.ts +74 -44
  386. package/src/domain/agentexecution/submit-approval.ts +9 -6
  387. package/src/domain/agentexecution/submit-file-decision.ts +5 -4
  388. package/src/domain/agentinstance/__tests__/agentinstance.test.ts +2 -0
  389. package/src/domain/agentshare/__tests__/agentshare.test.ts +17 -0
  390. package/src/domain/agentshare/__tests__/create-authorization.test.ts +5 -4
  391. package/src/domain/agentshare/steps.ts +6 -4
  392. package/src/domain/apikey/__tests__/verifier.test.ts +73 -1
  393. package/src/domain/apikey/verifier.ts +45 -1
  394. package/src/domain/artifact/__tests__/artifact.test.ts +13 -24
  395. package/src/domain/channelapp/__tests__/channelapp.test.ts +7 -0
  396. package/src/domain/channelapp/controller.ts +4 -3
  397. package/src/domain/environment/__tests__/environment.test.ts +13 -0
  398. package/src/domain/executioncontext/__tests__/executioncontext.test.ts +2 -0
  399. package/src/domain/executioncontext/steps.ts +2 -1
  400. package/src/domain/iampolicy/__tests__/access-lists.test.ts +79 -0
  401. package/src/domain/iampolicy/__tests__/change.test.ts +63 -0
  402. package/src/domain/iampolicy/__tests__/controller.test.ts +39 -3
  403. package/src/domain/iampolicy/__tests__/grant-path.test.ts +595 -27
  404. package/src/domain/iampolicy/__tests__/iampolicy.test.ts +33 -2
  405. package/src/domain/iampolicy/__tests__/membership.test.ts +47 -5
  406. package/src/domain/iampolicy/__tests__/resource-store.test.ts +1 -0
  407. package/src/domain/iampolicy/__tests__/role-lifecycle.test.ts +41 -8
  408. package/src/domain/iampolicy/__tests__/roles.test.ts +3 -2
  409. package/src/domain/iampolicy/__tests__/steps.test.ts +75 -6
  410. package/src/domain/iampolicy/__tests__/support.ts +68 -4
  411. package/src/domain/iampolicy/access-lists.ts +70 -2
  412. package/src/domain/iampolicy/change.ts +109 -0
  413. package/src/domain/iampolicy/constants.ts +8 -0
  414. package/src/domain/iampolicy/controller.ts +17 -3
  415. package/src/domain/iampolicy/grant-path.ts +349 -31
  416. package/src/domain/iampolicy/membership.ts +32 -12
  417. package/src/domain/iampolicy/resource-store.ts +4 -0
  418. package/src/domain/iampolicy/role-lifecycle.ts +2 -0
  419. package/src/domain/iampolicy/roles.ts +8 -0
  420. package/src/domain/iampolicy/steps.ts +15 -5
  421. package/src/domain/iampolicy/store-contract.ts +37 -1
  422. package/src/domain/iampolicy/store.ts +19 -5
  423. package/src/domain/identityaccount/__tests__/resolve.test.ts +246 -2
  424. package/src/domain/identityaccount/__tests__/resource-store.test.ts +1 -1
  425. package/src/domain/identityaccount/constants.ts +20 -0
  426. package/src/domain/identityaccount/controller.ts +20 -5
  427. package/src/domain/identityaccount/resolve.ts +80 -1
  428. package/src/domain/identityaccount/resource-store.ts +14 -1
  429. package/src/domain/identityaccount/steps.ts +4 -3
  430. package/src/domain/identityaccount/store-contract.ts +4 -4
  431. package/src/domain/identityaccount/store.ts +6 -1
  432. package/src/domain/mcpserver/__tests__/connect-authorization.test.ts +1 -0
  433. package/src/domain/mcpserver/__tests__/connect.test.ts +358 -15
  434. package/src/domain/mcpserver/__tests__/mcpserver.test.ts +2 -0
  435. package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +2 -0
  436. package/src/domain/mcpserver/__tests__/store-faults.test.ts +2 -0
  437. package/src/domain/mcpserver/connect-sandbox.ts +135 -0
  438. package/src/domain/mcpserver/connect.ts +226 -56
  439. package/src/domain/mcpserver/controller.ts +8 -2
  440. package/src/domain/mcpserver/engine.ts +24 -6
  441. package/src/domain/mcpserver/start-connect.ts +49 -10
  442. package/src/domain/memory/__tests__/memory.test.ts +92 -22
  443. package/src/domain/memory/__tests__/queries.test.ts +173 -0
  444. package/src/domain/memory/controller.ts +2 -1
  445. package/src/domain/memory/list-index.ts +32 -0
  446. package/src/domain/memory/queries.ts +72 -0
  447. package/src/domain/memory/steps.ts +26 -63
  448. package/src/domain/oauthapp/__tests__/oauthapp.test.ts +14 -0
  449. package/src/domain/organization/__tests__/support.ts +41 -0
  450. package/src/domain/organization/steps.ts +1 -0
  451. package/src/domain/platformclient/mint.ts +6 -2
  452. package/src/domain/platformclient/verifier.ts +6 -3
  453. package/src/domain/plugin/__tests__/plugin.test.ts +11 -24
  454. package/src/domain/plugin/push.ts +1 -0
  455. package/src/domain/schedule/__tests__/schedule.composed.test.ts +2 -0
  456. package/src/domain/schedule/steps.ts +3 -1
  457. package/src/domain/session/__tests__/session.test.ts +2 -0
  458. package/src/domain/skill/__tests__/skill.test.ts +7 -25
  459. package/src/domain/skill/push.ts +1 -0
  460. package/src/domain/workflow/__tests__/workflow.test.ts +2 -0
  461. package/src/domain/workflow/registry/data/task-kind-registry.json +27 -1
  462. package/src/domain/workflowexecution/__tests__/forward-attribution-composed.test.ts +270 -0
  463. package/src/domain/workflowexecution/__tests__/submit-workflow-task-approval.test.ts +196 -0
  464. package/src/domain/workflowexecution/__tests__/workflowexecution.test.ts +3 -57
  465. package/src/domain/workflowexecution/submit-approval.ts +9 -2
  466. package/src/domain/workflowexecution/submit-file-decision.ts +6 -1
  467. package/src/domain/workflowexecution/submit-workflow-task-approval.ts +23 -5
  468. package/src/domain/workflowinstance/controller.ts +27 -9
  469. package/src/domain/workflowinstance/steps.ts +123 -1
  470. package/src/extensions/__tests__/apikey-before-sign-in-composed.test.ts +172 -0
  471. package/src/extensions/__tests__/built-in-authorization-composed.test.ts +80 -1
  472. package/src/extensions/__tests__/composed-services-composed.test.ts +236 -0
  473. package/src/extensions/__tests__/extension-composition.test.ts +229 -16
  474. package/src/extensions/__tests__/identity-account-composed.test.ts +84 -4
  475. package/src/extensions/__tests__/list-read-scope-composed.test.ts +2 -0
  476. package/src/extensions/__tests__/registry.test.ts +147 -1
  477. package/src/extensions/__tests__/secret-cleanup-composed.test.ts +2 -0
  478. package/src/extensions/__tests__/visitor-classifier-points.test.ts +42 -0
  479. package/src/extensions/composed-services.ts +61 -0
  480. package/src/extensions/drivers.ts +33 -1
  481. package/src/extensions/identity.ts +4 -1
  482. package/src/extensions/registry.ts +105 -0
  483. package/src/extensions/resource-authorization.ts +87 -0
  484. package/src/extensions/resource-row-reader.ts +43 -0
  485. package/src/extensions/visitor-classifier.ts +41 -0
  486. package/src/identity/__tests__/oidc-verifier.test.ts +38 -12
  487. package/src/identity/oidc-userinfo.ts +6 -1
  488. package/src/identity/oidc-verifier.ts +42 -8
  489. package/src/index.ts +61 -6
  490. package/src/pipeline/__tests__/steps.test.ts +31 -4
  491. package/src/pipeline/errors.ts +30 -16
  492. package/src/pipeline/interceptors/auth.ts +17 -9
  493. package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +20 -0
  494. package/src/pipeline/steps/__tests__/guard-memory-capture.test.ts +72 -15
  495. package/src/pipeline/steps/authorization-tuples.ts +54 -0
  496. package/src/pipeline/steps/authorize.ts +6 -5
  497. package/src/pipeline/steps/defaults.ts +52 -7
  498. package/src/pipeline/steps/guard-memory-capture.ts +15 -20
  499. package/src/runnerauth/__tests__/built-in-runner-credential-provider.test.ts +1 -1
  500. package/src/runnerauth/__tests__/runner-subject-composed.test.ts +13 -0
  501. package/src/runnerauth/bound-execution.ts +2 -2
  502. package/src/runnerauth/built-in-runner-credential-provider.ts +8 -21
  503. package/src/runnerauth/runner-credential-provider.ts +17 -7
  504. package/src/sandbox/__tests__/docker.integration.test.ts +4 -0
  505. package/src/sandbox/__tests__/kubernetes.test.ts +18 -1
  506. package/src/sandbox/__tests__/local-process.integration.test.ts +4 -0
  507. package/src/sandbox/__tests__/provisioner.test.ts +1 -0
  508. package/src/sandbox/docker.ts +3 -0
  509. package/src/sandbox/kubernetes.ts +3 -0
  510. package/src/sandbox/local-process.ts +4 -0
  511. package/src/sandbox/provisioner.ts +18 -6
  512. package/src/store/postgres/__tests__/support.ts +11 -2
  513. package/src/temporal/README.md +1 -0
  514. package/src/temporal/__tests__/manager.test.ts +56 -4
  515. package/src/temporal/__tests__/sdk-log-workflows.ts +26 -0
  516. package/src/temporal/__tests__/sdk-logger.e2e.test.ts +150 -0
  517. package/src/temporal/__tests__/sdk-logger.test.ts +238 -0
  518. package/src/temporal/manager.ts +9 -0
  519. package/src/temporal/mcpserver/engine-client.ts +8 -3
  520. package/src/temporal/mcpserver/names.ts +16 -2
  521. package/src/temporal/sdk-logger.ts +173 -0
  522. package/dist/authorization/lane-admission.d.ts +0 -50
  523. package/dist/authorization/lane-admission.d.ts.map +0 -1
  524. package/dist/authorization/lane-admission.js +0 -13
  525. package/dist/authorization/lane-admission.js.map +0 -1
  526. package/src/authorization/__tests__/lane-admission.test.ts +0 -115
  527. package/src/authorization/lane-admission.ts +0 -73
@@ -46,6 +46,52 @@
46
46
  * `cleanupResource` and `revokeOrgAccess` take refs and ids their callers
47
47
  * read from rows, so they do not refuse.
48
48
  *
49
+ * Leaving an organization. The model bounds every direct grant on an
50
+ * organization-scoped object by the organization (`[identity_account]
51
+ * and affiliated from organization`, fga/model/tenancy/organization.fga),
52
+ * so a person with no role left in an organization reaches nothing in it
53
+ * on the next check. This path keeps the ROWS truthful to that: when a
54
+ * revoke leaves an account with no row on an organization, it revokes the
55
+ * rows the account holds on that organization's resources (a share, a
56
+ * team membership, an owner granted by someone else), each through the
57
+ * revoke order, so a departed person is listed nowhere and a return does
58
+ * not bring the shares back. It keeps AUTHORSHIP: an `owner` or `creator`
59
+ * row whose principal is the resource's recorded creator, exactly the
60
+ * tuple open source derives from the creator stamp instead of storing it
61
+ * (authorization/derived-tuples.ts), so both editions keep the same fact
62
+ * and the model's bound governs it in both. `revokeOrgAccess` always
63
+ * sweeps, so a retry after a crash mid-sweep converges; `revokeBySpec`
64
+ * sweeps when the row it revoked was the account's last on that
65
+ * organization; `cleanupResource` never sweeps (an organization's or an
66
+ * account's delete, where the bound already leaves every row inert and a
67
+ * sweep per member would add failure points to a delete that stops on
68
+ * the first fault). A resource's organization is read from the scope
69
+ * links the rows hold (`resolveHierarchy`); open source writes none and
70
+ * grants nothing below the organization (grant-scope.ts), so there the
71
+ * sweep finds nothing to do.
72
+ *
73
+ * Affiliation. The model's bound reads `organization#affiliated`, a stored
74
+ * relation that stands exactly while the person holds a row on the
75
+ * organization. This path is the one writer of those rows, so it announces
76
+ * every change of them through the lifecycle and never decides the answer
77
+ * itself: `onOrganizationAffiliationChanging` before a row naming an
78
+ * account on an organization is deleted (the driver removes the tuple
79
+ * first, fail-closed), `onOrganizationAffiliationChanged` after such a row
80
+ * is written or deleted (the driver re-derives the tuple from the committed
81
+ * rows). `affiliated` itself is refused as a grant on every lane; it is
82
+ * derived, never granted.
83
+ *
84
+ * Who and why. Every method takes the caller, and the grants take the door
85
+ * they came through (change.ts `PolicyChangeCause`); the revokes know
86
+ * theirs. For every access row it writes or deletes, the path hands the
87
+ * store a change record (the actor, the cause, the row's organization), so
88
+ * an edition that keeps a permission history writes it in the same atomic
89
+ * unit as the row (store.ts). The organization is resolved before any row
90
+ * of the operation is deleted: `cleanupResource` removes a resource's
91
+ * scope link before its owner rows, and the sweep already knows its
92
+ * organization. The grant and revoke log lines carry the same facts, open
93
+ * source's own trail.
94
+ *
49
95
  * The row this path builds: the proto's apiVersion const and kind, the
50
96
  * derived id, the spec as given, and the caller's audit stamp through the
51
97
  * platform's one stamper (setAuditFieldsForCreate) — the cloud's
@@ -54,6 +100,7 @@
54
100
  * span organizations and none owns it.
55
101
  */
56
102
  import { create } from "@bufbuild/protobuf";
103
+ import { Code, ConnectError } from "@connectrpc/connect";
57
104
 
58
105
  import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
59
106
  import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
@@ -67,14 +114,25 @@ import type {
67
114
 
68
115
  import type { Logger } from "../../boot/logger.js";
69
116
  import type { CallerIdentity } from "../../extensions/identity.js";
70
- import type { ResourceAuthorizationLifecycle } from "../../extensions/resource-authorization.js";
117
+ import type {
118
+ OrganizationAffiliationEvent,
119
+ ResourceAuthorizationLifecycle,
120
+ } from "../../extensions/resource-authorization.js";
71
121
  import { kindEnumName } from "../../pipeline/apiresource-meta.js";
72
122
  import { setAuditFieldsForCreate } from "../../pipeline/steps/defaults.js";
73
123
  import {
124
+ AFFILIATION_NOT_GRANTABLE_MESSAGE,
74
125
  IAM_POLICY_API_VERSION,
75
126
  IAM_POLICY_KIND,
76
127
  policyIdFor,
77
128
  } from "./constants.js";
129
+ import { resolveHierarchy } from "./access-lists.js";
130
+ import { grantsAccess, policyActorOf } from "./change.js";
131
+ import type {
132
+ PolicyActor,
133
+ PolicyChangeCause,
134
+ PolicyChangeRecord,
135
+ } from "./change.js";
78
136
  import { DuplicatePolicyError } from "./store.js";
79
137
  import type { IamPolicyStore } from "./store.js";
80
138
  import { refsOf, requireWellFormedTriple } from "./wire-refusals.js";
@@ -82,6 +140,45 @@ import { refsOf, requireWellFormedTriple } from "./wire-refusals.js";
82
140
  /** The relation `cleanupResource` revokes last on the ref's own rows. */
83
141
  const OWNER_RELATION = IamRole[IamRole.owner];
84
142
 
143
+ const ACCOUNT_KIND = kindEnumName(ApiResourceKind.identity_account);
144
+ const ORGANIZATION_KIND = kindEnumName(ApiResourceKind.organization);
145
+
146
+ /** The organization relation derived from a person's roles (fga/model/tenancy/organization.fga). */
147
+ const AFFILIATED_RELATION = "affiliated";
148
+
149
+ /**
150
+ * The (account, organization) pair a row's affiliation hangs on, or
151
+ * undefined when the row is not a person's row on an organization (a
152
+ * structural link, a userset principal, a row on any other kind).
153
+ */
154
+ function affiliationOf(
155
+ spec: IamPolicySpec,
156
+ ): OrganizationAffiliationEvent | undefined {
157
+ const principal = spec.principal;
158
+ const resource = spec.resource;
159
+ if (
160
+ principal === undefined ||
161
+ resource === undefined ||
162
+ principal.kind !== ACCOUNT_KIND ||
163
+ principal.relation !== "" ||
164
+ resource.kind !== ORGANIZATION_KIND
165
+ ) {
166
+ return undefined;
167
+ }
168
+ return { identityAccountId: principal.id, organizationId: resource.id };
169
+ }
170
+
171
+ /**
172
+ * The relations a resource's creation records for its creator: `owner`
173
+ * on a kind whose owner is its creator, `creator` on a kind that also
174
+ * records one (the proto's `requires_creator_tuple`). The removal sweep
175
+ * keeps these when they name the resource's recorded creator.
176
+ */
177
+ const AUTHORSHIP_RELATIONS: ReadonlySet<string> = new Set([
178
+ OWNER_RELATION,
179
+ "creator",
180
+ ]);
181
+
85
182
  export interface GrantResult {
86
183
  readonly policy: IamPolicy;
87
184
  /** True when the triple was already held: no row was written, the hook still fired. */
@@ -90,18 +187,26 @@ export interface GrantResult {
90
187
 
91
188
  export interface IamPolicyGrantPath {
92
189
  /**
93
- * Grant the triple as `caller`: gate, find by triple, write the row when
94
- * absent (the caller's audit stamp), then `onPolicyGranted` — on the
95
- * duplicate arm too. A hook throw fails the grant with the row in place.
190
+ * Grant the triple as `caller`, through the door `cause` names: gate,
191
+ * find by triple, write the row when absent (the caller's audit stamp),
192
+ * then `onPolicyGranted` — on the duplicate arm too. A hook throw fails
193
+ * the grant with the row in place.
96
194
  */
97
- grant(spec: IamPolicySpec, caller: CallerIdentity): Promise<GrantResult>;
195
+ grant(
196
+ spec: IamPolicySpec,
197
+ caller: CallerIdentity,
198
+ cause: PolicyChangeCause,
199
+ ): Promise<GrantResult>;
98
200
  /**
99
- * Revoke the triple: gate, find by triple, `onPolicyRevoked` (with the
100
- * row, or with the spec alone on the absent arm), then delete the row.
101
- * A hook throw leaves row and tuple. Answers the revoked row, or
102
- * `undefined` when there was none.
201
+ * Revoke the triple as `caller` (IamPolicy.delete's door): gate, find by
202
+ * triple, `onPolicyRevoked` (with the row, or with the spec alone on the
203
+ * absent arm), then delete the row. A hook throw leaves row and tuple.
204
+ * Answers the revoked row, or `undefined` when there was none.
103
205
  */
104
- revokeBySpec(spec: IamPolicySpec): Promise<IamPolicy | undefined>;
206
+ revokeBySpec(
207
+ spec: IamPolicySpec,
208
+ caller: CallerIdentity,
209
+ ): Promise<IamPolicy | undefined>;
105
210
  /**
106
211
  * Revoke every row naming the ref as its principal, then every row naming
107
212
  * it as its resource with the `owner` rows last, each through the revoke
@@ -109,27 +214,88 @@ export interface IamPolicyGrantPath {
109
214
  * The order matters where the ref still exists: an organization's delete
110
215
  * runs this before its row goes and fails on the first fault, so a
111
216
  * cleanup that stops partway has not yet removed the owners who may
112
- * retry it.
217
+ * retry it. `caller` is whoever deleted the resource.
218
+ */
219
+ cleanupResource(ref: ApiResourceRef, caller: CallerIdentity): Promise<void>;
220
+ /**
221
+ * Revoke every relation the account holds directly on the organization,
222
+ * then every row it holds on the organization's resources except its
223
+ * authorship (the module header's sweep), as `caller`.
113
224
  */
114
- cleanupResource(ref: ApiResourceRef): Promise<void>;
115
- /** Revoke every relation the account holds directly on the organization. */
116
225
  revokeOrgAccess(
117
226
  identityAccountId: string,
118
227
  organizationId: string,
228
+ caller: CallerIdentity,
119
229
  ): Promise<void>;
120
230
  }
121
231
 
232
+ /**
233
+ * The recorded creator of a stored resource, the one fact the removal
234
+ * sweep needs from outside the policy rows.
235
+ */
236
+ export interface ResourceCreators {
237
+ /**
238
+ * The row's `status.audit.spec_audit.created_by.id`, or undefined when
239
+ * this server stores no row of that kind and id.
240
+ */
241
+ creatorOf(kind: string, id: string): Promise<string | undefined>;
242
+ }
243
+
122
244
  export interface IamPolicyGrantPathDeps {
123
245
  readonly policies: IamPolicyStore;
246
+ readonly creators: ResourceCreators;
124
247
  /** The composed driver, if any; a driver without the two policy hooks is the same as none. */
125
248
  readonly lifecycle: ResourceAuthorizationLifecycle | undefined;
126
249
  readonly logger: Logger;
127
250
  }
128
251
 
252
+ /** Who made a change and through which door; the organization is resolved per row. */
253
+ interface Change {
254
+ readonly actor: PolicyActor;
255
+ readonly cause: PolicyChangeCause;
256
+ }
257
+
258
+ /** How a row's organization is found: the scope walk, or a value its operation already knows. */
259
+ type OrganizationOf = (resource: ApiResourceRef) => Promise<string>;
260
+
129
261
  export function newIamPolicyGrantPath(
130
262
  deps: IamPolicyGrantPathDeps,
131
263
  ): IamPolicyGrantPath {
132
- const { policies, lifecycle, logger } = deps;
264
+ const { policies, creators, lifecycle, logger } = deps;
265
+
266
+ /** The organization a resource belongs to, through its scope links; "" when it names none. */
267
+ async function organizationByScope(
268
+ resource: ApiResourceRef,
269
+ ): Promise<string> {
270
+ if (resource.kind === ORGANIZATION_KIND) {
271
+ return resource.id;
272
+ }
273
+ const hierarchy = await resolveHierarchy(
274
+ policies,
275
+ resource.kind,
276
+ resource.id,
277
+ true,
278
+ );
279
+ return (
280
+ hierarchy.find((level) => level.kind === ORGANIZATION_KIND)?.id ?? ""
281
+ );
282
+ }
283
+
284
+ /** The record the store keeps beside an access row; none for a structural link. */
285
+ async function recordFor(
286
+ spec: IamPolicySpec,
287
+ change: Change,
288
+ organizationOf: OrganizationOf,
289
+ ): Promise<PolicyChangeRecord | undefined> {
290
+ if (spec.resource === undefined || !grantsAccess(spec)) {
291
+ return undefined;
292
+ }
293
+ return {
294
+ actor: change.actor,
295
+ cause: change.cause,
296
+ organizationId: await organizationOf(spec.resource),
297
+ };
298
+ }
133
299
 
134
300
  /** The row holding this exact triple — the pair's rows, filtered by relation. */
135
301
  async function findByTriple(
@@ -150,31 +316,129 @@ export function newIamPolicyGrantPath(
150
316
  );
151
317
  }
152
318
 
153
- /** The revoke order for one row: the hook, then the delete. */
154
- async function revokeRow(policy: IamPolicy): Promise<void> {
319
+ /** The revoke order for one row: its record resolved, the hook, then the delete. */
320
+ async function revokeRow(
321
+ policy: IamPolicy,
322
+ change: Change,
323
+ organizationOf: OrganizationOf = organizationByScope,
324
+ ): Promise<void> {
155
325
  const spec = policy.spec;
156
326
  if (spec === undefined) {
157
327
  throw new Error(
158
328
  `policy ${policy.metadata?.id ?? "?"} has no spec — corrupt row`,
159
329
  );
160
330
  }
331
+ const record = await recordFor(spec, change, organizationOf);
332
+ const affiliation = affiliationOf(spec);
333
+ if (affiliation !== undefined) {
334
+ await lifecycle?.onOrganizationAffiliationChanging?.(affiliation);
335
+ }
161
336
  await lifecycle?.onPolicyRevoked?.({ spec, policy });
162
337
  const id = policy.metadata?.id ?? "";
163
- await policies.deleteById(id);
164
- logger.info("iam policy revoked", fieldsOf(id, spec));
338
+ await policies.deleteById(id, record);
339
+ logger.info("iam policy revoked", fieldsOf(id, spec, change, record));
340
+ if (affiliation !== undefined) {
341
+ await lifecycle?.onOrganizationAffiliationChanged?.(affiliation);
342
+ }
343
+ }
344
+
345
+ /** Whether the account still holds any row on the organization. */
346
+ async function holdsOrganizationRow(
347
+ accountId: string,
348
+ organizationId: string,
349
+ ): Promise<boolean> {
350
+ const held = await policies.findByPrincipal(ACCOUNT_KIND, accountId);
351
+ return held.some(
352
+ (policy) =>
353
+ policy.spec?.resource?.kind === ORGANIZATION_KIND &&
354
+ policy.spec.resource.id === organizationId,
355
+ );
356
+ }
357
+
358
+ /** Whether the row records the resource's creator as its author. */
359
+ async function isAuthorship(
360
+ policy: IamPolicy,
361
+ accountId: string,
362
+ ): Promise<boolean> {
363
+ const spec = policy.spec;
364
+ if (
365
+ spec?.resource === undefined ||
366
+ !AUTHORSHIP_RELATIONS.has(spec.relation)
367
+ ) {
368
+ return false;
369
+ }
370
+ const creator = await creators.creatorOf(
371
+ spec.resource.kind,
372
+ spec.resource.id,
373
+ );
374
+ return creator === accountId;
375
+ }
376
+
377
+ /** Revoke what the account holds on the organization's resources, authorship kept. */
378
+ async function sweepOrganization(
379
+ accountId: string,
380
+ organizationId: string,
381
+ actor: PolicyActor,
382
+ ): Promise<void> {
383
+ const change: Change = { actor, cause: "left_organization" };
384
+ const inThisOrganization: OrganizationOf = async () => organizationId;
385
+ const held = await policies.findByPrincipal(ACCOUNT_KIND, accountId);
386
+ let revoked = 0;
387
+ for (const policy of held) {
388
+ const resource = policy.spec?.resource;
389
+ if (resource === undefined || resource.kind === ORGANIZATION_KIND) {
390
+ continue;
391
+ }
392
+ const hierarchy = await resolveHierarchy(
393
+ policies,
394
+ resource.kind,
395
+ resource.id,
396
+ true,
397
+ );
398
+ const inOrganization = hierarchy.some(
399
+ (level) =>
400
+ level.kind === ORGANIZATION_KIND && level.id === organizationId,
401
+ );
402
+ if (!inOrganization || (await isAuthorship(policy, accountId))) {
403
+ continue;
404
+ }
405
+ await revokeRow(policy, change, inThisOrganization);
406
+ revoked++;
407
+ }
408
+ if (revoked > 0) {
409
+ logger.info("iam policy organization access swept", {
410
+ identityAccountId: accountId,
411
+ organizationId,
412
+ revoked: String(revoked),
413
+ });
414
+ }
165
415
  }
166
416
 
167
417
  return {
168
- async grant(spec, caller): Promise<GrantResult> {
418
+ async grant(spec, caller, cause): Promise<GrantResult> {
169
419
  requireWellFormedTriple(spec);
420
+ const change: Change = { actor: policyActorOf(caller), cause };
421
+ if (
422
+ spec.relation === AFFILIATED_RELATION &&
423
+ spec.resource?.kind === ORGANIZATION_KIND
424
+ ) {
425
+ throw new ConnectError(
426
+ AFFILIATION_NOT_GRANTABLE_MESSAGE,
427
+ Code.InvalidArgument,
428
+ );
429
+ }
170
430
  let policy = await findByTriple(spec);
171
431
  let duplicate = policy !== undefined;
172
432
  if (policy === undefined) {
173
433
  const fresh = buildRow(spec, caller);
434
+ const record = await recordFor(spec, change, organizationByScope);
174
435
  try {
175
- await policies.save(fresh);
436
+ await policies.save(fresh, record);
176
437
  policy = fresh;
177
- logger.info("iam policy granted", fieldsOf(policyIdFor(spec), spec));
438
+ logger.info(
439
+ "iam policy granted",
440
+ fieldsOf(policyIdFor(spec), spec, change, record),
441
+ );
178
442
  } catch (error) {
179
443
  if (!(error instanceof DuplicatePolicyError)) {
180
444
  throw error;
@@ -194,31 +458,66 @@ export function newIamPolicyGrantPath(
194
458
  if (duplicate) {
195
459
  logger.debug(
196
460
  "iam policy already held",
197
- fieldsOf(policy.metadata?.id ?? "", spec),
461
+ fieldsOf(policy.metadata?.id ?? "", spec, change, undefined),
198
462
  );
199
463
  }
200
464
  // Deliberately unconditional (cloud#425): a duplicate re-grant is the
201
465
  // inline heal for a row whose tuple never landed.
202
466
  await lifecycle?.onPolicyGranted?.({ policy, duplicate });
467
+ // The same unconditional heal for the affiliation the row stands for.
468
+ const affiliation = affiliationOf(spec);
469
+ if (affiliation !== undefined) {
470
+ await lifecycle?.onOrganizationAffiliationChanged?.(affiliation);
471
+ }
203
472
  return { policy, duplicate };
204
473
  },
205
474
 
206
- async revokeBySpec(spec): Promise<IamPolicy | undefined> {
475
+ async revokeBySpec(spec, caller): Promise<IamPolicy | undefined> {
207
476
  requireWellFormedTriple(spec);
477
+ const actor = policyActorOf(caller);
208
478
  const existing = await findByTriple(spec);
209
479
  if (existing === undefined) {
210
480
  // No row: a composition still deletes the bare tuple (one written
211
481
  // before the row mirror existed); converges the store either way.
212
482
  await lifecycle?.onPolicyRevoked?.({ spec, policy: undefined });
213
- return undefined;
483
+ const affiliation = affiliationOf(spec);
484
+ if (affiliation !== undefined) {
485
+ // Nothing was deleted; re-deriving from the rows heals a tuple
486
+ // that outlived them.
487
+ await lifecycle?.onOrganizationAffiliationChanged?.(affiliation);
488
+ }
489
+ } else {
490
+ await revokeRow(existing, { actor, cause: "revoke" });
491
+ }
492
+ const { principal, resource } = refsOf(spec);
493
+ if (
494
+ principal.kind === ACCOUNT_KIND &&
495
+ resource.kind === ORGANIZATION_KIND &&
496
+ !(await holdsOrganizationRow(principal.id, resource.id))
497
+ ) {
498
+ await sweepOrganization(principal.id, resource.id, actor);
214
499
  }
215
- await revokeRow(existing);
216
500
  return existing;
217
501
  },
218
502
 
219
- async cleanupResource(ref): Promise<void> {
503
+ async cleanupResource(ref, caller): Promise<void> {
504
+ const change: Change = {
505
+ actor: policyActorOf(caller),
506
+ cause: "resource_deleted",
507
+ };
220
508
  const asPrincipal = await policies.findByPrincipal(ref.kind, ref.id);
221
509
  const asResource = await policies.findByResource(ref.kind, ref.id);
510
+ // The ref's own scope link is one of its resource-side rows and goes
511
+ // before its owners, so its organization is read once, up front.
512
+ const refOrganization = asResource.some(
513
+ (policy) => policy.spec !== undefined && grantsAccess(policy.spec),
514
+ )
515
+ ? await organizationByScope(ref)
516
+ : "";
517
+ const organizationOf: OrganizationOf = async (resource) =>
518
+ resource.kind === ref.kind && resource.id === ref.id
519
+ ? refOrganization
520
+ : organizationByScope(resource);
222
521
  const isOwner = (policy: IamPolicy): boolean =>
223
522
  policy.spec?.relation === OWNER_RELATION;
224
523
  for (const policy of distinctById([
@@ -226,11 +525,17 @@ export function newIamPolicyGrantPath(
226
525
  ...asResource.filter((policy) => !isOwner(policy)),
227
526
  ...asResource.filter(isOwner),
228
527
  ])) {
229
- await revokeRow(policy);
528
+ await revokeRow(policy, change, organizationOf);
230
529
  }
231
530
  },
232
531
 
233
- async revokeOrgAccess(identityAccountId, organizationId): Promise<void> {
532
+ async revokeOrgAccess(
533
+ identityAccountId,
534
+ organizationId,
535
+ caller,
536
+ ): Promise<void> {
537
+ const actor = policyActorOf(caller);
538
+ const change: Change = { actor, cause: "organization_access_revoked" };
234
539
  const direct = await policies.findByPrincipalAndResource(
235
540
  kindEnumName(ApiResourceKind.identity_account),
236
541
  identityAccountId,
@@ -238,8 +543,9 @@ export function newIamPolicyGrantPath(
238
543
  organizationId,
239
544
  );
240
545
  for (const policy of direct) {
241
- await revokeRow(policy);
546
+ await revokeRow(policy, change);
242
547
  }
548
+ await sweepOrganization(identityAccountId, organizationId, actor);
243
549
  },
244
550
  };
245
551
  }
@@ -271,8 +577,16 @@ function distinctById(
271
577
  });
272
578
  }
273
579
 
274
- /** The structured fields every log line carries — ids and kinds, never a token. */
275
- function fieldsOf(id: string, spec: IamPolicySpec): Record<string, string> {
580
+ /**
581
+ * The structured fields every log line carries — ids, kinds, who and why,
582
+ * never a token; the organization when the row is an access row.
583
+ */
584
+ function fieldsOf(
585
+ id: string,
586
+ spec: IamPolicySpec,
587
+ change: Change,
588
+ record: PolicyChangeRecord | undefined,
589
+ ): Record<string, string> {
276
590
  return {
277
591
  policyId: id,
278
592
  relation: spec.relation,
@@ -280,5 +594,9 @@ function fieldsOf(id: string, spec: IamPolicySpec): Record<string, string> {
280
594
  principalId: spec.principal?.id ?? "",
281
595
  resourceKind: spec.resource?.kind ?? "",
282
596
  resourceId: spec.resource?.id ?? "",
597
+ actorId: change.actor.id,
598
+ actorClass: change.actor.callerClass,
599
+ cause: change.cause,
600
+ ...(record === undefined ? {} : { organizationId: record.organizationId }),
283
601
  };
284
602
  }
@@ -59,8 +59,9 @@
59
59
  * one of them would be an outsider on every organization with nobody
60
60
  * able to grant a way back. At the first boot where the bootstrap-state
61
61
  * marker (ROLES_RECONCILED_KEY) is absent, the arms above run for every
62
- * PERSON account (`isPersonAccount`: not a machine account, the row-
63
- * level twin of the `user`-class gate), acting as that account, in
62
+ * PERSON account (`isPersonAccount`: not a machine, platform-client or
63
+ * federated account, the row-level twin of the `user`-class gate),
64
+ * acting as that account, in
64
65
  * creation order — the order the sign-ins would have run the hook in,
65
66
  * so arm 4 hands an unclaimed organization to its first sign-in and
66
67
  * not to whoever sorts first by id — and the marker is written after
@@ -131,6 +132,7 @@ import type { Store } from "../../store/interface.js";
131
132
  import { rfc3339Seconds } from "../../store/rfc3339.js";
132
133
  import { accountAsCaller } from "../identityaccount/actor.js";
133
134
  import type { AccountCreatedHook } from "../identityaccount/provisioning.js";
135
+ import type { PolicyChangeCause } from "./change.js";
134
136
  import { BLUEPRINT_KINDS, ROLES_RECONCILED_KEY } from "./constants.js";
135
137
  import type { IamPolicyGrantPath } from "./grant-path.js";
136
138
  import { organizationRole, relationOf } from "./specs.js";
@@ -200,7 +202,14 @@ export function isPersonStamp(stamp: string): boolean {
200
202
  * it exactly its client's auto-grant role on the owning organization and
201
203
  * never runs these rules, and the reconciliation must not either, or every
202
204
  * product user would become a member of every organization (and the
203
- * operator-email arm would read an email the platform asserted).
205
+ * operator-email arm would read an email the platform asserted). Nor does a
206
+ * federated account, for the same reason at every arm: its subject and its
207
+ * email are the ones an organization's identity provider asserted, so the
208
+ * alias rule would read a subject the provider chose as a founder's stamp
209
+ * (`owner`), the operator-email arm an email it chose (`admin`), and arm 5
210
+ * would make it a member of every organization. A federated person's roles
211
+ * come from their provider's configuration and the organization's
212
+ * administrators, never from these rules.
204
213
  */
205
214
  export function isPersonAccount(account: IdentityAccount): boolean {
206
215
  const spec = account.spec;
@@ -208,7 +217,8 @@ export function isPersonAccount(account: IdentityAccount): boolean {
208
217
  spec !== undefined &&
209
218
  !spec.isMachineAccount &&
210
219
  spec.provisioningMode !== IdentityAccountProvisioningMode.machine &&
211
- spec.provisioningMode !== IdentityAccountProvisioningMode.platform_client
220
+ spec.provisioningMode !== IdentityAccountProvisioningMode.platform_client &&
221
+ spec.provisioningMode !== IdentityAccountProvisioningMode.federated
212
222
  );
213
223
  }
214
224
 
@@ -331,14 +341,15 @@ export function newMembershipRules(deps: MembershipRulesDeps): MembershipRules {
331
341
 
332
342
  /**
333
343
  * The arms for ONE account over a scanned world: a row on every
334
- * organization the account holds none on, granted as `caller`. Shared
335
- * by the hook (one account, the world scanned for it) and the
336
- * reconciliation (the world scanned once for every account).
344
+ * organization the account holds none on, granted as `caller` through
345
+ * `cause`'s door. Shared by the hook (one account, the world scanned for
346
+ * it) and the reconciliation (the world scanned once for every account).
337
347
  */
338
348
  async function applyRulesTo(
339
349
  account: IdentityAccount,
340
350
  caller: CallerIdentity,
341
351
  world: ScannedWorld,
352
+ cause: PolicyChangeCause,
342
353
  ): Promise<void> {
343
354
  const accountId = account.metadata?.id ?? "";
344
355
  if (accountId === "") {
@@ -369,6 +380,7 @@ export function newMembershipRules(deps: MembershipRulesDeps): MembershipRules {
369
380
  await grantPath.grant(
370
381
  organizationRole(accountId, role, organization.id),
371
382
  caller,
383
+ cause,
372
384
  );
373
385
  }
374
386
  }
@@ -402,10 +414,12 @@ export function newMembershipRules(deps: MembershipRulesDeps): MembershipRules {
402
414
  if (organizations.length === 0) {
403
415
  return;
404
416
  }
405
- await applyRulesTo(account, caller, {
406
- organizations,
407
- blueprints: await scanBlueprints(),
408
- });
417
+ await applyRulesTo(
418
+ account,
419
+ caller,
420
+ { organizations, blueprints: await scanBlueprints() },
421
+ "first_sign_in",
422
+ );
409
423
  },
410
424
 
411
425
  async ensureRolesForExistingAccounts(): Promise<void> {
@@ -419,7 +433,12 @@ export function newMembershipRules(deps: MembershipRulesDeps): MembershipRules {
419
433
  // As the account itself (actor.ts, the one construction), so the
420
434
  // row's audit actor reads exactly as the person's own first
421
435
  // sign-in would have stamped it.
422
- await applyRulesTo(account, accountAsCaller(account), world);
436
+ await applyRulesTo(
437
+ account,
438
+ accountAsCaller(account),
439
+ world,
440
+ "role_reconciliation",
441
+ );
423
442
  }
424
443
  }
425
444
  // After the last account, never before: a fault above leaves the
@@ -452,6 +471,7 @@ export function newMembershipRules(deps: MembershipRulesDeps): MembershipRules {
452
471
  await grantPath.grant(
453
472
  organizationRole(accountId, IamRole.owner, organization.id),
454
473
  actor,
474
+ "operator_ownership",
455
475
  );
456
476
  }
457
477
  },
@@ -32,6 +32,10 @@
32
32
  * way). Conditional store writes are a platform-wide follow-up, not this
33
33
  * adapter's to invent.
34
34
  *
35
+ * History. Open source keeps no permission history: the change record the
36
+ * grant path hands `save` and `deleteById` (store.ts) is not read here, and
37
+ * the same facts ride the grant path's log lines.
38
+ *
35
39
  * Store faults follow the ratified mapping (domain/apikey/lookup.ts): a
36
40
  * typed ResourceNotFoundError reads as `undefined`; anything else
37
41
  * propagates — an outage must never read as "no grant".
@@ -109,6 +109,7 @@ export function newBuiltInRoleLifecycle(
109
109
  await grantPath.grant(
110
110
  organizationRole(accountId, IamRole.owner, event.resourceId),
111
111
  { ...event.caller, identityId: accountId },
112
+ "organization_created",
112
113
  );
113
114
  },
114
115
 
@@ -121,6 +122,7 @@ export function newBuiltInRoleLifecycle(
121
122
  kind: kindEnumName(event.kind),
122
123
  id: event.resourceId,
123
124
  }),
125
+ event.caller,
124
126
  );
125
127
  },
126
128
 
@@ -60,6 +60,14 @@ const ROLE_DISPLAY: ReadonlyArray<RoleDisplay> = [
60
60
  description:
61
61
  "Reply to customers and manage conversation takeover on a channel",
62
62
  },
63
+ // Grantable per resource on agent, workflow and mcp_server; omitting it
64
+ // would hide every editor from the resource's access listing.
65
+ {
66
+ role: IamRole.editor,
67
+ name: "Editor",
68
+ description:
69
+ "Edit and run the resource; cannot delete it or change who has access",
70
+ },
63
71
  ];
64
72
 
65
73
  const RELATION_TO_DISPLAY: ReadonlyMap<string, RoleDisplay> = new Map(