@stigmer/server 3.22.1-dev.20260922095755 → 3.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/artifactstorage/artifact-storage.d.ts +29 -31
- package/dist/artifactstorage/artifact-storage.d.ts.map +1 -1
- package/dist/artifactstorage/artifact-storage.js +5 -7
- package/dist/artifactstorage/artifact-storage.js.map +1 -1
- package/dist/artifactstorage/r2-storage.d.ts +12 -7
- package/dist/artifactstorage/r2-storage.d.ts.map +1 -1
- package/dist/artifactstorage/r2-storage.js +6 -14
- package/dist/artifactstorage/r2-storage.js.map +1 -1
- package/dist/authorization/authorizer.d.ts +8 -4
- package/dist/authorization/authorizer.d.ts.map +1 -1
- package/dist/authorization/authorizer.js +9 -5
- package/dist/authorization/authorizer.js.map +1 -1
- package/dist/authorization/derived-tuples.d.ts.map +1 -1
- package/dist/authorization/derived-tuples.js +25 -10
- package/dist/authorization/derived-tuples.js.map +1 -1
- package/dist/authorization/evaluator.d.ts +8 -7
- package/dist/authorization/evaluator.d.ts.map +1 -1
- package/dist/authorization/evaluator.js +20 -4
- 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 +9 -5
- 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 +5 -4
- 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/plugin.d.ts.map +1 -1
- package/dist/authorization/model/plugin.js +4 -3
- package/dist/authorization/model/plugin.js.map +1 -1
- package/dist/authorization/model/rewrite.d.ts +10 -8
- package/dist/authorization/model/rewrite.d.ts.map +1 -1
- package/dist/authorization/model/rewrite.js +3 -0
- 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 +3 -2
- package/dist/authorization/organization-directory.js.map +1 -1
- package/dist/authorization/store-test-kit.d.ts +6 -0
- package/dist/authorization/store-test-kit.d.ts.map +1 -1
- package/dist/authorization/store-test-kit.js +62 -16
- package/dist/authorization/store-test-kit.js.map +1 -1
- package/dist/authorization/tuples.d.ts +32 -13
- package/dist/authorization/tuples.d.ts.map +1 -1
- package/dist/authorization/tuples.js +11 -3
- package/dist/authorization/tuples.js.map +1 -1
- package/dist/boot/compose.d.ts.map +1 -1
- package/dist/boot/compose.js +49 -24
- package/dist/boot/compose.js.map +1 -1
- package/dist/boot/config.d.ts +4 -3
- package/dist/boot/config.d.ts.map +1 -1
- package/dist/boot/config.js.map +1 -1
- package/dist/boot/skill-transfer-origin.d.ts +52 -0
- package/dist/boot/skill-transfer-origin.d.ts.map +1 -0
- package/dist/boot/skill-transfer-origin.js +54 -0
- package/dist/boot/skill-transfer-origin.js.map +1 -0
- package/dist/domain/agent/controller.d.ts.map +1 -1
- package/dist/domain/agent/controller.js +4 -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 +1 -3
- package/dist/domain/agentchannel/controller.js.map +1 -1
- package/dist/domain/agentexecution/controller.d.ts.map +1 -1
- package/dist/domain/agentexecution/controller.js +1 -3
- package/dist/domain/agentexecution/controller.js.map +1 -1
- package/dist/domain/agentinstance/controller.d.ts.map +1 -1
- package/dist/domain/agentinstance/controller.js +4 -3
- package/dist/domain/agentinstance/controller.js.map +1 -1
- package/dist/domain/agentshare/constants.d.ts +11 -6
- package/dist/domain/agentshare/constants.d.ts.map +1 -1
- package/dist/domain/agentshare/constants.js +16 -8
- 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 +1 -3
- package/dist/domain/agentshare/controller.js.map +1 -1
- package/dist/domain/agentshare/steps.d.ts +25 -18
- package/dist/domain/agentshare/steps.d.ts.map +1 -1
- package/dist/domain/agentshare/steps.js +142 -41
- package/dist/domain/agentshare/steps.js.map +1 -1
- package/dist/domain/environment/controller.d.ts.map +1 -1
- package/dist/domain/environment/controller.js +3 -2
- 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 +1 -2
- package/dist/domain/executioncontext/controller.js.map +1 -1
- package/dist/domain/mcpserver/controller.d.ts.map +1 -1
- package/dist/domain/mcpserver/controller.js +4 -3
- package/dist/domain/mcpserver/controller.js.map +1 -1
- package/dist/domain/plugin/controller.d.ts +3 -7
- package/dist/domain/plugin/controller.d.ts.map +1 -1
- package/dist/domain/plugin/controller.js +11 -9
- package/dist/domain/plugin/controller.js.map +1 -1
- package/dist/domain/plugin/push.d.ts +5 -7
- package/dist/domain/plugin/push.d.ts.map +1 -1
- package/dist/domain/plugin/push.js +14 -8
- 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 +1 -3
- package/dist/domain/schedule/controller.js.map +1 -1
- package/dist/domain/session/controller.d.ts.map +1 -1
- package/dist/domain/session/controller.js +2 -3
- package/dist/domain/session/controller.js.map +1 -1
- package/dist/domain/skill/constants.d.ts +26 -3
- package/dist/domain/skill/constants.d.ts.map +1 -1
- package/dist/domain/skill/constants.js +26 -3
- package/dist/domain/skill/constants.js.map +1 -1
- package/dist/domain/skill/controller.d.ts +6 -11
- package/dist/domain/skill/controller.d.ts.map +1 -1
- package/dist/domain/skill/controller.js +35 -22
- package/dist/domain/skill/controller.js.map +1 -1
- package/dist/domain/skill/push.d.ts +2 -2
- package/dist/domain/skill/push.d.ts.map +1 -1
- package/dist/domain/skill/push.js +2 -2
- package/dist/domain/skill/push.js.map +1 -1
- package/dist/domain/skill/transfer/handler.d.ts +17 -9
- package/dist/domain/skill/transfer/handler.d.ts.map +1 -1
- package/dist/domain/skill/transfer/handler.js +19 -8
- package/dist/domain/skill/transfer/handler.js.map +1 -1
- package/dist/domain/skill/transfer/slots.d.ts +26 -41
- package/dist/domain/skill/transfer/slots.d.ts.map +1 -1
- package/dist/domain/skill/transfer/slots.js +80 -87
- package/dist/domain/skill/transfer/slots.js.map +1 -1
- package/dist/domain/skill/transfer/staging.d.ts +48 -0
- package/dist/domain/skill/transfer/staging.d.ts.map +1 -0
- package/dist/domain/skill/transfer/staging.js +127 -0
- package/dist/domain/skill/transfer/staging.js.map +1 -0
- package/dist/domain/workflow/controller.d.ts.map +1 -1
- package/dist/domain/workflow/controller.js +6 -14
- 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 +1 -10
- package/dist/domain/workflow/validation/task-config-constraints.d.ts.map +1 -1
- package/dist/domain/workflow/validation/task-config-constraints.js +2 -3
- package/dist/domain/workflow/validation/task-config-constraints.js.map +1 -1
- package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
- package/dist/domain/workflowexecution/controller.js +2 -4
- 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 +4 -3
- package/dist/domain/workflowinstance/controller.js.map +1 -1
- package/dist/extensions/authorization-queries.d.ts +5 -6
- package/dist/extensions/authorization-queries.d.ts.map +1 -1
- package/dist/extensions/list-read-scope.d.ts +1 -1
- package/dist/extensions/resource-authorization.d.ts +2 -3
- package/dist/extensions/resource-authorization.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/pipeline/apiresource-meta.d.ts +3 -12
- package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
- package/dist/pipeline/apiresource-meta.js +10 -21
- package/dist/pipeline/apiresource-meta.js.map +1 -1
- package/dist/pipeline/steps/authorization-tuples.d.ts +3 -9
- package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
- package/dist/pipeline/steps/authorization-tuples.js +11 -9
- package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
- package/dist/pipeline/steps/references.d.ts +20 -178
- package/dist/pipeline/steps/references.d.ts.map +1 -1
- package/dist/pipeline/steps/references.js +43 -344
- package/dist/pipeline/steps/references.js.map +1 -1
- package/dist/pipeline/steps/resolve-artifact-source.d.ts +11 -8
- package/dist/pipeline/steps/resolve-artifact-source.d.ts.map +1 -1
- package/dist/pipeline/steps/resolve-artifact-source.js +8 -4
- package/dist/pipeline/steps/resolve-artifact-source.js.map +1 -1
- package/dist/pipeline/steps/visibility-gates.d.ts +27 -0
- package/dist/pipeline/steps/visibility-gates.d.ts.map +1 -0
- package/dist/pipeline/steps/visibility-gates.js +139 -0
- package/dist/pipeline/steps/visibility-gates.js.map +1 -0
- package/dist/query/search/controller.js +1 -0
- package/dist/query/search/controller.js.map +1 -1
- package/dist/query/search/criteria.d.ts +5 -1
- package/dist/query/search/criteria.d.ts.map +1 -1
- package/dist/query/search/criteria.js +13 -3
- package/dist/query/search/criteria.js.map +1 -1
- package/dist/query/search/handler.d.ts +4 -5
- package/dist/query/search/handler.d.ts.map +1 -1
- package/dist/query/search/handler.js +6 -7
- 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 +2 -0
- package/dist/query/search/query-store.js.map +1 -1
- package/dist/store/interface.d.ts +6 -3
- package/dist/store/interface.d.ts.map +1 -1
- package/dist/store/interface.js.map +1 -1
- package/dist/store/postgres/migrations.d.ts +1 -3
- package/dist/store/postgres/migrations.d.ts.map +1 -1
- package/dist/store/postgres/migrations.js +1 -35
- 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 +9 -4
- package/dist/store/postgres/store.js.map +1 -1
- package/dist/store/sqlite/migrations.d.ts +1 -3
- package/dist/store/sqlite/migrations.d.ts.map +1 -1
- package/dist/store/sqlite/migrations.js +1 -36
- 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 +8 -4
- package/dist/store/sqlite/store.js.map +1 -1
- package/package.json +6 -6
- package/src/artifactstorage/__tests__/artifact-storage.test.ts +36 -33
- package/src/artifactstorage/__tests__/r2-storage.test.ts +11 -13
- package/src/artifactstorage/artifact-storage.ts +37 -33
- package/src/artifactstorage/r2-storage.ts +6 -15
- package/src/authorization/README.md +26 -24
- package/src/authorization/__tests__/authorizer.test.ts +9 -10
- package/src/authorization/__tests__/derived-tuples.test.ts +11 -4
- package/src/authorization/__tests__/evaluator.test.ts +73 -14
- package/src/authorization/__tests__/facts.test.ts +2 -2
- package/src/authorization/__tests__/fixtures/fga/agent-instance-creation.fga.yaml +185 -0
- package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +98 -6
- 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 +61 -4
- package/src/authorization/__tests__/fixtures/fga/mcp-server-authoring.fga.yaml +143 -0
- package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +21 -1
- package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +25 -1
- package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +52 -0
- package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +3 -1
- package/src/authorization/__tests__/list-read-scope.test.ts +17 -18
- package/src/authorization/__tests__/store-tests.test.ts +8 -1
- package/src/authorization/__tests__/tuples.test.ts +11 -12
- package/src/authorization/authorizer.ts +9 -4
- package/src/authorization/derived-tuples.ts +31 -14
- package/src/authorization/evaluator.ts +44 -8
- package/src/authorization/list-read-scope.ts +11 -5
- package/src/authorization/model/agent.ts +5 -2
- package/src/authorization/model/agent_instance.ts +2 -0
- package/src/authorization/model/mcp_server.ts +2 -0
- package/src/authorization/model/plugin.ts +4 -1
- package/src/authorization/model/rewrite.ts +13 -8
- package/src/authorization/model/skill.ts +2 -0
- package/src/authorization/model/workflow.ts +2 -0
- package/src/authorization/model/workflow_instance.ts +2 -0
- package/src/authorization/organization-directory.ts +3 -1
- package/src/authorization/store-test-kit.ts +75 -16
- package/src/authorization/tuples.ts +39 -16
- package/src/boot/__tests__/skill-transfer-origin.test.ts +72 -0
- package/src/boot/compose.ts +62 -25
- package/src/boot/config.ts +4 -3
- package/src/boot/skill-transfer-origin.ts +76 -0
- package/src/domain/agent/__tests__/agent.test.ts +4 -11
- package/src/domain/agent/controller.ts +7 -7
- package/src/domain/agentchannel/__tests__/agentchannel.test.ts +48 -223
- package/src/domain/agentchannel/controller.ts +1 -6
- package/src/domain/agentexecution/controller.ts +1 -6
- package/src/domain/agentinstance/controller.ts +12 -6
- package/src/domain/agentshare/__tests__/agentshare.test.ts +172 -196
- package/src/domain/agentshare/__tests__/create-authorization.test.ts +31 -16
- package/src/domain/agentshare/constants.ts +26 -14
- package/src/domain/agentshare/controller.ts +1 -6
- package/src/domain/agentshare/steps.ts +194 -41
- package/src/domain/environment/controller.ts +8 -5
- package/src/domain/executioncontext/controller.ts +1 -5
- package/src/domain/mcpserver/__tests__/mcpserver.test.ts +28 -115
- package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +18 -53
- package/src/domain/mcpserver/controller.ts +12 -6
- package/src/domain/plugin/controller.ts +23 -18
- package/src/domain/plugin/push.ts +16 -8
- package/src/domain/schedule/controller.ts +1 -6
- package/src/domain/session/controller.ts +4 -12
- package/src/domain/skill/__tests__/skill.test.ts +5 -3
- package/src/domain/skill/__tests__/slots.test.ts +113 -60
- package/src/domain/skill/__tests__/staging.test.ts +304 -0
- package/src/domain/skill/constants.ts +28 -3
- package/src/domain/skill/controller.ts +51 -35
- package/src/domain/skill/push.ts +3 -3
- package/src/domain/skill/transfer/handler.ts +33 -15
- package/src/domain/skill/transfer/slots.ts +89 -100
- package/src/domain/skill/transfer/staging.ts +191 -0
- package/src/domain/workflow/controller.ts +10 -28
- package/src/domain/workflow/registry/data/task-kind-registry.json +1 -1
- package/src/domain/workflow/validation/task-config-constraints.ts +3 -7
- package/src/domain/workflowexecution/controller.ts +2 -7
- package/src/domain/workflowinstance/controller.ts +12 -6
- package/src/extensions/__tests__/built-in-authorization-composed.test.ts +19 -32
- package/src/extensions/__tests__/extension-composition.test.ts +4 -4
- package/src/extensions/__tests__/list-read-scope-composed.test.ts +6 -9
- package/src/extensions/authorization-queries.ts +5 -6
- package/src/extensions/list-read-scope.ts +1 -1
- package/src/extensions/resource-authorization.ts +5 -3
- package/src/index.ts +14 -0
- package/src/pipeline/apiresource-meta.ts +10 -21
- package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +31 -18
- package/src/pipeline/steps/__tests__/visibility-gates.test.ts +187 -0
- package/src/pipeline/steps/authorization-tuples.ts +11 -9
- package/src/pipeline/steps/references.ts +70 -578
- package/src/pipeline/steps/resolve-artifact-source.ts +20 -13
- package/src/pipeline/steps/visibility-gates.ts +174 -0
- package/src/query/search/__tests__/criteria.test.ts +4 -0
- package/src/query/search/__tests__/query-store.test.ts +40 -11
- package/src/query/search/controller.ts +1 -0
- package/src/query/search/criteria.ts +14 -0
- package/src/query/search/handler.ts +7 -6
- package/src/query/search/query-store.ts +2 -0
- package/src/store/__tests__/store-contract.ts +51 -6
- package/src/store/interface.ts +6 -3
- package/src/store/postgres/__tests__/migrations.test.ts +6 -187
- package/src/store/postgres/__tests__/store-contract.test.ts +2 -0
- package/src/store/postgres/migrations.ts +1 -48
- package/src/store/postgres/store.ts +11 -4
- package/src/store/sqlite/__tests__/migrations.test.ts +5 -191
- package/src/store/sqlite/migrations.ts +1 -45
- package/src/store/sqlite/store.ts +10 -4
- package/src/transport/registry/__tests__/lanes.test.ts +1 -1
- package/dist/domain/workflow/agent-call-references.d.ts +0 -54
- package/dist/domain/workflow/agent-call-references.d.ts.map +0 -1
- package/dist/domain/workflow/agent-call-references.js +0 -97
- package/dist/domain/workflow/agent-call-references.js.map +0 -1
- package/dist/store/public-visibility-retired.d.ts +0 -67
- package/dist/store/public-visibility-retired.d.ts.map +0 -1
- package/dist/store/public-visibility-retired.js +0 -55
- package/dist/store/public-visibility-retired.js.map +0 -1
- package/src/domain/workflow/__tests__/agent-call-references.test.ts +0 -222
- package/src/domain/workflow/agent-call-references.ts +0 -157
- package/src/pipeline/__tests__/supports-visibility.test.ts +0 -112
- package/src/pipeline/steps/__tests__/references.test.ts +0 -703
- package/src/store/__tests__/public-visibility-retired.test.ts +0 -127
- package/src/store/public-visibility-retired.ts +0 -119
|
@@ -8,18 +8,22 @@
|
|
|
8
8
|
* are indistinguishable past this point.
|
|
9
9
|
*
|
|
10
10
|
* Skills carried this step alone (the Go ResolveArtifactSource port);
|
|
11
|
-
* plugins are pushed the same two ways over the same
|
|
12
|
-
* upload surface, as boot/compose.ts wires it), so the step lives
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* plugins are pushed the same two ways over the same staging port (one
|
|
12
|
+
* upload surface, as boot/compose.ts wires it), so the step lives here
|
|
13
|
+
* and each kind names its lane-absent sentence and the request fields it
|
|
14
|
+
* reads. The staging port (domain/skill/transfer/staging.ts) hides which
|
|
15
|
+
* blob driver holds the bytes: the step never sees a slot or a bucket.
|
|
15
16
|
*
|
|
16
17
|
* The unusable-reference arm is INVALID_ARGUMENT, not a server fault: an
|
|
17
|
-
* unknown, expired, already consumed, or
|
|
18
|
-
*
|
|
18
|
+
* unknown, expired, already consumed, or never-uploaded reference all mean
|
|
19
|
+
* the client must re-mint and re-upload. Any other failure reading the
|
|
20
|
+
* staged bytes is the driver's — an infrastructure fault the executor
|
|
21
|
+
* answers as a sanitized Internal, never dressed as the client's mistake.
|
|
19
22
|
*/
|
|
20
23
|
import type { DescMessage, MessageShape } from "@bufbuild/protobuf";
|
|
21
24
|
|
|
22
|
-
import
|
|
25
|
+
import { SlotUnknownError } from "../../domain/skill/transfer/slots.js";
|
|
26
|
+
import type { ArchiveStaging } from "../../domain/skill/transfer/staging.js";
|
|
23
27
|
import { failedPreconditionError, invalidArgumentError } from "../errors.js";
|
|
24
28
|
import type { PipelineStep } from "../pipeline.js";
|
|
25
29
|
import type { RequestContext } from "../request-context.js";
|
|
@@ -38,7 +42,7 @@ export interface ArtifactSourceBinding<Desc extends DescMessage> {
|
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
export function newResolveArtifactSourceStep<Desc extends DescMessage>(
|
|
41
|
-
|
|
45
|
+
staging: ArchiveStaging | undefined,
|
|
42
46
|
binding: ArtifactSourceBinding<Desc>,
|
|
43
47
|
): PipelineStep<Desc> {
|
|
44
48
|
return {
|
|
@@ -49,16 +53,19 @@ export function newResolveArtifactSourceStep<Desc extends DescMessage>(
|
|
|
49
53
|
ctx.set(ARTIFACT_BYTES_KEY, artifact);
|
|
50
54
|
return;
|
|
51
55
|
}
|
|
52
|
-
if (
|
|
56
|
+
if (staging === undefined) {
|
|
53
57
|
throw failedPreconditionError(binding.laneNotConfigured);
|
|
54
58
|
}
|
|
55
59
|
let data: Uint8Array;
|
|
56
60
|
try {
|
|
57
|
-
data = await
|
|
61
|
+
data = await staging.consume(artifactUploadRef);
|
|
58
62
|
} catch (error) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
if (error instanceof SlotUnknownError) {
|
|
64
|
+
throw invalidArgumentError(
|
|
65
|
+
`artifact_upload_ref not usable: ${error.message} — request a new upload URL via createArtifactUploadUrl`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
62
69
|
}
|
|
63
70
|
ctx.set(ARTIFACT_BYTES_KEY, data);
|
|
64
71
|
},
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The PUBLIC-visibility operator gates — the two write doors a resource
|
|
3
|
+
* can become public through, both consulting the ONE composed Authorizer
|
|
4
|
+
* with the same platform-scoped check (the Java
|
|
5
|
+
* PublicVisibilityEscalationPolicy port; C2 Stage 3, 20260827.10).
|
|
6
|
+
*
|
|
7
|
+
* PUBLIC is the only level that crosses every org boundary (one flip
|
|
8
|
+
* lists a resource in every tenant's cross-org catalog), so entering it
|
|
9
|
+
* is a curation decision: the owner requests, the platform team grants.
|
|
10
|
+
* The answer is `can_set_public_visibility` on `platform:stigmer` — a
|
|
11
|
+
* named operator capability, never a bare operator lookup.
|
|
12
|
+
*
|
|
13
|
+
* - GuardPublicVisibility: the CREATE door, in the create chains of
|
|
14
|
+
* the kinds whose VisibilityConfig supports PUBLIC (agent, workflow,
|
|
15
|
+
* mcp_server, agent_instance, workflow_instance). After
|
|
16
|
+
* BuildNewState — it inspects the state that will persist — which
|
|
17
|
+
* keeps the pinned INVALID_ARGUMENT level-support rejections (the
|
|
18
|
+
* earlier ValidateVisibility) their precedence over this
|
|
19
|
+
* PERMISSION_DENIED.
|
|
20
|
+
* - AuthorizeVisibilityTransition: the UPDATE door, in every
|
|
21
|
+
* updateVisibility chain after ValidateVisibilityUpdate (the pinned
|
|
22
|
+
* FAILED_PRECONDITION default-instance rejection keeps precedence,
|
|
23
|
+
* the Java ordering the conformance suite depends on). Gates only
|
|
24
|
+
* the ESCALATION to public (stored level is anything else).
|
|
25
|
+
*
|
|
26
|
+
* Both run LAZILY — only requests that actually involve the PUBLIC level
|
|
27
|
+
* reach the Authorizer — and both pass for internal callers (server-side
|
|
28
|
+
* flows publish platform resources by design). The OSS permissive
|
|
29
|
+
* default allows, so the local posture keeps today's behavior
|
|
30
|
+
* byte-identically; the cloud's FGA Authorizer supplies the gate.
|
|
31
|
+
*
|
|
32
|
+
* DELIBERATE partial port, recorded owner-visibly (Stage-3 execution
|
|
33
|
+
* record): Java's transition step additionally lets operators WITHOUT
|
|
34
|
+
* resource can_edit publish and take down (its updateVisibility chains
|
|
35
|
+
* authorize post-load, transition-aware); this edition's position-1
|
|
36
|
+
* Authorize enforces can_edit on updateVisibility before any step here
|
|
37
|
+
* runs, so those operator-without-edit lanes require can_edit until the
|
|
38
|
+
* Stage-4 chain disposition addresses them. No conformance lane pins
|
|
39
|
+
* them.
|
|
40
|
+
*/
|
|
41
|
+
import { Code, ConnectError } from "@connectrpc/connect";
|
|
42
|
+
import type { DescMessage } from "@bufbuild/protobuf";
|
|
43
|
+
|
|
44
|
+
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
45
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
46
|
+
import type { UpdateVisibilityInput } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
|
|
47
|
+
import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
48
|
+
|
|
49
|
+
import type { Authorizer, AuthzDecision } from "../../extensions/authorizer.js";
|
|
50
|
+
import type { CallerIdentity } from "../../extensions/identity.js";
|
|
51
|
+
import { internalError } from "../errors.js";
|
|
52
|
+
import type { PipelineStep } from "../pipeline.js";
|
|
53
|
+
import type { RequestContext } from "../request-context.js";
|
|
54
|
+
import { metadataOf } from "./shapes.js";
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The denial callers see at both doors (the Java policy copy verbatim).
|
|
58
|
+
* Deliberately not byte-pinned by the OSS conformance suite; the cloud
|
|
59
|
+
* gate itself is recorded via the clientPublicVisibilityWrites flag.
|
|
60
|
+
*/
|
|
61
|
+
export const PUBLIC_VISIBILITY_DENY_MESSAGE =
|
|
62
|
+
"Public visibility is granted by the platform team. " +
|
|
63
|
+
"Ask a platform operator to publish this resource.";
|
|
64
|
+
|
|
65
|
+
/** The CREATE door: a new state declaring PUBLIC needs the operator grant. */
|
|
66
|
+
export function newGuardPublicVisibilityStep<Desc extends DescMessage>(
|
|
67
|
+
authorizer: Authorizer,
|
|
68
|
+
): PipelineStep<Desc> {
|
|
69
|
+
return {
|
|
70
|
+
name: "GuardPublicVisibility",
|
|
71
|
+
async execute(ctx: RequestContext<Desc>): Promise<void> {
|
|
72
|
+
if (ctx.callerIdentity.callerClass === "internal") {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (
|
|
76
|
+
metadataOf(ctx.newState)?.visibility !==
|
|
77
|
+
ApiResourceVisibility.visibility_public
|
|
78
|
+
) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
await requireOperatorMaySetPublic(authorizer, ctx.callerIdentity);
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The UPDATE door: escalation to PUBLIC (the stored level is anything
|
|
88
|
+
* else) needs the operator grant. Reads the loaded target from the
|
|
89
|
+
* chain's own context key (every updateVisibility chain stores it —
|
|
90
|
+
* the RecordVisibilityBeforeUpdate pattern).
|
|
91
|
+
*/
|
|
92
|
+
export function newAuthorizeVisibilityTransitionStep<Desc extends DescMessage>(
|
|
93
|
+
targetKey: string,
|
|
94
|
+
authorizer: Authorizer,
|
|
95
|
+
): PipelineStep<Desc> {
|
|
96
|
+
return {
|
|
97
|
+
name: "AuthorizeVisibilityTransition",
|
|
98
|
+
async execute(ctx: RequestContext<Desc>): Promise<void> {
|
|
99
|
+
if (ctx.callerIdentity.callerClass === "internal") {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const requested = (ctx.input as unknown as UpdateVisibilityInput)
|
|
103
|
+
.visibility;
|
|
104
|
+
if (requested !== ApiResourceVisibility.visibility_public) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const target = ctx.get(targetKey);
|
|
108
|
+
if (target === undefined) {
|
|
109
|
+
// Wiring error, not a user error: without the loaded target there
|
|
110
|
+
// is no stored level, and a gate that silently passes un-guards
|
|
111
|
+
// the boundary it exists to protect.
|
|
112
|
+
throw internalError(
|
|
113
|
+
new Error(
|
|
114
|
+
"AuthorizeVisibilityTransition ran without a loaded target — step must be placed after the load step",
|
|
115
|
+
),
|
|
116
|
+
"visibility authorization requires the loaded resource",
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
const stored = metadataOf(target as typeof ctx.newState)?.visibility;
|
|
120
|
+
if (stored === ApiResourceVisibility.visibility_public) {
|
|
121
|
+
return; // Re-asserting a stored PUBLIC is not an escalation.
|
|
122
|
+
}
|
|
123
|
+
await requireOperatorMaySetPublic(authorizer, ctx.callerIdentity);
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The single owner of "may this caller set public?" — both doors call it,
|
|
130
|
+
* and so does the plugin push chain, whose requested level rides the
|
|
131
|
+
* request (the level then flows to every member through the members' own
|
|
132
|
+
* create and updateVisibility doors, which run this check again).
|
|
133
|
+
*/
|
|
134
|
+
export async function requireOperatorMaySetPublic(
|
|
135
|
+
authorizer: Authorizer,
|
|
136
|
+
caller: CallerIdentity,
|
|
137
|
+
): Promise<void> {
|
|
138
|
+
let decision: AuthzDecision;
|
|
139
|
+
try {
|
|
140
|
+
decision = await authorizer.authorize(caller, {
|
|
141
|
+
permission: IamPermission.can_set_public_visibility,
|
|
142
|
+
resourceKind: ApiResourceKind.platform,
|
|
143
|
+
resourceId: "stigmer",
|
|
144
|
+
});
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw publicVisibilityCheckFailure(error);
|
|
147
|
+
}
|
|
148
|
+
switch (decision.kind) {
|
|
149
|
+
case "allow":
|
|
150
|
+
return;
|
|
151
|
+
case "deny":
|
|
152
|
+
case "not-found":
|
|
153
|
+
throw new ConnectError(
|
|
154
|
+
PUBLIC_VISIBILITY_DENY_MESSAGE,
|
|
155
|
+
Code.PermissionDenied,
|
|
156
|
+
);
|
|
157
|
+
case "unavailable":
|
|
158
|
+
throw publicVisibilityCheckFailure(decision.cause);
|
|
159
|
+
default: {
|
|
160
|
+
const exhaustive: never = decision;
|
|
161
|
+
throw publicVisibilityCheckFailure(
|
|
162
|
+
new Error(`unknown decision ${JSON.stringify(exhaustive)}`),
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Authorization infrastructure failure: fail closed, sanitized (#478). */
|
|
169
|
+
function publicVisibilityCheckFailure(error: unknown): ConnectError {
|
|
170
|
+
return internalError(
|
|
171
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
172
|
+
"public-visibility authorization could not be completed",
|
|
173
|
+
);
|
|
174
|
+
}
|
|
@@ -25,6 +25,8 @@ function criteria(overrides?: {
|
|
|
25
25
|
kinds?: ApiResourceKind[];
|
|
26
26
|
query?: string;
|
|
27
27
|
org?: string;
|
|
28
|
+
excludePublic?: boolean;
|
|
29
|
+
crossOrgPublic?: boolean;
|
|
28
30
|
pageNumber?: number;
|
|
29
31
|
pageSize?: number;
|
|
30
32
|
}): SearchCriteria {
|
|
@@ -32,6 +34,8 @@ function criteria(overrides?: {
|
|
|
32
34
|
overrides?.kinds ?? [],
|
|
33
35
|
overrides?.query ?? "",
|
|
34
36
|
overrides?.org ?? "",
|
|
37
|
+
overrides?.excludePublic ?? false,
|
|
38
|
+
overrides?.crossOrgPublic ?? false,
|
|
35
39
|
overrides?.pageNumber ?? 1,
|
|
36
40
|
overrides?.pageSize ?? 20,
|
|
37
41
|
);
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* sqlite_search_query_store_test.go (the kind-parsing table) and
|
|
4
4
|
* sqlite_search_query_store_query_test.go (the end-to-end
|
|
5
5
|
* write→index→query pins: session list mode, the #440 emptiness arm, the
|
|
6
|
-
* #439 newly-searchable-kind arm), plus the scope
|
|
7
|
-
*
|
|
6
|
+
* #439 newly-searchable-kind arm), plus the scope-filter matrix
|
|
7
|
+
* (org strict / crossOrgPublic / excludePublic) and RebuildIndex —
|
|
8
8
|
* including the DD-D proof: rebuilding over an ADOPTED Go-created
|
|
9
9
|
* database re-indexes the rows it already holds. The escaping and
|
|
10
10
|
* score-normalization tables moved with their code into the sqlite
|
|
@@ -118,6 +118,8 @@ function criteria(overrides: {
|
|
|
118
118
|
kinds?: ApiResourceKind[];
|
|
119
119
|
query?: string;
|
|
120
120
|
org?: string;
|
|
121
|
+
excludePublic?: boolean;
|
|
122
|
+
crossOrgPublic?: boolean;
|
|
121
123
|
pageNumber?: number;
|
|
122
124
|
pageSize?: number;
|
|
123
125
|
}): SearchCriteria {
|
|
@@ -125,6 +127,8 @@ function criteria(overrides: {
|
|
|
125
127
|
overrides.kinds ?? [],
|
|
126
128
|
overrides.query ?? "",
|
|
127
129
|
overrides.org ?? "",
|
|
130
|
+
overrides.excludePublic ?? false,
|
|
131
|
+
overrides.crossOrgPublic ?? false,
|
|
128
132
|
overrides.pageNumber ?? 1,
|
|
129
133
|
overrides.pageSize ?? 20,
|
|
130
134
|
);
|
|
@@ -245,7 +249,7 @@ describe("write→index→query pins (Go's query_test.go)", () => {
|
|
|
245
249
|
});
|
|
246
250
|
});
|
|
247
251
|
|
|
248
|
-
describe("scope
|
|
252
|
+
describe("scope-filter matrix (Go buildScopeFilter)", () => {
|
|
249
253
|
beforeEach(async () => {
|
|
250
254
|
await seed(
|
|
251
255
|
ApiResourceKind.session,
|
|
@@ -265,10 +269,10 @@ describe("scope filter (the org filter is strict)", () => {
|
|
|
265
269
|
);
|
|
266
270
|
await seed(
|
|
267
271
|
ApiResourceKind.session,
|
|
268
|
-
"ses-b-
|
|
272
|
+
"ses-b-public",
|
|
269
273
|
SessionSchema,
|
|
270
|
-
newSession("ses-b-
|
|
271
|
-
visibility: ApiResourceVisibility.
|
|
274
|
+
newSession("ses-b-public", "org-b", "b public", {
|
|
275
|
+
visibility: ApiResourceVisibility.visibility_public,
|
|
272
276
|
createdAtSeconds: 1_700_000_001,
|
|
273
277
|
}),
|
|
274
278
|
);
|
|
@@ -284,15 +288,38 @@ describe("scope filter (the org filter is strict)", () => {
|
|
|
284
288
|
expect(ids(result)).toEqual(["ses-a-private"]);
|
|
285
289
|
});
|
|
286
290
|
|
|
287
|
-
it("
|
|
291
|
+
it("crossOrgPublic widens to OTHER orgs' public rows only", async () => {
|
|
288
292
|
const result = await queryStore.search(
|
|
289
|
-
criteria({
|
|
293
|
+
criteria({
|
|
294
|
+
kinds: [ApiResourceKind.session],
|
|
295
|
+
org: "org-a",
|
|
296
|
+
crossOrgPublic: true,
|
|
297
|
+
}),
|
|
290
298
|
);
|
|
291
299
|
expect(new Set(ids(result))).toEqual(
|
|
292
|
-
new Set(["ses-
|
|
300
|
+
new Set(["ses-a-private", "ses-b-public"]),
|
|
293
301
|
);
|
|
294
302
|
});
|
|
295
303
|
|
|
304
|
+
it("excludePublic subtracts public rows from any scope", async () => {
|
|
305
|
+
const unscoped = await queryStore.search(
|
|
306
|
+
criteria({ kinds: [ApiResourceKind.session], excludePublic: true }),
|
|
307
|
+
);
|
|
308
|
+
expect(new Set(ids(unscoped))).toEqual(
|
|
309
|
+
new Set(["ses-a-private", "ses-b-private"]),
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
const widened = await queryStore.search(
|
|
313
|
+
criteria({
|
|
314
|
+
kinds: [ApiResourceKind.session],
|
|
315
|
+
org: "org-a",
|
|
316
|
+
crossOrgPublic: true,
|
|
317
|
+
excludePublic: true,
|
|
318
|
+
}),
|
|
319
|
+
);
|
|
320
|
+
expect(ids(widened)).toEqual(["ses-a-private"]);
|
|
321
|
+
});
|
|
322
|
+
|
|
296
323
|
it("no org filter returns every row, newest first (list mode ordering)", async () => {
|
|
297
324
|
const result = await queryStore.search(
|
|
298
325
|
criteria({ kinds: [ApiResourceKind.session] }),
|
|
@@ -300,7 +327,7 @@ describe("scope filter (the org filter is strict)", () => {
|
|
|
300
327
|
expect(ids(result)).toEqual([
|
|
301
328
|
"ses-a-private",
|
|
302
329
|
"ses-b-private",
|
|
303
|
-
"ses-b-
|
|
330
|
+
"ses-b-public",
|
|
304
331
|
]);
|
|
305
332
|
});
|
|
306
333
|
});
|
|
@@ -447,7 +474,9 @@ describe("rebuildIndex", () => {
|
|
|
447
474
|
"skl_1",
|
|
448
475
|
SkillSchema,
|
|
449
476
|
);
|
|
450
|
-
expect(toBinary(SkillSchema, raw)).toEqual(
|
|
477
|
+
expect(toBinary(SkillSchema, raw)).toEqual(
|
|
478
|
+
toBinary(SkillSchema, skill),
|
|
479
|
+
);
|
|
451
480
|
} finally {
|
|
452
481
|
await adopted.close();
|
|
453
482
|
fixture.cleanup();
|
|
@@ -98,6 +98,8 @@ export class SearchCriteria {
|
|
|
98
98
|
private readonly requestedKinds: readonly ApiResourceKind[],
|
|
99
99
|
private readonly queryText: string,
|
|
100
100
|
private readonly orgFilterValue: string,
|
|
101
|
+
private readonly excludePublicFlag: boolean,
|
|
102
|
+
private readonly crossOrgPublicFlag: boolean,
|
|
101
103
|
private readonly pageNumberValue: number,
|
|
102
104
|
private readonly pageSizeValue: number,
|
|
103
105
|
) {}
|
|
@@ -119,6 +121,8 @@ export class SearchCriteria {
|
|
|
119
121
|
kinds: readonly ApiResourceKind[],
|
|
120
122
|
query: string,
|
|
121
123
|
orgFilter: string,
|
|
124
|
+
excludePublic: boolean,
|
|
125
|
+
crossOrgPublic: boolean,
|
|
122
126
|
pageNumber: number,
|
|
123
127
|
pageSize: number,
|
|
124
128
|
): SearchCriteria {
|
|
@@ -132,6 +136,8 @@ export class SearchCriteria {
|
|
|
132
136
|
[...kinds],
|
|
133
137
|
normalizedQuery,
|
|
134
138
|
goTrimSpace(orgFilter),
|
|
139
|
+
excludePublic,
|
|
140
|
+
crossOrgPublic,
|
|
135
141
|
pageNumber < 1 ? 1 : pageNumber,
|
|
136
142
|
pageSize < 1 ? DEFAULT_PAGE_SIZE : Math.min(pageSize, MAX_PAGE_SIZE),
|
|
137
143
|
);
|
|
@@ -150,6 +156,14 @@ export class SearchCriteria {
|
|
|
150
156
|
return this.orgFilterValue;
|
|
151
157
|
}
|
|
152
158
|
|
|
159
|
+
excludePublic(): boolean {
|
|
160
|
+
return this.excludePublicFlag;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
crossOrgPublic(): boolean {
|
|
164
|
+
return this.crossOrgPublicFlag;
|
|
165
|
+
}
|
|
166
|
+
|
|
153
167
|
pageNumber(): number {
|
|
154
168
|
return this.pageNumberValue;
|
|
155
169
|
}
|
|
@@ -52,11 +52,10 @@ export class SearchHandler {
|
|
|
52
52
|
* mapping string-matches them (#478 sanitization contract).
|
|
53
53
|
*
|
|
54
54
|
* With a composed ListReadScope (20260830.01, census lane 21) the
|
|
55
|
-
* store read
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* visibility with FGA never consulted) left with the level. A scope
|
|
55
|
+
* store read carries a per-effective-kind authorized-id map — the Java
|
|
56
|
+
* SearchHandler's QueryAuthorizedIds step, with its crossOrgPublic
|
|
57
|
+
* bypass preserved verbatim (public-widened discovery is
|
|
58
|
+
* visibility-filtered by the engine, FGA never consulted). A scope
|
|
60
59
|
* failure propagates — the controller's default arm answers the
|
|
61
60
|
* sanitized Internal, never a silently unscoped result.
|
|
62
61
|
*/
|
|
@@ -75,6 +74,8 @@ export class SearchHandler {
|
|
|
75
74
|
request.kinds,
|
|
76
75
|
request.query,
|
|
77
76
|
request.org,
|
|
77
|
+
request.excludePublic,
|
|
78
|
+
request.crossOrgPublic,
|
|
78
79
|
request.page?.num ?? 0,
|
|
79
80
|
request.page?.size ?? 0,
|
|
80
81
|
);
|
|
@@ -86,7 +87,7 @@ export class SearchHandler {
|
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
let authorizedIdsByKind: Map<string, ReadonlySet<string>> | undefined;
|
|
89
|
-
if (this.listReadScope !== undefined) {
|
|
90
|
+
if (this.listReadScope !== undefined && !criteria.crossOrgPublic()) {
|
|
90
91
|
authorizedIdsByKind = new Map<string, ReadonlySet<string>>();
|
|
91
92
|
for (const kind of criteria.effectiveKinds()) {
|
|
92
93
|
authorizedIdsByKind.set(
|
|
@@ -81,6 +81,8 @@ export class SqliteSearchQueryStore implements SearchQueryStore {
|
|
|
81
81
|
// is already goTrimSpace'd). Engine syntax is the driver's job.
|
|
82
82
|
terms: criteria.hasQuery() ? goFields(criteria.query()) : undefined,
|
|
83
83
|
orgFilter: criteria.orgFilter(),
|
|
84
|
+
crossOrgPublic: criteria.crossOrgPublic(),
|
|
85
|
+
excludePublic: criteria.excludePublic(),
|
|
84
86
|
limit: criteria.pageSize(),
|
|
85
87
|
offset: criteria.offset(),
|
|
86
88
|
});
|
|
@@ -934,6 +934,8 @@ export function describeStoreContract(
|
|
|
934
934
|
kinds: ["agent"],
|
|
935
935
|
terms: ["kubernetes"],
|
|
936
936
|
orgFilter: "",
|
|
937
|
+
crossOrgPublic: false,
|
|
938
|
+
excludePublic: false,
|
|
937
939
|
limit: 20,
|
|
938
940
|
offset: 0,
|
|
939
941
|
});
|
|
@@ -957,6 +959,8 @@ export function describeStoreContract(
|
|
|
957
959
|
kinds: ["agent"],
|
|
958
960
|
terms: ["kuber"],
|
|
959
961
|
orgFilter: "",
|
|
962
|
+
crossOrgPublic: false,
|
|
963
|
+
excludePublic: false,
|
|
960
964
|
limit: 20,
|
|
961
965
|
offset: 0,
|
|
962
966
|
});
|
|
@@ -966,6 +970,8 @@ export function describeStoreContract(
|
|
|
966
970
|
kinds: ["agent"],
|
|
967
971
|
terms: ["kubernetes", "deployment"],
|
|
968
972
|
orgFilter: "",
|
|
973
|
+
crossOrgPublic: false,
|
|
974
|
+
excludePublic: false,
|
|
969
975
|
limit: 20,
|
|
970
976
|
offset: 0,
|
|
971
977
|
});
|
|
@@ -975,6 +981,8 @@ export function describeStoreContract(
|
|
|
975
981
|
kinds: ["agent"],
|
|
976
982
|
terms: ["kubernetes", "absent"],
|
|
977
983
|
orgFilter: "",
|
|
984
|
+
crossOrgPublic: false,
|
|
985
|
+
excludePublic: false,
|
|
978
986
|
limit: 20,
|
|
979
987
|
offset: 0,
|
|
980
988
|
});
|
|
@@ -1000,6 +1008,8 @@ export function describeStoreContract(
|
|
|
1000
1008
|
kinds: ["agent"],
|
|
1001
1009
|
terms: ["NEAR", "plain"],
|
|
1002
1010
|
orgFilter: "",
|
|
1011
|
+
crossOrgPublic: false,
|
|
1012
|
+
excludePublic: false,
|
|
1003
1013
|
limit: 20,
|
|
1004
1014
|
offset: 0,
|
|
1005
1015
|
});
|
|
@@ -1029,6 +1039,8 @@ export function describeStoreContract(
|
|
|
1029
1039
|
kinds: ["agent", "workflow"],
|
|
1030
1040
|
terms: ["scoped"],
|
|
1031
1041
|
orgFilter: "",
|
|
1042
|
+
crossOrgPublic: false,
|
|
1043
|
+
excludePublic: false,
|
|
1032
1044
|
authorizedIdsByKind: new Map([["agent", new Set(["agt-mine"])]]),
|
|
1033
1045
|
limit: 20,
|
|
1034
1046
|
offset: 0,
|
|
@@ -1044,6 +1056,8 @@ export function describeStoreContract(
|
|
|
1044
1056
|
kinds: ["agent", "workflow"],
|
|
1045
1057
|
terms: ["scoped"],
|
|
1046
1058
|
orgFilter: "",
|
|
1059
|
+
crossOrgPublic: false,
|
|
1060
|
+
excludePublic: false,
|
|
1047
1061
|
authorizedIdsByKind: new Map([
|
|
1048
1062
|
["agent", new Set<string>()],
|
|
1049
1063
|
["workflow", new Set(["wfl-any"])],
|
|
@@ -1058,6 +1072,8 @@ export function describeStoreContract(
|
|
|
1058
1072
|
kinds: ["agent", "workflow"],
|
|
1059
1073
|
terms: ["scoped"],
|
|
1060
1074
|
orgFilter: "",
|
|
1075
|
+
crossOrgPublic: false,
|
|
1076
|
+
excludePublic: false,
|
|
1061
1077
|
authorizedIdsByKind: new Map([
|
|
1062
1078
|
["agent", new Set<string>()],
|
|
1063
1079
|
["workflow", new Set<string>()],
|
|
@@ -1073,13 +1089,15 @@ export function describeStoreContract(
|
|
|
1073
1089
|
kinds: ["agent", "workflow"],
|
|
1074
1090
|
terms: ["scoped"],
|
|
1075
1091
|
orgFilter: "",
|
|
1092
|
+
crossOrgPublic: false,
|
|
1093
|
+
excludePublic: false,
|
|
1076
1094
|
limit: 20,
|
|
1077
1095
|
offset: 0,
|
|
1078
1096
|
});
|
|
1079
1097
|
expect(unscoped.totalCount).toBe(3);
|
|
1080
1098
|
});
|
|
1081
1099
|
|
|
1082
|
-
it("org scoping
|
|
1100
|
+
it("org scoping: strict filter, cross-org public widening, and the public subtraction", async () => {
|
|
1083
1101
|
await fx.store.upsertSearchIndex(
|
|
1084
1102
|
ApiResourceKind.agent,
|
|
1085
1103
|
"agt-mine",
|
|
@@ -1087,11 +1105,11 @@ export function describeStoreContract(
|
|
|
1087
1105
|
);
|
|
1088
1106
|
await fx.store.upsertSearchIndex(
|
|
1089
1107
|
ApiResourceKind.agent,
|
|
1090
|
-
"agt-
|
|
1108
|
+
"agt-public",
|
|
1091
1109
|
entry({
|
|
1092
1110
|
name: "searchable beta",
|
|
1093
1111
|
org: "globex",
|
|
1094
|
-
visibility: "
|
|
1112
|
+
visibility: "visibility_public",
|
|
1095
1113
|
}),
|
|
1096
1114
|
);
|
|
1097
1115
|
await fx.store.upsertSearchIndex(
|
|
@@ -1104,20 +1122,37 @@ export function describeStoreContract(
|
|
|
1104
1122
|
kinds: ["agent"],
|
|
1105
1123
|
terms: ["searchable"],
|
|
1106
1124
|
orgFilter: "acme",
|
|
1125
|
+
crossOrgPublic: false,
|
|
1126
|
+
excludePublic: false,
|
|
1107
1127
|
limit: 20,
|
|
1108
1128
|
offset: 0,
|
|
1109
1129
|
});
|
|
1110
1130
|
expect(strict.hits.map((hit) => hit.resourceId)).toEqual(["agt-mine"]);
|
|
1111
1131
|
|
|
1112
|
-
const
|
|
1132
|
+
const widened = await fx.store.querySearchIndex({
|
|
1133
|
+
kinds: ["agent"],
|
|
1134
|
+
terms: ["searchable"],
|
|
1135
|
+
orgFilter: "acme",
|
|
1136
|
+
crossOrgPublic: true,
|
|
1137
|
+
excludePublic: false,
|
|
1138
|
+
limit: 20,
|
|
1139
|
+
offset: 0,
|
|
1140
|
+
});
|
|
1141
|
+
expect(new Set(widened.hits.map((hit) => hit.resourceId))).toEqual(
|
|
1142
|
+
new Set(["agt-mine", "agt-public"]),
|
|
1143
|
+
);
|
|
1144
|
+
|
|
1145
|
+
const noPublic = await fx.store.querySearchIndex({
|
|
1113
1146
|
kinds: ["agent"],
|
|
1114
1147
|
terms: ["searchable"],
|
|
1115
1148
|
orgFilter: "",
|
|
1149
|
+
crossOrgPublic: false,
|
|
1150
|
+
excludePublic: true,
|
|
1116
1151
|
limit: 20,
|
|
1117
1152
|
offset: 0,
|
|
1118
1153
|
});
|
|
1119
|
-
expect(new Set(
|
|
1120
|
-
new Set(["agt-mine", "agt-
|
|
1154
|
+
expect(new Set(noPublic.hits.map((hit) => hit.resourceId))).toEqual(
|
|
1155
|
+
new Set(["agt-mine", "agt-foreign"]),
|
|
1121
1156
|
);
|
|
1122
1157
|
});
|
|
1123
1158
|
|
|
@@ -1137,6 +1172,8 @@ export function describeStoreContract(
|
|
|
1137
1172
|
kinds: ["agent"],
|
|
1138
1173
|
terms: undefined,
|
|
1139
1174
|
orgFilter: "",
|
|
1175
|
+
crossOrgPublic: false,
|
|
1176
|
+
excludePublic: false,
|
|
1140
1177
|
limit: 20,
|
|
1141
1178
|
offset: 0,
|
|
1142
1179
|
});
|
|
@@ -1166,6 +1203,8 @@ export function describeStoreContract(
|
|
|
1166
1203
|
kinds: ["organization"],
|
|
1167
1204
|
terms: ["original"],
|
|
1168
1205
|
orgFilter: "",
|
|
1206
|
+
crossOrgPublic: false,
|
|
1207
|
+
excludePublic: false,
|
|
1169
1208
|
limit: 20,
|
|
1170
1209
|
offset: 0,
|
|
1171
1210
|
});
|
|
@@ -1175,6 +1214,8 @@ export function describeStoreContract(
|
|
|
1175
1214
|
kinds: ["organization"],
|
|
1176
1215
|
terms: ["renamed"],
|
|
1177
1216
|
orgFilter: "",
|
|
1217
|
+
crossOrgPublic: false,
|
|
1218
|
+
excludePublic: false,
|
|
1178
1219
|
limit: 20,
|
|
1179
1220
|
offset: 0,
|
|
1180
1221
|
});
|
|
@@ -1185,6 +1226,8 @@ export function describeStoreContract(
|
|
|
1185
1226
|
kinds: ["organization"],
|
|
1186
1227
|
terms: undefined,
|
|
1187
1228
|
orgFilter: "",
|
|
1229
|
+
crossOrgPublic: false,
|
|
1230
|
+
excludePublic: false,
|
|
1188
1231
|
limit: 20,
|
|
1189
1232
|
offset: 0,
|
|
1190
1233
|
});
|
|
@@ -1200,6 +1243,8 @@ export function describeStoreContract(
|
|
|
1200
1243
|
kinds: ["organization"],
|
|
1201
1244
|
terms: undefined,
|
|
1202
1245
|
orgFilter: "",
|
|
1246
|
+
crossOrgPublic: false,
|
|
1247
|
+
excludePublic: false,
|
|
1203
1248
|
limit: 20,
|
|
1204
1249
|
offset: 0,
|
|
1205
1250
|
});
|
package/src/store/interface.ts
CHANGED
|
@@ -135,9 +135,8 @@ export interface SearchIndexEntry {
|
|
|
135
135
|
/** Owning org (metadata.org) — org-scoped filtering. */
|
|
136
136
|
readonly org: string;
|
|
137
137
|
/**
|
|
138
|
-
* Visibility enum NAME (e.g. "
|
|
139
|
-
*
|
|
140
|
-
* this column.
|
|
138
|
+
* Visibility enum NAME (e.g. "visibility_public"); scope filtering only
|
|
139
|
+
* special-cases "visibility_public", all other levels are org-scoped.
|
|
141
140
|
*/
|
|
142
141
|
readonly visibility: string;
|
|
143
142
|
/** Unix seconds creation time — sorting in list mode (no query). */
|
|
@@ -167,6 +166,10 @@ export interface SearchIndexQuery {
|
|
|
167
166
|
readonly terms: readonly string[] | undefined;
|
|
168
167
|
/** Org scope; "" = no org filter. */
|
|
169
168
|
readonly orgFilter: string;
|
|
169
|
+
/** With orgFilter: also admit visibility_public rows from ANY org. */
|
|
170
|
+
readonly crossOrgPublic: boolean;
|
|
171
|
+
/** Independent subtraction: drop visibility_public rows from any scope. */
|
|
172
|
+
readonly excludePublic: boolean;
|
|
170
173
|
/**
|
|
171
174
|
* Optional per-kind authorized-id allowlist (kind NAME → ids) — the
|
|
172
175
|
* multi-tenant list-read scoping arm (20260830.01): a listed kind
|