@stigmer/server 3.21.0 → 3.22.1-dev.20260922095755

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 (383) hide show
  1. package/dist/authorization/authorizer.d.ts +4 -8
  2. package/dist/authorization/authorizer.d.ts.map +1 -1
  3. package/dist/authorization/authorizer.js +5 -9
  4. package/dist/authorization/authorizer.js.map +1 -1
  5. package/dist/authorization/derived-tuples.d.ts.map +1 -1
  6. package/dist/authorization/derived-tuples.js +10 -25
  7. package/dist/authorization/derived-tuples.js.map +1 -1
  8. package/dist/authorization/evaluator.d.ts +13 -8
  9. package/dist/authorization/evaluator.d.ts.map +1 -1
  10. package/dist/authorization/evaluator.js +4 -20
  11. package/dist/authorization/evaluator.js.map +1 -1
  12. package/dist/authorization/list-read-scope.d.ts.map +1 -1
  13. package/dist/authorization/list-read-scope.js +24 -20
  14. package/dist/authorization/list-read-scope.js.map +1 -1
  15. package/dist/authorization/model/agent.d.ts.map +1 -1
  16. package/dist/authorization/model/agent.js +4 -5
  17. package/dist/authorization/model/agent.js.map +1 -1
  18. package/dist/authorization/model/agent_instance.d.ts.map +1 -1
  19. package/dist/authorization/model/agent_instance.js +2 -2
  20. package/dist/authorization/model/agent_instance.js.map +1 -1
  21. package/dist/authorization/model/mcp_server.d.ts.map +1 -1
  22. package/dist/authorization/model/mcp_server.js +2 -2
  23. package/dist/authorization/model/mcp_server.js.map +1 -1
  24. package/dist/authorization/model/organization.d.ts.map +1 -1
  25. package/dist/authorization/model/organization.js +2 -0
  26. package/dist/authorization/model/organization.js.map +1 -1
  27. package/dist/authorization/model/plugin.d.ts.map +1 -1
  28. package/dist/authorization/model/plugin.js +3 -4
  29. package/dist/authorization/model/plugin.js.map +1 -1
  30. package/dist/authorization/model/rewrite.d.ts +8 -10
  31. package/dist/authorization/model/rewrite.d.ts.map +1 -1
  32. package/dist/authorization/model/rewrite.js +0 -3
  33. package/dist/authorization/model/rewrite.js.map +1 -1
  34. package/dist/authorization/model/skill.d.ts.map +1 -1
  35. package/dist/authorization/model/skill.js +2 -2
  36. package/dist/authorization/model/skill.js.map +1 -1
  37. package/dist/authorization/model/workflow.d.ts.map +1 -1
  38. package/dist/authorization/model/workflow.js +2 -2
  39. package/dist/authorization/model/workflow.js.map +1 -1
  40. package/dist/authorization/model/workflow_instance.d.ts.map +1 -1
  41. package/dist/authorization/model/workflow_instance.js +2 -2
  42. package/dist/authorization/model/workflow_instance.js.map +1 -1
  43. package/dist/authorization/organization-directory.d.ts.map +1 -1
  44. package/dist/authorization/organization-directory.js +2 -3
  45. package/dist/authorization/organization-directory.js.map +1 -1
  46. package/dist/authorization/store-test-kit.d.ts +0 -6
  47. package/dist/authorization/store-test-kit.d.ts.map +1 -1
  48. package/dist/authorization/store-test-kit.js +16 -62
  49. package/dist/authorization/store-test-kit.js.map +1 -1
  50. package/dist/authorization/tuples.d.ts +13 -32
  51. package/dist/authorization/tuples.d.ts.map +1 -1
  52. package/dist/authorization/tuples.js +3 -11
  53. package/dist/authorization/tuples.js.map +1 -1
  54. package/dist/domain/agent/controller.d.ts.map +1 -1
  55. package/dist/domain/agent/controller.js +6 -4
  56. package/dist/domain/agent/controller.js.map +1 -1
  57. package/dist/domain/agentchannel/controller.d.ts.map +1 -1
  58. package/dist/domain/agentchannel/controller.js +9 -2
  59. package/dist/domain/agentchannel/controller.js.map +1 -1
  60. package/dist/domain/agentchannel/steps.d.ts +19 -0
  61. package/dist/domain/agentchannel/steps.d.ts.map +1 -1
  62. package/dist/domain/agentchannel/steps.js +32 -0
  63. package/dist/domain/agentchannel/steps.js.map +1 -1
  64. package/dist/domain/agentexecution/controller.d.ts.map +1 -1
  65. package/dist/domain/agentexecution/controller.js +3 -1
  66. package/dist/domain/agentexecution/controller.js.map +1 -1
  67. package/dist/domain/agentinstance/controller.d.ts +5 -5
  68. package/dist/domain/agentinstance/controller.d.ts.map +1 -1
  69. package/dist/domain/agentinstance/controller.js +9 -5
  70. package/dist/domain/agentinstance/controller.js.map +1 -1
  71. package/dist/domain/agentinstance/steps.d.ts +43 -8
  72. package/dist/domain/agentinstance/steps.d.ts.map +1 -1
  73. package/dist/domain/agentinstance/steps.js +71 -8
  74. package/dist/domain/agentinstance/steps.js.map +1 -1
  75. package/dist/domain/agentshare/constants.d.ts +6 -11
  76. package/dist/domain/agentshare/constants.d.ts.map +1 -1
  77. package/dist/domain/agentshare/constants.js +8 -16
  78. package/dist/domain/agentshare/constants.js.map +1 -1
  79. package/dist/domain/agentshare/controller.d.ts.map +1 -1
  80. package/dist/domain/agentshare/controller.js +10 -2
  81. package/dist/domain/agentshare/controller.js.map +1 -1
  82. package/dist/domain/agentshare/steps.d.ts +61 -10
  83. package/dist/domain/agentshare/steps.d.ts.map +1 -1
  84. package/dist/domain/agentshare/steps.js +121 -117
  85. package/dist/domain/agentshare/steps.js.map +1 -1
  86. package/dist/domain/artifact/controller.js +21 -25
  87. package/dist/domain/artifact/controller.js.map +1 -1
  88. package/dist/domain/channelapp/controller.d.ts.map +1 -1
  89. package/dist/domain/channelapp/controller.js +2 -0
  90. package/dist/domain/channelapp/controller.js.map +1 -1
  91. package/dist/domain/environment/controller.d.ts.map +1 -1
  92. package/dist/domain/environment/controller.js +4 -3
  93. package/dist/domain/environment/controller.js.map +1 -1
  94. package/dist/domain/executioncontext/controller.d.ts.map +1 -1
  95. package/dist/domain/executioncontext/controller.js +4 -1
  96. package/dist/domain/executioncontext/controller.js.map +1 -1
  97. package/dist/domain/executioncontext/steps.d.ts.map +1 -1
  98. package/dist/domain/executioncontext/steps.js +2 -1
  99. package/dist/domain/executioncontext/steps.js.map +1 -1
  100. package/dist/domain/mcpserver/connect.d.ts.map +1 -1
  101. package/dist/domain/mcpserver/connect.js +8 -7
  102. package/dist/domain/mcpserver/connect.js.map +1 -1
  103. package/dist/domain/mcpserver/controller.d.ts.map +1 -1
  104. package/dist/domain/mcpserver/controller.js +5 -4
  105. package/dist/domain/mcpserver/controller.js.map +1 -1
  106. package/dist/domain/mcpserver/start-connect.d.ts.map +1 -1
  107. package/dist/domain/mcpserver/start-connect.js +8 -7
  108. package/dist/domain/mcpserver/start-connect.js.map +1 -1
  109. package/dist/domain/memory/controller.d.ts.map +1 -1
  110. package/dist/domain/memory/controller.js +6 -1
  111. package/dist/domain/memory/controller.js.map +1 -1
  112. package/dist/domain/memory/steps.d.ts +23 -0
  113. package/dist/domain/memory/steps.d.ts.map +1 -1
  114. package/dist/domain/memory/steps.js +35 -0
  115. package/dist/domain/memory/steps.js.map +1 -1
  116. package/dist/domain/oauthapp/controller.d.ts.map +1 -1
  117. package/dist/domain/oauthapp/controller.js +2 -0
  118. package/dist/domain/oauthapp/controller.js.map +1 -1
  119. package/dist/domain/plugin/controller.d.ts.map +1 -1
  120. package/dist/domain/plugin/controller.js +6 -27
  121. package/dist/domain/plugin/controller.js.map +1 -1
  122. package/dist/domain/plugin/push.d.ts +7 -5
  123. package/dist/domain/plugin/push.d.ts.map +1 -1
  124. package/dist/domain/plugin/push.js +8 -14
  125. package/dist/domain/plugin/push.js.map +1 -1
  126. package/dist/domain/schedule/controller.d.ts.map +1 -1
  127. package/dist/domain/schedule/controller.js +10 -2
  128. package/dist/domain/schedule/controller.js.map +1 -1
  129. package/dist/domain/schedule/steps.d.ts +19 -0
  130. package/dist/domain/schedule/steps.d.ts.map +1 -1
  131. package/dist/domain/schedule/steps.js +32 -0
  132. package/dist/domain/schedule/steps.js.map +1 -1
  133. package/dist/domain/session/controller.d.ts.map +1 -1
  134. package/dist/domain/session/controller.js +3 -2
  135. package/dist/domain/session/controller.js.map +1 -1
  136. package/dist/domain/session/steps.d.ts +8 -9
  137. package/dist/domain/session/steps.d.ts.map +1 -1
  138. package/dist/domain/session/steps.js +17 -21
  139. package/dist/domain/session/steps.js.map +1 -1
  140. package/dist/domain/skill/controller.d.ts.map +1 -1
  141. package/dist/domain/skill/controller.js +8 -19
  142. package/dist/domain/skill/controller.js.map +1 -1
  143. package/dist/domain/workflow/agent-call-references.d.ts +54 -0
  144. package/dist/domain/workflow/agent-call-references.d.ts.map +1 -0
  145. package/dist/domain/workflow/agent-call-references.js +97 -0
  146. package/dist/domain/workflow/agent-call-references.js.map +1 -0
  147. package/dist/domain/workflow/controller.d.ts.map +1 -1
  148. package/dist/domain/workflow/controller.js +44 -113
  149. package/dist/domain/workflow/controller.js.map +1 -1
  150. package/dist/domain/workflow/registry/data/task-kind-registry.json +1 -1
  151. package/dist/domain/workflow/validation/task-config-constraints.d.ts +10 -1
  152. package/dist/domain/workflow/validation/task-config-constraints.d.ts.map +1 -1
  153. package/dist/domain/workflow/validation/task-config-constraints.js +3 -2
  154. package/dist/domain/workflow/validation/task-config-constraints.js.map +1 -1
  155. package/dist/domain/workflow/version-resolution.d.ts +5 -0
  156. package/dist/domain/workflow/version-resolution.d.ts.map +1 -0
  157. package/dist/domain/workflow/version-resolution.js +113 -0
  158. package/dist/domain/workflow/version-resolution.js.map +1 -0
  159. package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
  160. package/dist/domain/workflowexecution/controller.js +4 -2
  161. package/dist/domain/workflowexecution/controller.js.map +1 -1
  162. package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
  163. package/dist/domain/workflowinstance/controller.js +9 -5
  164. package/dist/domain/workflowinstance/controller.js.map +1 -1
  165. package/dist/domain/workflowinstance/steps.d.ts +20 -0
  166. package/dist/domain/workflowinstance/steps.d.ts.map +1 -1
  167. package/dist/domain/workflowinstance/steps.js +39 -0
  168. package/dist/domain/workflowinstance/steps.js.map +1 -1
  169. package/dist/extensions/authorization-queries.d.ts +6 -5
  170. package/dist/extensions/authorization-queries.d.ts.map +1 -1
  171. package/dist/extensions/identity.d.ts +19 -0
  172. package/dist/extensions/identity.d.ts.map +1 -1
  173. package/dist/extensions/identity.js +22 -3
  174. package/dist/extensions/identity.js.map +1 -1
  175. package/dist/extensions/list-read-scope.d.ts +42 -8
  176. package/dist/extensions/list-read-scope.d.ts.map +1 -1
  177. package/dist/extensions/list-read-scope.js +13 -2
  178. package/dist/extensions/list-read-scope.js.map +1 -1
  179. package/dist/extensions/resource-authorization.d.ts +3 -2
  180. package/dist/extensions/resource-authorization.d.ts.map +1 -1
  181. package/dist/index.d.ts +1 -1
  182. package/dist/index.d.ts.map +1 -1
  183. package/dist/index.js.map +1 -1
  184. package/dist/pipeline/apiresource-meta.d.ts +12 -3
  185. package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
  186. package/dist/pipeline/apiresource-meta.js +21 -10
  187. package/dist/pipeline/apiresource-meta.js.map +1 -1
  188. package/dist/pipeline/steps/authorization-tuples.d.ts +9 -3
  189. package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
  190. package/dist/pipeline/steps/authorization-tuples.js +9 -11
  191. package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
  192. package/dist/pipeline/steps/authorize-resolved-target.d.ts +88 -0
  193. package/dist/pipeline/steps/authorize-resolved-target.d.ts.map +1 -0
  194. package/dist/pipeline/steps/authorize-resolved-target.js +36 -0
  195. package/dist/pipeline/steps/authorize-resolved-target.js.map +1 -0
  196. package/dist/pipeline/steps/authorize.d.ts +27 -0
  197. package/dist/pipeline/steps/authorize.d.ts.map +1 -1
  198. package/dist/pipeline/steps/authorize.js +49 -10
  199. package/dist/pipeline/steps/authorize.js.map +1 -1
  200. package/dist/pipeline/steps/guard-memory-capture.d.ts.map +1 -1
  201. package/dist/pipeline/steps/guard-memory-capture.js +2 -1
  202. package/dist/pipeline/steps/guard-memory-capture.js.map +1 -1
  203. package/dist/pipeline/steps/guard-reserved-labels.d.ts.map +1 -1
  204. package/dist/pipeline/steps/guard-reserved-labels.js +6 -7
  205. package/dist/pipeline/steps/guard-reserved-labels.js.map +1 -1
  206. package/dist/pipeline/steps/helpers.d.ts +9 -5
  207. package/dist/pipeline/steps/helpers.d.ts.map +1 -1
  208. package/dist/pipeline/steps/helpers.js +11 -15
  209. package/dist/pipeline/steps/helpers.js.map +1 -1
  210. package/dist/pipeline/steps/references.d.ts +178 -20
  211. package/dist/pipeline/steps/references.d.ts.map +1 -1
  212. package/dist/pipeline/steps/references.js +344 -43
  213. package/dist/pipeline/steps/references.js.map +1 -1
  214. package/dist/pipeline/steps/version-history.d.ts +11 -0
  215. package/dist/pipeline/steps/version-history.d.ts.map +1 -1
  216. package/dist/pipeline/steps/version-history.js +26 -0
  217. package/dist/pipeline/steps/version-history.js.map +1 -1
  218. package/dist/query/search/controller.js +0 -1
  219. package/dist/query/search/controller.js.map +1 -1
  220. package/dist/query/search/criteria.d.ts +1 -5
  221. package/dist/query/search/criteria.d.ts.map +1 -1
  222. package/dist/query/search/criteria.js +3 -13
  223. package/dist/query/search/criteria.js.map +1 -1
  224. package/dist/query/search/handler.d.ts +5 -4
  225. package/dist/query/search/handler.d.ts.map +1 -1
  226. package/dist/query/search/handler.js +7 -6
  227. package/dist/query/search/handler.js.map +1 -1
  228. package/dist/query/search/query-store.d.ts.map +1 -1
  229. package/dist/query/search/query-store.js +0 -2
  230. package/dist/query/search/query-store.js.map +1 -1
  231. package/dist/store/interface.d.ts +3 -6
  232. package/dist/store/interface.d.ts.map +1 -1
  233. package/dist/store/interface.js.map +1 -1
  234. package/dist/store/postgres/migrations.d.ts +3 -1
  235. package/dist/store/postgres/migrations.d.ts.map +1 -1
  236. package/dist/store/postgres/migrations.js +35 -1
  237. package/dist/store/postgres/migrations.js.map +1 -1
  238. package/dist/store/postgres/store.d.ts.map +1 -1
  239. package/dist/store/postgres/store.js +4 -9
  240. package/dist/store/postgres/store.js.map +1 -1
  241. package/dist/store/public-visibility-retired.d.ts +67 -0
  242. package/dist/store/public-visibility-retired.d.ts.map +1 -0
  243. package/dist/store/public-visibility-retired.js +55 -0
  244. package/dist/store/public-visibility-retired.js.map +1 -0
  245. package/dist/store/sqlite/migrations.d.ts +3 -1
  246. package/dist/store/sqlite/migrations.d.ts.map +1 -1
  247. package/dist/store/sqlite/migrations.js +36 -1
  248. package/dist/store/sqlite/migrations.js.map +1 -1
  249. package/dist/store/sqlite/store.d.ts.map +1 -1
  250. package/dist/store/sqlite/store.js +4 -8
  251. package/dist/store/sqlite/store.js.map +1 -1
  252. package/package.json +6 -6
  253. package/src/authorization/README.md +24 -26
  254. package/src/authorization/__tests__/authorizer.test.ts +10 -9
  255. package/src/authorization/__tests__/derived-tuples.test.ts +4 -11
  256. package/src/authorization/__tests__/evaluator.test.ts +14 -73
  257. package/src/authorization/__tests__/facts.test.ts +2 -2
  258. package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +6 -98
  259. package/src/authorization/__tests__/fixtures/fga/default-instance-inheritance.fga.yaml +4 -61
  260. package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +1 -21
  261. package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +1 -25
  262. package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +1 -3
  263. package/src/authorization/__tests__/list-read-scope.test.ts +41 -29
  264. package/src/authorization/__tests__/skip-lane-inventory.test.ts +160 -0
  265. package/src/authorization/__tests__/store-tests.test.ts +1 -6
  266. package/src/authorization/__tests__/tuples.test.ts +12 -11
  267. package/src/authorization/__tests__/wire-permissions.test.ts +5 -5
  268. package/src/authorization/authorizer.ts +4 -9
  269. package/src/authorization/derived-tuples.ts +14 -31
  270. package/src/authorization/evaluator.ts +15 -44
  271. package/src/authorization/list-read-scope.ts +27 -22
  272. package/src/authorization/model/__tests__/registry.test.ts +2 -0
  273. package/src/authorization/model/agent.ts +2 -5
  274. package/src/authorization/model/agent_instance.ts +0 -2
  275. package/src/authorization/model/mcp_server.ts +0 -2
  276. package/src/authorization/model/organization.ts +2 -0
  277. package/src/authorization/model/plugin.ts +1 -4
  278. package/src/authorization/model/rewrite.ts +8 -13
  279. package/src/authorization/model/skill.ts +0 -2
  280. package/src/authorization/model/workflow.ts +0 -2
  281. package/src/authorization/model/workflow_instance.ts +0 -2
  282. package/src/authorization/organization-directory.ts +1 -3
  283. package/src/authorization/store-test-kit.ts +16 -75
  284. package/src/authorization/tuples.ts +16 -39
  285. package/src/domain/agent/__tests__/agent.test.ts +11 -4
  286. package/src/domain/agent/controller.ts +17 -7
  287. package/src/domain/agentchannel/__tests__/agentchannel.test.ts +223 -48
  288. package/src/domain/agentchannel/__tests__/create-authorization.test.ts +58 -0
  289. package/src/domain/agentchannel/controller.ts +25 -1
  290. package/src/domain/agentchannel/steps.ts +40 -0
  291. package/src/domain/agentexecution/controller.ts +6 -1
  292. package/src/domain/agentinstance/__tests__/create-authorization.composed.test.ts +243 -0
  293. package/src/domain/agentinstance/__tests__/create-authorization.test.ts +144 -0
  294. package/src/domain/agentinstance/controller.ts +30 -17
  295. package/src/domain/agentinstance/steps.ts +82 -8
  296. package/src/domain/agentshare/__tests__/agentshare.test.ts +196 -172
  297. package/src/domain/agentshare/__tests__/create-authorization.test.ts +71 -0
  298. package/src/domain/agentshare/__tests__/member-audience.test.ts +113 -0
  299. package/src/domain/agentshare/constants.ts +14 -26
  300. package/src/domain/agentshare/controller.ts +27 -1
  301. package/src/domain/agentshare/steps.ts +168 -155
  302. package/src/domain/artifact/controller.ts +18 -22
  303. package/src/domain/channelapp/controller.ts +10 -0
  304. package/src/domain/environment/controller.ts +15 -8
  305. package/src/domain/executioncontext/__tests__/executioncontext.test.ts +1 -0
  306. package/src/domain/executioncontext/controller.ts +15 -1
  307. package/src/domain/executioncontext/steps.ts +2 -1
  308. package/src/domain/mcpserver/__tests__/mcpserver.test.ts +115 -28
  309. package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +53 -18
  310. package/src/domain/mcpserver/connect.ts +11 -10
  311. package/src/domain/mcpserver/controller.ts +19 -13
  312. package/src/domain/mcpserver/start-connect.ts +17 -11
  313. package/src/domain/memory/__tests__/create-authorization.test.ts +59 -0
  314. package/src/domain/memory/controller.ts +11 -0
  315. package/src/domain/memory/steps.ts +41 -0
  316. package/src/domain/oauthapp/controller.ts +10 -0
  317. package/src/domain/plugin/controller.ts +23 -44
  318. package/src/domain/plugin/push.ts +8 -16
  319. package/src/domain/schedule/__tests__/create-authorization.test.ts +58 -0
  320. package/src/domain/schedule/controller.ts +26 -1
  321. package/src/domain/schedule/steps.ts +45 -2
  322. package/src/domain/session/controller.ts +12 -4
  323. package/src/domain/session/steps.ts +24 -32
  324. package/src/domain/skill/controller.ts +24 -30
  325. package/src/domain/workflow/__tests__/agent-call-references.test.ts +222 -0
  326. package/src/domain/workflow/agent-call-references.ts +157 -0
  327. package/src/domain/workflow/controller.ts +86 -155
  328. package/src/domain/workflow/registry/data/task-kind-registry.json +1 -1
  329. package/src/domain/workflow/validation/task-config-constraints.ts +7 -3
  330. package/src/domain/workflow/version-resolution.ts +166 -0
  331. package/src/domain/workflowexecution/controller.ts +7 -2
  332. package/src/domain/workflowinstance/__tests__/create-authorization.test.ts +109 -0
  333. package/src/domain/workflowinstance/controller.ts +25 -12
  334. package/src/domain/workflowinstance/steps.ts +49 -1
  335. package/src/extensions/__tests__/built-in-authorization-composed.test.ts +32 -19
  336. package/src/extensions/__tests__/composed-support.ts +38 -4
  337. package/src/extensions/__tests__/extension-composition.test.ts +4 -4
  338. package/src/extensions/__tests__/identity.test.ts +44 -1
  339. package/src/extensions/__tests__/list-read-scope-composed.test.ts +96 -7
  340. package/src/extensions/__tests__/list-read-scope.test.ts +63 -0
  341. package/src/extensions/authorization-queries.ts +6 -5
  342. package/src/extensions/identity.ts +23 -5
  343. package/src/extensions/list-read-scope.ts +48 -8
  344. package/src/extensions/resource-authorization.ts +3 -5
  345. package/src/index.ts +0 -1
  346. package/src/pipeline/__tests__/supports-visibility.test.ts +112 -0
  347. package/src/pipeline/apiresource-meta.ts +21 -10
  348. package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +18 -31
  349. package/src/pipeline/steps/__tests__/authorize-resolved-target.test.ts +285 -0
  350. package/src/pipeline/steps/__tests__/references.test.ts +703 -0
  351. package/src/pipeline/steps/authorization-tuples.ts +9 -11
  352. package/src/pipeline/steps/authorize-resolved-target.ts +129 -0
  353. package/src/pipeline/steps/authorize.ts +70 -13
  354. package/src/pipeline/steps/guard-memory-capture.ts +2 -1
  355. package/src/pipeline/steps/guard-reserved-labels.ts +6 -9
  356. package/src/pipeline/steps/helpers.ts +11 -15
  357. package/src/pipeline/steps/references.ts +578 -70
  358. package/src/pipeline/steps/version-history.ts +34 -0
  359. package/src/query/search/__tests__/criteria.test.ts +0 -4
  360. package/src/query/search/__tests__/query-store.test.ts +11 -40
  361. package/src/query/search/controller.ts +0 -1
  362. package/src/query/search/criteria.ts +0 -14
  363. package/src/query/search/handler.ts +6 -7
  364. package/src/query/search/query-store.ts +0 -2
  365. package/src/store/__tests__/public-visibility-retired.test.ts +127 -0
  366. package/src/store/__tests__/store-contract.ts +6 -51
  367. package/src/store/interface.ts +3 -6
  368. package/src/store/postgres/__tests__/migrations.test.ts +187 -6
  369. package/src/store/postgres/__tests__/store-contract.test.ts +0 -2
  370. package/src/store/postgres/migrations.ts +48 -1
  371. package/src/store/postgres/store.ts +4 -11
  372. package/src/store/public-visibility-retired.ts +119 -0
  373. package/src/store/sqlite/__tests__/migrations.test.ts +191 -5
  374. package/src/store/sqlite/migrations.ts +45 -1
  375. package/src/store/sqlite/store.ts +4 -10
  376. package/dist/pipeline/steps/visibility-gates.d.ts +0 -27
  377. package/dist/pipeline/steps/visibility-gates.d.ts.map +0 -1
  378. package/dist/pipeline/steps/visibility-gates.js +0 -139
  379. package/dist/pipeline/steps/visibility-gates.js.map +0 -1
  380. package/src/authorization/__tests__/fixtures/fga/cross-org-share-creation.fga.yaml +0 -98
  381. package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +0 -52
  382. package/src/pipeline/steps/__tests__/visibility-gates.test.ts +0 -187
  383. package/src/pipeline/steps/visibility-gates.ts +0 -174
