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