@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
|
@@ -41,11 +41,7 @@ import { composeServer } from "../../../boot/compose.js";
|
|
|
41
41
|
import type { ComposedServer } from "../../../boot/compose.js";
|
|
42
42
|
import { createLogger } from "../../../boot/logger.js";
|
|
43
43
|
|
|
44
|
-
const silentLogger = createLogger({
|
|
45
|
-
level: "error",
|
|
46
|
-
pretty: false,
|
|
47
|
-
write: () => {},
|
|
48
|
-
});
|
|
44
|
+
const silentLogger = createLogger({ level: "error", pretty: false, write: () => {} });
|
|
49
45
|
|
|
50
46
|
const API_VERSION = "agentic.stigmer.ai/v1";
|
|
51
47
|
const KIND = "McpServer";
|
|
@@ -132,11 +128,7 @@ function serverInput(overrides?: {
|
|
|
132
128
|
};
|
|
133
129
|
}
|
|
134
130
|
|
|
135
|
-
async function expectCode(
|
|
136
|
-
promise: Promise<unknown>,
|
|
137
|
-
code: Code,
|
|
138
|
-
arm: string,
|
|
139
|
-
): Promise<ConnectError> {
|
|
131
|
+
async function expectCode(promise: Promise<unknown>, code: Code, arm: string): Promise<ConnectError> {
|
|
140
132
|
try {
|
|
141
133
|
await promise;
|
|
142
134
|
} catch (error) {
|
|
@@ -165,10 +157,7 @@ async function seedCapabilities(
|
|
|
165
157
|
serverId,
|
|
166
158
|
McpServerSchema,
|
|
167
159
|
);
|
|
168
|
-
const patched = fromBinary(
|
|
169
|
-
McpServerSchema,
|
|
170
|
-
toBinary(McpServerSchema, stored),
|
|
171
|
-
);
|
|
160
|
+
const patched = fromBinary(McpServerSchema, toBinary(McpServerSchema, stored));
|
|
172
161
|
patched.status ??= create(McpServerStatusSchema, {});
|
|
173
162
|
patched.status.discoveredCapabilities = create(DiscoveredCapabilitiesSchema, {
|
|
174
163
|
tools: tools.map((name) => ({ name })),
|
|
@@ -187,19 +176,13 @@ describe("CRUD", () => {
|
|
|
187
176
|
const created = await command.create(serverInput({ name: "GitHub Tools" }));
|
|
188
177
|
expect(created.metadata?.id).toMatch(/^mcp_[0-9a-z]{26}$/);
|
|
189
178
|
expect(created.metadata?.slug).toBe("github-tools");
|
|
190
|
-
expect(created.metadata?.visibility).toBe(
|
|
191
|
-
ApiResourceVisibility.visibility_org,
|
|
192
|
-
);
|
|
179
|
+
expect(created.metadata?.visibility).toBe(ApiResourceVisibility.visibility_org);
|
|
193
180
|
});
|
|
194
181
|
|
|
195
182
|
it("rejects a duplicate create by slug within the org; a different org reuses the slug", async () => {
|
|
196
183
|
const name = `Dup Target ${++counter}`;
|
|
197
184
|
await command.create(serverInput({ name }));
|
|
198
|
-
await expectCode(
|
|
199
|
-
command.create(serverInput({ name })),
|
|
200
|
-
Code.AlreadyExists,
|
|
201
|
-
"duplicate create",
|
|
202
|
-
);
|
|
185
|
+
await expectCode(command.create(serverInput({ name })), Code.AlreadyExists, "duplicate create");
|
|
203
186
|
const other = await command.create(serverInput({ name, org: "other-org" }));
|
|
204
187
|
expect(other.metadata?.org).toBe("other-org");
|
|
205
188
|
});
|
|
@@ -218,17 +201,10 @@ describe("CRUD", () => {
|
|
|
218
201
|
it("get and getByReference resolve the same resource; unknowns answer NotFound", async () => {
|
|
219
202
|
const created = await command.create(serverInput());
|
|
220
203
|
const byId = await query.get({ value: created.metadata!.id });
|
|
221
|
-
const byRef = await query.getByReference({
|
|
222
|
-
org: ORG,
|
|
223
|
-
slug: created.metadata!.slug,
|
|
224
|
-
});
|
|
204
|
+
const byRef = await query.getByReference({ org: ORG, slug: created.metadata!.slug });
|
|
225
205
|
expect(byId.metadata?.id).toBe(created.metadata?.id);
|
|
226
206
|
expect(byRef.metadata?.id).toBe(created.metadata?.id);
|
|
227
|
-
await expectCode(
|
|
228
|
-
query.get({ value: "mcps_missing" }),
|
|
229
|
-
Code.NotFound,
|
|
230
|
-
"get unknown",
|
|
231
|
-
);
|
|
207
|
+
await expectCode(query.get({ value: "mcps_missing" }), Code.NotFound, "get unknown");
|
|
232
208
|
await expectCode(
|
|
233
209
|
query.getByReference({ org: ORG, slug: "never-created" }),
|
|
234
210
|
Code.NotFound,
|
|
@@ -240,11 +216,7 @@ describe("CRUD", () => {
|
|
|
240
216
|
const created = await command.create(serverInput());
|
|
241
217
|
const deleted = await command.delete({ resourceId: created.metadata!.id });
|
|
242
218
|
expect(deleted.metadata?.id).toBe(created.metadata?.id);
|
|
243
|
-
await expectCode(
|
|
244
|
-
query.get({ value: created.metadata!.id }),
|
|
245
|
-
Code.NotFound,
|
|
246
|
-
"get after delete",
|
|
247
|
-
);
|
|
219
|
+
await expectCode(query.get({ value: created.metadata!.id }), Code.NotFound, "get after delete");
|
|
248
220
|
});
|
|
249
221
|
|
|
250
222
|
it("update of a non-existent server and delete of a non-existent server answer NotFound; delete with an empty id is InvalidArgument", async () => {
|
|
@@ -261,11 +233,7 @@ describe("CRUD", () => {
|
|
|
261
233
|
Code.NotFound,
|
|
262
234
|
"delete non-existent",
|
|
263
235
|
);
|
|
264
|
-
await expectCode(
|
|
265
|
-
command.delete({}),
|
|
266
|
-
Code.InvalidArgument,
|
|
267
|
-
"delete empty id",
|
|
268
|
-
);
|
|
236
|
+
await expectCode(command.delete({}), Code.InvalidArgument, "delete empty id");
|
|
269
237
|
});
|
|
270
238
|
});
|
|
271
239
|
|
|
@@ -276,17 +244,13 @@ describe("updateVisibility (no conformance coverage for this domain — the D4-d
|
|
|
276
244
|
resourceId: created.metadata!.id,
|
|
277
245
|
visibility: ApiResourceVisibility.visibility_private,
|
|
278
246
|
});
|
|
279
|
-
expect(updated.metadata?.visibility).toBe(
|
|
280
|
-
ApiResourceVisibility.visibility_private,
|
|
281
|
-
);
|
|
247
|
+
expect(updated.metadata?.visibility).toBe(ApiResourceVisibility.visibility_private);
|
|
282
248
|
expect(updated.spec?.description).toBe(created.spec?.description);
|
|
283
249
|
// A visibility change is a STATUS mutation: status_audit re-stamped
|
|
284
250
|
// (updated event, fresh timestamp bounds are creation-or-later),
|
|
285
251
|
// spec_audit byte-untouched.
|
|
286
252
|
expect(updated.status?.audit?.statusAudit?.event).toBe("updated");
|
|
287
|
-
expect(updated.status?.audit?.specAudit).toEqual(
|
|
288
|
-
created.status?.audit?.specAudit,
|
|
289
|
-
);
|
|
253
|
+
expect(updated.status?.audit?.specAudit).toEqual(created.status?.audit?.specAudit);
|
|
290
254
|
});
|
|
291
255
|
|
|
292
256
|
it("answers NotFound for an unknown id", async () => {
|
|
@@ -332,9 +296,7 @@ describe("ValidateDefaultEnabledTools (#402)", () => {
|
|
|
332
296
|
it("accepts names the server exposes; skips when the list is empty or the server never connected", async () => {
|
|
333
297
|
// Never connected: any names pass (no authoritative toolset yet).
|
|
334
298
|
const fresh = await command.create(serverInput());
|
|
335
|
-
const freshUpdate = await command.update(
|
|
336
|
-
updateInput(fresh, ["anything-goes"]),
|
|
337
|
-
);
|
|
299
|
+
const freshUpdate = await command.update(updateInput(fresh, ["anything-goes"]));
|
|
338
300
|
expect(freshUpdate.spec?.defaultEnabledTools).toEqual(["anything-goes"]);
|
|
339
301
|
|
|
340
302
|
// Connected: valid names pass.
|
|
@@ -346,11 +308,7 @@ describe("ValidateDefaultEnabledTools (#402)", () => {
|
|
|
346
308
|
|
|
347
309
|
it("rejects unknown tools and resource templates with the byte-pinned teaching copy", async () => {
|
|
348
310
|
const created = await command.create(serverInput());
|
|
349
|
-
await seedCapabilities(
|
|
350
|
-
created.metadata!.id,
|
|
351
|
-
["search", "fetch"],
|
|
352
|
-
["files"],
|
|
353
|
-
);
|
|
311
|
+
await seedCapabilities(created.metadata!.id, ["search", "fetch"], ["files"]);
|
|
354
312
|
|
|
355
313
|
const err = await expectCode(
|
|
356
314
|
command.update(updateInput(created, ["serch", "files"])),
|
|
@@ -376,10 +334,7 @@ describe("EnrichOAuthStatus (#523) — response-only oauth_status", () => {
|
|
|
376
334
|
OAuthAppSchema,
|
|
377
335
|
create(OAuthAppSchema, {
|
|
378
336
|
metadata: { id, org: ORG, slug, name: slug },
|
|
379
|
-
spec: {
|
|
380
|
-
vendorApprovalStatus: approval,
|
|
381
|
-
vendorApprovalDocsUrl: docsUrl,
|
|
382
|
-
},
|
|
337
|
+
spec: { vendorApprovalStatus: approval, vendorApprovalDocsUrl: docsUrl },
|
|
383
338
|
}),
|
|
384
339
|
);
|
|
385
340
|
}
|
|
@@ -391,25 +346,14 @@ describe("EnrichOAuthStatus (#523) — response-only oauth_status", () => {
|
|
|
391
346
|
});
|
|
392
347
|
|
|
393
348
|
it("a missing OAuthApp skips enrichment (the initiate path owns refusing)", async () => {
|
|
394
|
-
|
|
395
|
-
// a reference dangles when its target leaves afterwards.
|
|
396
|
-
await seedOAuthApp("never-applied", VendorApprovalStatus.UNSPECIFIED, "");
|
|
397
|
-
const created = await command.create(
|
|
398
|
-
serverInput({ oauthAppSlug: "never-applied" }),
|
|
399
|
-
);
|
|
400
|
-
await server.store.deleteResource(
|
|
401
|
-
ApiResourceKind.oauth_app,
|
|
402
|
-
"oaa_neverapplied",
|
|
403
|
-
);
|
|
349
|
+
const created = await command.create(serverInput({ oauthAppSlug: "never-applied" }));
|
|
404
350
|
const got = await query.get({ value: created.metadata!.id });
|
|
405
351
|
expect(got.status?.oauthStatus).toBeUndefined();
|
|
406
352
|
});
|
|
407
353
|
|
|
408
354
|
it("nothing-to-report means ABSENT — presence itself is the SDK's signal", async () => {
|
|
409
355
|
await seedOAuthApp("plain-app", VendorApprovalStatus.UNSPECIFIED, "");
|
|
410
|
-
const created = await command.create(
|
|
411
|
-
serverInput({ oauthAppSlug: "plain-app" }),
|
|
412
|
-
);
|
|
356
|
+
const created = await command.create(serverInput({ oauthAppSlug: "plain-app" }));
|
|
413
357
|
const got = await query.get({ value: created.metadata!.id });
|
|
414
358
|
expect(got.status?.oauthStatus).toBeUndefined();
|
|
415
359
|
});
|
|
@@ -419,42 +363,24 @@ describe("EnrichOAuthStatus (#523) — response-only oauth_status", () => {
|
|
|
419
363
|
// alone must enrich (Go enrich_oauth_status_test.go's docs-only and
|
|
420
364
|
// status-only arms — the executable spec of the #523 shared contract).
|
|
421
365
|
it("a docs URL ALONE enriches, even with an UNSPECIFIED approval status", async () => {
|
|
422
|
-
await seedOAuthApp(
|
|
423
|
-
|
|
424
|
-
VendorApprovalStatus.UNSPECIFIED,
|
|
425
|
-
"https://vendor.example/setup",
|
|
426
|
-
);
|
|
427
|
-
const created = await command.create(
|
|
428
|
-
serverInput({ oauthAppSlug: "docs-only-app" }),
|
|
429
|
-
);
|
|
366
|
+
await seedOAuthApp("docs-only-app", VendorApprovalStatus.UNSPECIFIED, "https://vendor.example/setup");
|
|
367
|
+
const created = await command.create(serverInput({ oauthAppSlug: "docs-only-app" }));
|
|
430
368
|
const got = await query.get({ value: created.metadata!.id });
|
|
431
|
-
expect(got.status?.oauthStatus?.vendorApprovalStatus).toBe(
|
|
432
|
-
|
|
433
|
-
);
|
|
434
|
-
expect(got.status?.oauthStatus?.vendorApprovalDocsUrl).toBe(
|
|
435
|
-
"https://vendor.example/setup",
|
|
436
|
-
);
|
|
369
|
+
expect(got.status?.oauthStatus?.vendorApprovalStatus).toBe(VendorApprovalStatus.UNSPECIFIED);
|
|
370
|
+
expect(got.status?.oauthStatus?.vendorApprovalDocsUrl).toBe("https://vendor.example/setup");
|
|
437
371
|
});
|
|
438
372
|
|
|
439
373
|
it("a non-default approval status ALONE enriches — REJECTED and even APPROVED are reported", async () => {
|
|
440
374
|
await seedOAuthApp("rejected-app", VendorApprovalStatus.REJECTED, "");
|
|
441
|
-
const rejected = await command.create(
|
|
442
|
-
serverInput({ oauthAppSlug: "rejected-app" }),
|
|
443
|
-
);
|
|
375
|
+
const rejected = await command.create(serverInput({ oauthAppSlug: "rejected-app" }));
|
|
444
376
|
const gotRejected = await query.get({ value: rejected.metadata!.id });
|
|
445
|
-
expect(gotRejected.status?.oauthStatus?.vendorApprovalStatus).toBe(
|
|
446
|
-
VendorApprovalStatus.REJECTED,
|
|
447
|
-
);
|
|
377
|
+
expect(gotRejected.status?.oauthStatus?.vendorApprovalStatus).toBe(VendorApprovalStatus.REJECTED);
|
|
448
378
|
expect(gotRejected.status?.oauthStatus?.vendorApprovalDocsUrl).toBe("");
|
|
449
379
|
|
|
450
380
|
await seedOAuthApp("approved-app", VendorApprovalStatus.APPROVED, "");
|
|
451
|
-
const approved = await command.create(
|
|
452
|
-
serverInput({ oauthAppSlug: "approved-app" }),
|
|
453
|
-
);
|
|
381
|
+
const approved = await command.create(serverInput({ oauthAppSlug: "approved-app" }));
|
|
454
382
|
const gotApproved = await query.get({ value: approved.metadata!.id });
|
|
455
|
-
expect(gotApproved.status?.oauthStatus?.vendorApprovalStatus).toBe(
|
|
456
|
-
VendorApprovalStatus.APPROVED,
|
|
457
|
-
);
|
|
383
|
+
expect(gotApproved.status?.oauthStatus?.vendorApprovalStatus).toBe(VendorApprovalStatus.APPROVED);
|
|
458
384
|
});
|
|
459
385
|
|
|
460
386
|
it("an auth block WITHOUT an oauth_app_ref (the DCR arm) is untouched", async () => {
|
|
@@ -465,14 +391,8 @@ describe("EnrichOAuthStatus (#523) — response-only oauth_status", () => {
|
|
|
465
391
|
});
|
|
466
392
|
|
|
467
393
|
it("a gating approval status or docs URL enriches BOTH read paths, response-only", async () => {
|
|
468
|
-
await seedOAuthApp(
|
|
469
|
-
|
|
470
|
-
VendorApprovalStatus.PENDING,
|
|
471
|
-
"https://vendor.example/approval",
|
|
472
|
-
);
|
|
473
|
-
const created = await command.create(
|
|
474
|
-
serverInput({ oauthAppSlug: "gated-app" }),
|
|
475
|
-
);
|
|
394
|
+
await seedOAuthApp("gated-app", VendorApprovalStatus.PENDING, "https://vendor.example/approval");
|
|
395
|
+
const created = await command.create(serverInput({ oauthAppSlug: "gated-app" }));
|
|
476
396
|
|
|
477
397
|
for (const loaded of [
|
|
478
398
|
await query.get({ value: created.metadata!.id }),
|
|
@@ -510,12 +430,7 @@ describe("org-OAuth-app surface — UNIMPLEMENTED by design (#558, DD-019)", ()
|
|
|
510
430
|
expect(getErr.rawMessage).toBe("method GetOrgOAuthApp not implemented");
|
|
511
431
|
|
|
512
432
|
const setErr = await expectCode(
|
|
513
|
-
command.setOrgOAuthApp({
|
|
514
|
-
resourceId: "mcps_test",
|
|
515
|
-
org: ORG,
|
|
516
|
-
clientId: "x",
|
|
517
|
-
clientSecret: "y",
|
|
518
|
-
}),
|
|
433
|
+
command.setOrgOAuthApp({ resourceId: "mcps_test", org: ORG, clientId: "x", clientSecret: "y" }),
|
|
519
434
|
Code.Unimplemented,
|
|
520
435
|
"setOrgOAuthApp",
|
|
521
436
|
);
|
|
@@ -526,8 +441,6 @@ describe("org-OAuth-app surface — UNIMPLEMENTED by design (#558, DD-019)", ()
|
|
|
526
441
|
Code.Unimplemented,
|
|
527
442
|
"deleteOrgOAuthApp",
|
|
528
443
|
);
|
|
529
|
-
expect(deleteErr.rawMessage).toBe(
|
|
530
|
-
"method DeleteOrgOAuthApp not implemented",
|
|
531
|
-
);
|
|
444
|
+
expect(deleteErr.rawMessage).toBe("method DeleteOrgOAuthApp not implemented");
|
|
532
445
|
});
|
|
533
446
|
});
|
|
@@ -41,11 +41,7 @@ import { composeServer } from "../../../boot/compose.js";
|
|
|
41
41
|
import type { ComposedServer } from "../../../boot/compose.js";
|
|
42
42
|
import { createLogger } from "../../../boot/logger.js";
|
|
43
43
|
|
|
44
|
-
const silentLogger = createLogger({
|
|
45
|
-
level: "error",
|
|
46
|
-
pretty: false,
|
|
47
|
-
write: () => {},
|
|
48
|
-
});
|
|
44
|
+
const silentLogger = createLogger({ level: "error", pretty: false, write: () => {} });
|
|
49
45
|
|
|
50
46
|
const REDIRECT_URI = "http://127.0.0.1:8234/auth/oauth/callback";
|
|
51
47
|
const ORG = "acme";
|
|
@@ -372,30 +368,20 @@ describe("initiateOAuthConnect", () => {
|
|
|
372
368
|
"OAuth sign-in is unavailable: the platform's OAuth app for 'exampleco' is pending approval by the vendor. This server only accepts OAuth sign-in; an org admin can configure your own OAuth app instead.",
|
|
373
369
|
],
|
|
374
370
|
];
|
|
375
|
-
it.each(refusals)(
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
expect(error.rawMessage).toBe(copy);
|
|
387
|
-
},
|
|
388
|
-
);
|
|
371
|
+
it.each(refusals)("vendor arm refuses %s", async (_label, status, oauthOnly, copy) => {
|
|
372
|
+
const slug = `vendor-${status}-${oauthOnly ? "only" : "manual"}`;
|
|
373
|
+
await seedOAuthApp(slug, status);
|
|
374
|
+
const id = await applyServer({ vendorSlug: slug, oauthOnly });
|
|
375
|
+
const error = await expectCode(
|
|
376
|
+
command.initiateOAuthConnect({ mcpServerId: id, org: ORG }),
|
|
377
|
+
Code.FailedPrecondition,
|
|
378
|
+
copy,
|
|
379
|
+
);
|
|
380
|
+
expect(error.rawMessage).toBe(copy);
|
|
381
|
+
});
|
|
389
382
|
|
|
390
383
|
it("vendor arm answers NotFound for an unresolvable oauth_app_ref", async () => {
|
|
391
|
-
// The app must exist when the server is written (the reference rule);
|
|
392
|
-
// the reference becomes unresolvable when its target leaves afterwards.
|
|
393
|
-
await seedOAuthApp("no-such-app", VendorApprovalStatus.APPROVED);
|
|
394
384
|
const id = await applyServer({ vendorSlug: "no-such-app" });
|
|
395
|
-
await server.store.deleteResource(
|
|
396
|
-
ApiResourceKind.oauth_app,
|
|
397
|
-
"oap_no-such-app",
|
|
398
|
-
);
|
|
399
385
|
await expectCode(
|
|
400
386
|
command.initiateOAuthConnect({ mcpServerId: id, org: ORG }),
|
|
401
387
|
Code.NotFound,
|
|
@@ -420,29 +406,17 @@ describe("initiateOAuthConnect", () => {
|
|
|
420
406
|
describe("completeOAuthConnect → grant → disconnect (the full lifecycle)", () => {
|
|
421
407
|
it("guards its inputs (proto rules answer first, exactly as on Go)", async () => {
|
|
422
408
|
await expectCode(
|
|
423
|
-
command.completeOAuthConnect({
|
|
424
|
-
mcpServerId: "",
|
|
425
|
-
state: "s",
|
|
426
|
-
authorizationCode: "c",
|
|
427
|
-
}),
|
|
409
|
+
command.completeOAuthConnect({ mcpServerId: "", state: "s", authorizationCode: "c" }),
|
|
428
410
|
Code.InvalidArgument,
|
|
429
411
|
"mcp_server_id: value is required [required]",
|
|
430
412
|
);
|
|
431
413
|
await expectCode(
|
|
432
|
-
command.completeOAuthConnect({
|
|
433
|
-
mcpServerId: "m",
|
|
434
|
-
state: "",
|
|
435
|
-
authorizationCode: "c",
|
|
436
|
-
}),
|
|
414
|
+
command.completeOAuthConnect({ mcpServerId: "m", state: "", authorizationCode: "c" }),
|
|
437
415
|
Code.InvalidArgument,
|
|
438
416
|
"state:",
|
|
439
417
|
);
|
|
440
418
|
await expectCode(
|
|
441
|
-
command.completeOAuthConnect({
|
|
442
|
-
mcpServerId: "m",
|
|
443
|
-
state: "s",
|
|
444
|
-
authorizationCode: "",
|
|
445
|
-
}),
|
|
419
|
+
command.completeOAuthConnect({ mcpServerId: "m", state: "s", authorizationCode: "" }),
|
|
446
420
|
Code.InvalidArgument,
|
|
447
421
|
"authorization_code:",
|
|
448
422
|
);
|
|
@@ -526,10 +500,7 @@ describe("completeOAuthConnect → grant → disconnect (the full lifecycle)", (
|
|
|
526
500
|
|
|
527
501
|
// The grant is queryable and HEALTHY; the refresh-token env var is
|
|
528
502
|
// stamped unconditionally (oss#863's precondition, ported as-is).
|
|
529
|
-
const status = await query.getOAuthGrantStatus({
|
|
530
|
-
resourceId: id,
|
|
531
|
-
org: ORG,
|
|
532
|
-
});
|
|
503
|
+
const status = await query.getOAuthGrantStatus({ resourceId: id, org: ORG });
|
|
533
504
|
expect(status.connected).toBe(true);
|
|
534
505
|
expect(status.targetEnvVar).toBe("EXAMPLE_TOKEN");
|
|
535
506
|
expect(status.authMethod).toBe("mcp_oauth");
|
|
@@ -543,10 +514,7 @@ describe("completeOAuthConnect → grant → disconnect (the full lifecycle)", (
|
|
|
543
514
|
expect(firstEnvId).not.toBe("");
|
|
544
515
|
|
|
545
516
|
// Re-connect reuses the managed environment.
|
|
546
|
-
const again = await command.initiateOAuthConnect({
|
|
547
|
-
mcpServerId: id,
|
|
548
|
-
org: ORG,
|
|
549
|
-
});
|
|
517
|
+
const again = await command.initiateOAuthConnect({ mcpServerId: id, org: ORG });
|
|
550
518
|
await command.completeOAuthConnect({
|
|
551
519
|
mcpServerId: id,
|
|
552
520
|
state: again.state,
|
|
@@ -557,10 +525,7 @@ describe("completeOAuthConnect → grant → disconnect (the full lifecycle)", (
|
|
|
557
525
|
|
|
558
526
|
// Disconnect tears down grant + environment; a second disconnect is
|
|
559
527
|
// the idempotent no-grant arm.
|
|
560
|
-
const disconnected = await command.disconnectOAuth({
|
|
561
|
-
resourceId: id,
|
|
562
|
-
org: ORG,
|
|
563
|
-
});
|
|
528
|
+
const disconnected = await command.disconnectOAuth({ resourceId: id, org: ORG });
|
|
564
529
|
expect(disconnected.disconnected).toBe(true);
|
|
565
530
|
expect(await server.store.oauthGrants.find("", id, ORG)).toBeUndefined();
|
|
566
531
|
const againDisconnected = await command.disconnectOAuth({
|
|
@@ -58,6 +58,10 @@ import {
|
|
|
58
58
|
newAuthorizeResolvedTargetStep,
|
|
59
59
|
} from "../../pipeline/steps/authorize-resolved-target.js";
|
|
60
60
|
import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
|
|
61
|
+
import {
|
|
62
|
+
newAuthorizeVisibilityTransitionStep,
|
|
63
|
+
newGuardPublicVisibilityStep,
|
|
64
|
+
} from "../../pipeline/steps/visibility-gates.js";
|
|
61
65
|
import {
|
|
62
66
|
setAuditFieldsForUpdate,
|
|
63
67
|
newBuildNewStateStep,
|
|
@@ -88,10 +92,7 @@ import {
|
|
|
88
92
|
TARGET_RESOURCE_KEY,
|
|
89
93
|
newLoadTargetStep,
|
|
90
94
|
} from "../../pipeline/steps/load-target.js";
|
|
91
|
-
import {
|
|
92
|
-
newNormalizeReferencesStep,
|
|
93
|
-
newValidateReferencesStep,
|
|
94
|
-
} from "../../pipeline/steps/references.js";
|
|
95
|
+
import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
|
|
95
96
|
import {
|
|
96
97
|
newCleanupIamPoliciesStep,
|
|
97
98
|
newCreateAuthorizationTuplesStep,
|
|
@@ -240,13 +241,13 @@ async function createMcpServer(
|
|
|
240
241
|
.addStep(newResolveSlugStep())
|
|
241
242
|
.addStep(newCheckDuplicateStep(deps.store))
|
|
242
243
|
.addStep(newBuildNewStateStep())
|
|
244
|
+
.addStep(newGuardPublicVisibilityStep(deps.authorizer))
|
|
243
245
|
// A URL-only server is asked once whether it wants OAuth and completed
|
|
244
246
|
// when it does; immediately before GuardReservedLabels because the
|
|
245
247
|
// provenance label it stamps is one the guard diffs.
|
|
246
248
|
.addStep(newCompleteEndpointAuthStep(endpointAuthDeps(deps)))
|
|
247
249
|
.addStep(newGuardReservedLabelsStep(deps.authorizer))
|
|
248
250
|
.addStep(newNormalizeReferencesStep())
|
|
249
|
-
.addStep(newValidateReferencesStep(deps.store))
|
|
250
251
|
.addStep(newPersistStep(deps.store))
|
|
251
252
|
.addStep(
|
|
252
253
|
newCreateAuthorizationTuplesStep(
|
|
@@ -299,7 +300,6 @@ async function update(
|
|
|
299
300
|
.addStep(newGuardReservedLabelsStep(deps.authorizer))
|
|
300
301
|
.addStep(newValidateDefaultEnabledToolsStep())
|
|
301
302
|
.addStep(newNormalizeReferencesStep())
|
|
302
|
-
.addStep(newValidateReferencesStep(deps.store))
|
|
303
303
|
.addStep(newPersistStep(deps.store))
|
|
304
304
|
.addStep(
|
|
305
305
|
newIndexSearchStep(deps.store, mcpServerSearchExtractor, deps.logger),
|
|
@@ -463,6 +463,12 @@ async function updateVisibility(
|
|
|
463
463
|
newRecordVisibilityBeforeUpdateStep(UPDATE_VISIBILITY_MCP_SERVER_KEY),
|
|
464
464
|
)
|
|
465
465
|
.addStep(newValidateVisibilityUpdateStep())
|
|
466
|
+
.addStep(
|
|
467
|
+
newAuthorizeVisibilityTransitionStep(
|
|
468
|
+
UPDATE_VISIBILITY_MCP_SERVER_KEY,
|
|
469
|
+
deps.authorizer,
|
|
470
|
+
),
|
|
471
|
+
)
|
|
466
472
|
.addStep(newSetMcpServerVisibilityStep())
|
|
467
473
|
.addStep(newPersistMcpServerForVisibilityUpdateStep(deps.store))
|
|
468
474
|
.addStep(
|
|
@@ -103,10 +103,13 @@ import {
|
|
|
103
103
|
newAuthorizeResolvedTargetStep,
|
|
104
104
|
} from "../../pipeline/steps/authorize-resolved-target.js";
|
|
105
105
|
import type { VersionHistoryBinding } from "../../pipeline/steps/version-history.js";
|
|
106
|
+
import { newAuthorizeVisibilityTransitionStep } from "../../pipeline/steps/visibility-gates.js";
|
|
106
107
|
import { metadataOf } from "../../pipeline/steps/shapes.js";
|
|
107
108
|
import type { Store } from "../../store/interface.js";
|
|
108
|
-
import {
|
|
109
|
-
|
|
109
|
+
import type {
|
|
110
|
+
ArchiveStaging,
|
|
111
|
+
StagedUpload,
|
|
112
|
+
} from "../skill/transfer/staging.js";
|
|
110
113
|
import { TRANSFER_LANE_NOT_CONFIGURED } from "./constants.js";
|
|
111
114
|
import type { PluginMaterializerProvider } from "./materialize/ports.js";
|
|
112
115
|
import { findMembers } from "./members.js";
|
|
@@ -139,12 +142,6 @@ import {
|
|
|
139
142
|
} from "./push.js";
|
|
140
143
|
import { pluginSearchExtractor } from "./search-extractor.js";
|
|
141
144
|
|
|
142
|
-
/** The transfer lane's controller-side pair; the slots are the skill lane's (one upload surface). */
|
|
143
|
-
export interface PluginTransferLaneDeps {
|
|
144
|
-
readonly slots: UploadSlots;
|
|
145
|
-
readonly baseUrl: string;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
145
|
export interface PluginControllerDeps {
|
|
149
146
|
readonly store: Store;
|
|
150
147
|
readonly logger: Logger;
|
|
@@ -152,7 +149,8 @@ export interface PluginControllerDeps {
|
|
|
152
149
|
readonly authorizationLifecycle: ResourceAuthorizationLifecycle | undefined;
|
|
153
150
|
readonly artifactStorage: ContentAddressedArchiveStore;
|
|
154
151
|
readonly materializerProvider: PluginMaterializerProvider;
|
|
155
|
-
|
|
152
|
+
/** The skill lane's staging port (one upload surface for every archive); absent, the lane answers FailedPrecondition. */
|
|
153
|
+
readonly staging?: ArchiveStaging;
|
|
156
154
|
}
|
|
157
155
|
|
|
158
156
|
/** Registers both plugin services on the router (routes stage). */
|
|
@@ -207,7 +205,7 @@ async function push(
|
|
|
207
205
|
.addStep(newValidateProtoStep())
|
|
208
206
|
.addStep(
|
|
209
207
|
newResolveArtifactSourceStep<typeof PushPluginRequestSchema>(
|
|
210
|
-
deps.
|
|
208
|
+
deps.staging,
|
|
211
209
|
{
|
|
212
210
|
source: (input) => ({
|
|
213
211
|
artifact: input.artifact,
|
|
@@ -225,7 +223,7 @@ async function push(
|
|
|
225
223
|
.addStep(newParseOverlayDocumentsStep())
|
|
226
224
|
.addStep(newSanitizePluginMetadataStep(deps.authorizer))
|
|
227
225
|
.addStep(newPlanMaterializationStep(deps.store, deps.authorizer))
|
|
228
|
-
.addStep(newGuardPluginVisibilityStep())
|
|
226
|
+
.addStep(newGuardPluginVisibilityStep(deps.authorizer))
|
|
229
227
|
.addStep(newResolveConvergenceStep())
|
|
230
228
|
.build()
|
|
231
229
|
.execute(reqCtx);
|
|
@@ -273,16 +271,17 @@ async function push(
|
|
|
273
271
|
// ─── createArtifactUploadUrl ─────────────────────────────────────────────
|
|
274
272
|
|
|
275
273
|
/**
|
|
276
|
-
* Mints a short-lived, single-use upload URL
|
|
277
|
-
* over-limit declaration is refused with the limit BEFORE any
|
|
274
|
+
* Mints a short-lived, single-use upload URL through the shared staging
|
|
275
|
+
* port; an over-limit declaration is refused with the limit BEFORE any
|
|
276
|
+
* bytes move.
|
|
278
277
|
*/
|
|
279
278
|
async function createArtifactUploadUrl(
|
|
280
279
|
deps: PluginControllerDeps,
|
|
281
280
|
req: CreatePluginArtifactUploadUrlRequest,
|
|
282
281
|
ctx: HandlerContext,
|
|
283
282
|
): Promise<PluginArtifactUploadUrl> {
|
|
284
|
-
const
|
|
285
|
-
if (
|
|
283
|
+
const staging = deps.staging;
|
|
284
|
+
if (staging === undefined) {
|
|
286
285
|
throw failedPreconditionError(TRANSFER_LANE_NOT_CONFIGURED);
|
|
287
286
|
}
|
|
288
287
|
const reqCtx = new RequestContext(
|
|
@@ -309,14 +308,14 @@ async function createArtifactUploadUrl(
|
|
|
309
308
|
`plugin archive size ${req.sizeBytes} bytes exceeds the ${MAX_ZIP_SIZE}-byte (100MB) archive limit`,
|
|
310
309
|
);
|
|
311
310
|
}
|
|
312
|
-
let minted:
|
|
311
|
+
let minted: StagedUpload;
|
|
313
312
|
try {
|
|
314
|
-
minted =
|
|
313
|
+
minted = await staging.mint(Number(req.sizeBytes));
|
|
315
314
|
} catch (error) {
|
|
316
315
|
throw internalError(error, "failed to mint upload reference");
|
|
317
316
|
}
|
|
318
317
|
return create(PluginArtifactUploadUrlSchema, {
|
|
319
|
-
url:
|
|
318
|
+
url: minted.url,
|
|
320
319
|
artifactUploadRef: minted.ref,
|
|
321
320
|
ttlSeconds: Math.trunc(minted.ttlMs / 1000),
|
|
322
321
|
});
|
|
@@ -358,6 +357,12 @@ async function updateVisibility(
|
|
|
358
357
|
.addStep(newLoadPluginByIdStep(deps.store, UPDATE_VISIBILITY_PLUGIN_KEY))
|
|
359
358
|
.addStep(newRecordVisibilityBeforeUpdateStep(UPDATE_VISIBILITY_PLUGIN_KEY))
|
|
360
359
|
.addStep(newValidateVisibilityUpdateStep())
|
|
360
|
+
.addStep(
|
|
361
|
+
newAuthorizeVisibilityTransitionStep(
|
|
362
|
+
UPDATE_VISIBILITY_PLUGIN_KEY,
|
|
363
|
+
deps.authorizer,
|
|
364
|
+
),
|
|
365
|
+
)
|
|
361
366
|
.addStep(newSetPluginVisibilityStep())
|
|
362
367
|
.addStep(
|
|
363
368
|
newPersistPluginStep(
|
|
@@ -94,6 +94,7 @@ import { ARTIFACT_BYTES_KEY } from "../../pipeline/steps/resolve-artifact-source
|
|
|
94
94
|
import { generateSlug } from "../../pipeline/steps/slug.js";
|
|
95
95
|
import { rejectUnsupportedVisibility } from "../../pipeline/steps/validate-visibility.js";
|
|
96
96
|
import { newArchiveCurrentVersionStep } from "../../pipeline/steps/version-archive.js";
|
|
97
|
+
import { requireOperatorMaySetPublic } from "../../pipeline/steps/visibility-gates.js";
|
|
97
98
|
import { ResourceNotFoundError } from "../../store/interface.js";
|
|
98
99
|
import type { Store } from "../../store/interface.js";
|
|
99
100
|
import { openPluginArchive } from "./archive.js";
|
|
@@ -492,23 +493,30 @@ export function newPlanMaterializationStep(
|
|
|
492
493
|
|
|
493
494
|
/**
|
|
494
495
|
* GuardPluginVisibility — the requested level must be one the plugin and
|
|
495
|
-
* every planned member kind support
|
|
496
|
-
*
|
|
497
|
-
*
|
|
498
|
-
*
|
|
499
|
-
* Each member's own chain checks again in-process; refusing here keeps the
|
|
500
|
-
* head from being written before the answer is known.
|
|
496
|
+
* every planned member kind support, and PUBLIC needs the operator grant
|
|
497
|
+
* (the one owner of that question, shared with every other create door).
|
|
498
|
+
* Each member's own chain will check again in-process; refusing here keeps
|
|
499
|
+
* the head from being written before the answer is known.
|
|
501
500
|
*/
|
|
502
|
-
export function newGuardPluginVisibilityStep(
|
|
501
|
+
export function newGuardPluginVisibilityStep(
|
|
502
|
+
authorizer: Authorizer,
|
|
503
|
+
): PipelineStep<PushDesc> {
|
|
503
504
|
return {
|
|
504
505
|
name: "GuardPluginVisibility",
|
|
505
|
-
execute(ctx: RequestContext<PushDesc>): void {
|
|
506
|
+
async execute(ctx: RequestContext<PushDesc>): Promise<void> {
|
|
506
507
|
const level = requestedVisibility(ctx);
|
|
507
508
|
const plan = ctx.get(PLUGIN_PLAN_KEY) as MaterializationPlan;
|
|
508
509
|
rejectUnsupportedVisibility(ctx.apiResourceKind, level);
|
|
509
510
|
for (const kind of new Set(plan.members.map((member) => member.kind))) {
|
|
510
511
|
rejectUnsupportedVisibility(kind, level);
|
|
511
512
|
}
|
|
513
|
+
if (level !== ApiResourceVisibility.visibility_public) {
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
if (ctx.callerIdentity.callerClass === "internal") {
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
await requireOperatorMaySetPublic(authorizer, ctx.callerIdentity);
|
|
512
520
|
},
|
|
513
521
|
};
|
|
514
522
|
}
|
|
@@ -97,10 +97,7 @@ import {
|
|
|
97
97
|
newCreateAuthorizationTuplesStep,
|
|
98
98
|
} from "../../pipeline/steps/authorization-tuples.js";
|
|
99
99
|
import { newPersistStep } from "../../pipeline/steps/persist.js";
|
|
100
|
-
import {
|
|
101
|
-
newNormalizeReferencesStep,
|
|
102
|
-
newValidateReferencesStep,
|
|
103
|
-
} from "../../pipeline/steps/references.js";
|
|
100
|
+
import { newNormalizeReferencesStep } from "../../pipeline/steps/references.js";
|
|
104
101
|
import { newResolveSlugStep } from "../../pipeline/steps/slug.js";
|
|
105
102
|
import { newValidateProtoStep } from "../../pipeline/steps/validation.js";
|
|
106
103
|
import { newValidateVisibilityStep } from "../../pipeline/steps/validate-visibility.js";
|
|
@@ -223,7 +220,6 @@ async function createSchedule(
|
|
|
223
220
|
.addStep(newBuildNewStateStep())
|
|
224
221
|
.addStep(newGuardReservedLabelsStep(deps.authorizer))
|
|
225
222
|
.addStep(newNormalizeReferencesStep())
|
|
226
|
-
.addStep(newValidateReferencesStep(deps.store))
|
|
227
223
|
.addStep(newPersistStep(deps.store))
|
|
228
224
|
.addStep(
|
|
229
225
|
newCreateAuthorizationTuplesStep(
|
|
@@ -263,7 +259,6 @@ async function update(
|
|
|
263
259
|
.addStep(newBuildUpdateStateStep())
|
|
264
260
|
.addStep(newGuardReservedLabelsStep(deps.authorizer))
|
|
265
261
|
.addStep(newNormalizeReferencesStep())
|
|
266
|
-
.addStep(newValidateReferencesStep(deps.store))
|
|
267
262
|
.addStep(newPersistScheduleUpdateStep(deps.store))
|
|
268
263
|
.addStep(newArmScheduleStep(deps.clock, deps.logger))
|
|
269
264
|
.build()
|