@@ -41,7 +41,11 @@ import { composeServer } from "../../../boot/compose.js";
41
41
  import type { ComposedServer } from "../../../boot/compose.js";
42
42
  import { createLogger } from "../../../boot/logger.js";
43
43
 
44
- const silentLogger = createLogger({ level: "error", pretty: false, write: () => {} });
44
+ const silentLogger = createLogger({
45
+ level: "error",
46
+ pretty: false,
47
+ write: () => {},
48
+ });
45
49
 
46
50
  const API_VERSION = "agentic.stigmer.ai/v1";
47
51
  const KIND = "McpServer";
@@ -128,7 +132,11 @@ function serverInput(overrides?: {
128
132
  };
129
133
  }
130
134
 
131
- async function expectCode(promise: Promise<unknown>, code: Code, arm: string): Promise<ConnectError> {
135
+ async function expectCode(
136
+ promise: Promise<unknown>,
137
+ code: Code,
138
+ arm: string,
139
+ ): Promise<ConnectError> {
132
140
  try {
133
141
  await promise;
134
142
  } catch (error) {
@@ -157,7 +165,10 @@ async function seedCapabilities(
157
165
  serverId,
158
166
  McpServerSchema,
159
167
  );
160
- const patched = fromBinary(McpServerSchema, toBinary(McpServerSchema, stored));
168
+ const patched = fromBinary(
169
+ McpServerSchema,
170
+ toBinary(McpServerSchema, stored),
171
+ );
161
172
  patched.status ??= create(McpServerStatusSchema, {});
162
173
  patched.status.discoveredCapabilities = create(DiscoveredCapabilitiesSchema, {
163
174
  tools: tools.map((name) => ({ name })),
@@ -176,13 +187,19 @@ describe("CRUD", () => {
176
187
  const created = await command.create(serverInput({ name: "GitHub Tools" }));
177
188
  expect(created.metadata?.id).toMatch(/^mcp_[0-9a-z]{26}$/);
178
189
  expect(created.metadata?.slug).toBe("github-tools");
179
- expect(created.metadata?.visibility).toBe(ApiResourceVisibility.visibility_org);
190
+ expect(created.metadata?.visibility).toBe(
191
+ ApiResourceVisibility.visibility_org,
192
+ );
180
193
  });
181
194
 
182
195
  it("rejects a duplicate create by slug within the org; a different org reuses the slug", async () => {
183
196
  const name = `Dup Target ${++counter}`;
184
197
  await command.create(serverInput({ name }));
185
- await expectCode(command.create(serverInput({ name })), Code.AlreadyExists, "duplicate create");
198
+ await expectCode(
199
+ command.create(serverInput({ name })),
200
+ Code.AlreadyExists,
201
+ "duplicate create",
202
+ );
186
203
  const other = await command.create(serverInput({ name, org: "other-org" }));
187
204
  expect(other.metadata?.org).toBe("other-org");
188
205
  });
@@ -201,10 +218,17 @@ describe("CRUD", () => {
201
218
  it("get and getByReference resolve the same resource; unknowns answer NotFound", async () => {
202
219
  const created = await command.create(serverInput());
203
220
  const byId = await query.get({ value: created.metadata!.id });
204
- const byRef = await query.getByReference({ org: ORG, slug: created.metadata!.slug });
221
+ const byRef = await query.getByReference({
222
+ org: ORG,
223
+ slug: created.metadata!.slug,
224
+ });
205
225
  expect(byId.metadata?.id).toBe(created.metadata?.id);
206
226
  expect(byRef.metadata?.id).toBe(created.metadata?.id);
207
- await expectCode(query.get({ value: "mcps_missing" }), Code.NotFound, "get unknown");
227
+ await expectCode(
228
+ query.get({ value: "mcps_missing" }),
229
+ Code.NotFound,
230
+ "get unknown",
231
+ );
208
232
  await expectCode(
209
233
  query.getByReference({ org: ORG, slug: "never-created" }),
210
234
  Code.NotFound,
@@ -216,7 +240,11 @@ describe("CRUD", () => {
216
240
  const created = await command.create(serverInput());
217
241
  const deleted = await command.delete({ resourceId: created.metadata!.id });
218
242
  expect(deleted.metadata?.id).toBe(created.metadata?.id);
219
- await expectCode(query.get({ value: created.metadata!.id }), Code.NotFound, "get after delete");
243
+ await expectCode(
244
+ query.get({ value: created.metadata!.id }),
245
+ Code.NotFound,
246
+ "get after delete",
247
+ );
220
248
  });
221
249
 
222
250
  it("update of a non-existent server and delete of a non-existent server answer NotFound; delete with an empty id is InvalidArgument", async () => {
@@ -233,7 +261,11 @@ describe("CRUD", () => {
233
261
  Code.NotFound,
234
262
  "delete non-existent",
235
263
  );
236
- await expectCode(command.delete({}), Code.InvalidArgument, "delete empty id");
264
+ await expectCode(
265
+ command.delete({}),
266
+ Code.InvalidArgument,
267
+ "delete empty id",
268
+ );
237
269
  });
238
270
  });
239
271
 
@@ -244,13 +276,17 @@ describe("updateVisibility (no conformance coverage for this domain — the D4-d
244
276
  resourceId: created.metadata!.id,
245
277
  visibility: ApiResourceVisibility.visibility_private,
246
278
  });
247
- expect(updated.metadata?.visibility).toBe(ApiResourceVisibility.visibility_private);
279
+ expect(updated.metadata?.visibility).toBe(
280
+ ApiResourceVisibility.visibility_private,
281
+ );
248
282
  expect(updated.spec?.description).toBe(created.spec?.description);
249
283
  // A visibility change is a STATUS mutation: status_audit re-stamped
250
284
  // (updated event, fresh timestamp bounds are creation-or-later),
251
285
  // spec_audit byte-untouched.
252
286
  expect(updated.status?.audit?.statusAudit?.event).toBe("updated");
253
- expect(updated.status?.audit?.specAudit).toEqual(created.status?.audit?.specAudit);
287
+ expect(updated.status?.audit?.specAudit).toEqual(
288
+ created.status?.audit?.specAudit,
289
+ );
254
290
  });
255
291
 
256
292
  it("answers NotFound for an unknown id", async () => {
@@ -296,7 +332,9 @@ describe("ValidateDefaultEnabledTools (#402)", () => {
296
332
  it("accepts names the server exposes; skips when the list is empty or the server never connected", async () => {
297
333
  // Never connected: any names pass (no authoritative toolset yet).
298
334
  const fresh = await command.create(serverInput());
299
- const freshUpdate = await command.update(updateInput(fresh, ["anything-goes"]));
335
+ const freshUpdate = await command.update(
336
+ updateInput(fresh, ["anything-goes"]),
337
+ );
300
338
  expect(freshUpdate.spec?.defaultEnabledTools).toEqual(["anything-goes"]);
301
339
 
302
340
  // Connected: valid names pass.
@@ -308,7 +346,11 @@ describe("ValidateDefaultEnabledTools (#402)", () => {
308
346
 
309
347
  it("rejects unknown tools and resource templates with the byte-pinned teaching copy", async () => {
310
348
  const created = await command.create(serverInput());
311
- await seedCapabilities(created.metadata!.id, ["search", "fetch"], ["files"]);
349
+ await seedCapabilities(
350
+ created.metadata!.id,
351
+ ["search", "fetch"],
352
+ ["files"],
353
+ );
312
354
 
313
355
  const err = await expectCode(
314
356
  command.update(updateInput(created, ["serch", "files"])),
@@ -334,7 +376,10 @@ describe("EnrichOAuthStatus (#523) — response-only oauth_status", () => {
334
376
  OAuthAppSchema,
335
377
  create(OAuthAppSchema, {
336
378
  metadata: { id, org: ORG, slug, name: slug },
337
- spec: { vendorApprovalStatus: approval, vendorApprovalDocsUrl: docsUrl },
379
+ spec: {
380
+ vendorApprovalStatus: approval,
381
+ vendorApprovalDocsUrl: docsUrl,
382
+ },
338
383
  }),
339
384
  );
340
385
  }
@@ -346,14 +391,25 @@ describe("EnrichOAuthStatus (#523) — response-only oauth_status", () => {
346
391
  });
347
392
 
348
393
  it("a missing OAuthApp skips enrichment (the initiate path owns refusing)", async () => {
349
- const created = await command.create(serverInput({ oauthAppSlug: "never-applied" }));
394
+ // The app must exist when the server is written (the reference rule);
395
+ // a reference dangles when its target leaves afterwards.
396
+ await seedOAuthApp("never-applied", VendorApprovalStatus.UNSPECIFIED, "");
397
+ const created = await command.create(
398
+ serverInput({ oauthAppSlug: "never-applied" }),
399
+ );
400
+ await server.store.deleteResource(
401
+ ApiResourceKind.oauth_app,
402
+ "oaa_neverapplied",
403
+ );
350
404
  const got = await query.get({ value: created.metadata!.id });
351
405
  expect(got.status?.oauthStatus).toBeUndefined();
352
406
  });
353
407
 
354
408
  it("nothing-to-report means ABSENT — presence itself is the SDK's signal", async () => {
355
409
  await seedOAuthApp("plain-app", VendorApprovalStatus.UNSPECIFIED, "");
356
- const created = await command.create(serverInput({ oauthAppSlug: "plain-app" }));
410
+ const created = await command.create(
411
+ serverInput({ oauthAppSlug: "plain-app" }),
412
+ );
357
413
  const got = await query.get({ value: created.metadata!.id });
358
414
  expect(got.status?.oauthStatus).toBeUndefined();
359
415
  });
@@ -363,24 +419,42 @@ describe("EnrichOAuthStatus (#523) — response-only oauth_status", () => {
363
419
  // alone must enrich (Go enrich_oauth_status_test.go's docs-only and
364
420
  // status-only arms — the executable spec of the #523 shared contract).
365
421
  it("a docs URL ALONE enriches, even with an UNSPECIFIED approval status", async () => {
366
- await seedOAuthApp("docs-only-app", VendorApprovalStatus.UNSPECIFIED, "https://vendor.example/setup");
367
- const created = await command.create(serverInput({ oauthAppSlug: "docs-only-app" }));
422
+ await seedOAuthApp(
423
+ "docs-only-app",
424
+ VendorApprovalStatus.UNSPECIFIED,
425
+ "https://vendor.example/setup",
426
+ );
427
+ const created = await command.create(
428
+ serverInput({ oauthAppSlug: "docs-only-app" }),
429
+ );
368
430
  const got = await query.get({ value: created.metadata!.id });
369
- expect(got.status?.oauthStatus?.vendorApprovalStatus).toBe(VendorApprovalStatus.UNSPECIFIED);
370
- expect(got.status?.oauthStatus?.vendorApprovalDocsUrl).toBe("https://vendor.example/setup");
431
+ expect(got.status?.oauthStatus?.vendorApprovalStatus).toBe(
432
+ VendorApprovalStatus.UNSPECIFIED,
433
+ );
434
+ expect(got.status?.oauthStatus?.vendorApprovalDocsUrl).toBe(
435
+ "https://vendor.example/setup",
436
+ );
371
437
  });
372
438
 
373
439
  it("a non-default approval status ALONE enriches — REJECTED and even APPROVED are reported", async () => {
374
440
  await seedOAuthApp("rejected-app", VendorApprovalStatus.REJECTED, "");
375
- const rejected = await command.create(serverInput({ oauthAppSlug: "rejected-app" }));
441
+ const rejected = await command.create(
442
+ serverInput({ oauthAppSlug: "rejected-app" }),
443
+ );
376
444
  const gotRejected = await query.get({ value: rejected.metadata!.id });
377
- expect(gotRejected.status?.oauthStatus?.vendorApprovalStatus).toBe(VendorApprovalStatus.REJECTED);
445
+ expect(gotRejected.status?.oauthStatus?.vendorApprovalStatus).toBe(
446
+ VendorApprovalStatus.REJECTED,
447
+ );
378
448
  expect(gotRejected.status?.oauthStatus?.vendorApprovalDocsUrl).toBe("");
379
449
 
380
450
  await seedOAuthApp("approved-app", VendorApprovalStatus.APPROVED, "");
381
- const approved = await command.create(serverInput({ oauthAppSlug: "approved-app" }));
451
+ const approved = await command.create(
452
+ serverInput({ oauthAppSlug: "approved-app" }),
453
+ );
382
454
  const gotApproved = await query.get({ value: approved.metadata!.id });
383
- expect(gotApproved.status?.oauthStatus?.vendorApprovalStatus).toBe(VendorApprovalStatus.APPROVED);
455
+ expect(gotApproved.status?.oauthStatus?.vendorApprovalStatus).toBe(
456
+ VendorApprovalStatus.APPROVED,
457
+ );
384
458
  });
385
459
 
386
460
  it("an auth block WITHOUT an oauth_app_ref (the DCR arm) is untouched", async () => {
@@ -391,8 +465,14 @@ describe("EnrichOAuthStatus (#523) — response-only oauth_status", () => {
391
465
  });
392
466
 
393
467
  it("a gating approval status or docs URL enriches BOTH read paths, response-only", async () => {
394
- await seedOAuthApp("gated-app", VendorApprovalStatus.PENDING, "https://vendor.example/approval");
395
- const created = await command.create(serverInput({ oauthAppSlug: "gated-app" }));
468
+ await seedOAuthApp(
469
+ "gated-app",
470
+ VendorApprovalStatus.PENDING,
471
+ "https://vendor.example/approval",
472
+ );
473
+ const created = await command.create(
474
+ serverInput({ oauthAppSlug: "gated-app" }),
475
+ );
396
476
 
397
477
  for (const loaded of [
398
478
  await query.get({ value: created.metadata!.id }),
@@ -430,7 +510,12 @@ describe("org-OAuth-app surface — UNIMPLEMENTED by design (#558, DD-019)", ()
430
510
  expect(getErr.rawMessage).toBe("method GetOrgOAuthApp not implemented");
431
511
 
432
512
  const setErr = await expectCode(
433
- command.setOrgOAuthApp({ resourceId: "mcps_test", org: ORG, clientId: "x", clientSecret: "y" }),
513
+ command.setOrgOAuthApp({
514
+ resourceId: "mcps_test",
515
+ org: ORG,
516
+ clientId: "x",
517
+ clientSecret: "y",
518
+ }),
434
519
  Code.Unimplemented,
435
520
  "setOrgOAuthApp",
436
521
  );
@@ -441,6 +526,8 @@ describe("org-OAuth-app surface — UNIMPLEMENTED by design (#558, DD-019)", ()
441
526
  Code.Unimplemented,
442
527
  "deleteOrgOAuthApp",
443
528
  );
444
- expect(deleteErr.rawMessage).toBe("method DeleteOrgOAuthApp not implemented");
529
+ expect(deleteErr.rawMessage).toBe(
530
+ "method DeleteOrgOAuthApp not implemented",
531
+ );
445
532
  });
446
533
  });
@@ -41,7 +41,11 @@ import { composeServer } from "../../../boot/compose.js";
41
41
  import type { ComposedServer } from "../../../boot/compose.js";
42
42
  import { createLogger } from "../../../boot/logger.js";
43
43
 
44
- const silentLogger = createLogger({ level: "error", pretty: false, write: () => {} });
44
+ const silentLogger = createLogger({
45
+ level: "error",
46
+ pretty: false,
47
+ write: () => {},
48
+ });
45
49
 
46
50
  const REDIRECT_URI = "http://127.0.0.1:8234/auth/oauth/callback";
47
51
  const ORG = "acme";
@@ -368,20 +372,30 @@ describe("initiateOAuthConnect", () => {
368
372
  "OAuth sign-in is unavailable: the platform's OAuth app for 'exampleco' is pending approval by the vendor. This server only accepts OAuth sign-in; an org admin can configure your own OAuth app instead.",
369
373
  ],
370
374
  ];
371
- it.each(refusals)("vendor arm refuses %s", async (_label, status, oauthOnly, copy) => {
372
- const slug = `vendor-${status}-${oauthOnly ? "only" : "manual"}`;
373
- await seedOAuthApp(slug, status);
374
- const id = await applyServer({ vendorSlug: slug, oauthOnly });
375
- const error = await expectCode(
376
- command.initiateOAuthConnect({ mcpServerId: id, org: ORG }),
377
- Code.FailedPrecondition,
378
- copy,
379
- );
380
- expect(error.rawMessage).toBe(copy);
381
- });
375
+ it.each(refusals)(
376
+ "vendor arm refuses %s",
377
+ async (_label, status, oauthOnly, copy) => {
378
+ const slug = `vendor-${status}-${oauthOnly ? "only" : "manual"}`;
379
+ await seedOAuthApp(slug, status);
380
+ const id = await applyServer({ vendorSlug: slug, oauthOnly });
381
+ const error = await expectCode(
382
+ command.initiateOAuthConnect({ mcpServerId: id, org: ORG }),
383
+ Code.FailedPrecondition,
384
+ copy,
385
+ );
386
+ expect(error.rawMessage).toBe(copy);
387
+ },
388
+ );
382
389
 
383
390
  it("vendor arm answers NotFound for an unresolvable oauth_app_ref", async () => {
391
+ // The app must exist when the server is written (the reference rule);
392
+ // the reference becomes unresolvable when its target leaves afterwards.
393
+ await seedOAuthApp("no-such-app", VendorApprovalStatus.APPROVED);
384
394
  const id = await applyServer({ vendorSlug: "no-such-app" });
395
+ await server.store.deleteResource(
396
+ ApiResourceKind.oauth_app,
397
+ "oap_no-such-app",
398
+ );
385
399
  await expectCode(
386
400
  command.initiateOAuthConnect({ mcpServerId: id, org: ORG }),
387
401
  Code.NotFound,
@@ -406,17 +420,29 @@ describe("initiateOAuthConnect", () => {
406
420
  describe("completeOAuthConnect → grant → disconnect (the full lifecycle)", () => {
407
421
  it("guards its inputs (proto rules answer first, exactly as on Go)", async () => {
408
422
  await expectCode(
409
- command.completeOAuthConnect({ mcpServerId: "", state: "s", authorizationCode: "c" }),
423
+ command.completeOAuthConnect({
424
+ mcpServerId: "",
425
+ state: "s",
426
+ authorizationCode: "c",
427
+ }),
410
428
  Code.InvalidArgument,
411
429
  "mcp_server_id: value is required [required]",
412
430
  );
413
431
  await expectCode(
414
- command.completeOAuthConnect({ mcpServerId: "m", state: "", authorizationCode: "c" }),
432
+ command.completeOAuthConnect({
433
+ mcpServerId: "m",
434
+ state: "",
435
+ authorizationCode: "c",
436
+ }),
415
437
  Code.InvalidArgument,
416
438
  "state:",
417
439
  );
418
440
  await expectCode(
419
- command.completeOAuthConnect({ mcpServerId: "m", state: "s", authorizationCode: "" }),
441
+ command.completeOAuthConnect({
442
+ mcpServerId: "m",
443
+ state: "s",
444
+ authorizationCode: "",
445
+ }),
420
446
  Code.InvalidArgument,
421
447
  "authorization_code:",
422
448
  );
@@ -500,7 +526,10 @@ describe("completeOAuthConnect → grant → disconnect (the full lifecycle)", (
500
526
 
501
527
  // The grant is queryable and HEALTHY; the refresh-token env var is
502
528
  // stamped unconditionally (oss#863's precondition, ported as-is).
503
- const status = await query.getOAuthGrantStatus({ resourceId: id, org: ORG });
529
+ const status = await query.getOAuthGrantStatus({
530
+ resourceId: id,
531
+ org: ORG,
532
+ });
504
533
  expect(status.connected).toBe(true);
505
534
  expect(status.targetEnvVar).toBe("EXAMPLE_TOKEN");
506
535
  expect(status.authMethod).toBe("mcp_oauth");
@@ -514,7 +543,10 @@ describe("completeOAuthConnect → grant → disconnect (the full lifecycle)", (
514
543
  expect(firstEnvId).not.toBe("");
515
544
 
516
545
  // Re-connect reuses the managed environment.
517
- const again = await command.initiateOAuthConnect({ mcpServerId: id, org: ORG });
546
+ const again = await command.initiateOAuthConnect({
547
+ mcpServerId: id,
548
+ org: ORG,
549
+ });
518
550
  await command.completeOAuthConnect({
519
551
  mcpServerId: id,
520
552
  state: again.state,
@@ -525,7 +557,10 @@ describe("completeOAuthConnect → grant → disconnect (the full lifecycle)", (
525
557
 
526
558
  // Disconnect tears down grant + environment; a second disconnect is
527
559
  // the idempotent no-grant arm.
528
- const disconnected = await command.disconnectOAuth({ resourceId: id, org: ORG });
560
+ const disconnected = await command.disconnectOAuth({
561
+ resourceId: id,
562
+ org: ORG,
563
+ });
529
564
  expect(disconnected.disconnected).toBe(true);
530
565
  expect(await server.store.oauthGrants.find("", id, ORG)).toBeUndefined();
531
566
  const againDisconnected = await command.disconnectOAuth({
@@ -254,13 +254,6 @@ export async function connect(
254
254
  input: ConnectInput,
255
255
  identity: CallerIdentity,
256
256
  ): Promise<McpServer> {
257
- const engineState = deps.engineState();
258
- if (!engineState.connected) {
259
- throw failedPreconditionError(
260
- "connect is not available: Temporal not configured",
261
- );
262
- }
263
-
264
257
  const mcpServerId = input.mcpServerId;
265
258
  if (mcpServerId === "") {
266
259
  throw invalidArgumentError("mcp_server_id is required");
@@ -280,9 +273,10 @@ export async function connect(
280
273
  throw notFoundError("mcp_server", mcpServerId);
281
274
  }
282
275
 
283
- // The annotation's can_connect check AFTER the load — the Java
284
- // McpServerConnectHandler order (load-before-authorize, stigmer#224).
285
- // C2 Stage 4.
276
+ // The annotation's can_connect check after the load and BEFORE the engine
277
+ // check (the Java McpServerConnectHandler load-before-authorize order,
278
+ // stigmer#224): a caller who may not connect this server learns nothing
279
+ // about whether the engine is up.
286
280
  await authorizeDirect(
287
281
  McpServerCommandController.method.connect,
288
282
  deps.authorizer,
@@ -290,6 +284,13 @@ export async function connect(
290
284
  input,
291
285
  );
292
286
 
287
+ const engineState = deps.engineState();
288
+ if (!engineState.connected) {
289
+ throw failedPreconditionError(
290
+ "connect is not available: Temporal not configured",
291
+ );
292
+ }
293
+
293
294
  const prepared = await prepareConnect(deps, mcpServer, input, identity);
294
295
 
295
296
  try {
@@ -53,11 +53,11 @@ import type { PipelineStep } from "../../pipeline/pipeline.js";
53
53
  import { callerIdentityOf } from "../../pipeline/interceptors/auth.js";
54
54
  import { RequestContext } from "../../pipeline/request-context.js";
55
55
  import { newAuthorizeStep } from "../../pipeline/steps/authorize.js";
56
- import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
57
56
  import {
58
- newAuthorizeVisibilityTransitionStep,
59
- newGuardPublicVisibilityStep,
60
- } from "../../pipeline/steps/visibility-gates.js";
57
+ loadedTargetAsMethod,
58
+ newAuthorizeResolvedTargetStep,
59
+ } from "../../pipeline/steps/authorize-resolved-target.js";
60
+ import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
61
61
  import {
62
62
  setAuditFieldsForUpdate,
63
63
  newBuildNewStateStep,
@@ -88,7 +88,10 @@ import {
88
88
  TARGET_RESOURCE_KEY,
89
89
  newLoadTargetStep,
90
90
  } from "../../pipeline/steps/load-target.js";
91
- import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
91
+ import {
92
+ newNormalizeReferencesStep,
93
+ newValidateReferencesStep,
94
+ } from "../../pipeline/steps/references.js";
92
95
  import {
93
96
  newCleanupIamPoliciesStep,
94
97
  newCreateAuthorizationTuplesStep,
@@ -207,7 +210,9 @@ function kindOf(ctx: HandlerContext): ApiResourceKind {
207
210
  }
208
211
 
209
212
  /** The endpoint-auth step's slice of the deps: the guarded fetch the connect slice holds. */
210
- function endpointAuthDeps(deps: McpServerControllerDeps): CompleteEndpointAuthDeps {
213
+ function endpointAuthDeps(
214
+ deps: McpServerControllerDeps,
215
+ ): CompleteEndpointAuthDeps {
211
216
  return { outboundFetch: deps.connect.outboundFetch, logger: deps.logger };
212
217
  }
213
218
 
@@ -235,13 +240,13 @@ async function createMcpServer(
235
240
  .addStep(newResolveSlugStep())
236
241
  .addStep(newCheckDuplicateStep(deps.store))
237
242
  .addStep(newBuildNewStateStep())
238
- .addStep(newGuardPublicVisibilityStep(deps.authorizer))
239
243
  // A URL-only server is asked once whether it wants OAuth and completed
240
244
  // when it does; immediately before GuardReservedLabels because the
241
245
  // provenance label it stamps is one the guard diffs.
242
246
  .addStep(newCompleteEndpointAuthStep(endpointAuthDeps(deps)))
243
247
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
244
248
  .addStep(newNormalizeReferencesStep())
249
+ .addStep(newValidateReferencesStep(deps.store))
245
250
  .addStep(newPersistStep(deps.store))
246
251
  .addStep(
247
252
  newCreateAuthorizationTuplesStep(
@@ -294,6 +299,7 @@ async function update(
294
299
  .addStep(newGuardReservedLabelsStep(deps.authorizer))
295
300
  .addStep(newValidateDefaultEnabledToolsStep())
296
301
  .addStep(newNormalizeReferencesStep())
302
+ .addStep(newValidateReferencesStep(deps.store))
297
303
  .addStep(newPersistStep(deps.store))
298
304
  .addStep(
299
305
  newIndexSearchStep(deps.store, mcpServerSearchExtractor, deps.logger),
@@ -457,12 +463,6 @@ async function updateVisibility(
457
463
  newRecordVisibilityBeforeUpdateStep(UPDATE_VISIBILITY_MCP_SERVER_KEY),
458
464
  )
459
465
  .addStep(newValidateVisibilityUpdateStep())
460
- .addStep(
461
- newAuthorizeVisibilityTransitionStep(
462
- UPDATE_VISIBILITY_MCP_SERVER_KEY,
463
- deps.authorizer,
464
- ),
465
- )
466
466
  .addStep(newSetMcpServerVisibilityStep())
467
467
  .addStep(newPersistMcpServerForVisibilityUpdateStep(deps.store))
468
468
  .addStep(
@@ -629,6 +629,12 @@ async function getByReference(
629
629
  )
630
630
  .addStep(newValidateProtoStep())
631
631
  .addStep(newLoadByReferenceStep(deps.store, McpServerSchema))
632
+ .addStep(
633
+ newAuthorizeResolvedTargetStep(
634
+ deps.authorizer,
635
+ loadedTargetAsMethod(McpServerQueryController.method.get),
636
+ ),
637
+ )
632
638
  .addStep(newEnrichOAuthStatusStep(deps.store, deps.logger))
633
639
  .build()
634
640
  .execute(reqCtx);
@@ -69,13 +69,6 @@ export async function startConnect(
69
69
  input: ConnectInput,
70
70
  identity: CallerIdentity,
71
71
  ): Promise<McpServer> {
72
- const engineState = deps.engineState();
73
- if (!engineState.connected) {
74
- throw failedPreconditionError(
75
- "connect is not available: Temporal not configured",
76
- );
77
- }
78
-
79
72
  const mcpServerId = input.mcpServerId;
80
73
  if (mcpServerId === "") {
81
74
  throw invalidArgumentError("mcp_server_id is required");
@@ -95,9 +88,10 @@ export async function startConnect(
95
88
  throw notFoundError("mcp_server", mcpServerId);
96
89
  }
97
90
 
98
- // The annotation's can_connect check AFTER the load — the Java
99
- // McpServerStartConnectHandler order (the connect handler's shared
100
- // load/authorize steps, stigmer#224). C2 Stage 4.
91
+ // The annotation's can_connect check after the load and BEFORE the engine
92
+ // check (the Java McpServerStartConnectHandler load-before-authorize order,
93
+ // stigmer#224): a caller who may not connect this server learns nothing
94
+ // about whether the engine is up.
101
95
  await authorizeDirect(
102
96
  McpServerCommandController.method.startConnect,
103
97
  deps.authorizer,
@@ -105,6 +99,13 @@ export async function startConnect(
105
99
  input,
106
100
  );
107
101
 
102
+ const engineState = deps.engineState();
103
+ if (!engineState.connected) {
104
+ throw failedPreconditionError(
105
+ "connect is not available: Temporal not configured",
106
+ );
107
+ }
108
+
108
109
  const connectStatus = mcpServer.status?.connectStatus;
109
110
  if (connectStatus?.phase === ConnectPhase.connecting) {
110
111
  if (
@@ -249,7 +250,12 @@ async function settleConnectAsync(
249
250
  outcome.failure,
250
251
  ASYNC_CONNECT_TIMEOUT,
251
252
  );
252
- await persistConnectFailure(deps.store, deps.logger, mcpServerId, failure);
253
+ await persistConnectFailure(
254
+ deps.store,
255
+ deps.logger,
256
+ mcpServerId,
257
+ failure,
258
+ );
253
259
  return;
254
260
  }
255
261
 
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Pins the create lane's authorization question (steps.ts,
3
+ * resolveMemoryCreateTargets): a wire caller asks can_create_session on
4
+ * metadata.org — whoever may converse in an organization may remember
5
+ * there — and a server-composed request (internal, or any identity that
6
+ * entered in-process) asks nothing, as the capture gate before it already
7
+ * says.
8
+ */
9
+ import { describe, expect, it } from "vitest";
10
+ import { create } from "@bufbuild/protobuf";
11
+
12
+ import { MemorySchema } from "@stigmer/protos/ai/stigmer/agentic/memory/v1/api_pb";
13
+ import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
14
+ import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
15
+
16
+ import type { CallerIdentity } from "../../../extensions/identity.js";
17
+ import { testCallerIdentity } from "../../../pipeline/__tests__/support.js";
18
+ import { RequestContext } from "../../../pipeline/request-context.js";
19
+ import {
20
+ MEMORY_CREATE_DENIED_MESSAGE,
21
+ resolveMemoryCreateTargets,
22
+ } from "../steps.js";
23
+
24
+ function ctxFor(caller: CallerIdentity) {
25
+ return new RequestContext(
26
+ MemorySchema,
27
+ create(MemorySchema, { metadata: { name: "prefers-tea", org: "acme" } }),
28
+ caller,
29
+ ApiResourceKind.memory,
30
+ );
31
+ }
32
+
33
+ describe("resolveMemoryCreateTargets", () => {
34
+ it("a wire caller asks can_create_session on the memory's organization", () => {
35
+ expect(resolveMemoryCreateTargets(ctxFor(testCallerIdentity()))).toEqual([
36
+ {
37
+ permission: IamPermission.can_create_session,
38
+ resourceKind: ApiResourceKind.organization,
39
+ resourceId: "acme",
40
+ deniedMessage: MEMORY_CREATE_DENIED_MESSAGE,
41
+ },
42
+ ]);
43
+ });
44
+
45
+ it("a server-composed request asks nothing", () => {
46
+ expect(
47
+ resolveMemoryCreateTargets(
48
+ ctxFor(testCallerIdentity({ callerClass: "internal" })),
49
+ ),
50
+ ).toEqual([]);
51
+ expect(
52
+ resolveMemoryCreateTargets(
53
+ ctxFor(
54
+ testCallerIdentity({ callerClass: "user", origin: "in-process" }),
55
+ ),
56
+ ),
57
+ ).toEqual([]);
58
+ });
59
+ });
@@ -77,6 +77,7 @@ import { newPipeline } from "../../pipeline/pipeline.js";
77
77
  import { callerIdentityOf } from "../../pipeline/interceptors/auth.js";
78
78
  import { RequestContext } from "../../pipeline/request-context.js";
79
79
  import { newAuthorizeStep } from "../../pipeline/steps/authorize.js";
80
+ import { newAuthorizeResolvedTargetStep } from "../../pipeline/steps/authorize-resolved-target.js";
80
81
  import { newGuardMemoryCaptureStep } from "../../pipeline/steps/guard-memory-capture.js";
81
82
  import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
82
83
  import { newBuildNewStateStep } from "../../pipeline/steps/defaults.js";
@@ -118,6 +119,7 @@ import {
118
119
  newResolveMemoryDefaultsStep,
119
120
  newTransitionMemoryLifecycleStep,
120
121
  newValidateMemoryUpdateStep,
122
+ resolveMemoryCreateTargets,
121
123
  } from "./steps.js";
122
124
 
123
125
  export interface MemoryControllerDeps {
@@ -194,6 +196,15 @@ async function createMemory(
194
196
  .addStep(newGuardMemoryCaptureStep(deps.runnerCredentialProvider))
195
197
  .addStep(newValidateVisibilityStep())
196
198
  .addStep(newResolveMemoryDefaultsStep())
199
+ // Before the enablement and cap checks, so a refused caller learns
200
+ // nothing about the organization's settings (steps.ts,
201
+ // resolveMemoryCreateTargets).
202
+ .addStep(
203
+ newAuthorizeResolvedTargetStep(
204
+ deps.authorizer,
205
+ resolveMemoryCreateTargets,
206
+ ),
207
+ )
197
208
  .addStep(newCheckMemoryEnablementStep(deps.store))
198
209
  .addStep(newCheckMemoryCapStep(deps.store))
199
210
  .addStep(newResolveSlugStep())