@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
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pins the create lane's two
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* spends the organization's credits on the open internet (an admin's). A
|
|
9
|
-
* missing referenced agent throws.
|
|
2
|
+
* Pins the create lane's two-arm consent bar (steps.ts,
|
|
3
|
+
* resolveShareCreateTargets), the Java handler's: a same-org share asks
|
|
4
|
+
* can_edit on the referenced agent; a cross-org share asks can_execute on
|
|
5
|
+
* the agent and then can_create_agent_share on the SHARING organization,
|
|
6
|
+
* agent first; each question carries its byte-pinned copy; a missing
|
|
7
|
+
* referenced agent throws.
|
|
10
8
|
*/
|
|
11
9
|
import { describe, expect, it } from "vitest";
|
|
12
10
|
import { create } from "@bufbuild/protobuf";
|
|
@@ -26,15 +24,15 @@ import {
|
|
|
26
24
|
} from "../steps.js";
|
|
27
25
|
|
|
28
26
|
const agent = create(AgentSchema, {
|
|
29
|
-
metadata: { id: "
|
|
27
|
+
metadata: { id: "agt_01public", name: "helper", org: "publisher-org" },
|
|
30
28
|
});
|
|
31
29
|
|
|
32
|
-
function ctxFor(shareOrg: string, stash = true) {
|
|
30
|
+
function ctxFor(shareOrg: string, agentOrg: string, stash = true) {
|
|
33
31
|
const ctx = new RequestContext(
|
|
34
32
|
AgentShareSchema,
|
|
35
33
|
create(AgentShareSchema, {
|
|
36
34
|
metadata: { name: "helper", org: shareOrg },
|
|
37
|
-
spec: { agentRef: { org:
|
|
35
|
+
spec: { agentRef: { org: agentOrg, slug: "helper" } },
|
|
38
36
|
}),
|
|
39
37
|
testCallerIdentity(),
|
|
40
38
|
ApiResourceKind.agent_share,
|
|
@@ -46,18 +44,33 @@ function ctxFor(shareOrg: string, stash = true) {
|
|
|
46
44
|
}
|
|
47
45
|
|
|
48
46
|
describe("resolveShareCreateTargets", () => {
|
|
49
|
-
it("asks can_edit on the referenced agent
|
|
50
|
-
expect(
|
|
47
|
+
it("a same-org share asks can_edit on the referenced agent", () => {
|
|
48
|
+
expect(
|
|
49
|
+
resolveShareCreateTargets(ctxFor("publisher-org", "publisher-org")),
|
|
50
|
+
).toEqual([
|
|
51
51
|
{
|
|
52
52
|
permission: IamPermission.can_edit,
|
|
53
53
|
resourceKind: ApiResourceKind.agent,
|
|
54
|
-
resourceId: "
|
|
54
|
+
resourceId: "agt_01public",
|
|
55
|
+
deniedMessage: SHARE_AGENT_DENIED_MESSAGE,
|
|
56
|
+
},
|
|
57
|
+
]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("a cross-org share asks can_execute on the agent, then can_create_agent_share on the sharing organization", () => {
|
|
61
|
+
expect(
|
|
62
|
+
resolveShareCreateTargets(ctxFor("consumer-org", "publisher-org")),
|
|
63
|
+
).toEqual([
|
|
64
|
+
{
|
|
65
|
+
permission: IamPermission.can_execute,
|
|
66
|
+
resourceKind: ApiResourceKind.agent,
|
|
67
|
+
resourceId: "agt_01public",
|
|
55
68
|
deniedMessage: SHARE_AGENT_DENIED_MESSAGE,
|
|
56
69
|
},
|
|
57
70
|
{
|
|
58
71
|
permission: IamPermission.can_create_agent_share,
|
|
59
72
|
resourceKind: ApiResourceKind.organization,
|
|
60
|
-
resourceId: "
|
|
73
|
+
resourceId: "consumer-org",
|
|
61
74
|
deniedMessage: SHARE_ORGANIZATION_DENIED_MESSAGE,
|
|
62
75
|
},
|
|
63
76
|
]);
|
|
@@ -65,7 +78,9 @@ describe("resolveShareCreateTargets", () => {
|
|
|
65
78
|
|
|
66
79
|
it("a missing referenced agent is a broken chain invariant and throws", () => {
|
|
67
80
|
expect(() =>
|
|
68
|
-
resolveShareCreateTargets(
|
|
81
|
+
resolveShareCreateTargets(
|
|
82
|
+
ctxFor("publisher-org", "publisher-org", false),
|
|
83
|
+
),
|
|
69
84
|
).toThrow("referenced agent not found in context");
|
|
70
85
|
});
|
|
71
86
|
});
|
|
@@ -17,12 +17,10 @@ export const SHARE_LINK_TOKEN_BYTES = 20;
|
|
|
17
17
|
* resolveShareDefaultsStep, byte-pinned. The share's org appears in the
|
|
18
18
|
* hosted chat URL and is the billing org, so it can never be inferred.
|
|
19
19
|
*/
|
|
20
|
-
export const ORG_REQUIRED_MESSAGE =
|
|
21
|
-
"metadata.org is required for an agent share";
|
|
20
|
+
export const ORG_REQUIRED_MESSAGE = "metadata.org is required for an agent share";
|
|
22
21
|
|
|
23
22
|
/** InvalidArgument copy when spec.agent_ref.slug is absent — Go, pinned. */
|
|
24
|
-
export const AGENT_REF_SLUG_REQUIRED_MESSAGE =
|
|
25
|
-
"spec.agent_ref.slug is required";
|
|
23
|
+
export const AGENT_REF_SLUG_REQUIRED_MESSAGE = "spec.agent_ref.slug is required";
|
|
26
24
|
|
|
27
25
|
/**
|
|
28
26
|
* InvalidArgument copy for BOTH profile lanes when org is absent — Go
|
|
@@ -30,20 +28,34 @@ export const AGENT_REF_SLUG_REQUIRED_MESSAGE =
|
|
|
30
28
|
* Anti-enumeration: an empty org would mean "match slug across all orgs"
|
|
31
29
|
* on a public endpoint.
|
|
32
30
|
*/
|
|
33
|
-
export const ORG_REQUIRED_FOR_LOOKUP_MESSAGE =
|
|
34
|
-
"org is required for shared agent lookup";
|
|
31
|
+
export const ORG_REQUIRED_FOR_LOOKUP_MESSAGE = "org is required for shared agent lookup";
|
|
35
32
|
|
|
36
33
|
/**
|
|
37
|
-
* FailedPrecondition copy
|
|
38
|
-
*
|
|
39
|
-
* the
|
|
40
|
-
* owns; to share another organization's agent, install the plugin that
|
|
41
|
-
* carries it and share the installed copy.
|
|
34
|
+
* FailedPrecondition copy for an org-audience cross-org share (decision
|
|
35
|
+
* 013 D3) — Go validateCrossOrgShare AND validateShareUpdateStep (update
|
|
36
|
+
* replaces the spec wholesale and must not open a side door), byte-pinned.
|
|
42
37
|
*/
|
|
43
|
-
export function
|
|
38
|
+
export function crossOrgAudienceMessage(agentOrg: string): string {
|
|
44
39
|
return (
|
|
45
|
-
"
|
|
46
|
-
`the
|
|
40
|
+
"a cross-org share must have a public audience — org-audience shares " +
|
|
41
|
+
`are limited to the agent's own organization (${agentOrg})`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* FailedPrecondition copy naming every non-public dependency blocking a
|
|
47
|
+
* cross-org share (decision 013 D5) — Go validateCrossOrgShare,
|
|
48
|
+
* byte-pinned. Blockers are deduped, formatted "<kind> <org>/<slug>", and
|
|
49
|
+
* sorted, so the refusal is deterministic.
|
|
50
|
+
*/
|
|
51
|
+
export function crossOrgBlockersMessage(
|
|
52
|
+
agentOrg: string,
|
|
53
|
+
agentSlug: string,
|
|
54
|
+
blockers: readonly string[],
|
|
55
|
+
): string {
|
|
56
|
+
return (
|
|
57
|
+
`cannot share ${agentOrg}/${agentSlug} across organizations: ` +
|
|
58
|
+
`it references resources that are not public: ${blockers.join(", ")}`
|
|
47
59
|
);
|
|
48
60
|
}
|
|
49
61
|
|
|
@@ -93,10 +93,7 @@ import {
|
|
|
93
93
|
TARGET_RESOURCE_KEY,
|
|
94
94
|
newLoadTargetStep,
|
|
95
95
|
} from "../../pipeline/steps/load-target.js";
|
|
96
|
-
import {
|
|
97
|
-
newNormalizeReferencesStep,
|
|
98
|
-
newValidateReferencesStep,
|
|
99
|
-
} from "../../pipeline/steps/references.js";
|
|
96
|
+
import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
|
|
100
97
|
import {
|
|
101
98
|
newCleanupIamPoliciesStep,
|
|
102
99
|
newCreateAuthorizationTuplesStep,
|
|
@@ -198,7 +195,6 @@ async function createShare(
|
|
|
198
195
|
.addStep(newGuardReservedLabelsStep(deps.authorizer))
|
|
199
196
|
.addStep(newStampAgentPinStep())
|
|
200
197
|
.addStep(newNormalizeReferencesStep())
|
|
201
|
-
.addStep(newValidateReferencesStep(deps.store))
|
|
202
198
|
.addStep(newPersistStep(deps.store))
|
|
203
199
|
.addStep(
|
|
204
200
|
newCreateAuthorizationTuplesStep(
|
|
@@ -243,7 +239,6 @@ async function update(
|
|
|
243
239
|
.addStep(newBuildUpdateStateStep())
|
|
244
240
|
.addStep(newGuardReservedLabelsStep(deps.authorizer))
|
|
245
241
|
.addStep(newNormalizeReferencesStep())
|
|
246
|
-
.addStep(newValidateReferencesStep(deps.store))
|
|
247
242
|
.addStep(newPersistStep(deps.store))
|
|
248
243
|
.build()
|
|
249
244
|
.execute(reqCtx);
|
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AgentShare domain steps — ports pkg/domain/agentshare/controller/steps.go
|
|
3
|
-
* and the get_shared_profile.go helpers: share defaults
|
|
4
|
-
*
|
|
3
|
+
* and the get_shared_profile.go helpers: share defaults + the cross-org
|
|
4
|
+
* public-dependency contract (decision 013), the agent-id rebind pin, the
|
|
5
5
|
* update immutability rules, the uniform-NotFound profile resolution
|
|
6
6
|
* helpers, and the constant-time link-token predicate.
|
|
7
7
|
*
|
|
8
|
-
* A share's agent lives in the share's own organization. The
|
|
9
|
-
* cross-organization arm this domain once carried (a share of another
|
|
10
|
-
* organization's public agent, gated on a public audience and a sweep of
|
|
11
|
-
* the agent's dependencies for public visibility) left with the public
|
|
12
|
-
* level; sharing another organization's agent is done by installing the
|
|
13
|
-
* plugin that carries it and sharing the installed copy. A stored share
|
|
14
|
-
* whose agent is in another organization — a row from before — fails
|
|
15
|
-
* closed at the profile like a dangling reference.
|
|
16
|
-
*
|
|
17
8
|
* OD-1 (deliberate exclusion): Go's boot migration
|
|
18
9
|
* (pkg/domain/agentshare/migration/bootstrap_shares.go — protowire
|
|
19
10
|
* decoding of the REMOVED Agent.spec.sharing fields into AgentShare rows)
|
|
@@ -38,6 +29,11 @@ import type { AgentShare } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v
|
|
|
38
29
|
import { AgentShareStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/status_pb";
|
|
39
30
|
import { SharedAgentProfileSchema } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/io_pb";
|
|
40
31
|
import type { SharedAgentProfile } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/io_pb";
|
|
32
|
+
import { AgentShareAudience } from "@stigmer/protos/ai/stigmer/agentic/agentshare/v1/spec_pb";
|
|
33
|
+
import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
|
|
34
|
+
import { SkillSchema } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/api_pb";
|
|
35
|
+
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
36
|
+
import type { ApiResourceReference } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
|
|
41
37
|
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
42
38
|
import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
43
39
|
|
|
@@ -56,6 +52,7 @@ import {
|
|
|
56
52
|
} from "../../pipeline/steps/authorize.js";
|
|
57
53
|
import type { AuthorizationTarget } from "../../pipeline/steps/authorize.js";
|
|
58
54
|
import type { GetByReferenceDesc } from "../../pipeline/steps/authorize-resolved-target.js";
|
|
55
|
+
import { findResourceBySlug } from "../../pipeline/steps/helpers.js";
|
|
59
56
|
import { EXISTING_RESOURCE_KEY } from "../../pipeline/steps/load-existing.js";
|
|
60
57
|
import type { Store } from "../../store/interface.js";
|
|
61
58
|
import {
|
|
@@ -63,7 +60,8 @@ import {
|
|
|
63
60
|
ORG_REQUIRED_MESSAGE,
|
|
64
61
|
SHARE_LINK_TOKEN_BYTES,
|
|
65
62
|
agentRefImmutableMessage,
|
|
66
|
-
|
|
63
|
+
crossOrgAudienceMessage,
|
|
64
|
+
crossOrgBlockersMessage,
|
|
67
65
|
} from "./constants.js";
|
|
68
66
|
|
|
69
67
|
type AgentShareDesc = typeof AgentShareSchema;
|
|
@@ -86,14 +84,21 @@ export const SHARE_ORGANIZATION_DENIED_MESSAGE =
|
|
|
86
84
|
|
|
87
85
|
/**
|
|
88
86
|
* The create lane's authorization questions, for AuthorizeResolvedTarget
|
|
89
|
-
* after ResolveShareDefaults
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* made the reference absolute
|
|
96
|
-
*
|
|
87
|
+
* after ResolveShareDefaults: the two-arm consent bar the Java handler
|
|
88
|
+
* enforced and the model's comment on can_create_agent_share describes.
|
|
89
|
+
* The RPC is is_skip_authorization because the target is the referenced
|
|
90
|
+
* agent, resolved from a slug, not a request field.
|
|
91
|
+
*
|
|
92
|
+
* A same-org share (spec.agent_ref.org equals metadata.org, after the
|
|
93
|
+
* resolve step made the reference absolute) asks can_edit on the agent:
|
|
94
|
+
* sharing puts the agent in front of a wider audience, an editor's act.
|
|
95
|
+
*
|
|
96
|
+
* A cross-org share of another organization's public agent asks two
|
|
97
|
+
* questions, agent first as Java did: can_execute on the agent (whoever may
|
|
98
|
+
* run it may offer it) and then can_create_agent_share on the SHARING
|
|
99
|
+
* organization — a public share spends that organization's credits on the
|
|
100
|
+
* open internet, an admin-level act. The cross-org validity rules (public
|
|
101
|
+
* agent, no org audience, public dependencies) stay the resolve step's.
|
|
97
102
|
*/
|
|
98
103
|
export function resolveShareCreateTargets(
|
|
99
104
|
ctx: RequestContext<AgentShareDesc>,
|
|
@@ -102,17 +107,24 @@ export function resolveShareCreateTargets(
|
|
|
102
107
|
if (agent === undefined) {
|
|
103
108
|
throw new Error("referenced agent not found in context");
|
|
104
109
|
}
|
|
110
|
+
const share = ctx.newState;
|
|
111
|
+
const shareOrg = share.metadata?.org ?? "";
|
|
112
|
+
const crossOrg = (share.spec?.agentRef?.org ?? "") !== shareOrg;
|
|
113
|
+
const agentBar: AuthorizationTarget = {
|
|
114
|
+
permission: crossOrg ? IamPermission.can_execute : IamPermission.can_edit,
|
|
115
|
+
resourceKind: ApiResourceKind.agent,
|
|
116
|
+
resourceId: agent.metadata?.id ?? "",
|
|
117
|
+
deniedMessage: SHARE_AGENT_DENIED_MESSAGE,
|
|
118
|
+
};
|
|
119
|
+
if (!crossOrg) {
|
|
120
|
+
return [agentBar];
|
|
121
|
+
}
|
|
105
122
|
return [
|
|
106
|
-
|
|
107
|
-
permission: IamPermission.can_edit,
|
|
108
|
-
resourceKind: ApiResourceKind.agent,
|
|
109
|
-
resourceId: agent.metadata?.id ?? "",
|
|
110
|
-
deniedMessage: SHARE_AGENT_DENIED_MESSAGE,
|
|
111
|
-
},
|
|
123
|
+
agentBar,
|
|
112
124
|
{
|
|
113
125
|
permission: IamPermission.can_create_agent_share,
|
|
114
126
|
resourceKind: ApiResourceKind.organization,
|
|
115
|
-
resourceId:
|
|
127
|
+
resourceId: shareOrg,
|
|
116
128
|
deniedMessage: SHARE_ORGANIZATION_DENIED_MESSAGE,
|
|
117
129
|
},
|
|
118
130
|
];
|
|
@@ -294,12 +306,10 @@ export async function findShareByOrgAndSlug(
|
|
|
294
306
|
/**
|
|
295
307
|
* ResolveShareDefaults — Go resolveShareDefaultsStep:
|
|
296
308
|
* 1. Requires metadata.org (URL + billing identity, never inferred).
|
|
297
|
-
* 2. Normalizes spec.agent_ref.org (empty means same-org) and
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
* 3. Loads the referenced agent — a nonexistent agent is refused with
|
|
302
|
-
* the same NOT_FOUND a direct agent lookup would produce.
|
|
309
|
+
* 2. Normalizes spec.agent_ref.org (empty means same-org) and loads the
|
|
310
|
+
* referenced agent — a nonexistent agent is refused with the same
|
|
311
|
+
* NOT_FOUND a direct agent lookup would produce.
|
|
312
|
+
* 3. For a CROSS-ORG share, enforces the decision-013 contract.
|
|
303
313
|
* 4. Defaults metadata.slug (and name) from the agent when the caller
|
|
304
314
|
* provided neither — the canonical share keeps the agent's hosted URL.
|
|
305
315
|
* Runs before ResolveSlug, which skips already-set slugs.
|
|
@@ -327,9 +337,6 @@ export function newResolveShareDefaultsStep(
|
|
|
327
337
|
if (agentRef!.org === "") {
|
|
328
338
|
agentRef!.org = metadata!.org;
|
|
329
339
|
}
|
|
330
|
-
if (agentRef!.org !== metadata!.org) {
|
|
331
|
-
throw failedPreconditionError(sameOrgInvariantMessage(agentRef!.org));
|
|
332
|
-
}
|
|
333
340
|
|
|
334
341
|
const agent = await findAgentByOrgAndSlug(
|
|
335
342
|
store,
|
|
@@ -340,6 +347,10 @@ export function newResolveShareDefaultsStep(
|
|
|
340
347
|
throw notFoundError("Agent", agentRef!.slug);
|
|
341
348
|
}
|
|
342
349
|
|
|
350
|
+
if (agentRef!.org !== metadata!.org) {
|
|
351
|
+
await validateCrossOrgShare(store, share, agent);
|
|
352
|
+
}
|
|
353
|
+
|
|
343
354
|
ctx.set(REFERENCED_AGENT_KEY, agent);
|
|
344
355
|
|
|
345
356
|
// Canonical-share default: no slug and no name means "share this
|
|
@@ -353,6 +364,133 @@ export function newResolveShareDefaultsStep(
|
|
|
353
364
|
};
|
|
354
365
|
}
|
|
355
366
|
|
|
367
|
+
/**
|
|
368
|
+
* The cross-org share contract (decision 013) — Go validateCrossOrgShare:
|
|
369
|
+
* - The agent must be marketplace-public; a non-public agent is refused
|
|
370
|
+
* with the same NOT_FOUND as a missing one (no existence probe for
|
|
371
|
+
* private slugs).
|
|
372
|
+
* - The audience must be public — org-audience semantics don't carry
|
|
373
|
+
* across the org boundary.
|
|
374
|
+
* - Every declared dependency must itself be public; the refusal names
|
|
375
|
+
* every blocker (sorted) so the sharing org knows exactly what to ask
|
|
376
|
+
* the agent's org to publish.
|
|
377
|
+
* Runtime re-enforcement is cloud-side; this create-time sweep is the
|
|
378
|
+
* fail-loud half, mirrored in both editions.
|
|
379
|
+
*/
|
|
380
|
+
async function validateCrossOrgShare(
|
|
381
|
+
store: Store,
|
|
382
|
+
share: AgentShare,
|
|
383
|
+
agent: Agent,
|
|
384
|
+
): Promise<void> {
|
|
385
|
+
const agentMeta = agent.metadata;
|
|
386
|
+
|
|
387
|
+
if (agentMeta?.visibility !== ApiResourceVisibility.visibility_public) {
|
|
388
|
+
throw notFoundError("Agent", agentMeta?.slug ?? "");
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// protobuf-es strips the shared enum prefix: proto
|
|
392
|
+
// agent_share_audience_org generates as AgentShareAudience.org.
|
|
393
|
+
if (share.spec?.audience === AgentShareAudience.org) {
|
|
394
|
+
throw failedPreconditionError(crossOrgAudienceMessage(agentMeta.org));
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const blockers = await findNonPublicDependencies(store, agent);
|
|
398
|
+
if (blockers.length > 0) {
|
|
399
|
+
throw failedPreconditionError(
|
|
400
|
+
crossOrgBlockersMessage(agentMeta.org, agentMeta.slug, blockers),
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Sweeps the agent's declared blueprint dependencies — skill_refs
|
|
407
|
+
* (including every sub-agent's) and mcp_server_usages — and returns a
|
|
408
|
+
* deterministic "kind org/slug" entry for each that is missing or not
|
|
409
|
+
* visibility_public — Go findNonPublicDependencies. A reference with an
|
|
410
|
+
* empty org is relative to the AGENT's org (defensive parity with the
|
|
411
|
+
* cloud edition's referenceMatches; agent writes normalize refs to
|
|
412
|
+
* absolute form).
|
|
413
|
+
*/
|
|
414
|
+
async function findNonPublicDependencies(
|
|
415
|
+
store: Store,
|
|
416
|
+
agent: Agent,
|
|
417
|
+
): Promise<string[]> {
|
|
418
|
+
const spec = agent.spec;
|
|
419
|
+
const agentOrg = agent.metadata?.org ?? "";
|
|
420
|
+
|
|
421
|
+
interface DepRef {
|
|
422
|
+
kind: ApiResourceKind;
|
|
423
|
+
org: string;
|
|
424
|
+
slug: string;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const seen = new Set<string>();
|
|
428
|
+
const deps: DepRef[] = [];
|
|
429
|
+
const add = (
|
|
430
|
+
kind: ApiResourceKind,
|
|
431
|
+
ref: ApiResourceReference | undefined,
|
|
432
|
+
): void => {
|
|
433
|
+
if (ref === undefined || ref.slug === "") {
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
const org = ref.org !== "" ? ref.org : agentOrg;
|
|
437
|
+
const key = `${kind}|${org}|${ref.slug}`;
|
|
438
|
+
if (!seen.has(key)) {
|
|
439
|
+
seen.add(key);
|
|
440
|
+
deps.push({ kind, org, slug: ref.slug });
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
for (const ref of spec?.skillRefs ?? []) {
|
|
445
|
+
add(ApiResourceKind.skill, ref);
|
|
446
|
+
}
|
|
447
|
+
for (const sub of spec?.subAgents ?? []) {
|
|
448
|
+
for (const ref of sub.skillRefs) {
|
|
449
|
+
add(ApiResourceKind.skill, ref);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
for (const usage of spec?.mcpServerUsages ?? []) {
|
|
453
|
+
add(ApiResourceKind.mcp_server, usage.mcpServerRef);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const blockers: string[] = [];
|
|
457
|
+
for (const dep of deps) {
|
|
458
|
+
let visibility: ApiResourceVisibility | undefined;
|
|
459
|
+
try {
|
|
460
|
+
// Per-kind resolution, exactly Go's switch — skill and mcp_server
|
|
461
|
+
// are the only dependency kinds an agent blueprint declares.
|
|
462
|
+
const resolved =
|
|
463
|
+
dep.kind === ApiResourceKind.skill
|
|
464
|
+
? await findResourceBySlug(
|
|
465
|
+
store,
|
|
466
|
+
dep.kind,
|
|
467
|
+
SkillSchema,
|
|
468
|
+
dep.slug,
|
|
469
|
+
dep.org,
|
|
470
|
+
)
|
|
471
|
+
: await findResourceBySlug(
|
|
472
|
+
store,
|
|
473
|
+
dep.kind,
|
|
474
|
+
McpServerSchema,
|
|
475
|
+
dep.slug,
|
|
476
|
+
dep.org,
|
|
477
|
+
);
|
|
478
|
+
visibility = resolved?.metadata?.visibility;
|
|
479
|
+
} catch (error) {
|
|
480
|
+
throw internalError(
|
|
481
|
+
error,
|
|
482
|
+
`failed to resolve ${ApiResourceKind[dep.kind]} ${dep.org}/${dep.slug} while validating cross-org share`,
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
if (visibility !== ApiResourceVisibility.visibility_public) {
|
|
486
|
+
blockers.push(`${ApiResourceKind[dep.kind]} ${dep.org}/${dep.slug}`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
blockers.sort();
|
|
491
|
+
return blockers;
|
|
492
|
+
}
|
|
493
|
+
|
|
356
494
|
/**
|
|
357
495
|
* StampAgentPin — Go stampAgentPinStep: writes status.agent_id, the
|
|
358
496
|
* server-owned rebind pin (decision 013). agent_ref is org+slug and slugs
|
|
@@ -386,8 +524,10 @@ export function newStampAgentPinStep(): PipelineStep<AgentShareDesc> {
|
|
|
386
524
|
|
|
387
525
|
/**
|
|
388
526
|
* ValidateShareUpdate — Go validateShareUpdateStep: spec.agent_ref must
|
|
389
|
-
* keep referencing the same agent
|
|
390
|
-
*
|
|
527
|
+
* keep referencing the same agent, and the cross-org public-audience rule
|
|
528
|
+
* must hold on update too (update replaces the spec wholesale and must not
|
|
529
|
+
* open a side door to an org-audience cross-org share). Runs after
|
|
530
|
+
* LoadExisting. metadata.slug/org immutability needs no step — the generic
|
|
391
531
|
* BuildUpdateState preserves both, and status (including the pin and link
|
|
392
532
|
* token) wholesale.
|
|
393
533
|
*/
|
|
@@ -424,6 +564,14 @@ export function newValidateShareUpdateStep(): PipelineStep<AgentShareDesc> {
|
|
|
424
564
|
),
|
|
425
565
|
);
|
|
426
566
|
}
|
|
567
|
+
|
|
568
|
+
const isCrossOrg =
|
|
569
|
+
(existingRef?.org ?? "") !== (existing.metadata?.org ?? "");
|
|
570
|
+
if (isCrossOrg && ctx.input.spec?.audience === AgentShareAudience.org) {
|
|
571
|
+
throw failedPreconditionError(
|
|
572
|
+
crossOrgAudienceMessage(existingRef?.org ?? ""),
|
|
573
|
+
);
|
|
574
|
+
}
|
|
427
575
|
},
|
|
428
576
|
};
|
|
429
577
|
}
|
|
@@ -435,8 +583,8 @@ export function newValidateShareUpdateStep(): PipelineStep<AgentShareDesc> {
|
|
|
435
583
|
* SHARE; display fields and default_instance_id from the AGENT. Three
|
|
436
584
|
* misses all fail closed with the uniform refusal, indistinguishable from
|
|
437
585
|
* absence: a dangling agent_ref, a stale agent-id pin (the rebind guard),
|
|
438
|
-
* and
|
|
439
|
-
*
|
|
586
|
+
* and a cross-org agent no longer visibility_public (withdrawing public
|
|
587
|
+
* visibility must kill every external channel).
|
|
440
588
|
*/
|
|
441
589
|
export async function buildSharedAgentProfile(
|
|
442
590
|
store: Store,
|
|
@@ -457,7 +605,12 @@ export async function buildSharedAgentProfile(
|
|
|
457
605
|
throw sharedNotFound(share.metadata?.slug ?? "");
|
|
458
606
|
}
|
|
459
607
|
|
|
460
|
-
|
|
608
|
+
const isCrossOrg =
|
|
609
|
+
(share.metadata?.org ?? "") !== (agent.metadata?.org ?? "");
|
|
610
|
+
if (
|
|
611
|
+
isCrossOrg &&
|
|
612
|
+
agent.metadata?.visibility !== ApiResourceVisibility.visibility_public
|
|
613
|
+
) {
|
|
461
614
|
throw sharedNotFound(share.metadata?.slug ?? "");
|
|
462
615
|
}
|
|
463
616
|
|
|
@@ -63,6 +63,7 @@ import {
|
|
|
63
63
|
newAuthorizeResolvedTargetStep,
|
|
64
64
|
} from "../../pipeline/steps/authorize-resolved-target.js";
|
|
65
65
|
import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
|
|
66
|
+
import { newAuthorizeVisibilityTransitionStep } from "../../pipeline/steps/visibility-gates.js";
|
|
66
67
|
import {
|
|
67
68
|
newBuildNewStateStep,
|
|
68
69
|
setAuditFieldsForUpdate,
|
|
@@ -96,10 +97,7 @@ import {
|
|
|
96
97
|
TARGET_RESOURCE_KEY,
|
|
97
98
|
newLoadTargetStep,
|
|
98
99
|
} from "../../pipeline/steps/load-target.js";
|
|
99
|
-
import {
|
|
100
|
-
newNormalizeReferencesStep,
|
|
101
|
-
newValidateReferencesStep,
|
|
102
|
-
} from "../../pipeline/steps/references.js";
|
|
100
|
+
import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
|
|
103
101
|
import {
|
|
104
102
|
newCleanupIamPoliciesStep,
|
|
105
103
|
newCreateAuthorizationTuplesStep,
|
|
@@ -246,7 +244,6 @@ async function update(
|
|
|
246
244
|
.addStep(newPreserveRedactedSecretsStep())
|
|
247
245
|
.addStep(newEncryptSecretValuesStep(deps.secretService, deps.logger))
|
|
248
246
|
.addStep(newNormalizeReferencesStep())
|
|
249
|
-
.addStep(newValidateReferencesStep(deps.store))
|
|
250
247
|
.addStep(newPersistStep(deps.store))
|
|
251
248
|
.addStep(
|
|
252
249
|
newDestroyDroppedEnvironmentSecretsStep(deps.secretService, deps.logger),
|
|
@@ -401,6 +398,12 @@ async function updateVisibility(
|
|
|
401
398
|
// After load, per the cross-edition error precedence: unknown id +
|
|
402
399
|
// bad level = NOT_FOUND on both editions.
|
|
403
400
|
.addStep(newValidateVisibilityUpdateStep())
|
|
401
|
+
.addStep(
|
|
402
|
+
newAuthorizeVisibilityTransitionStep(
|
|
403
|
+
UPDATE_VISIBILITY_ENVIRONMENT_KEY,
|
|
404
|
+
deps.authorizer,
|
|
405
|
+
),
|
|
406
|
+
)
|
|
404
407
|
.addStep(newValidateEnvironmentShareRestrictionStep())
|
|
405
408
|
.addStep(newSetEnvironmentVisibilityStep())
|
|
406
409
|
.addStep(newPersistEnvironmentForVisibilityUpdateStep(deps.store))
|
|
@@ -82,10 +82,7 @@ import {
|
|
|
82
82
|
TARGET_RESOURCE_KEY,
|
|
83
83
|
newLoadTargetStep,
|
|
84
84
|
} from "../../pipeline/steps/load-target.js";
|
|
85
|
-
import {
|
|
86
|
-
newNormalizeReferencesStep,
|
|
87
|
-
newValidateReferencesStep,
|
|
88
|
-
} from "../../pipeline/steps/references.js";
|
|
85
|
+
import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
|
|
89
86
|
import {
|
|
90
87
|
newCleanupIamPoliciesStep,
|
|
91
88
|
newCreateAuthorizationTuplesStep,
|
|
@@ -189,7 +186,6 @@ async function createExecutionContext(
|
|
|
189
186
|
.addStep(newBuildNewStateStep())
|
|
190
187
|
.addStep(newGuardReservedLabelsStep(deps.authorizer))
|
|
191
188
|
.addStep(newNormalizeReferencesStep())
|
|
192
|
-
.addStep(newValidateReferencesStep(deps.store))
|
|
193
189
|
.addStep(newEncryptSecretValuesStep(deps.secretService, deps.logger))
|
|
194
190
|
.addStep(newPersistStep(deps.store))
|
|
195
191
|
.addStep(
|