@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.
- package/dist/authorization/authorizer.d.ts +4 -8
- package/dist/authorization/authorizer.d.ts.map +1 -1
- package/dist/authorization/authorizer.js +5 -9
- package/dist/authorization/authorizer.js.map +1 -1
- package/dist/authorization/derived-tuples.d.ts.map +1 -1
- package/dist/authorization/derived-tuples.js +10 -25
- package/dist/authorization/derived-tuples.js.map +1 -1
- package/dist/authorization/evaluator.d.ts +13 -8
- package/dist/authorization/evaluator.d.ts.map +1 -1
- package/dist/authorization/evaluator.js +4 -20
- package/dist/authorization/evaluator.js.map +1 -1
- package/dist/authorization/list-read-scope.d.ts.map +1 -1
- package/dist/authorization/list-read-scope.js +24 -20
- package/dist/authorization/list-read-scope.js.map +1 -1
- package/dist/authorization/model/agent.d.ts.map +1 -1
- package/dist/authorization/model/agent.js +4 -5
- package/dist/authorization/model/agent.js.map +1 -1
- package/dist/authorization/model/agent_instance.d.ts.map +1 -1
- package/dist/authorization/model/agent_instance.js +2 -2
- package/dist/authorization/model/agent_instance.js.map +1 -1
- package/dist/authorization/model/mcp_server.d.ts.map +1 -1
- package/dist/authorization/model/mcp_server.js +2 -2
- package/dist/authorization/model/mcp_server.js.map +1 -1
- package/dist/authorization/model/organization.d.ts.map +1 -1
- package/dist/authorization/model/organization.js +2 -0
- package/dist/authorization/model/organization.js.map +1 -1
- package/dist/authorization/model/plugin.d.ts.map +1 -1
- package/dist/authorization/model/plugin.js +3 -4
- package/dist/authorization/model/plugin.js.map +1 -1
- package/dist/authorization/model/rewrite.d.ts +8 -10
- package/dist/authorization/model/rewrite.d.ts.map +1 -1
- package/dist/authorization/model/rewrite.js +0 -3
- package/dist/authorization/model/rewrite.js.map +1 -1
- package/dist/authorization/model/skill.d.ts.map +1 -1
- package/dist/authorization/model/skill.js +2 -2
- package/dist/authorization/model/skill.js.map +1 -1
- package/dist/authorization/model/workflow.d.ts.map +1 -1
- package/dist/authorization/model/workflow.js +2 -2
- package/dist/authorization/model/workflow.js.map +1 -1
- package/dist/authorization/model/workflow_instance.d.ts.map +1 -1
- package/dist/authorization/model/workflow_instance.js +2 -2
- package/dist/authorization/model/workflow_instance.js.map +1 -1
- package/dist/authorization/organization-directory.d.ts.map +1 -1
- package/dist/authorization/organization-directory.js +2 -3
- package/dist/authorization/organization-directory.js.map +1 -1
- package/dist/authorization/store-test-kit.d.ts +0 -6
- package/dist/authorization/store-test-kit.d.ts.map +1 -1
- package/dist/authorization/store-test-kit.js +16 -62
- package/dist/authorization/store-test-kit.js.map +1 -1
- package/dist/authorization/tuples.d.ts +13 -32
- package/dist/authorization/tuples.d.ts.map +1 -1
- package/dist/authorization/tuples.js +3 -11
- package/dist/authorization/tuples.js.map +1 -1
- package/dist/domain/agent/controller.d.ts.map +1 -1
- package/dist/domain/agent/controller.js +6 -4
- package/dist/domain/agent/controller.js.map +1 -1
- package/dist/domain/agentchannel/controller.d.ts.map +1 -1
- package/dist/domain/agentchannel/controller.js +9 -2
- package/dist/domain/agentchannel/controller.js.map +1 -1
- package/dist/domain/agentchannel/steps.d.ts +19 -0
- package/dist/domain/agentchannel/steps.d.ts.map +1 -1
- package/dist/domain/agentchannel/steps.js +32 -0
- package/dist/domain/agentchannel/steps.js.map +1 -1
- package/dist/domain/agentexecution/controller.d.ts.map +1 -1
- package/dist/domain/agentexecution/controller.js +3 -1
- package/dist/domain/agentexecution/controller.js.map +1 -1
- package/dist/domain/agentinstance/controller.d.ts +5 -5
- package/dist/domain/agentinstance/controller.d.ts.map +1 -1
- package/dist/domain/agentinstance/controller.js +9 -5
- package/dist/domain/agentinstance/controller.js.map +1 -1
- package/dist/domain/agentinstance/steps.d.ts +43 -8
- package/dist/domain/agentinstance/steps.d.ts.map +1 -1
- package/dist/domain/agentinstance/steps.js +71 -8
- package/dist/domain/agentinstance/steps.js.map +1 -1
- package/dist/domain/agentshare/constants.d.ts +6 -11
- package/dist/domain/agentshare/constants.d.ts.map +1 -1
- package/dist/domain/agentshare/constants.js +8 -16
- package/dist/domain/agentshare/constants.js.map +1 -1
- package/dist/domain/agentshare/controller.d.ts.map +1 -1
- package/dist/domain/agentshare/controller.js +10 -2
- package/dist/domain/agentshare/controller.js.map +1 -1
- package/dist/domain/agentshare/steps.d.ts +61 -10
- package/dist/domain/agentshare/steps.d.ts.map +1 -1
- package/dist/domain/agentshare/steps.js +121 -117
- package/dist/domain/agentshare/steps.js.map +1 -1
- package/dist/domain/artifact/controller.js +21 -25
- package/dist/domain/artifact/controller.js.map +1 -1
- package/dist/domain/channelapp/controller.d.ts.map +1 -1
- package/dist/domain/channelapp/controller.js +2 -0
- package/dist/domain/channelapp/controller.js.map +1 -1
- package/dist/domain/environment/controller.d.ts.map +1 -1
- package/dist/domain/environment/controller.js +4 -3
- package/dist/domain/environment/controller.js.map +1 -1
- package/dist/domain/executioncontext/controller.d.ts.map +1 -1
- package/dist/domain/executioncontext/controller.js +4 -1
- package/dist/domain/executioncontext/controller.js.map +1 -1
- package/dist/domain/executioncontext/steps.d.ts.map +1 -1
- package/dist/domain/executioncontext/steps.js +2 -1
- package/dist/domain/executioncontext/steps.js.map +1 -1
- package/dist/domain/mcpserver/connect.d.ts.map +1 -1
- package/dist/domain/mcpserver/connect.js +8 -7
- package/dist/domain/mcpserver/connect.js.map +1 -1
- package/dist/domain/mcpserver/controller.d.ts.map +1 -1
- package/dist/domain/mcpserver/controller.js +5 -4
- package/dist/domain/mcpserver/controller.js.map +1 -1
- package/dist/domain/mcpserver/start-connect.d.ts.map +1 -1
- package/dist/domain/mcpserver/start-connect.js +8 -7
- package/dist/domain/mcpserver/start-connect.js.map +1 -1
- package/dist/domain/memory/controller.d.ts.map +1 -1
- package/dist/domain/memory/controller.js +6 -1
- package/dist/domain/memory/controller.js.map +1 -1
- package/dist/domain/memory/steps.d.ts +23 -0
- package/dist/domain/memory/steps.d.ts.map +1 -1
- package/dist/domain/memory/steps.js +35 -0
- package/dist/domain/memory/steps.js.map +1 -1
- package/dist/domain/oauthapp/controller.d.ts.map +1 -1
- package/dist/domain/oauthapp/controller.js +2 -0
- package/dist/domain/oauthapp/controller.js.map +1 -1
- package/dist/domain/plugin/controller.d.ts.map +1 -1
- package/dist/domain/plugin/controller.js +6 -27
- package/dist/domain/plugin/controller.js.map +1 -1
- package/dist/domain/plugin/push.d.ts +7 -5
- package/dist/domain/plugin/push.d.ts.map +1 -1
- package/dist/domain/plugin/push.js +8 -14
- package/dist/domain/plugin/push.js.map +1 -1
- package/dist/domain/schedule/controller.d.ts.map +1 -1
- package/dist/domain/schedule/controller.js +10 -2
- package/dist/domain/schedule/controller.js.map +1 -1
- package/dist/domain/schedule/steps.d.ts +19 -0
- package/dist/domain/schedule/steps.d.ts.map +1 -1
- package/dist/domain/schedule/steps.js +32 -0
- package/dist/domain/schedule/steps.js.map +1 -1
- package/dist/domain/session/controller.d.ts.map +1 -1
- package/dist/domain/session/controller.js +3 -2
- package/dist/domain/session/controller.js.map +1 -1
- package/dist/domain/session/steps.d.ts +8 -9
- package/dist/domain/session/steps.d.ts.map +1 -1
- package/dist/domain/session/steps.js +17 -21
- package/dist/domain/session/steps.js.map +1 -1
- package/dist/domain/skill/controller.d.ts.map +1 -1
- package/dist/domain/skill/controller.js +8 -19
- package/dist/domain/skill/controller.js.map +1 -1
- package/dist/domain/workflow/agent-call-references.d.ts +54 -0
- package/dist/domain/workflow/agent-call-references.d.ts.map +1 -0
- package/dist/domain/workflow/agent-call-references.js +97 -0
- package/dist/domain/workflow/agent-call-references.js.map +1 -0
- package/dist/domain/workflow/controller.d.ts.map +1 -1
- package/dist/domain/workflow/controller.js +44 -113
- package/dist/domain/workflow/controller.js.map +1 -1
- package/dist/domain/workflow/registry/data/task-kind-registry.json +1 -1
- package/dist/domain/workflow/validation/task-config-constraints.d.ts +10 -1
- package/dist/domain/workflow/validation/task-config-constraints.d.ts.map +1 -1
- package/dist/domain/workflow/validation/task-config-constraints.js +3 -2
- package/dist/domain/workflow/validation/task-config-constraints.js.map +1 -1
- package/dist/domain/workflow/version-resolution.d.ts +5 -0
- package/dist/domain/workflow/version-resolution.d.ts.map +1 -0
- package/dist/domain/workflow/version-resolution.js +113 -0
- package/dist/domain/workflow/version-resolution.js.map +1 -0
- package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
- package/dist/domain/workflowexecution/controller.js +4 -2
- package/dist/domain/workflowexecution/controller.js.map +1 -1
- package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
- package/dist/domain/workflowinstance/controller.js +9 -5
- package/dist/domain/workflowinstance/controller.js.map +1 -1
- package/dist/domain/workflowinstance/steps.d.ts +20 -0
- package/dist/domain/workflowinstance/steps.d.ts.map +1 -1
- package/dist/domain/workflowinstance/steps.js +39 -0
- package/dist/domain/workflowinstance/steps.js.map +1 -1
- package/dist/extensions/authorization-queries.d.ts +6 -5
- package/dist/extensions/authorization-queries.d.ts.map +1 -1
- package/dist/extensions/identity.d.ts +19 -0
- package/dist/extensions/identity.d.ts.map +1 -1
- package/dist/extensions/identity.js +22 -3
- package/dist/extensions/identity.js.map +1 -1
- package/dist/extensions/list-read-scope.d.ts +42 -8
- package/dist/extensions/list-read-scope.d.ts.map +1 -1
- package/dist/extensions/list-read-scope.js +13 -2
- package/dist/extensions/list-read-scope.js.map +1 -1
- package/dist/extensions/resource-authorization.d.ts +3 -2
- package/dist/extensions/resource-authorization.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/pipeline/apiresource-meta.d.ts +12 -3
- package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
- package/dist/pipeline/apiresource-meta.js +21 -10
- package/dist/pipeline/apiresource-meta.js.map +1 -1
- package/dist/pipeline/steps/authorization-tuples.d.ts +9 -3
- package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
- package/dist/pipeline/steps/authorization-tuples.js +9 -11
- package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
- package/dist/pipeline/steps/authorize-resolved-target.d.ts +88 -0
- package/dist/pipeline/steps/authorize-resolved-target.d.ts.map +1 -0
- package/dist/pipeline/steps/authorize-resolved-target.js +36 -0
- package/dist/pipeline/steps/authorize-resolved-target.js.map +1 -0
- package/dist/pipeline/steps/authorize.d.ts +27 -0
- package/dist/pipeline/steps/authorize.d.ts.map +1 -1
- package/dist/pipeline/steps/authorize.js +49 -10
- package/dist/pipeline/steps/authorize.js.map +1 -1
- package/dist/pipeline/steps/guard-memory-capture.d.ts.map +1 -1
- package/dist/pipeline/steps/guard-memory-capture.js +2 -1
- package/dist/pipeline/steps/guard-memory-capture.js.map +1 -1
- package/dist/pipeline/steps/guard-reserved-labels.d.ts.map +1 -1
- package/dist/pipeline/steps/guard-reserved-labels.js +6 -7
- package/dist/pipeline/steps/guard-reserved-labels.js.map +1 -1
- package/dist/pipeline/steps/helpers.d.ts +9 -5
- package/dist/pipeline/steps/helpers.d.ts.map +1 -1
- package/dist/pipeline/steps/helpers.js +11 -15
- package/dist/pipeline/steps/helpers.js.map +1 -1
- package/dist/pipeline/steps/references.d.ts +178 -20
- package/dist/pipeline/steps/references.d.ts.map +1 -1
- package/dist/pipeline/steps/references.js +344 -43
- package/dist/pipeline/steps/references.js.map +1 -1
- package/dist/pipeline/steps/version-history.d.ts +11 -0
- package/dist/pipeline/steps/version-history.d.ts.map +1 -1
- package/dist/pipeline/steps/version-history.js +26 -0
- package/dist/pipeline/steps/version-history.js.map +1 -1
- package/dist/query/search/controller.js +0 -1
- package/dist/query/search/controller.js.map +1 -1
- package/dist/query/search/criteria.d.ts +1 -5
- package/dist/query/search/criteria.d.ts.map +1 -1
- package/dist/query/search/criteria.js +3 -13
- package/dist/query/search/criteria.js.map +1 -1
- package/dist/query/search/handler.d.ts +5 -4
- package/dist/query/search/handler.d.ts.map +1 -1
- package/dist/query/search/handler.js +7 -6
- package/dist/query/search/handler.js.map +1 -1
- package/dist/query/search/query-store.d.ts.map +1 -1
- package/dist/query/search/query-store.js +0 -2
- package/dist/query/search/query-store.js.map +1 -1
- package/dist/store/interface.d.ts +3 -6
- package/dist/store/interface.d.ts.map +1 -1
- package/dist/store/interface.js.map +1 -1
- package/dist/store/postgres/migrations.d.ts +3 -1
- package/dist/store/postgres/migrations.d.ts.map +1 -1
- package/dist/store/postgres/migrations.js +35 -1
- package/dist/store/postgres/migrations.js.map +1 -1
- package/dist/store/postgres/store.d.ts.map +1 -1
- package/dist/store/postgres/store.js +4 -9
- package/dist/store/postgres/store.js.map +1 -1
- package/dist/store/public-visibility-retired.d.ts +67 -0
- package/dist/store/public-visibility-retired.d.ts.map +1 -0
- package/dist/store/public-visibility-retired.js +55 -0
- package/dist/store/public-visibility-retired.js.map +1 -0
- package/dist/store/sqlite/migrations.d.ts +3 -1
- package/dist/store/sqlite/migrations.d.ts.map +1 -1
- package/dist/store/sqlite/migrations.js +36 -1
- package/dist/store/sqlite/migrations.js.map +1 -1
- package/dist/store/sqlite/store.d.ts.map +1 -1
- package/dist/store/sqlite/store.js +4 -8
- package/dist/store/sqlite/store.js.map +1 -1
- package/package.json +6 -6
- package/src/authorization/README.md +24 -26
- package/src/authorization/__tests__/authorizer.test.ts +10 -9
- package/src/authorization/__tests__/derived-tuples.test.ts +4 -11
- package/src/authorization/__tests__/evaluator.test.ts +14 -73
- package/src/authorization/__tests__/facts.test.ts +2 -2
- package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +6 -98
- package/src/authorization/__tests__/fixtures/fga/default-instance-inheritance.fga.yaml +4 -61
- package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +1 -21
- package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +1 -25
- package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +1 -3
- package/src/authorization/__tests__/list-read-scope.test.ts +41 -29
- package/src/authorization/__tests__/skip-lane-inventory.test.ts +160 -0
- package/src/authorization/__tests__/store-tests.test.ts +1 -6
- package/src/authorization/__tests__/tuples.test.ts +12 -11
- package/src/authorization/__tests__/wire-permissions.test.ts +5 -5
- package/src/authorization/authorizer.ts +4 -9
- package/src/authorization/derived-tuples.ts +14 -31
- package/src/authorization/evaluator.ts +15 -44
- package/src/authorization/list-read-scope.ts +27 -22
- package/src/authorization/model/__tests__/registry.test.ts +2 -0
- package/src/authorization/model/agent.ts +2 -5
- package/src/authorization/model/agent_instance.ts +0 -2
- package/src/authorization/model/mcp_server.ts +0 -2
- package/src/authorization/model/organization.ts +2 -0
- package/src/authorization/model/plugin.ts +1 -4
- package/src/authorization/model/rewrite.ts +8 -13
- package/src/authorization/model/skill.ts +0 -2
- package/src/authorization/model/workflow.ts +0 -2
- package/src/authorization/model/workflow_instance.ts +0 -2
- package/src/authorization/organization-directory.ts +1 -3
- package/src/authorization/store-test-kit.ts +16 -75
- package/src/authorization/tuples.ts +16 -39
- package/src/domain/agent/__tests__/agent.test.ts +11 -4
- package/src/domain/agent/controller.ts +17 -7
- package/src/domain/agentchannel/__tests__/agentchannel.test.ts +223 -48
- package/src/domain/agentchannel/__tests__/create-authorization.test.ts +58 -0
- package/src/domain/agentchannel/controller.ts +25 -1
- package/src/domain/agentchannel/steps.ts +40 -0
- package/src/domain/agentexecution/controller.ts +6 -1
- package/src/domain/agentinstance/__tests__/create-authorization.composed.test.ts +243 -0
- package/src/domain/agentinstance/__tests__/create-authorization.test.ts +144 -0
- package/src/domain/agentinstance/controller.ts +30 -17
- package/src/domain/agentinstance/steps.ts +82 -8
- package/src/domain/agentshare/__tests__/agentshare.test.ts +196 -172
- package/src/domain/agentshare/__tests__/create-authorization.test.ts +71 -0
- package/src/domain/agentshare/__tests__/member-audience.test.ts +113 -0
- package/src/domain/agentshare/constants.ts +14 -26
- package/src/domain/agentshare/controller.ts +27 -1
- package/src/domain/agentshare/steps.ts +168 -155
- package/src/domain/artifact/controller.ts +18 -22
- package/src/domain/channelapp/controller.ts +10 -0
- package/src/domain/environment/controller.ts +15 -8
- package/src/domain/executioncontext/__tests__/executioncontext.test.ts +1 -0
- package/src/domain/executioncontext/controller.ts +15 -1
- package/src/domain/executioncontext/steps.ts +2 -1
- package/src/domain/mcpserver/__tests__/mcpserver.test.ts +115 -28
- package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +53 -18
- package/src/domain/mcpserver/connect.ts +11 -10
- package/src/domain/mcpserver/controller.ts +19 -13
- package/src/domain/mcpserver/start-connect.ts +17 -11
- package/src/domain/memory/__tests__/create-authorization.test.ts +59 -0
- package/src/domain/memory/controller.ts +11 -0
- package/src/domain/memory/steps.ts +41 -0
- package/src/domain/oauthapp/controller.ts +10 -0
- package/src/domain/plugin/controller.ts +23 -44
- package/src/domain/plugin/push.ts +8 -16
- package/src/domain/schedule/__tests__/create-authorization.test.ts +58 -0
- package/src/domain/schedule/controller.ts +26 -1
- package/src/domain/schedule/steps.ts +45 -2
- package/src/domain/session/controller.ts +12 -4
- package/src/domain/session/steps.ts +24 -32
- package/src/domain/skill/controller.ts +24 -30
- package/src/domain/workflow/__tests__/agent-call-references.test.ts +222 -0
- package/src/domain/workflow/agent-call-references.ts +157 -0
- package/src/domain/workflow/controller.ts +86 -155
- package/src/domain/workflow/registry/data/task-kind-registry.json +1 -1
- package/src/domain/workflow/validation/task-config-constraints.ts +7 -3
- package/src/domain/workflow/version-resolution.ts +166 -0
- package/src/domain/workflowexecution/controller.ts +7 -2
- package/src/domain/workflowinstance/__tests__/create-authorization.test.ts +109 -0
- package/src/domain/workflowinstance/controller.ts +25 -12
- package/src/domain/workflowinstance/steps.ts +49 -1
- package/src/extensions/__tests__/built-in-authorization-composed.test.ts +32 -19
- package/src/extensions/__tests__/composed-support.ts +38 -4
- package/src/extensions/__tests__/extension-composition.test.ts +4 -4
- package/src/extensions/__tests__/identity.test.ts +44 -1
- package/src/extensions/__tests__/list-read-scope-composed.test.ts +96 -7
- package/src/extensions/__tests__/list-read-scope.test.ts +63 -0
- package/src/extensions/authorization-queries.ts +6 -5
- package/src/extensions/identity.ts +23 -5
- package/src/extensions/list-read-scope.ts +48 -8
- package/src/extensions/resource-authorization.ts +3 -5
- package/src/index.ts +0 -1
- package/src/pipeline/__tests__/supports-visibility.test.ts +112 -0
- package/src/pipeline/apiresource-meta.ts +21 -10
- package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +18 -31
- package/src/pipeline/steps/__tests__/authorize-resolved-target.test.ts +285 -0
- package/src/pipeline/steps/__tests__/references.test.ts +703 -0
- package/src/pipeline/steps/authorization-tuples.ts +9 -11
- package/src/pipeline/steps/authorize-resolved-target.ts +129 -0
- package/src/pipeline/steps/authorize.ts +70 -13
- package/src/pipeline/steps/guard-memory-capture.ts +2 -1
- package/src/pipeline/steps/guard-reserved-labels.ts +6 -9
- package/src/pipeline/steps/helpers.ts +11 -15
- package/src/pipeline/steps/references.ts +578 -70
- package/src/pipeline/steps/version-history.ts +34 -0
- package/src/query/search/__tests__/criteria.test.ts +0 -4
- package/src/query/search/__tests__/query-store.test.ts +11 -40
- package/src/query/search/controller.ts +0 -1
- package/src/query/search/criteria.ts +0 -14
- package/src/query/search/handler.ts +6 -7
- package/src/query/search/query-store.ts +0 -2
- package/src/store/__tests__/public-visibility-retired.test.ts +127 -0
- package/src/store/__tests__/store-contract.ts +6 -51
- package/src/store/interface.ts +3 -6
- package/src/store/postgres/__tests__/migrations.test.ts +187 -6
- package/src/store/postgres/__tests__/store-contract.test.ts +0 -2
- package/src/store/postgres/migrations.ts +48 -1
- package/src/store/postgres/store.ts +4 -11
- package/src/store/public-visibility-retired.ts +119 -0
- package/src/store/sqlite/__tests__/migrations.test.ts +191 -5
- package/src/store/sqlite/migrations.ts +45 -1
- package/src/store/sqlite/store.ts +4 -10
- package/dist/pipeline/steps/visibility-gates.d.ts +0 -27
- package/dist/pipeline/steps/visibility-gates.d.ts.map +0 -1
- package/dist/pipeline/steps/visibility-gates.js +0 -139
- package/dist/pipeline/steps/visibility-gates.js.map +0 -1
- package/src/authorization/__tests__/fixtures/fga/cross-org-share-creation.fga.yaml +0 -98
- package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +0 -52
- package/src/pipeline/steps/__tests__/visibility-gates.test.ts +0 -187
- 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({
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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({
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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: {
|
|
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
|
-
|
|
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(
|
|
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(
|
|
367
|
-
|
|
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(
|
|
370
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
395
|
-
|
|
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({
|
|
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(
|
|
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({
|
|
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)(
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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
|
|
284
|
-
// McpServerConnectHandler
|
|
285
|
-
//
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
} from "../../pipeline/steps/
|
|
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 {
|
|
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(
|
|
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
|
|
99
|
-
//
|
|
100
|
-
//
|
|
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(
|
|
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())
|