@noodleseed/one 0.165.0 → 0.167.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/commands/author-loop.d.ts.map +1 -1
- package/dist/commands/author-loop.js +18 -3
- package/dist/commands/author-loop.js.map +1 -1
- package/dist/commands/deploy-ops.d.ts.map +1 -1
- package/dist/commands/deploy-ops.js +21 -2
- package/dist/commands/deploy-ops.js.map +1 -1
- package/dist/commands/deploy-status-ops.d.ts +2 -0
- package/dist/commands/deploy-status-ops.d.ts.map +1 -1
- package/dist/commands/deploy-status-ops.js +27 -0
- package/dist/commands/deploy-status-ops.js.map +1 -1
- package/dist/control-plane-request.d.ts +2 -0
- package/dist/control-plane-request.d.ts.map +1 -1
- package/dist/control-plane-request.js +18 -0
- package/dist/control-plane-request.js.map +1 -1
- package/dist/deploy.d.ts +2 -1
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +15 -0
- package/dist/deploy.js.map +1 -1
- package/dist/dev.d.ts +2 -0
- package/dist/dev.d.ts.map +1 -1
- package/dist/dev.js +12 -1
- package/dist/dev.js.map +1 -1
- package/dist/devtools-auth-session.d.ts +5 -0
- package/dist/devtools-auth-session.d.ts.map +1 -1
- package/dist/devtools-auth-session.js +41 -2
- package/dist/devtools-auth-session.js.map +1 -1
- package/dist/devtools-auth-types.d.ts +2 -1
- package/dist/devtools-auth-types.d.ts.map +1 -1
- package/dist/devtools-auth-types.js.map +1 -1
- package/dist/devtools-auth-ui.d.ts +1 -1
- package/dist/devtools-auth-ui.d.ts.map +1 -1
- package/dist/devtools-auth-ui.js +13 -5
- package/dist/devtools-auth-ui.js.map +1 -1
- package/dist/devtools-harness.d.ts +1 -0
- package/dist/devtools-harness.d.ts.map +1 -1
- package/dist/devtools-harness.js +12 -7
- package/dist/devtools-harness.js.map +1 -1
- package/dist/devtools-preview.d.ts +1 -0
- package/dist/devtools-preview.d.ts.map +1 -1
- package/dist/devtools-preview.js +21 -6
- package/dist/devtools-preview.js.map +1 -1
- package/dist/devtools-rpc-forwarder.d.ts +1 -0
- package/dist/devtools-rpc-forwarder.d.ts.map +1 -1
- package/dist/devtools-rpc-forwarder.js +2 -1
- package/dist/devtools-rpc-forwarder.js.map +1 -1
- package/dist/preview-session.d.ts +1 -0
- package/dist/preview-session.d.ts.map +1 -1
- package/dist/preview-session.js +1 -0
- package/dist/preview-session.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +3 -3
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-auth-ref.js +5 -2
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/agent-packaging/dist/product-skill-types.d.ts +1 -0
- package/node_modules/@noodle-borg/agent-packaging/dist/product-skill-validation.js +4 -0
- package/node_modules/@noodle-borg/app-package/dist/schema.js +1 -0
- package/node_modules/@noodle-borg/app-package/dist/types.d.ts +1 -0
- package/node_modules/@noodle-borg/authoring/dist/server.d.ts +3 -1
- package/node_modules/@noodle-borg/authoring/dist/server.js +7 -6
- package/node_modules/@noodle-borg/capabilities/dist/index.js +7 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-local-authoring.js +8 -0
- package/node_modules/@noodle-borg/compiler/dist/app-package/compile.js +9 -1
- package/node_modules/@noodle-borg/compiler/dist/artifact/catalog-emission.js +3 -0
- package/node_modules/@noodle-borg/compiler/dist/artifact/types.d.ts +2 -0
- package/node_modules/@noodle-borg/compiler/dist/artifact/version.d.ts +2 -1
- package/node_modules/@noodle-borg/compiler/dist/artifact/version.js +2 -1
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +5 -0
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +12 -2
- package/node_modules/@noodle-borg/module/dist/customer-auth-access.d.ts +7 -0
- package/node_modules/@noodle-borg/module/dist/customer-auth-access.js +6 -0
- package/node_modules/@noodle-borg/module/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/module/dist/index.js +1 -0
- package/node_modules/@noodle-borg/protocol/dist/handlers/tools.js +3 -0
- package/node_modules/@noodle-borg/protocol/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/protocol/dist/index.js +1 -0
- package/node_modules/@noodle-borg/protocol/dist/mapping.d.ts +5 -1
- package/node_modules/@noodle-borg/protocol/dist/mapping.js +15 -7
- package/node_modules/@noodle-borg/protocol/dist/sdk-server.d.ts +2 -0
- package/node_modules/@noodle-borg/protocol/dist/tool-discovery.d.ts +14 -0
- package/node_modules/@noodle-borg/protocol/dist/tool-discovery.js +12 -0
- package/node_modules/@noodle-borg/protocol/dist/v2/server.js +3 -0
- package/node_modules/@noodle-borg/service/dist/build-info.js +4 -2
- package/node_modules/@noodle-borg/service/dist/customer-auth-audience-binding.js +16 -5
- package/node_modules/@noodle-borg/service/dist/deployment-access-mode.js +24 -0
- package/node_modules/@noodle-borg/service/dist/deployment-activation-precondition.js +27 -0
- package/node_modules/@noodle-borg/service/dist/deployment-authentication.js +19 -0
- package/node_modules/@noodle-borg/service/dist/deployment-execution.js +2 -2
- package/node_modules/@noodle-borg/service/dist/deployment-record-version.js +55 -0
- package/node_modules/@noodle-borg/service/dist/developer-mcp/inspection.js +15 -1
- package/node_modules/@noodle-borg/service/dist/registry-access.js +47 -30
- package/node_modules/@noodle-borg/service/dist/registry-compile.js +42 -1
- package/node_modules/@noodle-borg/service/dist/registry-deploy-transaction.js +105 -15
- package/node_modules/@noodle-borg/service/dist/registry-rollback.js +15 -1
- package/node_modules/@noodle-borg/service/dist/registry-state.d.ts +3 -6
- package/node_modules/@noodle-borg/service/dist/registry-state.js +15 -7
- package/node_modules/@noodle-borg/service/dist/registry-status.js +5 -3
- package/node_modules/@noodle-borg/service/dist/registry-targets.js +43 -28
- package/node_modules/@noodle-borg/service/dist/registry-types.d.ts +4 -2
- package/node_modules/@noodle-borg/service/dist/registry.js +68 -72
- package/node_modules/@noodle-borg/service/dist/routes/access.js +7 -0
- package/node_modules/@noodle-borg/service/dist/routes/auth-doctor-live.js +3 -2
- package/node_modules/@noodle-borg/service/dist/routes/control-plane.js +1 -0
- package/node_modules/@noodle-borg/service/dist/routes/deploy-preflight.js +2 -2
- package/node_modules/@noodle-borg/service/dist/serve-resource-auth.js +1 -1
- package/node_modules/@noodle-borg/service/dist/store/in-memory.d.ts +3 -7
- package/node_modules/@noodle-borg/service/dist/store/in-memory.js +13 -4
- package/node_modules/@noodle-borg/service/dist/store/json-file.d.ts +3 -7
- package/node_modules/@noodle-borg/service/dist/store/json-file.js +15 -6
- package/node_modules/@noodle-borg/service/dist/store/records.js +15 -2
- package/node_modules/@noodle-borg/service/dist/store.d.ts +23 -8
- package/node_modules/@noodle-borg/service/package.json +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/handler.d.ts +2 -3
- package/node_modules/@noodle-borg/transport-http/dist/handler.js +3 -4
- package/node_modules/@noodle-borg/transport-http/dist/identity-authorization.d.ts +3 -2
- package/node_modules/@noodle-borg/transport-http/dist/identity-authorization.js +23 -12
- package/node_modules/@noodle-borg/transport-http/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/transport-http/dist/serve-request.js +3 -0
- package/node_modules/@noodle-borg/transport-http/dist/target-authentication.d.ts +15 -0
- package/node_modules/@noodle-borg/transport-http/dist/target-authentication.js +9 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/control-plane.d.ts +23 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/control-plane.js +34 -4
- package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +6 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/index.js +4 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/service-info.d.ts +41 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/service-info.js +26 -0
- package/package.json +2 -2
- package/node_modules/@noodle-borg/service/dist/routes/access-mode.js +0 -7
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
type ToolAuthorizationManifest = {
|
|
3
|
+
readonly discovery?: 'authorized' | 'public' | undefined;
|
|
3
4
|
readonly requiredScopes?: readonly string[] | undefined;
|
|
4
5
|
readonly allowedRoles?: readonly string[] | undefined;
|
|
5
6
|
};
|
|
@@ -504,6 +505,7 @@ export declare const manifestV1Schema: z.ZodObject<{
|
|
|
504
505
|
title: z.ZodOptional<z.ZodString>;
|
|
505
506
|
description: z.ZodString;
|
|
506
507
|
authorization: z.ZodOptional<z.ZodType<ToolAuthorizationManifest, unknown, z.core.$ZodTypeInternals<ToolAuthorizationManifest, unknown>>>;
|
|
508
|
+
securitySchemes: z.ZodOptional<z.ZodNever>;
|
|
507
509
|
inputSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
508
510
|
outputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
509
511
|
annotations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -1164,6 +1166,7 @@ export declare const manifestV2Schema: z.ZodObject<{
|
|
|
1164
1166
|
title: z.ZodOptional<z.ZodString>;
|
|
1165
1167
|
description: z.ZodString;
|
|
1166
1168
|
authorization: z.ZodOptional<z.ZodType<ToolAuthorizationManifest, unknown, z.core.$ZodTypeInternals<ToolAuthorizationManifest, unknown>>>;
|
|
1169
|
+
securitySchemes: z.ZodOptional<z.ZodNever>;
|
|
1167
1170
|
inputSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
1168
1171
|
outputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1169
1172
|
annotations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -1729,6 +1732,7 @@ export declare const manifestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
1729
1732
|
title: z.ZodOptional<z.ZodString>;
|
|
1730
1733
|
description: z.ZodString;
|
|
1731
1734
|
authorization: z.ZodOptional<z.ZodType<ToolAuthorizationManifest, unknown, z.core.$ZodTypeInternals<ToolAuthorizationManifest, unknown>>>;
|
|
1735
|
+
securitySchemes: z.ZodOptional<z.ZodNever>;
|
|
1732
1736
|
inputSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
1733
1737
|
outputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1734
1738
|
annotations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -2388,6 +2392,7 @@ export declare const manifestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
2388
2392
|
title: z.ZodOptional<z.ZodString>;
|
|
2389
2393
|
description: z.ZodString;
|
|
2390
2394
|
authorization: z.ZodOptional<z.ZodType<ToolAuthorizationManifest, unknown, z.core.$ZodTypeInternals<ToolAuthorizationManifest, unknown>>>;
|
|
2395
|
+
securitySchemes: z.ZodOptional<z.ZodNever>;
|
|
2391
2396
|
inputSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
2392
2397
|
outputSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
2393
2398
|
annotations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -70,25 +70,35 @@ const roleSchema = z
|
|
|
70
70
|
const authorizationListSchema = (item) => z.array(item).min(1).max(MAX_TOOL_AUTHORIZATION_VALUES);
|
|
71
71
|
const requiredScopesSchema = authorizationListSchema(scopeTokenSchema);
|
|
72
72
|
const allowedRolesSchema = authorizationListSchema(roleSchema);
|
|
73
|
-
const toolAuthorizationSchema = z
|
|
73
|
+
const toolAuthorizationSchema = z
|
|
74
|
+
.union([
|
|
74
75
|
z
|
|
75
76
|
.object({
|
|
77
|
+
discovery: z.enum(['authorized', 'public']).optional(),
|
|
76
78
|
requiredScopes: requiredScopesSchema,
|
|
77
79
|
allowedRoles: allowedRolesSchema.optional(),
|
|
78
80
|
})
|
|
79
81
|
.strict(),
|
|
80
82
|
z
|
|
81
83
|
.object({
|
|
84
|
+
discovery: z.enum(['authorized', 'public']).optional(),
|
|
82
85
|
requiredScopes: requiredScopesSchema.optional(),
|
|
83
86
|
allowedRoles: allowedRolesSchema,
|
|
84
87
|
})
|
|
85
88
|
.strict(),
|
|
86
|
-
])
|
|
89
|
+
])
|
|
90
|
+
.overwrite((authorization) => {
|
|
91
|
+
if (authorization.discovery !== 'authorized')
|
|
92
|
+
return authorization;
|
|
93
|
+
const { discovery: _discovery, ...normalized } = authorization;
|
|
94
|
+
return normalized;
|
|
95
|
+
});
|
|
87
96
|
const toolSchema = z.object({
|
|
88
97
|
name: nameSchema,
|
|
89
98
|
title: z.string().trim().min(1).optional(),
|
|
90
99
|
description: z.string().min(1),
|
|
91
100
|
authorization: toolAuthorizationSchema.optional(),
|
|
101
|
+
securitySchemes: z.never().optional(),
|
|
92
102
|
inputSchema: jsonSchemaSchema,
|
|
93
103
|
outputSchema: jsonSchemaSchema.optional(),
|
|
94
104
|
annotations: z.record(z.string(), z.unknown()).optional(),
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AccessMode } from './contract.js';
|
|
2
|
+
export declare function usesCustomerAuthentication(input: {
|
|
3
|
+
readonly schemaVersion: number;
|
|
4
|
+
readonly accessMode: AccessMode | undefined;
|
|
5
|
+
readonly hasServerAuth: boolean;
|
|
6
|
+
}): boolean;
|
|
7
|
+
//# sourceMappingURL=customer-auth-access.d.ts.map
|
|
@@ -15,6 +15,9 @@ export function registerTools(server, artifact, deps, context) {
|
|
|
15
15
|
server.setRequestHandler(ListToolsRequestSchema, async () => mapToolsList(artifact, context.caller, {
|
|
16
16
|
knowledgeTools: await knowledgeToolsEnabled(artifact, deps),
|
|
17
17
|
intentCapture: context.intentCapture?.enabled === true,
|
|
18
|
+
...(context.toolAuthentication === undefined
|
|
19
|
+
? {}
|
|
20
|
+
: { authentication: context.toolAuthentication }),
|
|
18
21
|
}));
|
|
19
22
|
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
20
23
|
const toolName = request.params.name;
|
|
@@ -8,6 +8,7 @@ export { buildMcpServer, type ProtocolRequestContext, type ProtocolToolDispatchC
|
|
|
8
8
|
export { handleStatelessHttp } from './stateless.js';
|
|
9
9
|
export { evaluateToolAuthorization, filterAuthorizedTools, TOOL_AUTHORIZATION_DENIED, type ToolAuthorizationCaller, type ToolAuthorizationDecision, type ToolAuthorizationRuleClass, toolAuthorizationRuleClass, toolAuthorizationRuleFingerprint, } from './tool-authorization.js';
|
|
10
10
|
export { toolRequiresConfirmation } from './tool-confirmation.js';
|
|
11
|
+
export { filterDiscoverableTools, type ToolAuthenticationPolicy } from './tool-discovery.js';
|
|
11
12
|
export { createDualEraMcpHandler, createPlatformDualEraMcpHandler, } from './v2/handler.js';
|
|
12
13
|
export { LEGACY_MCP_PROTOCOL_VERSION, type McpProtocolEra, type McpProtocolMode, MODERN_MCP_PROTOCOL_VERSION, SERVED_MCP_PROTOCOL_VERSIONS, type ServedMcpProtocolVersion, } from './v2/versions.js';
|
|
13
14
|
export { injectWidgetBridge } from './widget/inject.js';
|
|
@@ -7,6 +7,7 @@ export { buildMcpServer, } from './sdk-server.js';
|
|
|
7
7
|
export { handleStatelessHttp } from './stateless.js';
|
|
8
8
|
export { evaluateToolAuthorization, filterAuthorizedTools, TOOL_AUTHORIZATION_DENIED, toolAuthorizationRuleClass, toolAuthorizationRuleFingerprint, } from './tool-authorization.js';
|
|
9
9
|
export { toolRequiresConfirmation } from './tool-confirmation.js';
|
|
10
|
+
export { filterDiscoverableTools } from './tool-discovery.js';
|
|
10
11
|
export { createDualEraMcpHandler, createPlatformDualEraMcpHandler, } from './v2/handler.js';
|
|
11
12
|
export { LEGACY_MCP_PROTOCOL_VERSION, MODERN_MCP_PROTOCOL_VERSION, SERVED_MCP_PROTOCOL_VERSIONS, } from './v2/versions.js';
|
|
12
13
|
export { injectWidgetBridge } from './widget/inject.js';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ArtifactTool, RuntimeArtifact } from '@noodle-borg/compiler';
|
|
2
2
|
import type { JsonRpcErrorObject } from './jsonrpc.js';
|
|
3
|
-
import {
|
|
3
|
+
import type { ToolAuthorizationCaller } from './tool-authorization.js';
|
|
4
|
+
import { type ToolAuthenticationPolicy, type ToolSecurityScheme } from './tool-discovery.js';
|
|
4
5
|
import { type WidgetDomainProjection } from './widget/domain-projection.js';
|
|
5
6
|
/**
|
|
6
7
|
* Artifact → MCP wire mapping. The official `@modelcontextprotocol/sdk` owns JSON-RPC framing and
|
|
@@ -16,6 +17,7 @@ export interface ToolDescriptor {
|
|
|
16
17
|
readonly inputSchema: Record<string, unknown>;
|
|
17
18
|
readonly outputSchema?: Record<string, unknown>;
|
|
18
19
|
readonly annotations?: Record<string, unknown>;
|
|
20
|
+
readonly securitySchemes?: readonly ToolSecurityScheme[];
|
|
19
21
|
/** MCP `_meta` extension bag (e.g. MCP Apps `{ ui: { resourceUri } }` linking the tool to its widget). */
|
|
20
22
|
readonly _meta?: Record<string, unknown>;
|
|
21
23
|
}
|
|
@@ -44,6 +46,7 @@ export { mapExecutionError } from './execution-error-mapping.js';
|
|
|
44
46
|
/** Map a resolved artifact tool to an MCP tool descriptor (carrying its `_meta` extension bag, if any). */
|
|
45
47
|
export declare function mapTool(tool: ArtifactTool, options?: {
|
|
46
48
|
readonly intentCapture?: boolean;
|
|
49
|
+
readonly authentication?: ToolAuthenticationPolicy;
|
|
47
50
|
}): ToolDescriptor;
|
|
48
51
|
/**
|
|
49
52
|
* Map the artifact's tools to a `tools/list` result. App-only widget helpers remain discoverable here with
|
|
@@ -53,6 +56,7 @@ export declare function mapTool(tool: ArtifactTool, options?: {
|
|
|
53
56
|
export declare function mapToolsList(artifact: RuntimeArtifact, caller?: ToolAuthorizationCaller, options?: {
|
|
54
57
|
readonly knowledgeTools?: boolean;
|
|
55
58
|
readonly intentCapture?: boolean;
|
|
59
|
+
readonly authentication?: ToolAuthenticationPolicy;
|
|
56
60
|
}): ToolsListResult;
|
|
57
61
|
/**
|
|
58
62
|
* Map a successful tool output to a `tools/call` result. Structured (object) output is returned as
|
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import { splitResultMeta } from '@noodle-borg/runtime';
|
|
2
2
|
import { artifactDeclaresContext, assertNoContextToolCollision, CONTEXT_TOOL_DESCRIPTOR, } from './context-tool.js';
|
|
3
3
|
import { projectIntentCaptureInput } from './intent-capture.js';
|
|
4
|
-
import {
|
|
4
|
+
import { filterDiscoverableTools, toolSecuritySchemes, } from './tool-discovery.js';
|
|
5
5
|
import { projectWidgetResourceMeta, } from './widget/domain-projection.js';
|
|
6
6
|
import { injectWidgetBridge } from './widget/inject.js';
|
|
7
7
|
export { mapExecutionError } from './execution-error-mapping.js';
|
|
8
8
|
/** Map a resolved artifact tool to an MCP tool descriptor (carrying its `_meta` extension bag, if any). */
|
|
9
9
|
export function mapTool(tool, options) {
|
|
10
|
-
return {
|
|
10
|
+
return withToolAuthentication({
|
|
11
11
|
name: tool.name,
|
|
12
12
|
...(tool.title !== undefined ? { title: tool.title } : {}),
|
|
13
13
|
description: tool.description,
|
|
14
14
|
inputSchema: projectIntentCaptureInput(withPortableInteractionInput(tool), options?.intentCapture === true),
|
|
15
15
|
...(tool.outputSchema !== undefined ? { outputSchema: tool.outputSchema } : {}),
|
|
16
16
|
...(tool.annotations !== undefined ? { annotations: tool.annotations } : {}),
|
|
17
|
-
...(tool._meta
|
|
18
|
-
};
|
|
17
|
+
...(tool._meta === undefined ? {} : { _meta: tool._meta }),
|
|
18
|
+
}, tool, options?.authentication);
|
|
19
|
+
}
|
|
20
|
+
function withToolAuthentication(descriptor, tool, policy) {
|
|
21
|
+
if (policy !== 'mixed-customer')
|
|
22
|
+
return descriptor;
|
|
23
|
+
const securitySchemes = toolSecuritySchemes(tool);
|
|
24
|
+
return { ...descriptor, securitySchemes, _meta: { ...descriptor._meta, securitySchemes } };
|
|
19
25
|
}
|
|
20
26
|
const PORTABLE_INTERACTION_INPUT_SCHEMA = {
|
|
21
27
|
type: 'object',
|
|
@@ -65,10 +71,12 @@ export function mapToolsList(artifact, caller, options) {
|
|
|
65
71
|
assertNoContextToolCollision(artifact);
|
|
66
72
|
return {
|
|
67
73
|
tools: [
|
|
68
|
-
...
|
|
69
|
-
...(artifactDeclaresContext(artifact)
|
|
74
|
+
...filterDiscoverableTools(artifact.tools, caller).map((tool) => mapTool(tool, options)),
|
|
75
|
+
...(artifactDeclaresContext(artifact)
|
|
76
|
+
? [withToolAuthentication(CONTEXT_TOOL_DESCRIPTOR, {}, options?.authentication)]
|
|
77
|
+
: []),
|
|
70
78
|
...(options?.knowledgeTools === true
|
|
71
|
-
? knowledgeToolDescriptors(artifact, options?.intentCapture === true)
|
|
79
|
+
? knowledgeToolDescriptors(artifact, options?.intentCapture === true).map((descriptor) => withToolAuthentication(descriptor, {}, options?.authentication))
|
|
72
80
|
: []),
|
|
73
81
|
],
|
|
74
82
|
};
|
|
@@ -18,6 +18,8 @@ export interface ServedArtifact {
|
|
|
18
18
|
readonly appPackageSnapshot?: AppPackageSnapshotV1;
|
|
19
19
|
}
|
|
20
20
|
export interface ProtocolRequestContext {
|
|
21
|
+
/** Resolved endpoint policy used only to derive MCP discovery metadata. */
|
|
22
|
+
readonly toolAuthentication?: import('./tool-discovery.js').ToolAuthenticationPolicy;
|
|
21
23
|
readonly caller?: CallerIdentity;
|
|
22
24
|
/** Internal hosting attribution, never MCP payload metadata or caller-visible context. */
|
|
23
25
|
readonly publicAdmission?: NonNullable<ExecuteDeps['publicAdmission']>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ArtifactTool } from '@noodle-borg/compiler';
|
|
2
|
+
import { type ToolAuthorizationCaller } from './tool-authorization.js';
|
|
3
|
+
/** The hosting plane opts into schemes only for the resolved mixed customer policy. */
|
|
4
|
+
export type ToolAuthenticationPolicy = 'mixed-customer';
|
|
5
|
+
export type ToolSecurityScheme = {
|
|
6
|
+
readonly type: 'noauth';
|
|
7
|
+
} | {
|
|
8
|
+
readonly type: 'oauth2';
|
|
9
|
+
readonly scopes: readonly string[];
|
|
10
|
+
};
|
|
11
|
+
/** Descriptor publication only; execution and non-MCP capability filters remain authorization-only. */
|
|
12
|
+
export declare function filterDiscoverableTools(tools: readonly ArtifactTool[], caller: ToolAuthorizationCaller | undefined): readonly ArtifactTool[];
|
|
13
|
+
export declare function toolSecuritySchemes(tool: Pick<ArtifactTool, 'authorization'>): readonly ToolSecurityScheme[];
|
|
14
|
+
//# sourceMappingURL=tool-discovery.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { evaluateToolAuthorization } from './tool-authorization.js';
|
|
2
|
+
/** Descriptor publication only; execution and non-MCP capability filters remain authorization-only. */
|
|
3
|
+
export function filterDiscoverableTools(tools, caller) {
|
|
4
|
+
return tools.filter((tool) => tool.authorization?.discovery === 'public' ||
|
|
5
|
+
evaluateToolAuthorization(tool.authorization, caller).allow);
|
|
6
|
+
}
|
|
7
|
+
export function toolSecuritySchemes(tool) {
|
|
8
|
+
return tool.authorization === undefined
|
|
9
|
+
? [{ type: 'noauth' }]
|
|
10
|
+
: [{ type: 'oauth2', scopes: tool.authorization.requiredScopes ?? [] }];
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=tool-discovery.js.map
|
|
@@ -93,6 +93,9 @@ function registerV2Tools(server, artifact, deps, context, era) {
|
|
|
93
93
|
const mapped = mapToolsList(artifact, context.caller, {
|
|
94
94
|
knowledgeTools: await knowledgeToolsEnabled(artifact, deps),
|
|
95
95
|
intentCapture: context.intentCapture?.enabled === true,
|
|
96
|
+
...(context.toolAuthentication === undefined
|
|
97
|
+
? {}
|
|
98
|
+
: { authentication: context.toolAuthentication }),
|
|
96
99
|
});
|
|
97
100
|
return (era === 'modern' ? shapeModernToolsList(mapped) : mapped);
|
|
98
101
|
});
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { MIXED_CUSTOMER_AUTH_FEATURE_VERSION, serviceInfoResponseSchema, } from '@noodle-borg/wire-contracts';
|
|
1
2
|
export function serviceInfoPayload(buildInfo, developerMcp) {
|
|
2
|
-
return {
|
|
3
|
+
return serviceInfoResponseSchema.parse({
|
|
3
4
|
ok: true,
|
|
4
5
|
status: 'ok',
|
|
5
6
|
...buildInfo,
|
|
7
|
+
features: { mixedCustomerAuth: MIXED_CUSTOMER_AUTH_FEATURE_VERSION },
|
|
6
8
|
...(developerMcp
|
|
7
9
|
? { developerPlugin: { mcpCapabilityVersion: DEVELOPER_MCP_CAPABILITY_VERSION } }
|
|
8
10
|
: {}),
|
|
9
|
-
};
|
|
11
|
+
});
|
|
10
12
|
}
|
|
11
13
|
export function cliCompatibilityError(buildInfo, cliVersion) {
|
|
12
14
|
const supported = buildInfo.compatiblePackageVersions?.['@noodleseed/one'];
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import { usesCustomerAuthentication } from '@noodle-borg/module';
|
|
2
|
+
/** Match durable ownership, including an omitted stored projection when compilation declares auth. */
|
|
3
|
+
export function requiresCustomerAuthProjection(record, compiledAuth) {
|
|
4
|
+
return usesCustomerAuthentication({
|
|
5
|
+
schemaVersion: record.schemaVersion,
|
|
6
|
+
accessMode: record.accessMode,
|
|
7
|
+
hasServerAuth: record.serverAuth != null || compiledAuth !== undefined,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
1
10
|
/** Safe lifecycle error; tenant identities and configured values never enter its public message. */
|
|
2
11
|
export class CustomerAuthAudienceConflictError extends Error {
|
|
3
12
|
code = 'customer_auth_audience_conflict';
|
|
@@ -51,7 +60,7 @@ export function isTenantAuthConfig(value) {
|
|
|
51
60
|
}
|
|
52
61
|
/** Customer-serving records must exactly project the compiler-authoritative auth declaration. */
|
|
53
62
|
export function hasExactCustomerAuthProjection(record, compiledAuth) {
|
|
54
|
-
if (record
|
|
63
|
+
if (!requiresCustomerAuthProjection(record, compiledAuth))
|
|
55
64
|
return true;
|
|
56
65
|
if (compiledAuth === undefined || !isTenantAuthConfig(record.serverAuth))
|
|
57
66
|
return false;
|
|
@@ -65,7 +74,7 @@ export function hasExactCustomerAuthProjection(record, compiledAuth) {
|
|
|
65
74
|
}
|
|
66
75
|
/** Require an exact compiler-authenticated snapshot before clearing customer app archive stamps. */
|
|
67
76
|
export function assertCustomerAuthRestorePrecondition(records, precondition) {
|
|
68
|
-
const candidates = records.filter((record) => record.active && record
|
|
77
|
+
const candidates = records.filter((record) => record.active && requiresCustomerAuthProjection(record));
|
|
69
78
|
const projections = precondition?.customerAuthProjections ?? [];
|
|
70
79
|
if (candidates.length !== projections.length) {
|
|
71
80
|
throw new CustomerAuthAudienceProjectionError();
|
|
@@ -107,7 +116,7 @@ export function findActiveCustomerAuthAudienceConflict(records, tenant, auth) {
|
|
|
107
116
|
for (const record of records) {
|
|
108
117
|
if (!record.active ||
|
|
109
118
|
record.archivedAt !== undefined ||
|
|
110
|
-
record
|
|
119
|
+
!requiresCustomerAuthProjection(record) ||
|
|
111
120
|
sameTenant(record, tenant)) {
|
|
112
121
|
continue;
|
|
113
122
|
}
|
|
@@ -124,7 +133,9 @@ export function findActiveCustomerAuthAudienceConflict(records, tenant, auth) {
|
|
|
124
133
|
export function assertUniqueActiveCustomerAuthAudienceBindings(records) {
|
|
125
134
|
const owners = new Map();
|
|
126
135
|
for (const record of records) {
|
|
127
|
-
if (!record.active ||
|
|
136
|
+
if (!record.active ||
|
|
137
|
+
record.archivedAt !== undefined ||
|
|
138
|
+
!requiresCustomerAuthProjection(record)) {
|
|
128
139
|
continue;
|
|
129
140
|
}
|
|
130
141
|
if (!isTenantAuthConfig(record.serverAuth)) {
|
|
@@ -143,7 +154,7 @@ export function assertUniqueActiveCustomerAuthAudienceBindings(records) {
|
|
|
143
154
|
}
|
|
144
155
|
/** Shared registry guard with an optimized durable-store path and an in-memory fallback. */
|
|
145
156
|
export async function hasActiveCustomerAuthAudienceConflict(store, records, record, auth) {
|
|
146
|
-
if (record
|
|
157
|
+
if (!requiresCustomerAuthProjection(record, auth) || auth === undefined || auth.kind === 'bridge')
|
|
147
158
|
return false;
|
|
148
159
|
const tenant = { org: record.orgSlug, app: record.appSlug, env: record.environment };
|
|
149
160
|
const conflict = store?.findActiveCustomerAuthAudienceConflict !== undefined
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { parse as parseYaml } from 'yaml';
|
|
2
|
+
export function isIdentityAccessMode(accessMode, manifest) {
|
|
3
|
+
if (accessMode === 'mixed' && manifest !== undefined) {
|
|
4
|
+
try {
|
|
5
|
+
const parsed = parseYaml(manifest);
|
|
6
|
+
if (typeof parsed === 'object' && parsed !== null && 'server' in parsed) {
|
|
7
|
+
const server = parsed.server;
|
|
8
|
+
if (typeof server === 'object' &&
|
|
9
|
+
server !== null &&
|
|
10
|
+
'auth' in server &&
|
|
11
|
+
server.auth != null)
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
/* Compilation owns malformed manifest diagnostics. */
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return (accessMode === 'owner-only' ||
|
|
20
|
+
accessMode === 'org-members' ||
|
|
21
|
+
accessMode === 'customers' ||
|
|
22
|
+
accessMode === 'authenticated');
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=deployment-access-mode.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
2
|
+
/** Compare inside the lifecycle lock/transaction, before any projection or active-pointer writes. */
|
|
3
|
+
export function matchesDeploymentActivation(target, precondition) {
|
|
4
|
+
if (target.schemaVersion !== (precondition?.expectedSchemaVersion ?? 1))
|
|
5
|
+
return false;
|
|
6
|
+
if (precondition === undefined)
|
|
7
|
+
return true;
|
|
8
|
+
if (target.accessMode !== precondition.expectedAccessMode)
|
|
9
|
+
return false;
|
|
10
|
+
const expected = precondition.expectedRevision;
|
|
11
|
+
if (expected === undefined)
|
|
12
|
+
return true;
|
|
13
|
+
// These are all persisted compile inputs plus the authority and lifecycle state used by the target.
|
|
14
|
+
// Active status may legitimately change on repeated activation; it is not an executable input.
|
|
15
|
+
return [
|
|
16
|
+
'manifest',
|
|
17
|
+
'connectors',
|
|
18
|
+
'hostedAssets',
|
|
19
|
+
'serverAuth',
|
|
20
|
+
'serverVersion',
|
|
21
|
+
'ownerSubject',
|
|
22
|
+
'createdBySubject',
|
|
23
|
+
'orgMembershipSources',
|
|
24
|
+
'archivedAt',
|
|
25
|
+
].every((key) => isDeepStrictEqual(target[key], expected[key]));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=deployment-activation-precondition.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { usesCustomerAuthentication } from '@noodle-borg/module';
|
|
2
|
+
import { deploymentRecordVersionError } from './deployment-record-version.js';
|
|
3
|
+
/** Read the effective authentication authority only when this runtime understands the record. */
|
|
4
|
+
export function deploymentAuthenticationFor(record, compiledAuth) {
|
|
5
|
+
if (deploymentRecordVersionError(record) !== undefined || record.accessMode === undefined) {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
if (record.accessMode === 'public')
|
|
9
|
+
return 'none';
|
|
10
|
+
if (usesCustomerAuthentication({
|
|
11
|
+
schemaVersion: record.schemaVersion,
|
|
12
|
+
accessMode: record.accessMode,
|
|
13
|
+
hasServerAuth: record.serverAuth !== undefined || compiledAuth !== undefined,
|
|
14
|
+
})) {
|
|
15
|
+
return 'customer';
|
|
16
|
+
}
|
|
17
|
+
return 'platform';
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=deployment-authentication.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { cspFaultsInManifest } from '@noodle-borg/compiler';
|
|
2
2
|
import { noopLogger } from '@noodle-borg/transport-http';
|
|
3
3
|
import { BUSINESS_SETUP_MESSAGE, BusinessOnboarding } from './business-onboarding.js';
|
|
4
|
+
import { isIdentityAccessMode } from './deployment-access-mode.js';
|
|
4
5
|
import { manifestUsesUserRoot } from './registry-access.js';
|
|
5
|
-
import { isIdentityAccessMode } from './routes/access-mode.js';
|
|
6
6
|
import { provisionPublicEmbed } from './routes/deploy-public-embed.js';
|
|
7
7
|
import { deploymentActivationRejection } from './routes/deployment-activation-response.js';
|
|
8
8
|
/** Shared post-authorization deploy flow. Both API deploys and installations retain registry activation hooks. */
|
|
@@ -42,7 +42,7 @@ export async function executeAuthorizedDeployment(input, dependencies) {
|
|
|
42
42
|
}
|
|
43
43
|
// Identity access modes bind the data plane to verified identity, so the deployer must be authenticated.
|
|
44
44
|
// (Localhost dev runs the gate open; such deploys are rejected for lack of an owner/audit actor.)
|
|
45
|
-
if (isIdentityAccessMode(accessMode) && !identity) {
|
|
45
|
+
if (isIdentityAccessMode(accessMode, manifest) && !identity) {
|
|
46
46
|
return reject(401, {
|
|
47
47
|
error: `${accessMode} deployments require an authenticated deployer`,
|
|
48
48
|
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { sameDeploymentScope } from './deployment-versioning.js';
|
|
2
|
+
const VERSION_ERROR = {
|
|
3
|
+
code: 'unsupported_deployment_record_version',
|
|
4
|
+
path: 'schemaVersion',
|
|
5
|
+
message: 'Deployment record version is not supported by this runtime.',
|
|
6
|
+
};
|
|
7
|
+
export class UnsupportedDeploymentRecordVersionError extends Error {
|
|
8
|
+
code = VERSION_ERROR.code;
|
|
9
|
+
constructor() {
|
|
10
|
+
super(VERSION_ERROR.message);
|
|
11
|
+
this.name = 'UnsupportedDeploymentRecordVersionError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** R1 serves the two understood policy versions; future policy remains unavailable. */
|
|
15
|
+
export function deploymentRecordVersionError(record) {
|
|
16
|
+
return record.schemaVersion === 1 || record.schemaVersion === 2 ? undefined : VERSION_ERROR;
|
|
17
|
+
}
|
|
18
|
+
/** A stale writer cannot replace or deactivate a newer policy, even after registry preflight. */
|
|
19
|
+
export function assertDeploymentAppendVersion(records, candidate) {
|
|
20
|
+
if (records.some((record) => record.schemaVersion > candidate.schemaVersion &&
|
|
21
|
+
(record.deploymentId === candidate.deploymentId ||
|
|
22
|
+
(candidate.active &&
|
|
23
|
+
record.active &&
|
|
24
|
+
record.archivedAt === undefined &&
|
|
25
|
+
sameDeploymentScope(record, candidate)))))
|
|
26
|
+
throw new UnsupportedDeploymentRecordVersionError();
|
|
27
|
+
}
|
|
28
|
+
export function unsupportedDeploymentRecordFailure() {
|
|
29
|
+
return { ok: false, errors: [VERSION_ERROR] };
|
|
30
|
+
}
|
|
31
|
+
/** Reject a deployment compiled against an operator policy that has since changed. */
|
|
32
|
+
export class DeploymentPolicyChangedError extends Error {
|
|
33
|
+
code = 'deployment_policy_changed';
|
|
34
|
+
constructor() {
|
|
35
|
+
super('The active deployment policy changed. Retry the deployment.');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function assertDeploymentAppendPolicy(records, candidate, precondition) {
|
|
39
|
+
if (precondition === undefined)
|
|
40
|
+
return;
|
|
41
|
+
const current = records.find((record) => record.active && record.archivedAt === undefined && sameDeploymentScope(record, candidate));
|
|
42
|
+
const expected = precondition.active;
|
|
43
|
+
if (expected === null
|
|
44
|
+
? current !== undefined
|
|
45
|
+
: current === undefined ||
|
|
46
|
+
current.deploymentId !== expected.deploymentId ||
|
|
47
|
+
current.schemaVersion !== expected.schemaVersion ||
|
|
48
|
+
current.accessMode !== expected.accessMode ||
|
|
49
|
+
current.ownerSubject !== expected.ownerSubject ||
|
|
50
|
+
current.manifest !== expected.manifest ||
|
|
51
|
+
JSON.stringify(current.serverAuth) !== JSON.stringify(expected.serverAuth)) {
|
|
52
|
+
throw new DeploymentPolicyChangedError();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=deployment-record-version.js.map
|
|
@@ -8,7 +8,21 @@ export async function inspectServiceDeployment(registry, tenant, baseUrl, endpoi
|
|
|
8
8
|
return {
|
|
9
9
|
ok: true,
|
|
10
10
|
target: status.target,
|
|
11
|
-
|
|
11
|
+
// Keep the Developer MCP port projection explicit as status gains additive operator fields.
|
|
12
|
+
deployment: {
|
|
13
|
+
deploymentId: status.deployment.deploymentId,
|
|
14
|
+
endpointUrl: status.deployment.endpointUrl,
|
|
15
|
+
active: status.deployment.active,
|
|
16
|
+
serverName: status.deployment.serverName,
|
|
17
|
+
createdAt: status.deployment.createdAt,
|
|
18
|
+
...(status.deployment.createdByEmail === undefined
|
|
19
|
+
? {}
|
|
20
|
+
: { createdByEmail: status.deployment.createdByEmail }),
|
|
21
|
+
accessMode: status.deployment.accessMode,
|
|
22
|
+
...(status.deployment.ownerSubject === undefined
|
|
23
|
+
? {}
|
|
24
|
+
: { ownerSubject: status.deployment.ownerSubject }),
|
|
25
|
+
},
|
|
12
26
|
health: {
|
|
13
27
|
state: status.health.state,
|
|
14
28
|
missingSecrets: status.config.missingSecrets,
|