@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Pinned copy of stigmer-cloud backend/services/stigmer-server/fga/tests/org-admin-owner-inheritance.fga.yaml
|
|
2
|
-
# as changed by stigmer-cloud#
|
|
2
|
+
# as changed by stigmer-cloud#765 (the OpenFGA store test the cloud runs against its live model).
|
|
3
3
|
# The body below is byte-identical to the source; the cloud re-runs the LIVE
|
|
4
4
|
# file against this evaluator at the re-pin, so a stale copy is caught there.
|
|
5
5
|
# Store tests for org-admin owner inheritance (T08).
|
|
@@ -131,8 +131,6 @@ tests:
|
|
|
131
131
|
check:
|
|
132
132
|
- user: identity_account:ana
|
|
133
133
|
object: agent:carols-bot
|
|
134
|
-
context:
|
|
135
|
-
allow: false
|
|
136
134
|
assertions:
|
|
137
135
|
can_view: true
|
|
138
136
|
can_edit: true
|
|
@@ -169,8 +167,6 @@ tests:
|
|
|
169
167
|
can_grant_access: true
|
|
170
168
|
- user: identity_account:ana
|
|
171
169
|
object: skill:carols-notes
|
|
172
|
-
context:
|
|
173
|
-
allow: false
|
|
174
170
|
assertions:
|
|
175
171
|
can_view: true
|
|
176
172
|
can_edit: true
|
|
@@ -178,8 +174,6 @@ tests:
|
|
|
178
174
|
can_grant_access: true
|
|
179
175
|
- user: identity_account:ana
|
|
180
176
|
object: workflow:carols-flow
|
|
181
|
-
context:
|
|
182
|
-
allow: false
|
|
183
177
|
assertions:
|
|
184
178
|
can_view: true
|
|
185
179
|
can_edit: true
|
|
@@ -197,8 +191,6 @@ tests:
|
|
|
197
191
|
check:
|
|
198
192
|
- user: identity_account:root
|
|
199
193
|
object: agent:carols-bot
|
|
200
|
-
context:
|
|
201
|
-
allow: false
|
|
202
194
|
assertions:
|
|
203
195
|
can_edit: true
|
|
204
196
|
can_delete: true
|
|
@@ -218,8 +210,6 @@ tests:
|
|
|
218
210
|
check:
|
|
219
211
|
- user: identity_account:dave
|
|
220
212
|
object: agent:carols-bot
|
|
221
|
-
context:
|
|
222
|
-
allow: false
|
|
223
213
|
assertions:
|
|
224
214
|
can_view: false
|
|
225
215
|
can_edit: false
|
|
@@ -250,8 +240,6 @@ tests:
|
|
|
250
240
|
check:
|
|
251
241
|
- user: identity_account:zara
|
|
252
242
|
object: agent:carols-bot
|
|
253
|
-
context:
|
|
254
|
-
allow: false
|
|
255
243
|
assertions:
|
|
256
244
|
can_view: false
|
|
257
245
|
can_edit: false
|
|
@@ -266,8 +254,6 @@ tests:
|
|
|
266
254
|
check:
|
|
267
255
|
- user: identity_account:ana
|
|
268
256
|
object: agent_instance:carols-instance
|
|
269
|
-
context:
|
|
270
|
-
allow: false
|
|
271
257
|
assertions:
|
|
272
258
|
can_view: false
|
|
273
259
|
can_edit: false
|
|
@@ -297,8 +283,6 @@ tests:
|
|
|
297
283
|
check:
|
|
298
284
|
- user: identity_account:carol
|
|
299
285
|
object: agent:carols-bot
|
|
300
|
-
context:
|
|
301
|
-
allow: false
|
|
302
286
|
assertions:
|
|
303
287
|
can_view: true
|
|
304
288
|
can_edit: true
|
|
@@ -309,8 +293,6 @@ tests:
|
|
|
309
293
|
list_objects:
|
|
310
294
|
- user: identity_account:ana
|
|
311
295
|
type: agent
|
|
312
|
-
context:
|
|
313
|
-
allow: false
|
|
314
296
|
assertions:
|
|
315
297
|
can_view:
|
|
316
298
|
- agent:carols-bot
|
|
@@ -318,8 +300,6 @@ tests:
|
|
|
318
300
|
- agent:carols-bot
|
|
319
301
|
- user: identity_account:ana
|
|
320
302
|
type: agent_instance
|
|
321
|
-
context:
|
|
322
|
-
allow: false
|
|
323
303
|
assertions:
|
|
324
304
|
can_view: []
|
|
325
305
|
- user: identity_account:ana
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Pinned copy of stigmer-cloud backend/services/stigmer-server/fga/tests/platform-visibility.fga.yaml
|
|
2
|
-
#
|
|
2
|
+
# as changed by stigmer-cloud#765 (the OpenFGA store test the cloud runs against its live model).
|
|
3
3
|
# The body below is byte-identical to the source; the cloud re-runs the LIVE
|
|
4
4
|
# file against this evaluator at the re-pin, so a stale copy is caught there.
|
|
5
5
|
# Store tests for platform visibility (visibility_platform).
|
|
@@ -102,8 +102,6 @@ tests:
|
|
|
102
102
|
check:
|
|
103
103
|
- user: identity_account:alice
|
|
104
104
|
object: agent:sara
|
|
105
|
-
context:
|
|
106
|
-
allow: false
|
|
107
105
|
assertions:
|
|
108
106
|
can_view: true
|
|
109
107
|
can_execute: true
|
|
@@ -112,8 +110,6 @@ tests:
|
|
|
112
110
|
can_delete: false
|
|
113
111
|
- user: identity_account:bob
|
|
114
112
|
object: agent:sara
|
|
115
|
-
context:
|
|
116
|
-
allow: false
|
|
117
113
|
assertions:
|
|
118
114
|
can_view: true
|
|
119
115
|
can_execute: true
|
|
@@ -122,8 +118,6 @@ tests:
|
|
|
122
118
|
check:
|
|
123
119
|
- user: identity_account:mallory
|
|
124
120
|
object: agent:sara
|
|
125
|
-
context:
|
|
126
|
-
allow: false
|
|
127
121
|
assertions:
|
|
128
122
|
can_view: false
|
|
129
123
|
can_execute: false
|
|
@@ -133,8 +127,6 @@ tests:
|
|
|
133
127
|
check:
|
|
134
128
|
- user: identity_account:priya
|
|
135
129
|
object: agent:sara
|
|
136
|
-
context:
|
|
137
|
-
allow: false
|
|
138
130
|
assertions:
|
|
139
131
|
can_view: true
|
|
140
132
|
can_execute: true
|
|
@@ -144,8 +136,6 @@ tests:
|
|
|
144
136
|
# narrower: platform_user resolves member-from-managed_org.)
|
|
145
137
|
- user: identity_account:veda
|
|
146
138
|
object: agent:sara
|
|
147
|
-
context:
|
|
148
|
-
allow: false
|
|
149
139
|
assertions:
|
|
150
140
|
can_view: true
|
|
151
141
|
can_edit: false
|
|
@@ -154,8 +144,6 @@ tests:
|
|
|
154
144
|
check:
|
|
155
145
|
- user: identity_account:alice
|
|
156
146
|
object: agent:internal-bot
|
|
157
|
-
context:
|
|
158
|
-
allow: false
|
|
159
147
|
assertions:
|
|
160
148
|
can_view: false
|
|
161
149
|
can_execute: false
|
|
@@ -163,8 +151,6 @@ tests:
|
|
|
163
151
|
# without an explicit visibility tuple.
|
|
164
152
|
- user: identity_account:priya
|
|
165
153
|
object: agent:internal-bot
|
|
166
|
-
context:
|
|
167
|
-
allow: false
|
|
168
154
|
assertions:
|
|
169
155
|
can_view: false
|
|
170
156
|
can_execute: false
|
|
@@ -173,8 +159,6 @@ tests:
|
|
|
173
159
|
check:
|
|
174
160
|
- user: identity_account:alice
|
|
175
161
|
object: skill:research
|
|
176
|
-
context:
|
|
177
|
-
allow: false
|
|
178
162
|
assertions:
|
|
179
163
|
can_view: true
|
|
180
164
|
can_use: true
|
|
@@ -184,8 +168,6 @@ tests:
|
|
|
184
168
|
check:
|
|
185
169
|
- user: identity_account:alice
|
|
186
170
|
object: workflow:onboarding
|
|
187
|
-
context:
|
|
188
|
-
allow: false
|
|
189
171
|
assertions:
|
|
190
172
|
can_view: true
|
|
191
173
|
can_execute: true
|
|
@@ -194,8 +176,6 @@ tests:
|
|
|
194
176
|
check:
|
|
195
177
|
- user: identity_account:alice
|
|
196
178
|
object: mcp_server:github
|
|
197
|
-
context:
|
|
198
|
-
allow: false
|
|
199
179
|
assertions:
|
|
200
180
|
can_view: true
|
|
201
181
|
can_use: true
|
|
@@ -205,8 +185,6 @@ tests:
|
|
|
205
185
|
check:
|
|
206
186
|
- user: identity_account:swarup
|
|
207
187
|
object: agent:sara
|
|
208
|
-
context:
|
|
209
|
-
allow: false
|
|
210
188
|
assertions:
|
|
211
189
|
can_view: true
|
|
212
190
|
can_edit: true
|
|
@@ -216,8 +194,6 @@ tests:
|
|
|
216
194
|
list_objects:
|
|
217
195
|
- user: identity_account:alice
|
|
218
196
|
type: agent
|
|
219
|
-
context:
|
|
220
|
-
allow: false
|
|
221
197
|
assertions:
|
|
222
198
|
can_view:
|
|
223
199
|
- agent:sara
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Pinned copy of stigmer-cloud backend/services/stigmer-server/fga/tests/workflow-execution-sharing.fga.yaml
|
|
2
|
-
#
|
|
2
|
+
# as changed by stigmer-cloud#765 (the OpenFGA store test the cloud runs against its live model).
|
|
3
3
|
# The body below is byte-identical to the source; the cloud re-runs the LIVE
|
|
4
4
|
# file against this evaluator at the re-pin, so a stale copy is caught there.
|
|
5
5
|
# Store tests for workflow_execution sharing and run observability.
|
|
@@ -173,8 +173,6 @@ tests:
|
|
|
173
173
|
# never alice's run history.
|
|
174
174
|
- user: identity_account:vera
|
|
175
175
|
object: workflow_instance:inst1
|
|
176
|
-
context:
|
|
177
|
-
allow: false
|
|
178
176
|
assertions:
|
|
179
177
|
can_view: true
|
|
180
178
|
- user: identity_account:vera
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pins the built-in list read scope on both store drivers as the twin of
|
|
3
3
|
* the cloud's driver (stigmer-cloud iam/list-read-scope.ts): every
|
|
4
|
-
* candidate a list lane offers is answered by `can_view`
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* facts the candidate carries — no candidate row is read twice.
|
|
4
|
+
* candidate a list lane offers is answered by `can_view` through the same
|
|
5
|
+
* evaluator the Authorizer uses, over tuples derived from the facts the
|
|
6
|
+
* candidate carries — no candidate row is read twice.
|
|
8
7
|
*
|
|
9
8
|
* The adversarial cells come first, because until slice 5's sibling
|
|
10
9
|
* cells this file and the composed proof are the only proof that a
|
|
11
|
-
* member's list is a member's list: the outsider sees nothing (a
|
|
12
|
-
*
|
|
10
|
+
* member's list is a member's list: the outsider sees nothing (a row
|
|
11
|
+
* still carrying the retired public level included); the viewer rung sees
|
|
12
|
+
* the org-visible blueprints
|
|
13
13
|
* and nothing personal; the founder — an admin — sees the organization's
|
|
14
14
|
* blueprints and NOT its members' sessions, keys, environments or
|
|
15
15
|
* memories (the model's own line, now list-visible); an execution is its session's and
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
* org-observable reaches the organization's viewers; a memory with no
|
|
18
18
|
* subject is nobody's; an instance reaches whoever reads its blueprint
|
|
19
19
|
* only when it is the default. Then the contract: a scope only narrows
|
|
20
|
-
* and never reorders; the `internal` class is the in-process skip
|
|
20
|
+
* and never reorders; the `internal` class is the in-process skip on the
|
|
21
|
+
* enumeration verb and a loud consumer bug on the restrict verb (the
|
|
22
|
+
* shared helper answers the class before any driver, stigmer#1207); an
|
|
21
23
|
* unprovisioned subject is their raw subject (the 3.14 verifiers' stamp); a
|
|
22
24
|
* fault throws and is never an empty answer; an undeclared kind is a
|
|
23
25
|
* consumer bug, loud; the enumeration verb equals the restrict verb over
|
|
@@ -278,9 +280,10 @@ describe.each(driverFixtures(SEEDED_KINDS))(
|
|
|
278
280
|
await grant(orgRole(VIEWER, "viewer", ORG));
|
|
279
281
|
|
|
280
282
|
// Blueprints: the founder's private and org-visible agents, a
|
|
281
|
-
// member's private one,
|
|
282
|
-
//
|
|
283
|
-
// and
|
|
283
|
+
// member's private one, one still carrying the retired public
|
|
284
|
+
// level (a row the store migration has not met, which derives no
|
|
285
|
+
// viewer grant and so reads as its owner's alone), and one
|
|
286
|
+
// stamped by the 3.14 verifiers' raw subject.
|
|
284
287
|
await save("agent", {
|
|
285
288
|
id: "agt_private",
|
|
286
289
|
org: ORG,
|
|
@@ -425,7 +428,7 @@ describe.each(driverFixtures(SEEDED_KINDS))(
|
|
|
425
428
|
});
|
|
426
429
|
|
|
427
430
|
describe("the adversarial cells", () => {
|
|
428
|
-
it("an OUTSIDER lists nothing of the organization's —
|
|
431
|
+
it("an OUTSIDER lists nothing of the organization's — a row still carrying the retired public level included", async () => {
|
|
429
432
|
for (const kind of SEEDED_KINDS.filter(
|
|
430
433
|
(k) =>
|
|
431
434
|
k !== ApiResourceKind.iam_policy &&
|
|
@@ -439,13 +442,13 @@ describe.each(driverFixtures(SEEDED_KINDS))(
|
|
|
439
442
|
}
|
|
440
443
|
});
|
|
441
444
|
|
|
442
|
-
it("a VIEWER lists the org-visible
|
|
445
|
+
it("a VIEWER lists the org-visible blueprint and nothing private; a MEMBER adds their own private one; the retired level grants neither anything", async () => {
|
|
443
446
|
expect(
|
|
444
447
|
await listAs(resolved(VIEWER), ApiResourceKind.agent),
|
|
445
|
-
).toEqual(["agt_org"
|
|
448
|
+
).toEqual(["agt_org"]);
|
|
446
449
|
expect(
|
|
447
450
|
await listAs(resolved(MEMBER), ApiResourceKind.agent),
|
|
448
|
-
).toEqual(["agt_org", "agt_member_private"
|
|
451
|
+
).toEqual(["agt_org", "agt_member_private"]);
|
|
449
452
|
});
|
|
450
453
|
|
|
451
454
|
it("the FOUNDER and the ADMIN list every blueprint (`owner: … or admin from organization`), including a member's private one", async () => {
|
|
@@ -540,7 +543,7 @@ describe.each(driverFixtures(SEEDED_KINDS))(
|
|
|
540
543
|
const offered = [
|
|
541
544
|
entryOf(
|
|
542
545
|
ApiResourceKind.agent,
|
|
543
|
-
rows.get(ApiResourceKind.agent)!.get("
|
|
546
|
+
rows.get(ApiResourceKind.agent)!.get("agt_member_private")!,
|
|
544
547
|
),
|
|
545
548
|
entryOf(
|
|
546
549
|
ApiResourceKind.agent,
|
|
@@ -560,15 +563,15 @@ describe.each(driverFixtures(SEEDED_KINDS))(
|
|
|
560
563
|
ApiResourceKind.agent,
|
|
561
564
|
offered,
|
|
562
565
|
);
|
|
563
|
-
expect([...kept]).toEqual(["
|
|
566
|
+
expect([...kept]).toEqual(["agt_member_private", "agt_org"]);
|
|
564
567
|
// The lane's order is the lane's: the helper filters its own
|
|
565
568
|
// array by the kept set.
|
|
566
569
|
expect(
|
|
567
570
|
await listAs(resolved(MEMBER), ApiResourceKind.agent, [
|
|
568
|
-
rows.get(ApiResourceKind.agent)!.get("
|
|
571
|
+
rows.get(ApiResourceKind.agent)!.get("agt_member_private")!,
|
|
569
572
|
rows.get(ApiResourceKind.agent)!.get("agt_org")!,
|
|
570
573
|
]),
|
|
571
|
-
).toEqual(["
|
|
574
|
+
).toEqual(["agt_member_private", "agt_org"]);
|
|
572
575
|
});
|
|
573
576
|
|
|
574
577
|
it("no candidates: the empty set, with no read of any kind", async () => {
|
|
@@ -583,17 +586,7 @@ describe.each(driverFixtures(SEEDED_KINDS))(
|
|
|
583
586
|
expect(accountReads).toBe(0);
|
|
584
587
|
});
|
|
585
588
|
|
|
586
|
-
it("the `internal` class — the server acting as itself —
|
|
587
|
-
const offered = rowsOf(ApiResourceKind.agent).map((row) =>
|
|
588
|
-
entryOf(ApiResourceKind.agent, row),
|
|
589
|
-
);
|
|
590
|
-
expect([
|
|
591
|
-
...(await scope().restrictListEntries(
|
|
592
|
-
INTERNAL,
|
|
593
|
-
ApiResourceKind.agent,
|
|
594
|
-
offered,
|
|
595
|
-
)),
|
|
596
|
-
]).toEqual(offered.map((entry) => entry.id));
|
|
589
|
+
it("the `internal` class on the enumeration verb — the server acting as itself — is every id of the kind, with no account even asked for (the in-process skip; no helper stands before this verb)", async () => {
|
|
597
590
|
expect(
|
|
598
591
|
[
|
|
599
592
|
...(await scope().authorizedResourceIds(
|
|
@@ -605,6 +598,25 @@ describe.each(driverFixtures(SEEDED_KINDS))(
|
|
|
605
598
|
expect(accountReads).toBe(0);
|
|
606
599
|
});
|
|
607
600
|
|
|
601
|
+
it("the `internal` class on the restrict verb is a consumer bug, loud: the shared helper answers that class before any driver, so a driver offered it was reached around the idiom", async () => {
|
|
602
|
+
const offered = rowsOf(ApiResourceKind.agent).map((row) =>
|
|
603
|
+
entryOf(ApiResourceKind.agent, row),
|
|
604
|
+
);
|
|
605
|
+
const refusal = await scope()
|
|
606
|
+
.restrictListEntries(INTERNAL, ApiResourceKind.agent, offered)
|
|
607
|
+
.then(
|
|
608
|
+
() => undefined,
|
|
609
|
+
(error: unknown) => error,
|
|
610
|
+
);
|
|
611
|
+
expect(refusal).toBeInstanceOf(AuthorizationEvaluationError);
|
|
612
|
+
expect((refusal as AuthorizationEvaluationError).reason).toBe(
|
|
613
|
+
"internal-caller-offered",
|
|
614
|
+
);
|
|
615
|
+
// Refused before any read: the server was never evaluated as a person.
|
|
616
|
+
expect(accountReads).toBe(0);
|
|
617
|
+
expect(storeReads).toEqual({ rows: 0, scans: 0 });
|
|
618
|
+
});
|
|
619
|
+
|
|
608
620
|
it("an unprovisioned subject is their raw subject and nothing else: the 3.14-stamped row is theirs, the organization's rows are not", async () => {
|
|
609
621
|
// `agt_legacy` is stamped with LEGACY's raw subject; a caller
|
|
610
622
|
// who IS that subject and holds no account reaches it through
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pins the coverage inventory's own rule for `is_skip_authorization` lanes
|
|
3
|
+
* (docs/authorization-coverage.md, "How to read the tables"): a skip lane
|
|
4
|
+
* reaches no Authorizer in either edition, so what guards it is whatever
|
|
5
|
+
* its Handler cell names — and a cell that names nothing is a lane open to
|
|
6
|
+
* every authenticated caller that nobody has said so about. Two things are
|
|
7
|
+
* held here, so the doc cannot drift from the server it describes:
|
|
8
|
+
*
|
|
9
|
+
* 1. The set of skip-annotated methods the open-source server SERVES
|
|
10
|
+
* (the empty composition's routes replayed into a recorder, a method
|
|
11
|
+
* counted only when its service's implementation map carries it — a
|
|
12
|
+
* partially implemented service lists more on its descriptor than it
|
|
13
|
+
* serves) equals the set of skip rows in the doc, service by method.
|
|
14
|
+
* A new skip lane without a row, or a row for a lane that is no
|
|
15
|
+
* longer a skip, fails here.
|
|
16
|
+
* 2. Every skip row's Handler cell carries one of the three markers the
|
|
17
|
+
* doc defines — `guard: <Name>`, `driver: <Seam>`,
|
|
18
|
+
* `by design: <reason>` — and every `guard:` names a pipeline step or
|
|
19
|
+
* a handler's guard function that exists by that name in `src/`
|
|
20
|
+
* outside the tests, so a renamed or removed guard cannot leave the
|
|
21
|
+
* doc pointing at nothing.
|
|
22
|
+
*
|
|
23
|
+
* The rule lives in the doc; this test only enforces it. The doc is the
|
|
24
|
+
* one inventory (the package guide mandates updating it with every
|
|
25
|
+
* annotation change), and a second list here would be the drift this
|
|
26
|
+
* test exists to prevent.
|
|
27
|
+
*/
|
|
28
|
+
import {
|
|
29
|
+
mkdtempSync,
|
|
30
|
+
readFileSync,
|
|
31
|
+
readdirSync,
|
|
32
|
+
rmSync,
|
|
33
|
+
statSync,
|
|
34
|
+
} from "node:fs";
|
|
35
|
+
import { tmpdir } from "node:os";
|
|
36
|
+
import path from "node:path";
|
|
37
|
+
import { fileURLToPath } from "node:url";
|
|
38
|
+
|
|
39
|
+
import { getOption } from "@bufbuild/protobuf";
|
|
40
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
41
|
+
|
|
42
|
+
import { is_skip_authorization } from "@stigmer/protos/ai/stigmer/commons/rpc/method_options_pb";
|
|
43
|
+
|
|
44
|
+
import { loadConfig } from "../../boot/config.js";
|
|
45
|
+
import { composeServer } from "../../boot/compose.js";
|
|
46
|
+
import type { ComposedServer } from "../../boot/compose.js";
|
|
47
|
+
import {
|
|
48
|
+
baseConfig,
|
|
49
|
+
servedMethods,
|
|
50
|
+
silentLogger,
|
|
51
|
+
} from "../../extensions/__tests__/composed-support.js";
|
|
52
|
+
|
|
53
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
54
|
+
const PACKAGE_ROOT = path.resolve(HERE, "../../..");
|
|
55
|
+
const COVERAGE_DOC = path.join(PACKAGE_ROOT, "docs/authorization-coverage.md");
|
|
56
|
+
const SRC = path.join(PACKAGE_ROOT, "src");
|
|
57
|
+
|
|
58
|
+
/** A skip row: `| Service.method | is_skip_authorization | <handler cell> |`. */
|
|
59
|
+
const SKIP_ROW =
|
|
60
|
+
/^\| ([A-Za-z]+)\.([A-Za-z]+) \| is_skip_authorization \| (.*) \|$/;
|
|
61
|
+
|
|
62
|
+
const MARKERS = ["guard:", "driver:", "by design:"] as const;
|
|
63
|
+
|
|
64
|
+
interface SkipRow {
|
|
65
|
+
readonly method: string;
|
|
66
|
+
readonly handler: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function skipRowsOf(doc: string): SkipRow[] {
|
|
70
|
+
const rows: SkipRow[] = [];
|
|
71
|
+
for (const line of doc.split("\n")) {
|
|
72
|
+
const m = SKIP_ROW.exec(line);
|
|
73
|
+
if (m !== null) {
|
|
74
|
+
rows.push({ method: `${m[1]}.${m[2]}`, handler: m[3] ?? "" });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return rows;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Every `guard: <Name>` a handler cell names. */
|
|
81
|
+
function guardsOf(handler: string): string[] {
|
|
82
|
+
return [...handler.matchAll(/guard: ([A-Za-z]+)/g)].map((m) => m[1] ?? "");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Every non-test `.ts` source under `src/`, read once. */
|
|
86
|
+
function sourceText(): string {
|
|
87
|
+
const parts: string[] = [];
|
|
88
|
+
const walk = (dir: string): void => {
|
|
89
|
+
for (const entry of readdirSync(dir)) {
|
|
90
|
+
const full = path.join(dir, entry);
|
|
91
|
+
if (statSync(full).isDirectory()) {
|
|
92
|
+
if (entry !== "__tests__") {
|
|
93
|
+
walk(full);
|
|
94
|
+
}
|
|
95
|
+
} else if (full.endsWith(".ts") && !full.endsWith(".test.ts")) {
|
|
96
|
+
parts.push(readFileSync(full, "utf8"));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
walk(SRC);
|
|
101
|
+
return parts.join("\n");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
describe("the skip-lane inventory (docs/authorization-coverage.md) is true to the served server", () => {
|
|
105
|
+
let dir: string;
|
|
106
|
+
let server: ComposedServer;
|
|
107
|
+
|
|
108
|
+
beforeAll(async () => {
|
|
109
|
+
dir = mkdtempSync(path.join(tmpdir(), "skip-lane-inventory-test-"));
|
|
110
|
+
server = await composeServer({
|
|
111
|
+
config: loadConfig(baseConfig(dir)),
|
|
112
|
+
logger: silentLogger,
|
|
113
|
+
portOverride: 0,
|
|
114
|
+
host: "127.0.0.1",
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
afterAll(async () => {
|
|
119
|
+
await server.shutdown();
|
|
120
|
+
rmSync(dir, { recursive: true, force: true });
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("the doc's skip rows are exactly the skip-annotated methods the server serves", () => {
|
|
124
|
+
const served = new Set<string>();
|
|
125
|
+
for (const method of servedMethods(server.routes)) {
|
|
126
|
+
if (getOption(method, is_skip_authorization)) {
|
|
127
|
+
const serviceName = method.parent.typeName.split(".").at(-1) ?? "";
|
|
128
|
+
served.add(`${serviceName}.${method.name}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const documented = new Set(
|
|
132
|
+
skipRowsOf(readFileSync(COVERAGE_DOC, "utf8")).map((r) => r.method),
|
|
133
|
+
);
|
|
134
|
+
expect([...served].sort()).toEqual([...documented].sort());
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("every skip row names its guard, its driver or says the lane is open by design", () => {
|
|
138
|
+
const bare = skipRowsOf(readFileSync(COVERAGE_DOC, "utf8"))
|
|
139
|
+
.filter((r) => !MARKERS.some((marker) => r.handler.includes(marker)))
|
|
140
|
+
.map((r) => r.method);
|
|
141
|
+
expect(bare).toEqual([]);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("every guard a skip row names is a step or a guard function that exists by that name in src/", () => {
|
|
145
|
+
const source = sourceText();
|
|
146
|
+
const dangling: string[] = [];
|
|
147
|
+
for (const row of skipRowsOf(readFileSync(COVERAGE_DOC, "utf8"))) {
|
|
148
|
+
for (const guard of guardsOf(row.handler)) {
|
|
149
|
+
// A step is registered by its quoted name; a guard function by its
|
|
150
|
+
// declaration.
|
|
151
|
+
const isStep = source.includes(`"${guard}"`);
|
|
152
|
+
const isFunction = new RegExp(`function ${guard}\\(`).test(source);
|
|
153
|
+
if (!isStep && !isFunction) {
|
|
154
|
+
dangling.push(`${row.method} names guard ${guard}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
expect(dangling).toEqual([]);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
@@ -56,14 +56,12 @@ const DOCUMENTS = [
|
|
|
56
56
|
"channel-app-owner.fga.yaml",
|
|
57
57
|
"channel-participation.fga.yaml",
|
|
58
58
|
"channel-session-visibility.fga.yaml",
|
|
59
|
-
"cross-org-share-creation.fga.yaml",
|
|
60
59
|
"default-instance-inheritance.fga.yaml",
|
|
61
60
|
"memory-subject-only.fga.yaml",
|
|
62
61
|
"org-admin-owner-inheritance.fga.yaml",
|
|
63
62
|
"org-shared-environment.fga.yaml",
|
|
64
63
|
"platform-visibility.fga.yaml",
|
|
65
64
|
"provider-standing-viewer.fga.yaml",
|
|
66
|
-
"public-visibility-setter.fga.yaml",
|
|
67
65
|
"reserved-label-writer.fga.yaml",
|
|
68
66
|
"schedule-owner.fga.yaml",
|
|
69
67
|
"schedule-session-visibility.fga.yaml",
|
|
@@ -100,7 +98,7 @@ const SKIPPED_PINNED: ReadonlyArray<string> = [
|
|
|
100
98
|
"artifact-org-and-owner :: listing reflects org inheritance plus creator ownership :: identity_account:eve <artifact> :: list-objects",
|
|
101
99
|
"artifact-org-and-owner :: listing reflects org inheritance plus creator ownership :: identity_account:victor <artifact> :: list-objects",
|
|
102
100
|
"blueprint-private-visibility :: org admin's listable agents include private ones (T08) :: identity_account:oscar <agent> :: list-objects",
|
|
103
|
-
"blueprint-private-visibility :: org member's listable agents exclude private ones
|
|
101
|
+
"blueprint-private-visibility :: org member's listable agents exclude private ones :: identity_account:dave <agent> :: list-objects",
|
|
104
102
|
"blueprint-private-visibility :: org viewer's listable agents are exactly the viewer-shaped org-visible ones :: identity_account:vera <agent> :: list-objects",
|
|
105
103
|
"blueprint-private-visibility :: owner's listable agents include everything they authored :: identity_account:carol <agent> :: list-objects",
|
|
106
104
|
"channel-app-owner :: listing channel apps reflects ownership and grants, not membership :: identity_account:alice <channel_app> :: list-objects",
|
|
@@ -130,9 +128,6 @@ const SKIPPED_PINNED: ReadonlyArray<string> = [
|
|
|
130
128
|
// undeclared-kind: platform
|
|
131
129
|
"provider-standing-viewer :: operator may view provider standing, tenants may not :: identity_account:mallory platform:stigmer :: undeclared-kind",
|
|
132
130
|
"provider-standing-viewer :: operator may view provider standing, tenants may not :: identity_account:opal platform:stigmer :: undeclared-kind",
|
|
133
|
-
"public-visibility-setter :: operators may set public visibility, tenants may not :: identity_account:machine platform:stigmer :: undeclared-kind",
|
|
134
|
-
"public-visibility-setter :: operators may set public visibility, tenants may not :: identity_account:mallory platform:stigmer :: undeclared-kind",
|
|
135
|
-
"public-visibility-setter :: operators may set public visibility, tenants may not :: identity_account:opal platform:stigmer :: undeclared-kind",
|
|
136
131
|
"reserved-label-writer :: operator may write reserved labels, tenants may not :: identity_account:machine platform:stigmer :: undeclared-kind",
|
|
137
132
|
"reserved-label-writer :: operator may write reserved labels, tenants may not :: identity_account:mallory platform:stigmer :: undeclared-kind",
|
|
138
133
|
// undeclared-subject-type: identity_provider#platform_user
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from "../tuples.js";
|
|
14
14
|
|
|
15
15
|
describe("the string notation", () => {
|
|
16
|
-
it("parses an object
|
|
16
|
+
it("parses an object and a userset, and an id may carry a colon (issuer subjects do)", () => {
|
|
17
17
|
expect(parseObjectRef("agent:agt_1")).toEqual({
|
|
18
18
|
type: "agent",
|
|
19
19
|
id: "agt_1",
|
|
@@ -27,11 +27,6 @@ describe("the string notation", () => {
|
|
|
27
27
|
object: { type: "organization", id: "acme" },
|
|
28
28
|
relation: "viewer",
|
|
29
29
|
});
|
|
30
|
-
expect(parseSubject("identity_account:*")).toEqual({
|
|
31
|
-
form: "wildcard",
|
|
32
|
-
type: "identity_account",
|
|
33
|
-
condition: undefined,
|
|
34
|
-
});
|
|
35
30
|
expect(parseSubject("identity_account:ida_x")).toEqual({
|
|
36
31
|
form: "object",
|
|
37
32
|
object: { type: "identity_account", id: "ida_x" },
|
|
@@ -43,18 +38,24 @@ describe("the string notation", () => {
|
|
|
43
38
|
expect(() => parseObjectRef(":id")).toThrow("not an object reference");
|
|
44
39
|
});
|
|
45
40
|
|
|
46
|
-
it("
|
|
41
|
+
it("refuses the wildcard notation — no line of the model admits one", () => {
|
|
42
|
+
expect(() => parseSubject("identity_account:*")).toThrow(
|
|
43
|
+
"wildcard subject 'identity_account:*' is not admitted",
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("formats a tuple in the proto's notation", () => {
|
|
47
48
|
expect(
|
|
48
49
|
formatTuple({
|
|
49
50
|
object: parseObjectRef("agent:a"),
|
|
50
51
|
relation: "viewer",
|
|
51
52
|
subject: {
|
|
52
|
-
form: "
|
|
53
|
-
type: "
|
|
54
|
-
|
|
53
|
+
form: "userset",
|
|
54
|
+
object: { type: "organization", id: "acme" },
|
|
55
|
+
relation: "viewer",
|
|
55
56
|
},
|
|
56
57
|
}),
|
|
57
|
-
).toBe("agent:a#viewer@
|
|
58
|
+
).toBe("agent:a#viewer@organization:acme#viewer");
|
|
58
59
|
expect(formatSubject(parseSubject("organization:acme#member"))).toBe(
|
|
59
60
|
"organization:acme#member",
|
|
60
61
|
);
|
|
@@ -117,12 +117,11 @@ describe("every static (kind, permission) the served RPCs ask about is a declare
|
|
|
117
117
|
expect(undeclared).toEqual([]);
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
-
it("asks about every served kind the model declares except the
|
|
120
|
+
it("asks about every served kind the model declares except the one no RPC targets statically", () => {
|
|
121
121
|
// iam_policy's RPCs target the policy's RESOURCE (`resource_kind_path`
|
|
122
|
-
// or the load-then-authorize `get`)
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
// asked about by at least one static annotation.
|
|
122
|
+
// or the load-then-authorize `get`). Every other declared kind is asked
|
|
123
|
+
// about by at least one static annotation — execution_context through
|
|
124
|
+
// its `get` and `delete`; its runner-token lane stays a skip.
|
|
126
125
|
const asked = new Set(wireQuestions().map((q) => kindEnumName(q.kind)));
|
|
127
126
|
expect([...asked].sort()).toEqual(
|
|
128
127
|
[
|
|
@@ -135,6 +134,7 @@ describe("every static (kind, permission) the served RPCs ask about is a declare
|
|
|
135
134
|
"artifact",
|
|
136
135
|
"channel_app",
|
|
137
136
|
"environment",
|
|
137
|
+
"execution_context",
|
|
138
138
|
"identity_account",
|
|
139
139
|
"mcp_server",
|
|
140
140
|
"memory",
|
|
@@ -17,9 +17,7 @@
|
|
|
17
17
|
* 2. A kind this edition does not serve is `deny` (`kindServedByEdition`,
|
|
18
18
|
* the predicate 2b's `checkMyPermission` arm 1 uses, so the console
|
|
19
19
|
* and the server agree by construction). `platform` is the one that
|
|
20
|
-
*
|
|
21
|
-
* posture nobody sets public visibility, the model's own reason for
|
|
22
|
-
* making it a platform operator's act.
|
|
20
|
+
* can arrive, through an operator capability no self-host holds.
|
|
23
21
|
* 3. The caller as a person (person.ts) and one derived tuple source for
|
|
24
22
|
* them; the target loaded ONCE through the source's memoised loader,
|
|
25
23
|
* so the read that decides not-found is the read the derivation
|
|
@@ -31,11 +29,9 @@
|
|
|
31
29
|
* member cannot learn which account ids exist. Present or exempt, the
|
|
32
30
|
* row is then evaluated: the cloud asks OpenFGA whether or not the row
|
|
33
31
|
* exists, and so does this driver.
|
|
34
|
-
* 5. `checkRelation
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* the method annotation's byte-pinned `error_msg` wins on the wire,
|
|
38
|
-
* exactly the cloud's genuine-denial path.
|
|
32
|
+
* 5. `checkRelation`. True is `allow`; false is `deny` with an EMPTY
|
|
33
|
+
* reason, so the method annotation's byte-pinned `error_msg` wins on
|
|
34
|
+
* the wire, exactly the cloud's genuine-denial path.
|
|
39
35
|
*
|
|
40
36
|
* Faults. Everything past the pre-checks runs under one guard: a store
|
|
41
37
|
* fault, a person that names nobody (`personFor`), an evaluation fault
|
|
@@ -179,7 +175,6 @@ export function newBuiltInAuthorizer(deps: BuiltInAuthorizerDeps): Authorizer {
|
|
|
179
175
|
object,
|
|
180
176
|
relation,
|
|
181
177
|
person,
|
|
182
|
-
{ allow: true },
|
|
183
178
|
);
|
|
184
179
|
if (allowed) {
|
|
185
180
|
return { kind: "allow" };
|