@stigmer/server 3.15.3-dev.20260914100347 → 3.15.3-dev.20260916211208
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/README.md +3 -3
- package/dist/archive/content-store.d.ts +35 -0
- package/dist/archive/content-store.d.ts.map +1 -0
- package/dist/archive/content-store.js +98 -0
- package/dist/archive/content-store.js.map +1 -0
- package/dist/archive/inflate.d.ts +22 -0
- package/dist/archive/inflate.d.ts.map +1 -0
- package/dist/archive/inflate.js +75 -0
- package/dist/archive/inflate.js.map +1 -0
- package/dist/archive/limits.d.ts +33 -0
- package/dist/archive/limits.d.ts.map +1 -0
- package/dist/archive/limits.js +31 -0
- package/dist/archive/limits.js.map +1 -0
- package/dist/archive/open.d.ts +24 -0
- package/dist/archive/open.d.ts.map +1 -0
- package/dist/archive/open.js +93 -0
- package/dist/archive/open.js.map +1 -0
- package/dist/{domain/skill/storage → archive}/prefilter.d.ts +5 -0
- package/dist/archive/prefilter.d.ts.map +1 -0
- package/dist/archive/prefilter.js.map +1 -0
- package/dist/archive/write.d.ts +8 -0
- package/dist/archive/write.d.ts.map +1 -0
- package/dist/archive/write.js +44 -0
- package/dist/archive/write.js.map +1 -0
- package/dist/authorization/authorizer.d.ts +98 -0
- package/dist/authorization/authorizer.d.ts.map +1 -0
- package/dist/authorization/authorizer.js +156 -0
- package/dist/authorization/authorizer.js.map +1 -0
- package/dist/authorization/derived-tuples.d.ts +42 -0
- package/dist/authorization/derived-tuples.d.ts.map +1 -0
- package/dist/authorization/derived-tuples.js +240 -0
- package/dist/authorization/derived-tuples.js.map +1 -0
- package/dist/authorization/evaluator.d.ts +66 -0
- package/dist/authorization/evaluator.d.ts.map +1 -0
- package/dist/authorization/evaluator.js +153 -0
- package/dist/authorization/evaluator.js.map +1 -0
- package/dist/authorization/facts.d.ts +29 -0
- package/dist/authorization/facts.d.ts.map +1 -0
- package/dist/authorization/facts.js +17 -0
- package/dist/authorization/facts.js.map +1 -0
- package/dist/authorization/list-read-scope.d.ts +18 -0
- package/dist/authorization/list-read-scope.d.ts.map +1 -0
- package/dist/authorization/list-read-scope.js +155 -0
- package/dist/authorization/list-read-scope.js.map +1 -0
- package/dist/authorization/model/agent.d.ts +2 -0
- package/dist/authorization/model/agent.d.ts.map +1 -0
- package/dist/authorization/model/agent.js +42 -0
- package/dist/authorization/model/agent.js.map +1 -0
- package/dist/authorization/model/agent_channel.d.ts +2 -0
- package/dist/authorization/model/agent_channel.d.ts.map +1 -0
- package/dist/authorization/model/agent_channel.js +38 -0
- package/dist/authorization/model/agent_channel.js.map +1 -0
- package/dist/authorization/model/agent_execution.d.ts +2 -0
- package/dist/authorization/model/agent_execution.d.ts.map +1 -0
- package/dist/authorization/model/agent_execution.js +25 -0
- package/dist/authorization/model/agent_execution.js.map +1 -0
- package/dist/authorization/model/agent_instance.d.ts +2 -0
- package/dist/authorization/model/agent_instance.d.ts.map +1 -0
- package/dist/authorization/model/agent_instance.js +47 -0
- package/dist/authorization/model/agent_instance.js.map +1 -0
- package/dist/authorization/model/agent_share.d.ts +2 -0
- package/dist/authorization/model/agent_share.d.ts.map +1 -0
- package/dist/authorization/model/agent_share.js +29 -0
- package/dist/authorization/model/agent_share.js.map +1 -0
- package/dist/authorization/model/api_key.d.ts +2 -0
- package/dist/authorization/model/api_key.d.ts.map +1 -0
- package/dist/authorization/model/api_key.js +27 -0
- package/dist/authorization/model/api_key.js.map +1 -0
- package/dist/authorization/model/artifact.d.ts +2 -0
- package/dist/authorization/model/artifact.d.ts.map +1 -0
- package/dist/authorization/model/artifact.js +27 -0
- package/dist/authorization/model/artifact.js.map +1 -0
- package/dist/authorization/model/channel_app.d.ts +2 -0
- package/dist/authorization/model/channel_app.d.ts.map +1 -0
- package/dist/authorization/model/channel_app.js +28 -0
- package/dist/authorization/model/channel_app.js.map +1 -0
- package/dist/authorization/model/default-of.d.ts +38 -0
- package/dist/authorization/model/default-of.d.ts.map +1 -0
- package/dist/authorization/model/default-of.js +39 -0
- package/dist/authorization/model/default-of.js.map +1 -0
- package/dist/authorization/model/environment.d.ts +2 -0
- package/dist/authorization/model/environment.d.ts.map +1 -0
- package/dist/authorization/model/environment.js +33 -0
- package/dist/authorization/model/environment.js.map +1 -0
- package/dist/authorization/model/execution_context.d.ts +2 -0
- package/dist/authorization/model/execution_context.d.ts.map +1 -0
- package/dist/authorization/model/execution_context.js +19 -0
- package/dist/authorization/model/execution_context.js.map +1 -0
- package/dist/authorization/model/iam_policy.d.ts +2 -0
- package/dist/authorization/model/iam_policy.d.ts.map +1 -0
- package/dist/authorization/model/iam_policy.js +31 -0
- package/dist/authorization/model/iam_policy.js.map +1 -0
- package/dist/authorization/model/identity_account.d.ts +2 -0
- package/dist/authorization/model/identity_account.d.ts.map +1 -0
- package/dist/authorization/model/identity_account.js +25 -0
- package/dist/authorization/model/identity_account.js.map +1 -0
- package/dist/authorization/model/index.d.ts +36 -0
- package/dist/authorization/model/index.d.ts.map +1 -0
- package/dist/authorization/model/index.js +72 -0
- package/dist/authorization/model/index.js.map +1 -0
- package/dist/authorization/model/mcp_server.d.ts +2 -0
- package/dist/authorization/model/mcp_server.d.ts.map +1 -0
- package/dist/authorization/model/mcp_server.js +37 -0
- package/dist/authorization/model/mcp_server.js.map +1 -0
- package/dist/authorization/model/memory.d.ts +2 -0
- package/dist/authorization/model/memory.d.ts.map +1 -0
- package/dist/authorization/model/memory.js +26 -0
- package/dist/authorization/model/memory.js.map +1 -0
- package/dist/authorization/model/oauth_app.d.ts +2 -0
- package/dist/authorization/model/oauth_app.d.ts.map +1 -0
- package/dist/authorization/model/oauth_app.js +30 -0
- package/dist/authorization/model/oauth_app.js.map +1 -0
- package/dist/authorization/model/organization.d.ts +2 -0
- package/dist/authorization/model/organization.d.ts.map +1 -0
- package/dist/authorization/model/organization.js +54 -0
- package/dist/authorization/model/organization.js.map +1 -0
- package/dist/authorization/model/plugin.d.ts +2 -0
- package/dist/authorization/model/plugin.d.ts.map +1 -0
- package/dist/authorization/model/plugin.js +44 -0
- package/dist/authorization/model/plugin.js.map +1 -0
- package/dist/authorization/model/project.d.ts +2 -0
- package/dist/authorization/model/project.d.ts.map +1 -0
- package/dist/authorization/model/project.js +32 -0
- package/dist/authorization/model/project.js.map +1 -0
- package/dist/authorization/model/rewrite.d.ts +127 -0
- package/dist/authorization/model/rewrite.d.ts.map +1 -0
- package/dist/authorization/model/rewrite.js +82 -0
- package/dist/authorization/model/rewrite.js.map +1 -0
- package/dist/authorization/model/schedule.d.ts +2 -0
- package/dist/authorization/model/schedule.d.ts.map +1 -0
- package/dist/authorization/model/schedule.js +29 -0
- package/dist/authorization/model/schedule.js.map +1 -0
- package/dist/authorization/model/session.d.ts +2 -0
- package/dist/authorization/model/session.d.ts.map +1 -0
- package/dist/authorization/model/session.js +38 -0
- package/dist/authorization/model/session.js.map +1 -0
- package/dist/authorization/model/skill.d.ts +2 -0
- package/dist/authorization/model/skill.d.ts.map +1 -0
- package/dist/authorization/model/skill.js +38 -0
- package/dist/authorization/model/skill.js.map +1 -0
- package/dist/authorization/model/workflow.d.ts +2 -0
- package/dist/authorization/model/workflow.d.ts.map +1 -0
- package/dist/authorization/model/workflow.js +38 -0
- package/dist/authorization/model/workflow.js.map +1 -0
- package/dist/authorization/model/workflow_execution.d.ts +2 -0
- package/dist/authorization/model/workflow_execution.d.ts.map +1 -0
- package/dist/authorization/model/workflow_execution.js +32 -0
- package/dist/authorization/model/workflow_execution.js.map +1 -0
- package/dist/authorization/model/workflow_instance.d.ts +2 -0
- package/dist/authorization/model/workflow_instance.d.ts.map +1 -0
- package/dist/authorization/model/workflow_instance.js +92 -0
- package/dist/authorization/model/workflow_instance.js.map +1 -0
- package/dist/authorization/organization-directory.d.ts +13 -0
- package/dist/authorization/organization-directory.d.ts.map +1 -0
- package/dist/authorization/organization-directory.js +83 -0
- package/dist/authorization/organization-directory.js.map +1 -0
- package/dist/authorization/person.d.ts +42 -0
- package/dist/authorization/person.d.ts.map +1 -0
- package/dist/authorization/person.js +19 -0
- package/dist/authorization/person.js.map +1 -0
- package/dist/authorization/posture.d.ts +38 -0
- package/dist/authorization/posture.d.ts.map +1 -0
- package/dist/authorization/posture.js +7 -0
- package/dist/authorization/posture.js.map +1 -0
- package/dist/authorization/schedule-fire-caller.d.ts +12 -0
- package/dist/authorization/schedule-fire-caller.d.ts.map +1 -0
- package/dist/authorization/schedule-fire-caller.js +67 -0
- package/dist/authorization/schedule-fire-caller.js.map +1 -0
- package/dist/authorization/store-test-kit.d.ts +68 -0
- package/dist/authorization/store-test-kit.d.ts.map +1 -0
- package/dist/authorization/store-test-kit.js +311 -0
- package/dist/authorization/store-test-kit.js.map +1 -0
- package/dist/authorization/tuples.d.ts +115 -0
- package/dist/authorization/tuples.d.ts.map +1 -0
- package/dist/authorization/tuples.js +83 -0
- package/dist/authorization/tuples.js.map +1 -0
- package/dist/boot/compose.d.ts.map +1 -1
- package/dist/boot/compose.js +157 -32
- package/dist/boot/compose.js.map +1 -1
- package/dist/boot/inprocess.d.ts +12 -0
- package/dist/boot/inprocess.d.ts.map +1 -1
- package/dist/boot/inprocess.js +62 -20
- package/dist/boot/inprocess.js.map +1 -1
- package/dist/domain/agent/controller.d.ts.map +1 -1
- package/dist/domain/agent/controller.js +9 -0
- package/dist/domain/agent/controller.js.map +1 -1
- package/dist/domain/iampolicy/constants.d.ts +11 -0
- package/dist/domain/iampolicy/constants.d.ts.map +1 -1
- package/dist/domain/iampolicy/constants.js +11 -0
- package/dist/domain/iampolicy/constants.js.map +1 -1
- package/dist/domain/iampolicy/membership.d.ts +72 -1
- package/dist/domain/iampolicy/membership.d.ts.map +1 -1
- package/dist/domain/iampolicy/membership.js +141 -56
- package/dist/domain/iampolicy/membership.js.map +1 -1
- package/dist/domain/identityaccount/actor.d.ts +26 -0
- package/dist/domain/identityaccount/actor.d.ts.map +1 -0
- package/dist/domain/identityaccount/actor.js +17 -0
- package/dist/domain/identityaccount/actor.js.map +1 -0
- package/dist/domain/mcpserver/controller.d.ts.map +1 -1
- package/dist/domain/mcpserver/controller.js +9 -0
- package/dist/domain/mcpserver/controller.js.map +1 -1
- package/dist/domain/plugin/archive.d.ts +37 -0
- package/dist/domain/plugin/archive.d.ts.map +1 -0
- package/dist/domain/plugin/archive.js +50 -0
- package/dist/domain/plugin/archive.js.map +1 -0
- package/dist/domain/plugin/constants.d.ts +38 -0
- package/dist/domain/plugin/constants.d.ts.map +1 -0
- package/dist/domain/plugin/constants.js +46 -0
- package/dist/domain/plugin/constants.js.map +1 -0
- package/dist/domain/plugin/controller.d.ts +25 -0
- package/dist/domain/plugin/controller.d.ts.map +1 -0
- package/dist/domain/plugin/controller.js +493 -0
- package/dist/domain/plugin/controller.js.map +1 -0
- package/dist/domain/plugin/materialize/agent.d.ts +13 -0
- package/dist/domain/plugin/materialize/agent.d.ts.map +1 -0
- package/dist/domain/plugin/materialize/agent.js +128 -0
- package/dist/domain/plugin/materialize/agent.js.map +1 -0
- package/dist/domain/plugin/materialize/default-agent-instructions.d.ts +22 -0
- package/dist/domain/plugin/materialize/default-agent-instructions.d.ts.map +1 -0
- package/dist/domain/plugin/materialize/default-agent-instructions.js +31 -0
- package/dist/domain/plugin/materialize/default-agent-instructions.js.map +1 -0
- package/dist/domain/plugin/materialize/identity.d.ts +28 -0
- package/dist/domain/plugin/materialize/identity.d.ts.map +1 -0
- package/dist/domain/plugin/materialize/identity.js +40 -0
- package/dist/domain/plugin/materialize/identity.js.map +1 -0
- package/dist/domain/plugin/materialize/mcp-servers.d.ts +15 -0
- package/dist/domain/plugin/materialize/mcp-servers.d.ts.map +1 -0
- package/dist/domain/plugin/materialize/mcp-servers.js +131 -0
- package/dist/domain/plugin/materialize/mcp-servers.js.map +1 -0
- package/dist/domain/plugin/materialize/plan.d.ts +24 -0
- package/dist/domain/plugin/materialize/plan.d.ts.map +1 -0
- package/dist/domain/plugin/materialize/plan.js +77 -0
- package/dist/domain/plugin/materialize/plan.js.map +1 -0
- package/dist/domain/plugin/materialize/ports.d.ts +42 -0
- package/dist/domain/plugin/materialize/ports.d.ts.map +1 -0
- package/dist/domain/plugin/materialize/ports.js +2 -0
- package/dist/domain/plugin/materialize/ports.js.map +1 -0
- package/dist/domain/plugin/materialize/skills.d.ts +12 -0
- package/dist/domain/plugin/materialize/skills.d.ts.map +1 -0
- package/dist/domain/plugin/materialize/skills.js +44 -0
- package/dist/domain/plugin/materialize/skills.js.map +1 -0
- package/dist/domain/plugin/materialize/workflows.d.ts +15 -0
- package/dist/domain/plugin/materialize/workflows.d.ts.map +1 -0
- package/dist/domain/plugin/materialize/workflows.js +31 -0
- package/dist/domain/plugin/materialize/workflows.js.map +1 -0
- package/dist/domain/plugin/members.d.ts +42 -0
- package/dist/domain/plugin/members.d.ts.map +1 -0
- package/dist/domain/plugin/members.js +97 -0
- package/dist/domain/plugin/members.js.map +1 -0
- package/dist/domain/plugin/overlay/documents.d.ts +31 -0
- package/dist/domain/plugin/overlay/documents.d.ts.map +1 -0
- package/dist/domain/plugin/overlay/documents.js +38 -0
- package/dist/domain/plugin/overlay/documents.js.map +1 -0
- package/dist/domain/plugin/overlay/parse.d.ts +16 -0
- package/dist/domain/plugin/overlay/parse.d.ts.map +1 -0
- package/dist/domain/plugin/overlay/parse.js +79 -0
- package/dist/domain/plugin/overlay/parse.js.map +1 -0
- package/dist/domain/plugin/overlay/sanitize.d.ts +10 -0
- package/dist/domain/plugin/overlay/sanitize.d.ts.map +1 -0
- package/dist/domain/plugin/overlay/sanitize.js +101 -0
- package/dist/domain/plugin/overlay/sanitize.js.map +1 -0
- package/dist/domain/plugin/push.d.ts +133 -0
- package/dist/domain/plugin/push.d.ts.map +1 -0
- package/dist/domain/plugin/push.js +800 -0
- package/dist/domain/plugin/push.js.map +1 -0
- package/dist/domain/plugin/search-extractor.d.ts +3 -0
- package/dist/domain/plugin/search-extractor.d.ts.map +1 -0
- package/dist/domain/plugin/search-extractor.js +41 -0
- package/dist/domain/plugin/search-extractor.js.map +1 -0
- package/dist/domain/skill/constants.d.ts +6 -11
- package/dist/domain/skill/constants.d.ts.map +1 -1
- package/dist/domain/skill/constants.js +6 -11
- package/dist/domain/skill/constants.js.map +1 -1
- package/dist/domain/skill/controller.d.ts.map +1 -1
- package/dist/domain/skill/controller.js +33 -30
- package/dist/domain/skill/controller.js.map +1 -1
- package/dist/domain/skill/push.d.ts +9 -10
- package/dist/domain/skill/push.d.ts.map +1 -1
- package/dist/domain/skill/push.js +53 -122
- package/dist/domain/skill/push.js.map +1 -1
- package/dist/domain/skill/search-extractor.d.ts.map +1 -1
- package/dist/domain/skill/search-extractor.js.map +1 -1
- package/dist/domain/skill/storage/artifact-storage.d.ts +26 -29
- package/dist/domain/skill/storage/artifact-storage.d.ts.map +1 -1
- package/dist/domain/skill/storage/artifact-storage.js +6 -103
- package/dist/domain/skill/storage/artifact-storage.js.map +1 -1
- package/dist/domain/skill/storage/zip-gate.d.ts +1 -2
- package/dist/domain/skill/storage/zip-gate.d.ts.map +1 -1
- package/dist/domain/skill/storage/zip-gate.js +56 -126
- package/dist/domain/skill/storage/zip-gate.js.map +1 -1
- package/dist/domain/skill/version-resolution.d.ts +5 -5
- package/dist/domain/skill/version-resolution.d.ts.map +1 -1
- package/dist/domain/skill/version-resolution.js +34 -216
- package/dist/domain/skill/version-resolution.js.map +1 -1
- package/dist/domain/workflow/controller.d.ts.map +1 -1
- package/dist/domain/workflow/controller.js +30 -3
- package/dist/domain/workflow/controller.js.map +1 -1
- package/dist/domain/workflow/registry/data/task-kind-registry.json +1 -0
- package/dist/extensions/authorizer.d.ts +10 -5
- package/dist/extensions/authorizer.d.ts.map +1 -1
- package/dist/extensions/drivers.d.ts +4 -1
- package/dist/extensions/drivers.d.ts.map +1 -1
- package/dist/extensions/list-read-scope.d.ts +75 -11
- package/dist/extensions/list-read-scope.d.ts.map +1 -1
- package/dist/extensions/list-read-scope.js +40 -7
- package/dist/extensions/list-read-scope.js.map +1 -1
- package/dist/extensions/organization-directory.d.ts +13 -9
- package/dist/extensions/organization-directory.d.ts.map +1 -1
- package/dist/extensions/organization-directory.js.map +1 -1
- package/dist/extensions/resource-authorization.d.ts +33 -0
- package/dist/extensions/resource-authorization.d.ts.map +1 -1
- package/dist/extensions/schedule-fire-caller.d.ts +45 -18
- package/dist/extensions/schedule-fire-caller.d.ts.map +1 -1
- package/dist/extensions/schedule-fire-caller.js +12 -1
- package/dist/extensions/schedule-fire-caller.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/pipeline/apiresource-labels.d.ts +23 -3
- package/dist/pipeline/apiresource-labels.d.ts.map +1 -1
- package/dist/pipeline/apiresource-labels.js +20 -0
- package/dist/pipeline/apiresource-labels.js.map +1 -1
- package/dist/pipeline/apiresource-meta.d.ts +21 -0
- package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
- package/dist/pipeline/apiresource-meta.js +28 -0
- package/dist/pipeline/apiresource-meta.js.map +1 -1
- package/dist/pipeline/errors.d.ts.map +1 -1
- package/dist/pipeline/errors.js.map +1 -1
- package/dist/pipeline/steps/authorization-facts.d.ts +12 -0
- package/dist/pipeline/steps/authorization-facts.d.ts.map +1 -0
- package/dist/pipeline/steps/authorization-facts.js +100 -0
- package/dist/pipeline/steps/authorization-facts.js.map +1 -0
- package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
- package/dist/pipeline/steps/authorization-tuples.js +7 -26
- package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
- package/dist/pipeline/steps/delete.d.ts.map +1 -1
- package/dist/pipeline/steps/delete.js +1 -1
- package/dist/pipeline/steps/delete.js.map +1 -1
- package/dist/pipeline/steps/duplicate.d.ts.map +1 -1
- package/dist/pipeline/steps/duplicate.js.map +1 -1
- package/dist/pipeline/steps/guard-plugin-managed.d.ts +12 -0
- package/dist/pipeline/steps/guard-plugin-managed.d.ts.map +1 -0
- package/dist/pipeline/steps/guard-plugin-managed.js +96 -0
- package/dist/pipeline/steps/guard-plugin-managed.js.map +1 -0
- package/dist/pipeline/steps/guard-reserved-labels.d.ts +16 -2
- package/dist/pipeline/steps/guard-reserved-labels.d.ts.map +1 -1
- package/dist/pipeline/steps/guard-reserved-labels.js +11 -7
- package/dist/pipeline/steps/guard-reserved-labels.js.map +1 -1
- package/dist/pipeline/steps/helpers.d.ts.map +1 -1
- package/dist/pipeline/steps/helpers.js.map +1 -1
- package/dist/pipeline/steps/index-search.d.ts.map +1 -1
- package/dist/pipeline/steps/index-search.js.map +1 -1
- package/dist/pipeline/steps/load-existing.d.ts.map +1 -1
- package/dist/pipeline/steps/load-existing.js +1 -1
- package/dist/pipeline/steps/load-existing.js.map +1 -1
- package/dist/pipeline/steps/references.d.ts +16 -0
- package/dist/pipeline/steps/references.d.ts.map +1 -1
- package/dist/pipeline/steps/references.js +18 -0
- package/dist/pipeline/steps/references.js.map +1 -1
- package/dist/pipeline/steps/resolve-artifact-source.d.ts +35 -0
- package/dist/pipeline/steps/resolve-artifact-source.d.ts.map +1 -0
- package/dist/pipeline/steps/resolve-artifact-source.js +27 -0
- package/dist/pipeline/steps/resolve-artifact-source.js.map +1 -0
- package/dist/pipeline/steps/server-stamped-reserved-labels.d.ts.map +1 -1
- package/dist/pipeline/steps/server-stamped-reserved-labels.js.map +1 -1
- package/dist/pipeline/steps/shapes.d.ts +18 -0
- package/dist/pipeline/steps/shapes.d.ts.map +1 -1
- package/dist/pipeline/steps/shapes.js +29 -0
- package/dist/pipeline/steps/shapes.js.map +1 -1
- package/dist/pipeline/steps/slug.d.ts.map +1 -1
- package/dist/pipeline/steps/slug.js.map +1 -1
- package/dist/pipeline/steps/validate-visibility.d.ts +9 -0
- package/dist/pipeline/steps/validate-visibility.d.ts.map +1 -1
- package/dist/pipeline/steps/validate-visibility.js +6 -1
- package/dist/pipeline/steps/validate-visibility.js.map +1 -1
- package/dist/pipeline/steps/validation.d.ts.map +1 -1
- package/dist/pipeline/steps/validation.js.map +1 -1
- package/dist/pipeline/steps/version-archive.d.ts +63 -0
- package/dist/pipeline/steps/version-archive.d.ts.map +1 -0
- package/dist/pipeline/steps/version-archive.js +129 -0
- package/dist/pipeline/steps/version-archive.js.map +1 -0
- package/dist/pipeline/steps/version-history.d.ts +49 -0
- package/dist/pipeline/steps/version-history.d.ts.map +1 -0
- package/dist/pipeline/steps/version-history.js +229 -0
- package/dist/pipeline/steps/version-history.js.map +1 -0
- package/dist/pipeline/steps/visibility-gates.d.ts +8 -0
- package/dist/pipeline/steps/visibility-gates.d.ts.map +1 -1
- package/dist/pipeline/steps/visibility-gates.js +7 -2
- package/dist/pipeline/steps/visibility-gates.js.map +1 -1
- package/dist/query/search/registry.d.ts.map +1 -1
- package/dist/query/search/registry.js +2 -0
- package/dist/query/search/registry.js.map +1 -1
- package/dist/temporal/schedule/run-starter.d.ts +1 -1
- package/dist/temporal/schedule/run-starter.d.ts.map +1 -1
- package/dist/temporal/schedule/run-starter.js +14 -1
- package/dist/temporal/schedule/run-starter.js.map +1 -1
- package/package.json +5 -4
- package/src/archive/__tests__/archive.test.ts +233 -0
- package/src/{domain/skill → archive}/__tests__/prefilter.test.ts +1 -1
- package/src/archive/content-store.ts +132 -0
- package/src/archive/inflate.ts +107 -0
- package/src/archive/limits.ts +42 -0
- package/src/archive/open.ts +131 -0
- package/src/{domain/skill/storage → archive}/prefilter.ts +5 -0
- package/src/archive/write.ts +54 -0
- package/src/authorization/README.md +124 -0
- package/src/authorization/__tests__/authorizer.test.ts +719 -0
- package/src/authorization/__tests__/derived-tuples.test.ts +802 -0
- package/src/authorization/__tests__/drivers.ts +70 -0
- package/src/authorization/__tests__/evaluator.test.ts +359 -0
- package/src/authorization/__tests__/facts.test.ts +155 -0
- package/src/authorization/__tests__/fixtures/fga/agent-channel-owner.fga.yaml +112 -0
- package/src/authorization/__tests__/fixtures/fga/agent-share-owner.fga.yaml +109 -0
- package/src/authorization/__tests__/fixtures/fga/artifact-org-and-owner.fga.yaml +128 -0
- package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +410 -0
- package/src/authorization/__tests__/fixtures/fga/channel-app-owner.fga.yaml +125 -0
- package/src/authorization/__tests__/fixtures/fga/channel-participation.fga.yaml +201 -0
- package/src/authorization/__tests__/fixtures/fga/channel-session-visibility.fga.yaml +187 -0
- package/src/authorization/__tests__/fixtures/fga/cross-org-share-creation.fga.yaml +98 -0
- package/src/authorization/__tests__/fixtures/fga/default-instance-inheritance.fga.yaml +271 -0
- package/src/authorization/__tests__/fixtures/fga/memory-subject-only.fga.yaml +72 -0
- package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +328 -0
- package/src/authorization/__tests__/fixtures/fga/org-shared-environment.fga.yaml +144 -0
- package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +223 -0
- package/src/authorization/__tests__/fixtures/fga/provider-standing-viewer.fga.yaml +40 -0
- package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +52 -0
- package/src/authorization/__tests__/fixtures/fga/reserved-label-writer.fga.yaml +41 -0
- package/src/authorization/__tests__/fixtures/fga/schedule-owner.fga.yaml +113 -0
- package/src/authorization/__tests__/fixtures/fga/schedule-session-visibility.fga.yaml +214 -0
- package/src/authorization/__tests__/fixtures/fga/session-personal-resource.fga.yaml +117 -0
- package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +192 -0
- package/src/authorization/__tests__/list-read-scope.measure.test.ts +317 -0
- package/src/authorization/__tests__/list-read-scope.test.ts +796 -0
- package/src/authorization/__tests__/organization-directory.test.ts +236 -0
- package/src/authorization/__tests__/person.test.ts +114 -0
- package/src/authorization/__tests__/posture.test.ts +25 -0
- package/src/authorization/__tests__/schedule-fire-caller.test.ts +134 -0
- package/src/authorization/__tests__/store-tests.test.ts +306 -0
- package/src/authorization/__tests__/support.ts +101 -0
- package/src/authorization/__tests__/tuples.test.ts +62 -0
- package/src/authorization/__tests__/wire-permissions.test.ts +154 -0
- package/src/authorization/authorizer.ts +208 -0
- package/src/authorization/derived-tuples.ts +384 -0
- package/src/authorization/evaluator.ts +283 -0
- package/src/authorization/facts.ts +47 -0
- package/src/authorization/list-read-scope.ts +216 -0
- package/src/authorization/model/__tests__/registry.test.ts +317 -0
- package/src/authorization/model/agent.ts +64 -0
- package/src/authorization/model/agent_channel.ts +49 -0
- package/src/authorization/model/agent_execution.ts +33 -0
- package/src/authorization/model/agent_instance.ts +66 -0
- package/src/authorization/model/agent_share.ts +40 -0
- package/src/authorization/model/api_key.ts +28 -0
- package/src/authorization/model/artifact.ts +38 -0
- package/src/authorization/model/channel_app.ts +39 -0
- package/src/authorization/model/default-of.ts +99 -0
- package/src/authorization/model/environment.ts +48 -0
- package/src/authorization/model/execution_context.ts +20 -0
- package/src/authorization/model/iam_policy.ts +42 -0
- package/src/authorization/model/identity_account.ts +26 -0
- package/src/authorization/model/index.ts +108 -0
- package/src/authorization/model/mcp_server.ts +59 -0
- package/src/authorization/model/memory.ts +27 -0
- package/src/authorization/model/oauth_app.ts +42 -0
- package/src/authorization/model/organization.ts +55 -0
- package/src/authorization/model/plugin.ts +66 -0
- package/src/authorization/model/project.ts +47 -0
- package/src/authorization/model/rewrite.ts +213 -0
- package/src/authorization/model/schedule.ts +40 -0
- package/src/authorization/model/session.ts +50 -0
- package/src/authorization/model/skill.ts +60 -0
- package/src/authorization/model/workflow.ts +60 -0
- package/src/authorization/model/workflow_execution.ts +44 -0
- package/src/authorization/model/workflow_instance.ts +122 -0
- package/src/authorization/organization-directory.ts +114 -0
- package/src/authorization/person.ts +68 -0
- package/src/authorization/posture.ts +49 -0
- package/src/authorization/schedule-fire-caller.ts +91 -0
- package/src/authorization/store-test-kit.ts +454 -0
- package/src/authorization/tuples.ts +190 -0
- package/src/boot/compose.ts +175 -38
- package/src/boot/inprocess.ts +108 -30
- package/src/domain/agent/controller.ts +11 -0
- package/src/domain/iampolicy/__tests__/membership.test.ts +357 -3
- package/src/domain/iampolicy/constants.ts +12 -0
- package/src/domain/iampolicy/membership.ts +221 -66
- package/src/domain/identityaccount/actor.ts +44 -0
- package/src/domain/mcpserver/controller.ts +11 -0
- package/src/domain/plugin/__tests__/materialize.test.ts +303 -0
- package/src/domain/plugin/__tests__/overlay-parse.test.ts +85 -0
- package/src/domain/plugin/__tests__/plugin.test.ts +681 -0
- package/src/domain/plugin/__tests__/sanitize.test.ts +174 -0
- package/src/domain/plugin/archive.ts +89 -0
- package/src/domain/plugin/constants.ts +53 -0
- package/src/domain/plugin/controller.ts +913 -0
- package/src/domain/plugin/materialize/agent.ts +186 -0
- package/src/domain/plugin/materialize/default-agent-instructions.ts +59 -0
- package/src/domain/plugin/materialize/identity.ts +67 -0
- package/src/domain/plugin/materialize/mcp-servers.ts +175 -0
- package/src/domain/plugin/materialize/plan.ts +124 -0
- package/src/domain/plugin/materialize/ports.ts +53 -0
- package/src/domain/plugin/materialize/skills.ts +68 -0
- package/src/domain/plugin/materialize/workflows.ts +51 -0
- package/src/domain/plugin/members.ts +180 -0
- package/src/domain/plugin/overlay/documents.ts +78 -0
- package/src/domain/plugin/overlay/parse.ts +115 -0
- package/src/domain/plugin/overlay/sanitize.ts +149 -0
- package/src/domain/plugin/push.ts +1062 -0
- package/src/domain/plugin/search-extractor.ts +60 -0
- package/src/domain/skill/constants.ts +11 -14
- package/src/domain/skill/controller.ts +44 -36
- package/src/domain/skill/push.ts +61 -156
- package/src/domain/skill/search-extractor.ts +3 -1
- package/src/domain/skill/storage/artifact-storage.ts +23 -124
- package/src/domain/skill/storage/zip-gate.ts +58 -154
- package/src/domain/skill/version-resolution.ts +67 -269
- package/src/domain/workflow/controller.ts +38 -4
- package/src/domain/workflow/registry/data/task-kind-registry.json +1 -0
- package/src/extensions/__tests__/built-in-authorization-composed.test.ts +835 -0
- package/src/extensions/__tests__/composed-support.ts +32 -1
- package/src/extensions/__tests__/extension-composition.test.ts +35 -0
- package/src/extensions/__tests__/list-read-scope.test.ts +245 -3
- package/src/extensions/__tests__/role-reconciliation-composed.test.ts +209 -0
- package/src/extensions/__tests__/tier-truthfulness.test.ts +6 -14
- package/src/extensions/authorizer.ts +10 -5
- package/src/extensions/drivers.ts +4 -1
- package/src/extensions/list-read-scope.ts +116 -16
- package/src/extensions/organization-directory.ts +13 -9
- package/src/extensions/resource-authorization.ts +34 -0
- package/src/extensions/schedule-fire-caller.ts +49 -18
- package/src/index.ts +51 -1
- package/src/pipeline/__tests__/inherited-authorization-parent.test.ts +51 -0
- package/src/pipeline/__tests__/router-transport.test.ts +1 -3
- package/src/pipeline/apiresource-labels.ts +31 -3
- package/src/pipeline/apiresource-meta.ts +37 -0
- package/src/pipeline/errors.ts +5 -5
- package/src/pipeline/steps/__tests__/authorize-annotation-completeness.test.ts +1 -20
- package/src/pipeline/steps/__tests__/guard-memory-capture.test.ts +3 -9
- package/src/pipeline/steps/__tests__/guard-plugin-managed.test.ts +151 -0
- package/src/pipeline/steps/__tests__/guard-reserved-labels.test.ts +83 -8
- package/src/pipeline/steps/authorization-facts.ts +131 -0
- package/src/pipeline/steps/authorization-tuples.ts +7 -28
- package/src/pipeline/steps/delete.ts +11 -3
- package/src/pipeline/steps/duplicate.ts +8 -2
- package/src/pipeline/steps/guard-plugin-managed.ts +133 -0
- package/src/pipeline/steps/guard-reserved-labels.ts +29 -8
- package/src/pipeline/steps/helpers.ts +4 -1
- package/src/pipeline/steps/index-search.ts +28 -15
- package/src/pipeline/steps/load-existing.ts +12 -3
- package/src/pipeline/steps/references.ts +36 -2
- package/src/pipeline/steps/resolve-artifact-source.ts +66 -0
- package/src/pipeline/steps/server-stamped-reserved-labels.ts +2 -1
- package/src/pipeline/steps/shapes.ts +31 -0
- package/src/pipeline/steps/slug.ts +7 -2
- package/src/pipeline/steps/validate-visibility.ts +9 -2
- package/src/pipeline/steps/validation.ts +3 -1
- package/src/pipeline/steps/version-archive.ts +225 -0
- package/src/pipeline/steps/version-history.ts +362 -0
- package/src/pipeline/steps/visibility-gates.ts +12 -9
- package/src/query/README.md +1 -1
- package/src/query/search/__tests__/criteria.test.ts +6 -7
- package/src/query/search/__tests__/query-store.test.ts +9 -2
- package/src/query/search/__tests__/registry.test.ts +6 -4
- package/src/query/search/registry.ts +6 -1
- package/src/temporal/schedule/__tests__/run-starter.test.ts +86 -24
- package/src/temporal/schedule/run-starter.ts +31 -8
- package/dist/domain/skill/storage/prefilter.d.ts.map +0 -1
- package/dist/domain/skill/storage/prefilter.js.map +0 -1
- /package/dist/{domain/skill/storage → archive}/prefilter.js +0 -0
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pins the built-in list read scope on both store drivers as the twin of
|
|
3
|
+
* the cloud's driver (stigmer-cloud iam/list-read-scope.ts): every
|
|
4
|
+
* candidate a list lane offers is answered by `can_view` under the
|
|
5
|
+
* LISTING context (`allow: false`, the public wildcard suppressed) through
|
|
6
|
+
* the same evaluator the Authorizer uses, over tuples derived from the
|
|
7
|
+
* facts the candidate carries — no candidate row is read twice.
|
|
8
|
+
*
|
|
9
|
+
* The adversarial cells come first, because until slice 5's sibling
|
|
10
|
+
* 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 legacy
|
|
12
|
+
* PUBLIC row included); the viewer rung sees the org-visible blueprints
|
|
13
|
+
* and nothing personal; the founder — an admin — sees the organization's
|
|
14
|
+
* blueprints and NOT its members' sessions, keys, environments or
|
|
15
|
+
* memories (the model's own line, now list-visible); an execution is its session's and
|
|
16
|
+
* an orphaned execution is nobody's; a run whose instance is
|
|
17
|
+
* org-observable reaches the organization's viewers; a memory with no
|
|
18
|
+
* subject is nobody's; an instance reaches whoever reads its blueprint
|
|
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; an
|
|
21
|
+
* unprovisioned subject is their raw subject (the 3.14 verifiers' stamp); a
|
|
22
|
+
* fault throws and is never an empty answer; an undeclared kind is a
|
|
23
|
+
* consumer bug, loud; the enumeration verb equals the restrict verb over
|
|
24
|
+
* the whole kind; and the reads are counted — distinct parents, never
|
|
25
|
+
* candidates.
|
|
26
|
+
*/
|
|
27
|
+
import { create } from "@bufbuild/protobuf";
|
|
28
|
+
import { afterAll, afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
29
|
+
|
|
30
|
+
import { WorkflowExecutionVisibility } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/spec_pb";
|
|
31
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
32
|
+
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
33
|
+
import { IamPolicySchema } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/api_pb";
|
|
34
|
+
import { IdentityAccountSchema } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/api_pb";
|
|
35
|
+
import { IdentityAccountProvisioningMode } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/enum_pb";
|
|
36
|
+
|
|
37
|
+
import {
|
|
38
|
+
IAM_POLICY_API_VERSION,
|
|
39
|
+
IAM_POLICY_KIND,
|
|
40
|
+
policyIdFor,
|
|
41
|
+
} from "../../domain/iampolicy/constants.js";
|
|
42
|
+
import { newResourceIamPolicyStore } from "../../domain/iampolicy/resource-store.js";
|
|
43
|
+
import type { IamPolicyStore } from "../../domain/iampolicy/store.js";
|
|
44
|
+
import { orgRole } from "../../domain/iampolicy/__tests__/support.js";
|
|
45
|
+
import { accountIdFor } from "../../domain/identityaccount/constants.js";
|
|
46
|
+
import { newResourceIdentityAccountStore } from "../../domain/identityaccount/resource-store.js";
|
|
47
|
+
import type { IdentityAccountStore } from "../../domain/identityaccount/store.js";
|
|
48
|
+
import { silentLogger } from "../../extensions/__tests__/composed-support.js";
|
|
49
|
+
import type { CallerIdentity } from "../../extensions/identity.js";
|
|
50
|
+
import type {
|
|
51
|
+
ListEntryMeta,
|
|
52
|
+
ListReadScope,
|
|
53
|
+
} from "../../extensions/list-read-scope.js";
|
|
54
|
+
import { restrictListByReadScope } from "../../extensions/list-read-scope.js";
|
|
55
|
+
import { kindEnumName } from "../../pipeline/apiresource-meta.js";
|
|
56
|
+
import { rowAuthorizationFactsOf } from "../../pipeline/steps/authorization-facts.js";
|
|
57
|
+
import type { Store } from "../../store/interface.js";
|
|
58
|
+
import { AuthorizationEvaluationError } from "../evaluator.js";
|
|
59
|
+
import { newBuiltInListReadScope } from "../list-read-scope.js";
|
|
60
|
+
import { builtInModel } from "../model/index.js";
|
|
61
|
+
import type { KindDeclaration } from "../model/rewrite.js";
|
|
62
|
+
import { driverFixtures, dropPostgresFixture } from "./drivers.js";
|
|
63
|
+
import type { OpenedStore } from "./drivers.js";
|
|
64
|
+
import { fixtureRow } from "./support.js";
|
|
65
|
+
import type { FixtureRowFacts } from "./support.js";
|
|
66
|
+
|
|
67
|
+
const FOUNDER = accountIdFor("auth0|founder");
|
|
68
|
+
const ADMIN = accountIdFor("auth0|admin");
|
|
69
|
+
const MEMBER = accountIdFor("auth0|member");
|
|
70
|
+
const VIEWER = accountIdFor("auth0|viewer");
|
|
71
|
+
const OUTSIDER = accountIdFor("auth0|outsider");
|
|
72
|
+
/** Provisioned, with rows stamped by the 3.14 verifiers' raw subject. */
|
|
73
|
+
const LEGACY_SUBJECT = "auth0|legacy";
|
|
74
|
+
const LEGACY = accountIdFor(LEGACY_SUBJECT);
|
|
75
|
+
/** Never provisioned: the caller is their raw subject and nothing else. */
|
|
76
|
+
const FRESH_SUBJECT = "auth0|fresh";
|
|
77
|
+
|
|
78
|
+
const ORG = "acme";
|
|
79
|
+
|
|
80
|
+
const SEEDED_KINDS = [
|
|
81
|
+
ApiResourceKind.iam_policy,
|
|
82
|
+
ApiResourceKind.identity_account,
|
|
83
|
+
ApiResourceKind.organization,
|
|
84
|
+
ApiResourceKind.agent,
|
|
85
|
+
ApiResourceKind.session,
|
|
86
|
+
ApiResourceKind.agent_execution,
|
|
87
|
+
ApiResourceKind.workflow_instance,
|
|
88
|
+
ApiResourceKind.workflow_execution,
|
|
89
|
+
ApiResourceKind.memory,
|
|
90
|
+
ApiResourceKind.api_key,
|
|
91
|
+
ApiResourceKind.environment,
|
|
92
|
+
ApiResourceKind.agent_instance,
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
function declared(type: string): KindDeclaration {
|
|
96
|
+
const declaration = builtInModel.byType(type);
|
|
97
|
+
if (declaration === undefined) {
|
|
98
|
+
throw new Error(`${type} is declared`);
|
|
99
|
+
}
|
|
100
|
+
return declaration;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function resolved(accountId: string): CallerIdentity {
|
|
104
|
+
return {
|
|
105
|
+
identityId: accountId,
|
|
106
|
+
callerClass: "user",
|
|
107
|
+
issuer: "https://issuer.example",
|
|
108
|
+
rawToken: "opaque",
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function idpShaped(subject: string): CallerIdentity {
|
|
113
|
+
const payload = Buffer.from(JSON.stringify({ sub: subject })).toString(
|
|
114
|
+
"base64url",
|
|
115
|
+
);
|
|
116
|
+
return {
|
|
117
|
+
identityId: subject,
|
|
118
|
+
callerClass: "user",
|
|
119
|
+
issuer: "https://issuer.example",
|
|
120
|
+
rawToken: `h.${payload}.unsigned`,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const INTERNAL: CallerIdentity = {
|
|
125
|
+
identityId: "system",
|
|
126
|
+
callerClass: "internal",
|
|
127
|
+
issuer: "",
|
|
128
|
+
rawToken: "",
|
|
129
|
+
origin: "in-process",
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/** The candidate a lane's helper would build for a row — the same resolver, plus the labels. */
|
|
133
|
+
function entryOf(kind: ApiResourceKind, row: object): ListEntryMeta {
|
|
134
|
+
return {
|
|
135
|
+
...rowAuthorizationFactsOf(kind, row),
|
|
136
|
+
labels: {},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** A stored row's decoded messages, keyed by id, as the lane holds them after its own predicates. */
|
|
141
|
+
type Rows = Map<string, object>;
|
|
142
|
+
|
|
143
|
+
afterAll(dropPostgresFixture);
|
|
144
|
+
|
|
145
|
+
describe.each(driverFixtures(SEEDED_KINDS))(
|
|
146
|
+
"the built-in list read scope on $name",
|
|
147
|
+
(fixture) => {
|
|
148
|
+
describe.skipIf(fixture.skip)(
|
|
149
|
+
"restrictListEntries and authorizedResourceIds",
|
|
150
|
+
() => {
|
|
151
|
+
let opened: OpenedStore;
|
|
152
|
+
let policies: IamPolicyStore;
|
|
153
|
+
let accounts: IdentityAccountStore;
|
|
154
|
+
let storeReads: { rows: number; scans: number };
|
|
155
|
+
let accountReads: number;
|
|
156
|
+
const rows = new Map<ApiResourceKind, Rows>();
|
|
157
|
+
|
|
158
|
+
async function save(
|
|
159
|
+
type: string,
|
|
160
|
+
facts: FixtureRowFacts,
|
|
161
|
+
): Promise<void> {
|
|
162
|
+
const declaration = declared(type);
|
|
163
|
+
const row = fixtureRow(declaration, facts);
|
|
164
|
+
await opened.store.saveResource(
|
|
165
|
+
declaration.kind,
|
|
166
|
+
facts.id,
|
|
167
|
+
declaration.schema,
|
|
168
|
+
row,
|
|
169
|
+
);
|
|
170
|
+
const held = rows.get(declaration.kind) ?? new Map<string, object>();
|
|
171
|
+
held.set(facts.id, row);
|
|
172
|
+
rows.set(declaration.kind, held);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function rowsOf(kind: ApiResourceKind): object[] {
|
|
176
|
+
return [...(rows.get(kind)?.values() ?? [])];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function grant(spec: ReturnType<typeof orgRole>) {
|
|
180
|
+
await policies.save(
|
|
181
|
+
create(IamPolicySchema, {
|
|
182
|
+
apiVersion: IAM_POLICY_API_VERSION,
|
|
183
|
+
kind: IAM_POLICY_KIND,
|
|
184
|
+
metadata: { id: policyIdFor(spec) },
|
|
185
|
+
spec,
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** The store, counting the two reads the scope may make: rows by key, and a scan of a kind. */
|
|
191
|
+
function countingStore(): Store {
|
|
192
|
+
return {
|
|
193
|
+
...opened.store,
|
|
194
|
+
getResource(kind, id, schema) {
|
|
195
|
+
storeReads.rows += 1;
|
|
196
|
+
return opened.store.getResource(kind, id, schema);
|
|
197
|
+
},
|
|
198
|
+
listResources(kind) {
|
|
199
|
+
storeReads.scans += 1;
|
|
200
|
+
return opened.store.listResources(kind);
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function scope(
|
|
206
|
+
overrides: Partial<
|
|
207
|
+
Parameters<typeof newBuiltInListReadScope>[0]
|
|
208
|
+
> = {},
|
|
209
|
+
): ListReadScope {
|
|
210
|
+
return newBuiltInListReadScope({
|
|
211
|
+
store: countingStore(),
|
|
212
|
+
policies,
|
|
213
|
+
accounts: {
|
|
214
|
+
findById: (id) => {
|
|
215
|
+
accountReads += 1;
|
|
216
|
+
return accounts.findById(id);
|
|
217
|
+
},
|
|
218
|
+
findDirectByIdpId: (idpId) => {
|
|
219
|
+
accountReads += 1;
|
|
220
|
+
return accounts.findDirectByIdpId(idpId);
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
logger: silentLogger,
|
|
224
|
+
...overrides,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** What a lane returns: the rows kept, in the lane's order, through the ONE consumption idiom. */
|
|
229
|
+
async function listAs(
|
|
230
|
+
caller: CallerIdentity,
|
|
231
|
+
kind: ApiResourceKind,
|
|
232
|
+
offered: object[] = rowsOf(kind),
|
|
233
|
+
): Promise<string[]> {
|
|
234
|
+
const kept = await restrictListByReadScope(
|
|
235
|
+
scope(),
|
|
236
|
+
caller,
|
|
237
|
+
kind,
|
|
238
|
+
offered as Array<{ metadata?: { id?: string } }>,
|
|
239
|
+
"",
|
|
240
|
+
);
|
|
241
|
+
return kept.map((row) => row.metadata?.id ?? "");
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
beforeEach(async () => {
|
|
245
|
+
opened = await fixture.open();
|
|
246
|
+
storeReads = { rows: 0, scans: 0 };
|
|
247
|
+
accountReads = 0;
|
|
248
|
+
rows.clear();
|
|
249
|
+
policies = newResourceIamPolicyStore(opened.store);
|
|
250
|
+
accounts = newResourceIdentityAccountStore(opened.store);
|
|
251
|
+
for (const [id, subject] of [
|
|
252
|
+
[FOUNDER, "auth0|founder"],
|
|
253
|
+
[ADMIN, "auth0|admin"],
|
|
254
|
+
[MEMBER, "auth0|member"],
|
|
255
|
+
[VIEWER, "auth0|viewer"],
|
|
256
|
+
[OUTSIDER, "auth0|outsider"],
|
|
257
|
+
[LEGACY, LEGACY_SUBJECT],
|
|
258
|
+
] as const) {
|
|
259
|
+
await accounts.save(
|
|
260
|
+
create(IdentityAccountSchema, {
|
|
261
|
+
metadata: { id, name: subject },
|
|
262
|
+
spec: {
|
|
263
|
+
idpId: subject,
|
|
264
|
+
provisioningMode: IdentityAccountProvisioningMode.direct,
|
|
265
|
+
},
|
|
266
|
+
}),
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
await save("organization", {
|
|
270
|
+
id: ORG,
|
|
271
|
+
org: "",
|
|
272
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
273
|
+
createdBy: FOUNDER,
|
|
274
|
+
});
|
|
275
|
+
await grant(orgRole(FOUNDER, "owner", ORG));
|
|
276
|
+
await grant(orgRole(ADMIN, "admin", ORG));
|
|
277
|
+
await grant(orgRole(MEMBER, "member", ORG));
|
|
278
|
+
await grant(orgRole(VIEWER, "viewer", ORG));
|
|
279
|
+
|
|
280
|
+
// Blueprints: the founder's private and org-visible agents, a
|
|
281
|
+
// member's private one, a legacy PUBLIC one (nobody can set public
|
|
282
|
+
// under the built-in posture; a row from before it can carry it),
|
|
283
|
+
// and one stamped by the 3.14 verifiers' raw subject.
|
|
284
|
+
await save("agent", {
|
|
285
|
+
id: "agt_private",
|
|
286
|
+
org: ORG,
|
|
287
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
288
|
+
createdBy: FOUNDER,
|
|
289
|
+
});
|
|
290
|
+
await save("agent", {
|
|
291
|
+
id: "agt_org",
|
|
292
|
+
org: ORG,
|
|
293
|
+
visibility: ApiResourceVisibility.visibility_org,
|
|
294
|
+
createdBy: FOUNDER,
|
|
295
|
+
status: { defaultInstanceId: "ai_default" },
|
|
296
|
+
});
|
|
297
|
+
await save("agent", {
|
|
298
|
+
id: "agt_member_private",
|
|
299
|
+
org: ORG,
|
|
300
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
301
|
+
createdBy: MEMBER,
|
|
302
|
+
});
|
|
303
|
+
await save("agent", {
|
|
304
|
+
id: "agt_public",
|
|
305
|
+
org: ORG,
|
|
306
|
+
visibility: ApiResourceVisibility.visibility_public,
|
|
307
|
+
createdBy: FOUNDER,
|
|
308
|
+
});
|
|
309
|
+
await save("agent", {
|
|
310
|
+
id: "agt_legacy",
|
|
311
|
+
org: ORG,
|
|
312
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
313
|
+
createdBy: LEGACY_SUBJECT,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// Personal kinds: one row each for the founder and the member.
|
|
317
|
+
for (const [type, prefix] of [
|
|
318
|
+
["session", "ses"],
|
|
319
|
+
["api_key", "key"],
|
|
320
|
+
["environment", "env"],
|
|
321
|
+
] as const) {
|
|
322
|
+
for (const [who, stamp] of [
|
|
323
|
+
["founder", FOUNDER],
|
|
324
|
+
["member", MEMBER],
|
|
325
|
+
] as const) {
|
|
326
|
+
await save(type, {
|
|
327
|
+
id: `${prefix}_${who}`,
|
|
328
|
+
org: ORG,
|
|
329
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
330
|
+
createdBy: stamp,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Executions: two in the founder's session, one in the member's,
|
|
336
|
+
// one whose session is gone. Stamped by nobody on purpose: an
|
|
337
|
+
// execution's owner is INHERITED, the stamp says nothing.
|
|
338
|
+
for (const [id, session] of [
|
|
339
|
+
["aex_f1", "ses_founder"],
|
|
340
|
+
["aex_f2", "ses_founder"],
|
|
341
|
+
["aex_m1", "ses_member"],
|
|
342
|
+
["aex_orphan", "ses_gone"],
|
|
343
|
+
] as const) {
|
|
344
|
+
await save("agent_execution", {
|
|
345
|
+
id,
|
|
346
|
+
org: ORG,
|
|
347
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
348
|
+
createdBy: "",
|
|
349
|
+
spec: { sessionId: session },
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Runs: the member's run of an org-observable instance and the
|
|
354
|
+
// founder's run of a private one.
|
|
355
|
+
await save("workflow_instance", {
|
|
356
|
+
id: "wfi_observable",
|
|
357
|
+
org: ORG,
|
|
358
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
359
|
+
createdBy: MEMBER,
|
|
360
|
+
spec: {
|
|
361
|
+
executionVisibility: WorkflowExecutionVisibility.organization,
|
|
362
|
+
},
|
|
363
|
+
});
|
|
364
|
+
await save("workflow_instance", {
|
|
365
|
+
id: "wfi_private",
|
|
366
|
+
org: ORG,
|
|
367
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
368
|
+
createdBy: FOUNDER,
|
|
369
|
+
spec: { executionVisibility: WorkflowExecutionVisibility.private },
|
|
370
|
+
});
|
|
371
|
+
await save("workflow_execution", {
|
|
372
|
+
id: "wex_member_observable",
|
|
373
|
+
org: ORG,
|
|
374
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
375
|
+
createdBy: MEMBER,
|
|
376
|
+
spec: { workflowInstanceId: "wfi_observable" },
|
|
377
|
+
});
|
|
378
|
+
await save("workflow_execution", {
|
|
379
|
+
id: "wex_founder_private",
|
|
380
|
+
org: ORG,
|
|
381
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
382
|
+
createdBy: FOUNDER,
|
|
383
|
+
spec: { workflowInstanceId: "wfi_private" },
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// Memories: one with no subject (every open-source memory row
|
|
387
|
+
// today), one whose subject is the member.
|
|
388
|
+
await save("memory", {
|
|
389
|
+
id: "mem_nobody",
|
|
390
|
+
org: ORG,
|
|
391
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
392
|
+
createdBy: MEMBER,
|
|
393
|
+
spec: { subjectIdentityAccountId: "" },
|
|
394
|
+
});
|
|
395
|
+
await save("memory", {
|
|
396
|
+
id: "mem_member",
|
|
397
|
+
org: ORG,
|
|
398
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
399
|
+
createdBy: MEMBER,
|
|
400
|
+
spec: { subjectIdentityAccountId: MEMBER },
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// Instances of the org-visible agent: its default (the
|
|
404
|
+
// blueprint's pointer names it) and the member's personal one.
|
|
405
|
+
await save("agent_instance", {
|
|
406
|
+
id: "ai_default",
|
|
407
|
+
org: ORG,
|
|
408
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
409
|
+
createdBy: FOUNDER,
|
|
410
|
+
spec: { agentId: "agt_org" },
|
|
411
|
+
});
|
|
412
|
+
await save("agent_instance", {
|
|
413
|
+
id: "ai_member",
|
|
414
|
+
org: ORG,
|
|
415
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
416
|
+
createdBy: MEMBER,
|
|
417
|
+
spec: { agentId: "agt_org" },
|
|
418
|
+
});
|
|
419
|
+
storeReads = { rows: 0, scans: 0 };
|
|
420
|
+
accountReads = 0;
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
afterEach(async () => {
|
|
424
|
+
await opened.close();
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
describe("the adversarial cells", () => {
|
|
428
|
+
it("an OUTSIDER lists nothing of the organization's — not even the legacy PUBLIC blueprint, which the listing context suppresses", async () => {
|
|
429
|
+
for (const kind of SEEDED_KINDS.filter(
|
|
430
|
+
(k) =>
|
|
431
|
+
k !== ApiResourceKind.iam_policy &&
|
|
432
|
+
k !== ApiResourceKind.identity_account &&
|
|
433
|
+
k !== ApiResourceKind.organization,
|
|
434
|
+
)) {
|
|
435
|
+
expect(
|
|
436
|
+
await listAs(resolved(OUTSIDER), kind),
|
|
437
|
+
kindEnumName(kind),
|
|
438
|
+
).toEqual([]);
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
it("a VIEWER lists the org-visible and the public blueprints and nothing private; a MEMBER adds their own private one", async () => {
|
|
443
|
+
expect(
|
|
444
|
+
await listAs(resolved(VIEWER), ApiResourceKind.agent),
|
|
445
|
+
).toEqual(["agt_org", "agt_public"]);
|
|
446
|
+
expect(
|
|
447
|
+
await listAs(resolved(MEMBER), ApiResourceKind.agent),
|
|
448
|
+
).toEqual(["agt_org", "agt_member_private", "agt_public"]);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
it("the FOUNDER and the ADMIN list every blueprint (`owner: … or admin from organization`), including a member's private one", async () => {
|
|
452
|
+
const all = [
|
|
453
|
+
"agt_private",
|
|
454
|
+
"agt_org",
|
|
455
|
+
"agt_member_private",
|
|
456
|
+
"agt_public",
|
|
457
|
+
"agt_legacy",
|
|
458
|
+
];
|
|
459
|
+
expect(
|
|
460
|
+
await listAs(resolved(FOUNDER), ApiResourceKind.agent),
|
|
461
|
+
).toEqual(all);
|
|
462
|
+
expect(
|
|
463
|
+
await listAs(resolved(ADMIN), ApiResourceKind.agent),
|
|
464
|
+
).toEqual(all);
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
it("sessions, API keys and environments are their owner's: the founder — an admin — does NOT list a member's, and the admin lists none", async () => {
|
|
468
|
+
for (const [kind, prefix] of [
|
|
469
|
+
[ApiResourceKind.session, "ses"],
|
|
470
|
+
[ApiResourceKind.api_key, "key"],
|
|
471
|
+
[ApiResourceKind.environment, "env"],
|
|
472
|
+
] as const) {
|
|
473
|
+
expect(await listAs(resolved(FOUNDER), kind)).toEqual([
|
|
474
|
+
`${prefix}_founder`,
|
|
475
|
+
]);
|
|
476
|
+
expect(await listAs(resolved(MEMBER), kind)).toEqual([
|
|
477
|
+
`${prefix}_member`,
|
|
478
|
+
]);
|
|
479
|
+
expect(await listAs(resolved(ADMIN), kind)).toEqual([]);
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
it("an execution is its SESSION's (`can_view from session`): each person lists the runs of their own sessions; an orphaned execution is nobody's", async () => {
|
|
484
|
+
expect(
|
|
485
|
+
await listAs(resolved(FOUNDER), ApiResourceKind.agent_execution),
|
|
486
|
+
).toEqual(["aex_f1", "aex_f2"]);
|
|
487
|
+
expect(
|
|
488
|
+
await listAs(resolved(MEMBER), ApiResourceKind.agent_execution),
|
|
489
|
+
).toEqual(["aex_m1"]);
|
|
490
|
+
expect(
|
|
491
|
+
await listAs(resolved(ADMIN), ApiResourceKind.agent_execution),
|
|
492
|
+
).toEqual([]);
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
it("a run of an org-observable instance reaches the organization's viewers through `execution_viewer`; a run of a private instance is its triggerer's alone", async () => {
|
|
496
|
+
expect(
|
|
497
|
+
await listAs(
|
|
498
|
+
resolved(VIEWER),
|
|
499
|
+
ApiResourceKind.workflow_execution,
|
|
500
|
+
),
|
|
501
|
+
).toEqual(["wex_member_observable"]);
|
|
502
|
+
expect(
|
|
503
|
+
await listAs(
|
|
504
|
+
resolved(FOUNDER),
|
|
505
|
+
ApiResourceKind.workflow_execution,
|
|
506
|
+
),
|
|
507
|
+
).toEqual(["wex_member_observable", "wex_founder_private"]);
|
|
508
|
+
expect(
|
|
509
|
+
await listAs(
|
|
510
|
+
resolved(MEMBER),
|
|
511
|
+
ApiResourceKind.workflow_execution,
|
|
512
|
+
),
|
|
513
|
+
).toEqual(["wex_member_observable"]);
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
it("a memory is its SUBJECT's and a memory with no subject is nobody's — the founder lists none, the member lists the one about them", async () => {
|
|
517
|
+
expect(
|
|
518
|
+
await listAs(resolved(FOUNDER), ApiResourceKind.memory),
|
|
519
|
+
).toEqual([]);
|
|
520
|
+
expect(
|
|
521
|
+
await listAs(resolved(MEMBER), ApiResourceKind.memory),
|
|
522
|
+
).toEqual(["mem_member"]);
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
it("an instance reaches whoever reads its blueprint only when it is the DEFAULT (`viewer from default_of`); a personal instance is its owner's", async () => {
|
|
526
|
+
expect(
|
|
527
|
+
await listAs(resolved(VIEWER), ApiResourceKind.agent_instance),
|
|
528
|
+
).toEqual(["ai_default"]);
|
|
529
|
+
expect(
|
|
530
|
+
await listAs(resolved(MEMBER), ApiResourceKind.agent_instance),
|
|
531
|
+
).toEqual(["ai_default", "ai_member"]);
|
|
532
|
+
expect(
|
|
533
|
+
await listAs(resolved(FOUNDER), ApiResourceKind.agent_instance),
|
|
534
|
+
).toEqual(["ai_default"]);
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
describe("the seam's contract", () => {
|
|
539
|
+
it("only narrows, never reorders, and answers a duplicate once", async () => {
|
|
540
|
+
const offered = [
|
|
541
|
+
entryOf(
|
|
542
|
+
ApiResourceKind.agent,
|
|
543
|
+
rows.get(ApiResourceKind.agent)!.get("agt_public")!,
|
|
544
|
+
),
|
|
545
|
+
entryOf(
|
|
546
|
+
ApiResourceKind.agent,
|
|
547
|
+
rows.get(ApiResourceKind.agent)!.get("agt_private")!,
|
|
548
|
+
),
|
|
549
|
+
entryOf(
|
|
550
|
+
ApiResourceKind.agent,
|
|
551
|
+
rows.get(ApiResourceKind.agent)!.get("agt_org")!,
|
|
552
|
+
),
|
|
553
|
+
entryOf(
|
|
554
|
+
ApiResourceKind.agent,
|
|
555
|
+
rows.get(ApiResourceKind.agent)!.get("agt_org")!,
|
|
556
|
+
),
|
|
557
|
+
];
|
|
558
|
+
const kept = await scope().restrictListEntries(
|
|
559
|
+
resolved(MEMBER),
|
|
560
|
+
ApiResourceKind.agent,
|
|
561
|
+
offered,
|
|
562
|
+
);
|
|
563
|
+
expect([...kept]).toEqual(["agt_public", "agt_org"]);
|
|
564
|
+
// The lane's order is the lane's: the helper filters its own
|
|
565
|
+
// array by the kept set.
|
|
566
|
+
expect(
|
|
567
|
+
await listAs(resolved(MEMBER), ApiResourceKind.agent, [
|
|
568
|
+
rows.get(ApiResourceKind.agent)!.get("agt_public")!,
|
|
569
|
+
rows.get(ApiResourceKind.agent)!.get("agt_org")!,
|
|
570
|
+
]),
|
|
571
|
+
).toEqual(["agt_public", "agt_org"]);
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
it("no candidates: the empty set, with no read of any kind", async () => {
|
|
575
|
+
expect(
|
|
576
|
+
await scope().restrictListEntries(
|
|
577
|
+
resolved(MEMBER),
|
|
578
|
+
ApiResourceKind.agent,
|
|
579
|
+
[],
|
|
580
|
+
),
|
|
581
|
+
).toEqual(new Set());
|
|
582
|
+
expect(storeReads).toEqual({ rows: 0, scans: 0 });
|
|
583
|
+
expect(accountReads).toBe(0);
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
it("the `internal` class — the server acting as itself — keeps every offered id and enumerates every id of the kind: the in-process authorization skip, with no account even asked for", async () => {
|
|
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));
|
|
597
|
+
expect(
|
|
598
|
+
[
|
|
599
|
+
...(await scope().authorizedResourceIds(
|
|
600
|
+
INTERNAL,
|
|
601
|
+
ApiResourceKind.session,
|
|
602
|
+
)),
|
|
603
|
+
].sort(),
|
|
604
|
+
).toEqual(["ses_founder", "ses_member"]);
|
|
605
|
+
expect(accountReads).toBe(0);
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
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
|
+
// `agt_legacy` is stamped with LEGACY's raw subject; a caller
|
|
610
|
+
// who IS that subject and holds no account reaches it through
|
|
611
|
+
// the alias, and reaches nothing the organization holds.
|
|
612
|
+
expect(
|
|
613
|
+
await listAs(idpShaped(LEGACY_SUBJECT), ApiResourceKind.agent, [
|
|
614
|
+
rows.get(ApiResourceKind.agent)!.get("agt_legacy")!,
|
|
615
|
+
rows.get(ApiResourceKind.agent)!.get("agt_org")!,
|
|
616
|
+
]),
|
|
617
|
+
).toEqual(["agt_legacy"]);
|
|
618
|
+
expect(
|
|
619
|
+
await listAs(idpShaped(FRESH_SUBJECT), ApiResourceKind.agent),
|
|
620
|
+
).toEqual([]);
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
it("a provisioned account whose idp subject stamped the row still owns it — the alias comparison the 3.14 rows need, on the list verb", async () => {
|
|
624
|
+
expect(
|
|
625
|
+
await listAs(resolved(LEGACY), ApiResourceKind.agent, [
|
|
626
|
+
rows.get(ApiResourceKind.agent)!.get("agt_legacy")!,
|
|
627
|
+
]),
|
|
628
|
+
).toEqual(["agt_legacy"]);
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
it("a store fault THROWS — never an empty answer (an empty set means 'authorized to see nothing')", async () => {
|
|
632
|
+
const fault = new Error("connection reset");
|
|
633
|
+
const faulting = scope({
|
|
634
|
+
policies: {
|
|
635
|
+
...policies,
|
|
636
|
+
findByPrincipal: () => Promise.reject(fault),
|
|
637
|
+
},
|
|
638
|
+
});
|
|
639
|
+
await expect(
|
|
640
|
+
faulting.restrictListEntries(
|
|
641
|
+
resolved(MEMBER),
|
|
642
|
+
ApiResourceKind.agent,
|
|
643
|
+
rowsOf(ApiResourceKind.agent).map((row) =>
|
|
644
|
+
entryOf(ApiResourceKind.agent, row),
|
|
645
|
+
),
|
|
646
|
+
),
|
|
647
|
+
).rejects.toBe(fault);
|
|
648
|
+
await expect(
|
|
649
|
+
faulting.authorizedResourceIds(
|
|
650
|
+
resolved(MEMBER),
|
|
651
|
+
ApiResourceKind.agent,
|
|
652
|
+
),
|
|
653
|
+
).rejects.toBe(fault);
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
it("a kind the model does not declare is a consumer bug — loud, never a silent empty answer", async () => {
|
|
657
|
+
await expect(
|
|
658
|
+
scope().restrictListEntries(
|
|
659
|
+
resolved(MEMBER),
|
|
660
|
+
ApiResourceKind.platform,
|
|
661
|
+
[
|
|
662
|
+
{
|
|
663
|
+
id: "stigmer",
|
|
664
|
+
org: "",
|
|
665
|
+
labels: {},
|
|
666
|
+
createdBy: "",
|
|
667
|
+
visibility:
|
|
668
|
+
ApiResourceVisibility.api_resource_visibility_unspecified,
|
|
669
|
+
parentLinks: [],
|
|
670
|
+
},
|
|
671
|
+
],
|
|
672
|
+
),
|
|
673
|
+
).rejects.toBeInstanceOf(AuthorizationEvaluationError);
|
|
674
|
+
await expect(
|
|
675
|
+
scope().authorizedResourceIds(
|
|
676
|
+
resolved(MEMBER),
|
|
677
|
+
ApiResourceKind.platform,
|
|
678
|
+
),
|
|
679
|
+
).rejects.toBeInstanceOf(AuthorizationEvaluationError);
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
it("a caller who names no person is a fault the pipeline sanitizes, never a list", async () => {
|
|
683
|
+
await expect(
|
|
684
|
+
scope().restrictListEntries(
|
|
685
|
+
{ ...resolved("system"), callerClass: "user" },
|
|
686
|
+
ApiResourceKind.agent,
|
|
687
|
+
[],
|
|
688
|
+
),
|
|
689
|
+
).resolves.toEqual(new Set());
|
|
690
|
+
await expect(
|
|
691
|
+
scope().restrictListEntries(
|
|
692
|
+
{ ...resolved("system"), callerClass: "user" },
|
|
693
|
+
ApiResourceKind.agent,
|
|
694
|
+
rowsOf(ApiResourceKind.agent).map((row) =>
|
|
695
|
+
entryOf(ApiResourceKind.agent, row),
|
|
696
|
+
),
|
|
697
|
+
),
|
|
698
|
+
).rejects.toThrow(/names no person/);
|
|
699
|
+
});
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
describe("the enumeration verb", () => {
|
|
703
|
+
it("equals the restrict verb over the whole kind, for every seeded kind and every person", async () => {
|
|
704
|
+
for (const kind of SEEDED_KINDS.filter(
|
|
705
|
+
(k) =>
|
|
706
|
+
k !== ApiResourceKind.iam_policy &&
|
|
707
|
+
k !== ApiResourceKind.identity_account,
|
|
708
|
+
)) {
|
|
709
|
+
for (const who of [FOUNDER, ADMIN, MEMBER, VIEWER, OUTSIDER]) {
|
|
710
|
+
const enumerated = await scope().authorizedResourceIds(
|
|
711
|
+
resolved(who),
|
|
712
|
+
kind,
|
|
713
|
+
);
|
|
714
|
+
const restricted = await scope().restrictListEntries(
|
|
715
|
+
resolved(who),
|
|
716
|
+
kind,
|
|
717
|
+
rowsOf(kind).map((row) => entryOf(kind, row)),
|
|
718
|
+
);
|
|
719
|
+
expect(
|
|
720
|
+
[...enumerated].sort(),
|
|
721
|
+
`${kindEnumName(kind)} for ${who}`,
|
|
722
|
+
).toEqual([...restricted].sort());
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
it("a stored row that does not decode is skipped, never a fault — no lane can show it either", async () => {
|
|
728
|
+
const truncated = new Uint8Array([0x0a, 0xff]);
|
|
729
|
+
const enumerated = await scope({
|
|
730
|
+
store: {
|
|
731
|
+
...opened.store,
|
|
732
|
+
listResources: async (kind) => [
|
|
733
|
+
...(await opened.store.listResources(kind)),
|
|
734
|
+
truncated,
|
|
735
|
+
],
|
|
736
|
+
},
|
|
737
|
+
}).authorizedResourceIds(
|
|
738
|
+
resolved(FOUNDER),
|
|
739
|
+
ApiResourceKind.session,
|
|
740
|
+
);
|
|
741
|
+
expect([...enumerated]).toEqual(["ses_founder"]);
|
|
742
|
+
});
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
describe("cost", () => {
|
|
746
|
+
it("a list of executions reads each DISTINCT session once and no execution row at all — the candidates' facts are the entries'", async () => {
|
|
747
|
+
await listAs(resolved(FOUNDER), ApiResourceKind.agent_execution);
|
|
748
|
+
// Three sessions named across four candidates (one of them
|
|
749
|
+
// gone); the organization row is not walked for an execution.
|
|
750
|
+
expect(storeReads).toEqual({ rows: 3, scans: 0 });
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
it("a list of blueprints reads the organization row once for the userset hop and nothing per candidate; the account once; the person's rows once", async () => {
|
|
754
|
+
let principalReads = 0;
|
|
755
|
+
await restrictListByReadScope(
|
|
756
|
+
scope({
|
|
757
|
+
policies: {
|
|
758
|
+
...policies,
|
|
759
|
+
findByPrincipal(principalKind, principalId) {
|
|
760
|
+
principalReads += 1;
|
|
761
|
+
return policies.findByPrincipal(principalKind, principalId);
|
|
762
|
+
},
|
|
763
|
+
},
|
|
764
|
+
}),
|
|
765
|
+
resolved(MEMBER),
|
|
766
|
+
ApiResourceKind.agent,
|
|
767
|
+
rowsOf(ApiResourceKind.agent) as Array<{
|
|
768
|
+
metadata?: { id?: string };
|
|
769
|
+
}>,
|
|
770
|
+
"",
|
|
771
|
+
);
|
|
772
|
+
expect(storeReads).toEqual({ rows: 1, scans: 0 });
|
|
773
|
+
expect(accountReads).toBe(1);
|
|
774
|
+
expect(principalReads).toBe(1);
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
it("a list of instances reads each instance row once beside the blueprint — the `default_of` rule reads the pointer's spec, which a candidate's facts do not carry (stated, not hidden)", async () => {
|
|
778
|
+
// The viewer owns neither instance, so `viewer from default_of`
|
|
779
|
+
// is evaluated for both: two instance rows, the one blueprint,
|
|
780
|
+
// the one organization.
|
|
781
|
+
await listAs(resolved(VIEWER), ApiResourceKind.agent_instance);
|
|
782
|
+
expect(storeReads).toEqual({ rows: 4, scans: 0 });
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
it("the enumeration verb scans the kind exactly once", async () => {
|
|
786
|
+
await scope().authorizedResourceIds(
|
|
787
|
+
resolved(MEMBER),
|
|
788
|
+
ApiResourceKind.session,
|
|
789
|
+
);
|
|
790
|
+
expect(storeReads.scans).toBe(1);
|
|
791
|
+
});
|
|
792
|
+
});
|
|
793
|
+
},
|
|
794
|
+
);
|
|
795
|
+
},
|
|
796
|
+
);
|