veryfront 0.1.246 → 0.1.247
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/esm/deno.js +1 -1
- package/esm/src/agent/durable.d.ts +34 -0
- package/esm/src/agent/durable.d.ts.map +1 -1
- package/esm/src/agent/durable.js +39 -0
- package/esm/src/agent/index.d.ts +1 -1
- package/esm/src/agent/index.d.ts.map +1 -1
- package/esm/src/agent/index.js +1 -1
- package/esm/src/integrations/schema.d.ts +2 -2
- package/esm/src/mcp/index.d.ts +7 -2
- package/esm/src/mcp/index.d.ts.map +1 -1
- package/esm/src/mcp/index.js +7 -2
- package/esm/src/mcp/schemas/index.d.ts +1 -1
- package/esm/src/mcp/schemas/index.d.ts.map +1 -1
- package/esm/src/mcp/schemas/index.js +1 -1
- package/esm/src/mcp/schemas/mcp.schema.d.ts +13 -7
- package/esm/src/mcp/schemas/mcp.schema.d.ts.map +1 -1
- package/esm/src/mcp/schemas/mcp.schema.js +17 -7
- package/esm/src/mcp/server.d.ts +13 -0
- package/esm/src/mcp/server.d.ts.map +1 -1
- package/esm/src/mcp/server.js +43 -6
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/esm/src/workflow/claude-code/workspace-sync.d.ts +17 -2
- package/esm/src/workflow/claude-code/workspace-sync.d.ts.map +1 -1
- package/esm/src/workflow/claude-code/workspace-sync.js +106 -19
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/src/agent/durable.ts +83 -0
- package/src/src/agent/index.ts +2 -0
- package/src/src/mcp/index.ts +7 -2
- package/src/src/mcp/schemas/index.ts +1 -0
- package/src/src/mcp/schemas/mcp.schema.ts +20 -7
- package/src/src/mcp/server.ts +60 -6
- package/src/src/utils/version-constant.ts +1 -1
- package/src/src/workflow/claude-code/workspace-sync.ts +109 -20
package/esm/deno.js
CHANGED
|
@@ -80,6 +80,7 @@ export type TerminalConversationRunStatus = Extract<ConversationRunProjection["s
|
|
|
80
80
|
export type ConversationRunAppendCursorResyncResult = "advanced" | "non_appendable" | "unchanged";
|
|
81
81
|
export type ConversationRunAppendRecoveryOutcome = "resumed" | "stopped" | "bubbled";
|
|
82
82
|
export type ConversationRunAppendFailureOutcome = "resumed" | "stopped" | "retry_scheduled";
|
|
83
|
+
export type ConversationRunAppendExecutionOutcome = "resumed" | "stopped" | "retry_scheduled";
|
|
83
84
|
export declare const CreateConversationRunAcceptedSchema: z.ZodPipe<z.ZodObject<{
|
|
84
85
|
run: z.ZodObject<{
|
|
85
86
|
runId: z.ZodOptional<z.ZodString>;
|
|
@@ -250,6 +251,39 @@ export declare function recoverConversationRunAppendFailure(input: {
|
|
|
250
251
|
errorMessage?: string;
|
|
251
252
|
run?: ConversationRunProjection;
|
|
252
253
|
}>;
|
|
254
|
+
export declare function recoverConversationRunAppendExecution(input: {
|
|
255
|
+
error: unknown;
|
|
256
|
+
authToken: string;
|
|
257
|
+
apiUrl: string;
|
|
258
|
+
conversationId: string;
|
|
259
|
+
runId: string;
|
|
260
|
+
latestEventId: number;
|
|
261
|
+
latestExternalEventSequence: number;
|
|
262
|
+
remainingEvents: unknown[];
|
|
263
|
+
pendingEvents: unknown[];
|
|
264
|
+
cursorResyncsThisFlush: number;
|
|
265
|
+
consecutiveFailures: number;
|
|
266
|
+
maxCursorResyncsPerFlush: number;
|
|
267
|
+
abortSignal?: AbortSignal;
|
|
268
|
+
}): Promise<{
|
|
269
|
+
outcome: "resumed";
|
|
270
|
+
latestEventId: number;
|
|
271
|
+
latestExternalEventSequence: number;
|
|
272
|
+
pendingEvents: unknown[];
|
|
273
|
+
consecutiveFailures: number;
|
|
274
|
+
} | {
|
|
275
|
+
outcome: "stopped";
|
|
276
|
+
latestEventId: number;
|
|
277
|
+
latestExternalEventSequence: number;
|
|
278
|
+
disableReason?: "cursor_resyncs_exhausted" | "non_appendable" | "ignorable_append_rejection";
|
|
279
|
+
} | {
|
|
280
|
+
outcome: "retry_scheduled";
|
|
281
|
+
latestEventId: number;
|
|
282
|
+
latestExternalEventSequence: number;
|
|
283
|
+
pendingEvents: unknown[];
|
|
284
|
+
consecutiveFailures: number;
|
|
285
|
+
errorMessage: string;
|
|
286
|
+
}>;
|
|
253
287
|
export declare function getConversationRun(input: {
|
|
254
288
|
authToken: string;
|
|
255
289
|
apiUrl: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"durable.d.ts","sourceRoot":"","sources":["../../../src/src/agent/durable.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"durable.d.ts","sourceRoot":"","sources":["../../../src/src/agent/durable.ts"],"names":[],"mappings":"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"}
|
package/esm/src/agent/durable.js
CHANGED
|
@@ -361,6 +361,45 @@ export async function recoverConversationRunAppendFailure(input) {
|
|
|
361
361
|
...(cursorRecovery.run ? { run: cursorRecovery.run } : {}),
|
|
362
362
|
};
|
|
363
363
|
}
|
|
364
|
+
export async function recoverConversationRunAppendExecution(input) {
|
|
365
|
+
const recovered = await recoverConversationRunAppendFailure({
|
|
366
|
+
error: input.error,
|
|
367
|
+
authToken: input.authToken,
|
|
368
|
+
apiUrl: input.apiUrl,
|
|
369
|
+
conversationId: input.conversationId,
|
|
370
|
+
runId: input.runId,
|
|
371
|
+
latestEventId: input.latestEventId,
|
|
372
|
+
latestExternalEventSequence: input.latestExternalEventSequence,
|
|
373
|
+
cursorResyncsThisFlush: input.cursorResyncsThisFlush,
|
|
374
|
+
maxCursorResyncsPerFlush: input.maxCursorResyncsPerFlush,
|
|
375
|
+
abortSignal: input.abortSignal,
|
|
376
|
+
});
|
|
377
|
+
if (recovered.outcome === "resumed") {
|
|
378
|
+
return {
|
|
379
|
+
outcome: "resumed",
|
|
380
|
+
latestEventId: recovered.latestEventId,
|
|
381
|
+
latestExternalEventSequence: recovered.latestExternalEventSequence,
|
|
382
|
+
pendingEvents: [...input.remainingEvents, ...input.pendingEvents],
|
|
383
|
+
consecutiveFailures: 0,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
if (recovered.outcome === "stopped") {
|
|
387
|
+
return {
|
|
388
|
+
outcome: "stopped",
|
|
389
|
+
latestEventId: recovered.latestEventId,
|
|
390
|
+
latestExternalEventSequence: recovered.latestExternalEventSequence,
|
|
391
|
+
...(recovered.disableReason ? { disableReason: recovered.disableReason } : {}),
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
outcome: "retry_scheduled",
|
|
396
|
+
latestEventId: recovered.latestEventId,
|
|
397
|
+
latestExternalEventSequence: recovered.latestExternalEventSequence,
|
|
398
|
+
pendingEvents: [...input.remainingEvents, ...input.pendingEvents],
|
|
399
|
+
consecutiveFailures: input.consecutiveFailures + 1,
|
|
400
|
+
errorMessage: recovered.errorMessage ?? "Conversation run append failed",
|
|
401
|
+
};
|
|
402
|
+
}
|
|
364
403
|
async function waitForConversationRunPoll(ms, abortSignal) {
|
|
365
404
|
if (ms <= 0 || abortSignal?.aborted) {
|
|
366
405
|
return;
|
package/esm/src/agent/index.d.ts
CHANGED
|
@@ -93,7 +93,7 @@ export { type ConversationRunContext, createConversationRunContext, } from "./co
|
|
|
93
93
|
export { type ConversationRootRunContext, type ConversationRootRunDescriptor, createConversationRootRunContext, createConversationRootRunStartAdapter, prepareConversationRootRunContext, startConversationRootRun, } from "./conversation-root-run-context.js";
|
|
94
94
|
export { bootstrapConversationAgentRun, type BootstrapConversationAgentRunResult, type ConversationMessageRecord, ConversationMessageRecordSchema, type ConversationRecord, ConversationRecordSchema, createConversationMessage, createConversationRecord, ensureConversationProjectLink, fetchConversationRecord, } from "./conversation-bootstrap.js";
|
|
95
95
|
export { type ConversationChildLifecycleContext, type ConversationHostedLifecycleFinalizeInput, createConversationChildLifecycleAdapter, createConversationHostedLifecycleAdapter, type CreateConversationHostedLifecycleAdapterOptions, } from "./conversation-hosted-lifecycle.js";
|
|
96
|
-
export { type ActiveConversationRunStatus, appendConversationRunEvents, AppendConversationRunEventsError, type AppendConversationRunEventsResponse, AppendConversationRunEventsResponseSchema, CompleteConversationRunResponseSchema, type ConversationAgentRunUsage, type ConversationRunAppendCursorResyncResult, type ConversationRunAppendFailureOutcome, type ConversationRunAppendRecoveryOutcome, type ConversationRunProjection, ConversationRunProjectionSchema, ConversationRunStatusSchema, type ConversationRunTargets, ConversationRunTargetsSchema, ConversationRunTerminalStateError, createConversationAgentRun, finalizeConversationAgentRun, getConversationRun, isActiveConversationRunStatus, isAppendableConversationRunProjection, isCursorMismatchConversationRunAppendError, isIgnorableConversationRunAppendError, monitorConversationRunStatus, parseAppendConversationRunEventsErrorBody, recoverConversationRunAppendFailure, recoverConversationRunCursorMismatch, resolveConversationRunTargets, resyncConversationRunAppendCursor, type TerminalConversationRunStatus, } from "./durable.js";
|
|
96
|
+
export { type ActiveConversationRunStatus, appendConversationRunEvents, AppendConversationRunEventsError, type AppendConversationRunEventsResponse, AppendConversationRunEventsResponseSchema, CompleteConversationRunResponseSchema, type ConversationAgentRunUsage, type ConversationRunAppendCursorResyncResult, type ConversationRunAppendExecutionOutcome, type ConversationRunAppendFailureOutcome, type ConversationRunAppendRecoveryOutcome, type ConversationRunProjection, ConversationRunProjectionSchema, ConversationRunStatusSchema, type ConversationRunTargets, ConversationRunTargetsSchema, ConversationRunTerminalStateError, createConversationAgentRun, finalizeConversationAgentRun, getConversationRun, isActiveConversationRunStatus, isAppendableConversationRunProjection, isCursorMismatchConversationRunAppendError, isIgnorableConversationRunAppendError, monitorConversationRunStatus, parseAppendConversationRunEventsErrorBody, recoverConversationRunAppendExecution, recoverConversationRunAppendFailure, recoverConversationRunCursorMismatch, resolveConversationRunTargets, resyncConversationRunAppendCursor, type TerminalConversationRunStatus, } from "./durable.js";
|
|
97
97
|
export { buildInvokeAgentChildRunLifecycleCustomEvent, buildInvokeAgentChildRunProgressEvents, buildInvokeAgentChildRunStateDelta, type InvokeAgentChildRunLifecycleCustomEvent, InvokeAgentChildRunLifecycleCustomEventSchema, type InvokeAgentChildRunLifecycleValue, InvokeAgentChildRunLifecycleValueSchema, type InvokeAgentChildRunProgressEvent, type InvokeAgentChildRunProgressInput, type InvokeAgentChildRunStateDelta, InvokeAgentChildRunStateDeltaSchema, publishInvokeAgentChildRunProgress, } from "./invoke-agent-child-runs.js";
|
|
98
98
|
export { type HostedChildLifecycleAdapter, type HostedChildLifecycleRunnerOptions, type HostedChildLifecycleRunResult, type HostedChildLifecycleTerminalState, runHostedChildLifecycle, } from "./hosted-child-lifecycle.js";
|
|
99
99
|
export { type HostedLifecycleAdapter, type HostedLifecycleExecution, type HostedLifecycleRunnerOptions, type HostedLifecycleRunResult, type HostedLifecycleTerminalState, runHostedLifecycle, } from "./hosted-lifecycle.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/agent/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/agent/index.ts"],"names":[],"mappings":"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"}
|
package/esm/src/agent/index.js
CHANGED
|
@@ -92,7 +92,7 @@ export { createConversationRunContext, } from "./conversation-run-context.js";
|
|
|
92
92
|
export { createConversationRootRunContext, createConversationRootRunStartAdapter, prepareConversationRootRunContext, startConversationRootRun, } from "./conversation-root-run-context.js";
|
|
93
93
|
export { bootstrapConversationAgentRun, ConversationMessageRecordSchema, ConversationRecordSchema, createConversationMessage, createConversationRecord, ensureConversationProjectLink, fetchConversationRecord, } from "./conversation-bootstrap.js";
|
|
94
94
|
export { createConversationChildLifecycleAdapter, createConversationHostedLifecycleAdapter, } from "./conversation-hosted-lifecycle.js";
|
|
95
|
-
export { appendConversationRunEvents, AppendConversationRunEventsError, AppendConversationRunEventsResponseSchema, CompleteConversationRunResponseSchema, ConversationRunProjectionSchema, ConversationRunStatusSchema, ConversationRunTargetsSchema, ConversationRunTerminalStateError, createConversationAgentRun, finalizeConversationAgentRun, getConversationRun, isActiveConversationRunStatus, isAppendableConversationRunProjection, isCursorMismatchConversationRunAppendError, isIgnorableConversationRunAppendError, monitorConversationRunStatus, parseAppendConversationRunEventsErrorBody, recoverConversationRunAppendFailure, recoverConversationRunCursorMismatch, resolveConversationRunTargets, resyncConversationRunAppendCursor, } from "./durable.js";
|
|
95
|
+
export { appendConversationRunEvents, AppendConversationRunEventsError, AppendConversationRunEventsResponseSchema, CompleteConversationRunResponseSchema, ConversationRunProjectionSchema, ConversationRunStatusSchema, ConversationRunTargetsSchema, ConversationRunTerminalStateError, createConversationAgentRun, finalizeConversationAgentRun, getConversationRun, isActiveConversationRunStatus, isAppendableConversationRunProjection, isCursorMismatchConversationRunAppendError, isIgnorableConversationRunAppendError, monitorConversationRunStatus, parseAppendConversationRunEventsErrorBody, recoverConversationRunAppendExecution, recoverConversationRunAppendFailure, recoverConversationRunCursorMismatch, resolveConversationRunTargets, resyncConversationRunAppendCursor, } from "./durable.js";
|
|
96
96
|
export { buildInvokeAgentChildRunLifecycleCustomEvent, buildInvokeAgentChildRunProgressEvents, buildInvokeAgentChildRunStateDelta, InvokeAgentChildRunLifecycleCustomEventSchema, InvokeAgentChildRunLifecycleValueSchema, InvokeAgentChildRunStateDeltaSchema, publishInvokeAgentChildRunProgress, } from "./invoke-agent-child-runs.js";
|
|
97
97
|
export { runHostedChildLifecycle, } from "./hosted-child-lifecycle.js";
|
|
98
98
|
export { runHostedLifecycle, } from "./hosted-lifecycle.js";
|
|
@@ -70,9 +70,9 @@ export declare const OAuthFieldSchema: z.ZodObject<{
|
|
|
70
70
|
}, z.core.$strip>;
|
|
71
71
|
export declare const OAuthConfigSchema: z.ZodObject<{
|
|
72
72
|
type: z.ZodEnum<{
|
|
73
|
-
"api-key": "api-key";
|
|
74
73
|
oauth2: "oauth2";
|
|
75
74
|
oauth1: "oauth1";
|
|
75
|
+
"api-key": "api-key";
|
|
76
76
|
}>;
|
|
77
77
|
provider: z.ZodOptional<z.ZodString>;
|
|
78
78
|
authorizationUrl: z.ZodOptional<z.ZodString>;
|
|
@@ -310,9 +310,9 @@ export declare const IntegrationConfigSchema: z.ZodObject<{
|
|
|
310
310
|
description: z.ZodString;
|
|
311
311
|
auth: z.ZodObject<{
|
|
312
312
|
type: z.ZodEnum<{
|
|
313
|
-
"api-key": "api-key";
|
|
314
313
|
oauth2: "oauth2";
|
|
315
314
|
oauth1: "oauth1";
|
|
315
|
+
"api-key": "api-key";
|
|
316
316
|
}>;
|
|
317
317
|
provider: z.ZodOptional<z.ZodString>;
|
|
318
318
|
authorizationUrl: z.ZodOptional<z.ZodString>;
|
package/esm/src/mcp/index.d.ts
CHANGED
|
@@ -17,8 +17,13 @@
|
|
|
17
17
|
* execute: async ({ query }) => ({ results: [] }),
|
|
18
18
|
* });
|
|
19
19
|
*
|
|
20
|
-
* // Start MCP server — registered tools are exposed automatically
|
|
21
|
-
*
|
|
20
|
+
* // Start MCP server — registered tools are exposed automatically.
|
|
21
|
+
* // `auth` is required: use bearer for production, or the explicit
|
|
22
|
+
* // `{ type: "none", allowUnauthenticated: true }` opt-in for local dev only.
|
|
23
|
+
* const server = createMCPServer({
|
|
24
|
+
* enabled: true,
|
|
25
|
+
* auth: { type: "none", allowUnauthenticated: true },
|
|
26
|
+
* });
|
|
22
27
|
* ```
|
|
23
28
|
*/
|
|
24
29
|
import "../../_dnt.polyfills.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,yBAAyB,CAAC;AAGjC,YAAY,EACV,eAAe,EACf,QAAQ,EACR,OAAO,EACP,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,YAAY,GACb,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,eAAe,EAAE,KAAK,uBAAuB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEvF,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC"}
|
package/esm/src/mcp/index.js
CHANGED
|
@@ -17,8 +17,13 @@
|
|
|
17
17
|
* execute: async ({ query }) => ({ results: [] }),
|
|
18
18
|
* });
|
|
19
19
|
*
|
|
20
|
-
* // Start MCP server — registered tools are exposed automatically
|
|
21
|
-
*
|
|
20
|
+
* // Start MCP server — registered tools are exposed automatically.
|
|
21
|
+
* // `auth` is required: use bearer for production, or the explicit
|
|
22
|
+
* // `{ type: "none", allowUnauthenticated: true }` opt-in for local dev only.
|
|
23
|
+
* const server = createMCPServer({
|
|
24
|
+
* enabled: true,
|
|
25
|
+
* auth: { type: "none", allowUnauthenticated: true },
|
|
26
|
+
* });
|
|
22
27
|
* ```
|
|
23
28
|
*/
|
|
24
29
|
import "../../_dnt.polyfills.js";
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module mcp/schemas
|
|
5
5
|
*/
|
|
6
|
-
export { type MCPServerConfig, MCPServerConfigSchema, type MCPStats, MCPStatsSchema, } from "./mcp.schema.js";
|
|
6
|
+
export { MCPAuthConfigSchema, type MCPServerConfig, MCPServerConfigSchema, type MCPStats, MCPStatsSchema, } from "./mcp.schema.js";
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,QAAQ,EACb,cAAc,GACf,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,mBAAmB,EACnB,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,QAAQ,EACb,cAAc,GACf,MAAM,iBAAiB,CAAC"}
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
export declare const MCPAuthConfigSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
3
|
+
type: z.ZodLiteral<"bearer">;
|
|
4
|
+
validate: z.ZodOptional<z.ZodFunction<z.core.$ZodFunctionArgs, z.core.$ZodFunctionOut>>;
|
|
5
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
6
|
+
type: z.ZodLiteral<"none">;
|
|
7
|
+
allowUnauthenticated: z.ZodLiteral<true>;
|
|
8
|
+
}, z.core.$strip>]>;
|
|
2
9
|
export declare const MCPServerConfigSchema: z.ZodObject<{
|
|
3
10
|
enabled: z.ZodBoolean;
|
|
4
11
|
port: z.ZodOptional<z.ZodNumber>;
|
|
5
|
-
auth: z.
|
|
6
|
-
type: z.
|
|
7
|
-
bearer: "bearer";
|
|
8
|
-
none: "none";
|
|
9
|
-
"api-key": "api-key";
|
|
10
|
-
}>;
|
|
12
|
+
auth: z.ZodUnion<readonly [z.ZodObject<{
|
|
13
|
+
type: z.ZodLiteral<"bearer">;
|
|
11
14
|
validate: z.ZodOptional<z.ZodFunction<z.core.$ZodFunctionArgs, z.core.$ZodFunctionOut>>;
|
|
12
|
-
}, z.core.$strip
|
|
15
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
16
|
+
type: z.ZodLiteral<"none">;
|
|
17
|
+
allowUnauthenticated: z.ZodLiteral<true>;
|
|
18
|
+
}, z.core.$strip>]>;
|
|
13
19
|
cors: z.ZodOptional<z.ZodObject<{
|
|
14
20
|
enabled: z.ZodBoolean;
|
|
15
21
|
origins: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.schema.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/schemas/mcp.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp.schema.d.ts","sourceRoot":"","sources":["../../../../src/src/mcp/schemas/mcp.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAmBxB,eAAO,MAAM,mBAAmB;;;;;;mBAAiD,CAAC;AAElF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;iBAUhC,CAAC;AAEH,eAAO,MAAM,cAAc;;;;;iBAKzB,CAAC;AAGH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC"}
|
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* MCP auth configuration. One of:
|
|
4
|
+
* - `{ type: "bearer", validate?: (token) => Promise<boolean> }` — bearer-token auth.
|
|
5
|
+
* - `{ type: "none", allowUnauthenticated: true }` — explicit opt-in to an
|
|
6
|
+
* unauthenticated server. Required for local dev/testing; prevents accidental
|
|
7
|
+
* exposure of the JSON-RPC surface in production (VULN-SRV-5).
|
|
8
|
+
*/
|
|
9
|
+
const AuthValidatedSchema = z.object({
|
|
10
|
+
type: z.literal("bearer"),
|
|
11
|
+
validate: z.function().optional(),
|
|
12
|
+
});
|
|
13
|
+
const AuthNoneSchema = z.object({
|
|
14
|
+
type: z.literal("none"),
|
|
15
|
+
allowUnauthenticated: z.literal(true),
|
|
16
|
+
});
|
|
17
|
+
export const MCPAuthConfigSchema = z.union([AuthValidatedSchema, AuthNoneSchema]);
|
|
2
18
|
export const MCPServerConfigSchema = z.object({
|
|
3
19
|
enabled: z.boolean(),
|
|
4
20
|
port: z.number().int().positive().optional(),
|
|
5
|
-
auth:
|
|
6
|
-
.object({
|
|
7
|
-
type: z.enum(["bearer", "api-key", "none"]),
|
|
8
|
-
validate: z.function()
|
|
9
|
-
.optional(),
|
|
10
|
-
})
|
|
11
|
-
.optional(),
|
|
21
|
+
auth: MCPAuthConfigSchema,
|
|
12
22
|
cors: z
|
|
13
23
|
.object({
|
|
14
24
|
enabled: z.boolean(),
|
package/esm/src/mcp/server.d.ts
CHANGED
|
@@ -41,6 +41,19 @@ export declare class MCPServer {
|
|
|
41
41
|
params?: unknown;
|
|
42
42
|
}) => void;
|
|
43
43
|
constructor(config: MCPServerConfig);
|
|
44
|
+
/**
|
|
45
|
+
* Fail-closed validation of the auth configuration (VULN-SRV-5).
|
|
46
|
+
*
|
|
47
|
+
* Historically, an unset `auth` field — or `{ type: "none" }` — silently
|
|
48
|
+
* accepted every request with only a warning log. That meant an operator who
|
|
49
|
+
* forgot to configure auth shipped an unauthenticated JSON-RPC surface.
|
|
50
|
+
*
|
|
51
|
+
* The new contract: `auth` is required, and the only way to accept
|
|
52
|
+
* unauthenticated traffic is to explicitly set
|
|
53
|
+
* `{ type: "none", allowUnauthenticated: true }`. Any other shape is
|
|
54
|
+
* rejected at construction time.
|
|
55
|
+
*/
|
|
56
|
+
private static validateAuthConfig;
|
|
44
57
|
notifyToolsChanged(): void;
|
|
45
58
|
notifyResourcesChanged(): void;
|
|
46
59
|
notifyPromptsChanged(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAI7D,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,YAAY,CAAC;AAIjE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAWzE,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,CAAC;AA2CzD,UAAU,cAAc;IACtB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC,CAAC;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,UAAU,CASd;IACX,OAAO,CAAC,QAAQ,CAAkD;IAClE,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,iBAAiB,CAAC,CAA0B;IACpD,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,kBAAkB,CAA+B;IACzD,OAAO,CAAC,mBAAmB,CAA8C;IAEzE,2EAA2E;IAC3E,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;gBAElF,MAAM,EAAE,eAAe;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/src/mcp/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAI7D,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,YAAY,CAAC;AAIjE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAWzE,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,CAAC;AA2CzD,UAAU,cAAc;IACtB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC,CAAC;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,UAAU,CASd;IACX,OAAO,CAAC,QAAQ,CAAkD;IAClE,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,iBAAiB,CAAC,CAA0B;IACpD,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,kBAAkB,CAA+B;IACzD,OAAO,CAAC,mBAAmB,CAA8C;IAEzE,2EAA2E;IAC3E,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;gBAElF,MAAM,EAAE,eAAe;IAWnC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAyCjC,kBAAkB,IAAI,IAAI;IAI1B,sBAAsB,IAAI,IAAI;IAI9B,oBAAoB,IAAI,IAAI;IAI5B;;;;;;OAMG;IACH,oBAAoB,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI;IAK3D,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO;IAY5E,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC;IAmBhG,OAAO,CAAC,QAAQ;IAiDhB,OAAO,CAAC,UAAU;YAgCJ,SAAS;IA6BvB,OAAO,CAAC,QAAQ;IAkGhB,OAAO,CAAC,qBAAqB;IAuB7B,OAAO,CAAC,aAAa;IAoBrB,OAAO,CAAC,YAAY;IA6CpB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,SAAS;IAuCjB,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,SAAS;IAIjB,0EAA0E;IAC1E,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC,iBAAiB,IAAI,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC;IAiB5D,OAAO,CAAC,qBAAqB;YAgBf,YAAY;IAoB1B,OAAO,CAAC,cAAc;YAsBR,0BAA0B;CA0BzC;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAElE"}
|
package/esm/src/mcp/server.js
CHANGED
|
@@ -73,11 +73,50 @@ export class MCPServer {
|
|
|
73
73
|
/** Callback for server-initiated notifications. Set by transport layer. */
|
|
74
74
|
onNotification;
|
|
75
75
|
constructor(config) {
|
|
76
|
+
MCPServer.validateAuthConfig(config);
|
|
76
77
|
this.config = config;
|
|
77
|
-
if (
|
|
78
|
-
logger.warn("MCP server
|
|
78
|
+
if (config.auth.type === "none") {
|
|
79
|
+
logger.warn("MCP server started with auth.type='none' (allowUnauthenticated) — all requests will be accepted");
|
|
79
80
|
}
|
|
80
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Fail-closed validation of the auth configuration (VULN-SRV-5).
|
|
84
|
+
*
|
|
85
|
+
* Historically, an unset `auth` field — or `{ type: "none" }` — silently
|
|
86
|
+
* accepted every request with only a warning log. That meant an operator who
|
|
87
|
+
* forgot to configure auth shipped an unauthenticated JSON-RPC surface.
|
|
88
|
+
*
|
|
89
|
+
* The new contract: `auth` is required, and the only way to accept
|
|
90
|
+
* unauthenticated traffic is to explicitly set
|
|
91
|
+
* `{ type: "none", allowUnauthenticated: true }`. Any other shape is
|
|
92
|
+
* rejected at construction time.
|
|
93
|
+
*/
|
|
94
|
+
static validateAuthConfig(config) {
|
|
95
|
+
const auth = config.auth;
|
|
96
|
+
if (auth === undefined || auth === null) {
|
|
97
|
+
throw new Error("MCP auth must be configured. For local dev, pass " +
|
|
98
|
+
"{ auth: { type: 'none', allowUnauthenticated: true } } explicitly.");
|
|
99
|
+
}
|
|
100
|
+
if (typeof auth !== "object") {
|
|
101
|
+
throw new Error("MCP auth must be an object. For local dev, pass " +
|
|
102
|
+
"{ auth: { type: 'none', allowUnauthenticated: true } } explicitly.");
|
|
103
|
+
}
|
|
104
|
+
const type = auth.type;
|
|
105
|
+
if (type === "none") {
|
|
106
|
+
const allow = auth.allowUnauthenticated;
|
|
107
|
+
if (allow !== true) {
|
|
108
|
+
throw new Error("MCP auth type 'none' requires allowUnauthenticated: true to acknowledge " +
|
|
109
|
+
"the server will accept all requests.");
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (type === "bearer") {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
throw new Error(`MCP auth type '${String(type)}' is not supported. Use 'bearer' ` +
|
|
117
|
+
"or { type: 'none', allowUnauthenticated: true } for explicit opt-in to " +
|
|
118
|
+
"unauthenticated traffic.");
|
|
119
|
+
}
|
|
81
120
|
notifyToolsChanged() {
|
|
82
121
|
this.onNotification?.({ jsonrpc: "2.0", method: "notifications/tools/list_changed" });
|
|
83
122
|
}
|
|
@@ -470,7 +509,7 @@ export class MCPServer {
|
|
|
470
509
|
}
|
|
471
510
|
createHTTPHandler() {
|
|
472
511
|
return createMCPHTTPHandler({
|
|
473
|
-
authEnabled:
|
|
512
|
+
authEnabled: this.config.auth.type !== "none",
|
|
474
513
|
getCORSHeaders: (requestOrigin) => this.getCORSHeaders(requestOrigin),
|
|
475
514
|
validateAuth: (request) => this.validateAuth(request),
|
|
476
515
|
handleRequest: (request, context) => this.handleRequest(request, context),
|
|
@@ -497,13 +536,11 @@ export class MCPServer {
|
|
|
497
536
|
}
|
|
498
537
|
async validateAuth(request) {
|
|
499
538
|
const auth = this.config.auth;
|
|
500
|
-
if (
|
|
539
|
+
if (auth.type === "none")
|
|
501
540
|
return true;
|
|
502
541
|
const authHeader = request.headers.get("Authorization");
|
|
503
542
|
if (!authHeader)
|
|
504
543
|
return false;
|
|
505
|
-
if (auth.type !== "bearer")
|
|
506
|
-
return false;
|
|
507
544
|
const token = authHeader.replace("Bearer ", "");
|
|
508
545
|
// When bearer auth is configured without a validate function, reject all requests
|
|
509
546
|
if (!auth.validate) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.1.
|
|
1
|
+
export declare const VERSION = "0.1.247";
|
|
2
2
|
//# sourceMappingURL=version-constant.d.ts.map
|
|
@@ -77,7 +77,11 @@ export declare class WorkspaceSync {
|
|
|
77
77
|
*/
|
|
78
78
|
detectChanges(): Promise<FileChange[]>;
|
|
79
79
|
/**
|
|
80
|
-
* Recursively walk directory and detect changes
|
|
80
|
+
* Recursively walk directory and detect changes.
|
|
81
|
+
*
|
|
82
|
+
* SECURITY: Uses lstat (not stat) and skips any symlink it finds, so a
|
|
83
|
+
* symlink planted inside the workspace cannot cause us to descend into —
|
|
84
|
+
* or read the contents of — files outside the workspace (VULN-FS-4).
|
|
81
85
|
*/
|
|
82
86
|
private walkAndDetect;
|
|
83
87
|
/**
|
|
@@ -91,7 +95,18 @@ export declare class WorkspaceSync {
|
|
|
91
95
|
onUpload?: (path: string, content: string, type: FileChange["type"]) => Promise<void>;
|
|
92
96
|
}): Promise<UploadResult>;
|
|
93
97
|
/**
|
|
94
|
-
* Safely resolve a path within the workspace, preventing path traversal
|
|
98
|
+
* Safely resolve a path within the workspace, preventing path traversal
|
|
99
|
+
* and symlink-based escapes (VULN-FS-4).
|
|
100
|
+
*
|
|
101
|
+
* - Rejects NUL bytes outright.
|
|
102
|
+
* - Rejects any intermediate path segment that is a symlink.
|
|
103
|
+
* - Re-checks containment by realpath-ing the parent directory after the
|
|
104
|
+
* segment walk, so a symlink that resolves through a non-symlink directory
|
|
105
|
+
* chain still cannot escape the workspace.
|
|
106
|
+
*
|
|
107
|
+
* Note: this deliberately rejects ALL symlinks inside the workspace — even
|
|
108
|
+
* those whose targets remain within it — because the race window between
|
|
109
|
+
* resolution and use is not worth the complexity for our use-case.
|
|
95
110
|
*/
|
|
96
111
|
private resolveSafePath;
|
|
97
112
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-sync.d.ts","sourceRoot":"","sources":["../../../../src/src/workflow/claude-code/workspace-sync.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"workspace-sync.d.ts","sourceRoot":"","sources":["../../../../src/src/workflow/claude-code/workspace-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
import * as dntShim from "../../../_dnt.shims.js";
|
|
13
13
|
import { logger as baseLogger } from "../../utils/index.js";
|
|
14
14
|
import { api } from "../api.js";
|
|
15
|
-
import { join, relative, resolve } from "../../../deps/jsr.io/@std/path/1.1.4/mod.js";
|
|
15
|
+
import { dirname, join, relative, resolve } from "../../../deps/jsr.io/@std/path/1.1.4/mod.js";
|
|
16
16
|
import { INITIALIZATION_ERROR, INVALID_ARGUMENT, SECURITY_VIOLATION } from "../../errors/index.js";
|
|
17
|
+
import { isWithinDirectory } from "../../utils/path-utils.js";
|
|
17
18
|
const logger = baseLogger.component("workspace-sync");
|
|
18
19
|
/** Maximum file size for workspace sync (10 MB) */
|
|
19
20
|
const MAX_WORKSPACE_FILE_SIZE = 10 * 1024 * 1024;
|
|
@@ -136,8 +137,8 @@ export class WorkspaceSync {
|
|
|
136
137
|
const hash = await checksum(content);
|
|
137
138
|
this.fileChecksums.set(path, hash);
|
|
138
139
|
// Write to local filesystem (use safe path resolution)
|
|
139
|
-
const localPath = this.resolveSafePath(path);
|
|
140
|
-
const dir =
|
|
140
|
+
const localPath = await this.resolveSafePath(path);
|
|
141
|
+
const dir = dirname(localPath);
|
|
141
142
|
await dntShim.Deno.mkdir(dir, { recursive: true });
|
|
142
143
|
await dntShim.Deno.writeTextFile(localPath, content);
|
|
143
144
|
filesDownloaded++;
|
|
@@ -188,7 +189,7 @@ export class WorkspaceSync {
|
|
|
188
189
|
// Check for deleted files
|
|
189
190
|
for (const [path, originalHash] of this.fileChecksums) {
|
|
190
191
|
try {
|
|
191
|
-
const localPath = this.resolveSafePath(path);
|
|
192
|
+
const localPath = await this.resolveSafePath(path);
|
|
192
193
|
await dntShim.Deno.stat(localPath);
|
|
193
194
|
}
|
|
194
195
|
catch (_) {
|
|
@@ -206,17 +207,28 @@ export class WorkspaceSync {
|
|
|
206
207
|
return changes;
|
|
207
208
|
}
|
|
208
209
|
/**
|
|
209
|
-
* Recursively walk directory and detect changes
|
|
210
|
+
* Recursively walk directory and detect changes.
|
|
211
|
+
*
|
|
212
|
+
* SECURITY: Uses lstat (not stat) and skips any symlink it finds, so a
|
|
213
|
+
* symlink planted inside the workspace cannot cause us to descend into —
|
|
214
|
+
* or read the contents of — files outside the workspace (VULN-FS-4).
|
|
210
215
|
*/
|
|
211
216
|
async walkAndDetect(localPath, relativePath, changes) {
|
|
212
|
-
const stat = await dntShim.Deno.
|
|
217
|
+
const stat = await dntShim.Deno.lstat(localPath);
|
|
218
|
+
// Ignore symlinks outright — we never treat them as real files here.
|
|
219
|
+
if (stat.isSymlink) {
|
|
220
|
+
if (this.config.debug) {
|
|
221
|
+
logger.info("Skipping symlink during change detection", { localPath });
|
|
222
|
+
}
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
213
225
|
if (stat.isDirectory) {
|
|
214
226
|
for await (const entry of dntShim.Deno.readDir(localPath)) {
|
|
215
227
|
await this.walkAndDetect(`${localPath}/${entry.name}`, `${relativePath}/${entry.name}`, changes);
|
|
216
228
|
}
|
|
217
229
|
return;
|
|
218
230
|
}
|
|
219
|
-
// It's a file - check for changes
|
|
231
|
+
// It's a regular file - check for changes
|
|
220
232
|
const content = await dntShim.Deno.readTextFile(localPath);
|
|
221
233
|
const newHash = await checksum(content);
|
|
222
234
|
const originalHash = this.fileChecksums.get(relativePath);
|
|
@@ -258,7 +270,7 @@ export class WorkspaceSync {
|
|
|
258
270
|
continue;
|
|
259
271
|
}
|
|
260
272
|
try {
|
|
261
|
-
const localPath = this.resolveSafePath(change.path);
|
|
273
|
+
const localPath = await this.resolveSafePath(change.path);
|
|
262
274
|
const content = await dntShim.Deno.readTextFile(localPath);
|
|
263
275
|
if (options.onUpload) {
|
|
264
276
|
await options.onUpload(change.path, content, change.type);
|
|
@@ -287,34 +299,109 @@ export class WorkspaceSync {
|
|
|
287
299
|
};
|
|
288
300
|
}
|
|
289
301
|
/**
|
|
290
|
-
* Safely resolve a path within the workspace, preventing path traversal
|
|
302
|
+
* Safely resolve a path within the workspace, preventing path traversal
|
|
303
|
+
* and symlink-based escapes (VULN-FS-4).
|
|
304
|
+
*
|
|
305
|
+
* - Rejects NUL bytes outright.
|
|
306
|
+
* - Rejects any intermediate path segment that is a symlink.
|
|
307
|
+
* - Re-checks containment by realpath-ing the parent directory after the
|
|
308
|
+
* segment walk, so a symlink that resolves through a non-symlink directory
|
|
309
|
+
* chain still cannot escape the workspace.
|
|
310
|
+
*
|
|
311
|
+
* Note: this deliberately rejects ALL symlinks inside the workspace — even
|
|
312
|
+
* those whose targets remain within it — because the race window between
|
|
313
|
+
* resolution and use is not worth the complexity for our use-case.
|
|
291
314
|
*/
|
|
292
|
-
resolveSafePath(path) {
|
|
293
|
-
//
|
|
315
|
+
async resolveSafePath(path) {
|
|
316
|
+
// Reject NUL bytes — they confuse filesystem APIs and are never legitimate.
|
|
317
|
+
if (path.includes("\0")) {
|
|
318
|
+
throw SECURITY_VIOLATION.create({ detail: `NUL byte in path` });
|
|
319
|
+
}
|
|
320
|
+
// Workspace-relative paths only. A single leading "/" is the canonical
|
|
321
|
+
// API form for "the project root" (e.g. "/src/foo.ts") and is accepted;
|
|
322
|
+
// anything that syntactically looks like a system-absolute path beyond
|
|
323
|
+
// that one-slash convention is rejected.
|
|
324
|
+
//
|
|
325
|
+
// - Windows drive letters (C:\...) — rejected.
|
|
326
|
+
// - UNC paths (//host/share) — rejected.
|
|
327
|
+
// - Unix absolute paths with a leading slash are treated as
|
|
328
|
+
// workspace-relative, but any component that tries to escape the
|
|
329
|
+
// workspace is still caught by the traversal / realpath checks below.
|
|
330
|
+
if (/^[A-Za-z]:[\\/]/.test(path)) {
|
|
331
|
+
throw SECURITY_VIOLATION.create({ detail: `Absolute path not allowed: ${path}` });
|
|
332
|
+
}
|
|
333
|
+
if (path.startsWith("//")) {
|
|
334
|
+
throw SECURITY_VIOLATION.create({ detail: `Absolute path not allowed: ${path}` });
|
|
335
|
+
}
|
|
336
|
+
// Normalize the input path (treat leading "/" as workspace-relative).
|
|
294
337
|
const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
|
|
295
|
-
//
|
|
338
|
+
// Empty path resolves to the workspace dir itself — writing to it would
|
|
339
|
+
// clobber the workspace as a regular file. Reject explicitly.
|
|
340
|
+
if (normalizedPath === "") {
|
|
341
|
+
throw SECURITY_VIOLATION.create({ detail: `Empty path not allowed` });
|
|
342
|
+
}
|
|
343
|
+
// Resolve the full path lexically first (catches literal "..").
|
|
296
344
|
const fullPath = resolve(join(this.workspaceDir, normalizedPath));
|
|
297
|
-
// Verify the resolved path is within the workspace
|
|
298
345
|
const relativePath = relative(this.workspaceDir, fullPath);
|
|
299
|
-
if (relativePath.startsWith("..") ||
|
|
346
|
+
if (!relativePath || relativePath.startsWith("..") || relativePath === "..") {
|
|
300
347
|
throw SECURITY_VIOLATION.create({ detail: `Path traversal detected: ${path}` });
|
|
301
348
|
}
|
|
349
|
+
// Walk each segment and reject any existing symlink along the way.
|
|
350
|
+
// A segment that does not yet exist is fine — it will be created later.
|
|
351
|
+
const relSegments = relativePath === "" ? [] : relativePath.split(/[\\/]/).filter(Boolean);
|
|
352
|
+
let cursor = this.workspaceDir;
|
|
353
|
+
for (const seg of relSegments) {
|
|
354
|
+
cursor = join(cursor, seg);
|
|
355
|
+
try {
|
|
356
|
+
const info = await dntShim.Deno.lstat(cursor);
|
|
357
|
+
if (info.isSymlink) {
|
|
358
|
+
throw SECURITY_VIOLATION.create({
|
|
359
|
+
detail: `Refusing to traverse symlink: ${cursor}`,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
catch (e) {
|
|
364
|
+
if (e instanceof dntShim.Deno.errors.NotFound) {
|
|
365
|
+
// Segment doesn't exist yet — the rest of the chain will be
|
|
366
|
+
// created under a verified-non-symlink parent, so stop walking.
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
throw e;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
// Final containment check against the realpath of the parent directory,
|
|
373
|
+
// to defeat any symlink-in-parent we might have missed (e.g. one that
|
|
374
|
+
// appeared mid-walk). If the parent doesn't exist yet, that's fine —
|
|
375
|
+
// the segment walk above already proved every existing ancestor is real.
|
|
376
|
+
try {
|
|
377
|
+
const parentReal = await dntShim.Deno.realPath(dirname(fullPath));
|
|
378
|
+
const workspaceReal = await dntShim.Deno.realPath(this.workspaceDir);
|
|
379
|
+
if (!isWithinDirectory(workspaceReal, parentReal)) {
|
|
380
|
+
throw SECURITY_VIOLATION.create({
|
|
381
|
+
detail: `Resolved parent outside workspace: ${parentReal}`,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
catch (e) {
|
|
386
|
+
if (!(e instanceof dntShim.Deno.errors.NotFound))
|
|
387
|
+
throw e;
|
|
388
|
+
}
|
|
302
389
|
return fullPath;
|
|
303
390
|
}
|
|
304
391
|
/**
|
|
305
392
|
* Read a file from the workspace
|
|
306
393
|
*/
|
|
307
394
|
async readFile(path) {
|
|
308
|
-
const localPath = this.resolveSafePath(path);
|
|
395
|
+
const localPath = await this.resolveSafePath(path);
|
|
309
396
|
return await dntShim.Deno.readTextFile(localPath);
|
|
310
397
|
}
|
|
311
398
|
/**
|
|
312
399
|
* Write a file to the workspace
|
|
313
400
|
*/
|
|
314
401
|
async writeFile(path, content) {
|
|
315
|
-
const localPath = this.resolveSafePath(path);
|
|
402
|
+
const localPath = await this.resolveSafePath(path);
|
|
316
403
|
// Ensure directory exists
|
|
317
|
-
const dir =
|
|
404
|
+
const dir = dirname(localPath);
|
|
318
405
|
await dntShim.Deno.mkdir(dir, { recursive: true });
|
|
319
406
|
await dntShim.Deno.writeTextFile(localPath, content);
|
|
320
407
|
}
|
|
@@ -322,7 +409,7 @@ export class WorkspaceSync {
|
|
|
322
409
|
* Delete a file from the workspace
|
|
323
410
|
*/
|
|
324
411
|
async deleteFile(path) {
|
|
325
|
-
const localPath = this.resolveSafePath(path);
|
|
412
|
+
const localPath = await this.resolveSafePath(path);
|
|
326
413
|
await dntShim.Deno.remove(localPath);
|
|
327
414
|
}
|
|
328
415
|
/**
|
|
@@ -330,7 +417,7 @@ export class WorkspaceSync {
|
|
|
330
417
|
*/
|
|
331
418
|
async fileExists(path) {
|
|
332
419
|
try {
|
|
333
|
-
const localPath = this.resolveSafePath(path);
|
|
420
|
+
const localPath = await this.resolveSafePath(path);
|
|
334
421
|
await dntShim.Deno.stat(localPath);
|
|
335
422
|
return true;
|
|
336
423
|
}
|
package/package.json
CHANGED
package/src/deno.js
CHANGED
package/src/src/agent/durable.ts
CHANGED
|
@@ -142,6 +142,10 @@ export type ConversationRunAppendFailureOutcome =
|
|
|
142
142
|
| "resumed"
|
|
143
143
|
| "stopped"
|
|
144
144
|
| "retry_scheduled";
|
|
145
|
+
export type ConversationRunAppendExecutionOutcome =
|
|
146
|
+
| "resumed"
|
|
147
|
+
| "stopped"
|
|
148
|
+
| "retry_scheduled";
|
|
145
149
|
|
|
146
150
|
export const CreateConversationRunAcceptedSchema = z
|
|
147
151
|
.object({
|
|
@@ -531,6 +535,85 @@ export async function recoverConversationRunAppendFailure(input: {
|
|
|
531
535
|
};
|
|
532
536
|
}
|
|
533
537
|
|
|
538
|
+
export async function recoverConversationRunAppendExecution(input: {
|
|
539
|
+
error: unknown;
|
|
540
|
+
authToken: string;
|
|
541
|
+
apiUrl: string;
|
|
542
|
+
conversationId: string;
|
|
543
|
+
runId: string;
|
|
544
|
+
latestEventId: number;
|
|
545
|
+
latestExternalEventSequence: number;
|
|
546
|
+
remainingEvents: unknown[];
|
|
547
|
+
pendingEvents: unknown[];
|
|
548
|
+
cursorResyncsThisFlush: number;
|
|
549
|
+
consecutiveFailures: number;
|
|
550
|
+
maxCursorResyncsPerFlush: number;
|
|
551
|
+
abortSignal?: AbortSignal;
|
|
552
|
+
}): Promise<
|
|
553
|
+
| {
|
|
554
|
+
outcome: "resumed";
|
|
555
|
+
latestEventId: number;
|
|
556
|
+
latestExternalEventSequence: number;
|
|
557
|
+
pendingEvents: unknown[];
|
|
558
|
+
consecutiveFailures: number;
|
|
559
|
+
}
|
|
560
|
+
| {
|
|
561
|
+
outcome: "stopped";
|
|
562
|
+
latestEventId: number;
|
|
563
|
+
latestExternalEventSequence: number;
|
|
564
|
+
disableReason?: "cursor_resyncs_exhausted" | "non_appendable" | "ignorable_append_rejection";
|
|
565
|
+
}
|
|
566
|
+
| {
|
|
567
|
+
outcome: "retry_scheduled";
|
|
568
|
+
latestEventId: number;
|
|
569
|
+
latestExternalEventSequence: number;
|
|
570
|
+
pendingEvents: unknown[];
|
|
571
|
+
consecutiveFailures: number;
|
|
572
|
+
errorMessage: string;
|
|
573
|
+
}
|
|
574
|
+
> {
|
|
575
|
+
const recovered = await recoverConversationRunAppendFailure({
|
|
576
|
+
error: input.error,
|
|
577
|
+
authToken: input.authToken,
|
|
578
|
+
apiUrl: input.apiUrl,
|
|
579
|
+
conversationId: input.conversationId,
|
|
580
|
+
runId: input.runId,
|
|
581
|
+
latestEventId: input.latestEventId,
|
|
582
|
+
latestExternalEventSequence: input.latestExternalEventSequence,
|
|
583
|
+
cursorResyncsThisFlush: input.cursorResyncsThisFlush,
|
|
584
|
+
maxCursorResyncsPerFlush: input.maxCursorResyncsPerFlush,
|
|
585
|
+
abortSignal: input.abortSignal,
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
if (recovered.outcome === "resumed") {
|
|
589
|
+
return {
|
|
590
|
+
outcome: "resumed",
|
|
591
|
+
latestEventId: recovered.latestEventId,
|
|
592
|
+
latestExternalEventSequence: recovered.latestExternalEventSequence,
|
|
593
|
+
pendingEvents: [...input.remainingEvents, ...input.pendingEvents],
|
|
594
|
+
consecutiveFailures: 0,
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if (recovered.outcome === "stopped") {
|
|
599
|
+
return {
|
|
600
|
+
outcome: "stopped",
|
|
601
|
+
latestEventId: recovered.latestEventId,
|
|
602
|
+
latestExternalEventSequence: recovered.latestExternalEventSequence,
|
|
603
|
+
...(recovered.disableReason ? { disableReason: recovered.disableReason } : {}),
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
return {
|
|
608
|
+
outcome: "retry_scheduled",
|
|
609
|
+
latestEventId: recovered.latestEventId,
|
|
610
|
+
latestExternalEventSequence: recovered.latestExternalEventSequence,
|
|
611
|
+
pendingEvents: [...input.remainingEvents, ...input.pendingEvents],
|
|
612
|
+
consecutiveFailures: input.consecutiveFailures + 1,
|
|
613
|
+
errorMessage: recovered.errorMessage ?? "Conversation run append failed",
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
534
617
|
async function waitForConversationRunPoll(
|
|
535
618
|
ms: number,
|
|
536
619
|
abortSignal?: AbortSignal,
|
package/src/src/agent/index.ts
CHANGED
|
@@ -220,6 +220,7 @@ export {
|
|
|
220
220
|
CompleteConversationRunResponseSchema,
|
|
221
221
|
type ConversationAgentRunUsage,
|
|
222
222
|
type ConversationRunAppendCursorResyncResult,
|
|
223
|
+
type ConversationRunAppendExecutionOutcome,
|
|
223
224
|
type ConversationRunAppendFailureOutcome,
|
|
224
225
|
type ConversationRunAppendRecoveryOutcome,
|
|
225
226
|
type ConversationRunProjection,
|
|
@@ -237,6 +238,7 @@ export {
|
|
|
237
238
|
isIgnorableConversationRunAppendError,
|
|
238
239
|
monitorConversationRunStatus,
|
|
239
240
|
parseAppendConversationRunEventsErrorBody,
|
|
241
|
+
recoverConversationRunAppendExecution,
|
|
240
242
|
recoverConversationRunAppendFailure,
|
|
241
243
|
recoverConversationRunCursorMismatch,
|
|
242
244
|
resolveConversationRunTargets,
|
package/src/src/mcp/index.ts
CHANGED
|
@@ -17,8 +17,13 @@
|
|
|
17
17
|
* execute: async ({ query }) => ({ results: [] }),
|
|
18
18
|
* });
|
|
19
19
|
*
|
|
20
|
-
* // Start MCP server — registered tools are exposed automatically
|
|
21
|
-
*
|
|
20
|
+
* // Start MCP server — registered tools are exposed automatically.
|
|
21
|
+
* // `auth` is required: use bearer for production, or the explicit
|
|
22
|
+
* // `{ type: "none", allowUnauthenticated: true }` opt-in for local dev only.
|
|
23
|
+
* const server = createMCPServer({
|
|
24
|
+
* enabled: true,
|
|
25
|
+
* auth: { type: "none", allowUnauthenticated: true },
|
|
26
|
+
* });
|
|
22
27
|
* ```
|
|
23
28
|
*/
|
|
24
29
|
import "../../_dnt.polyfills.js";
|
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* MCP auth configuration. One of:
|
|
5
|
+
* - `{ type: "bearer", validate?: (token) => Promise<boolean> }` — bearer-token auth.
|
|
6
|
+
* - `{ type: "none", allowUnauthenticated: true }` — explicit opt-in to an
|
|
7
|
+
* unauthenticated server. Required for local dev/testing; prevents accidental
|
|
8
|
+
* exposure of the JSON-RPC surface in production (VULN-SRV-5).
|
|
9
|
+
*/
|
|
10
|
+
const AuthValidatedSchema = z.object({
|
|
11
|
+
type: z.literal("bearer"),
|
|
12
|
+
validate: z.function().optional(),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const AuthNoneSchema = z.object({
|
|
16
|
+
type: z.literal("none"),
|
|
17
|
+
allowUnauthenticated: z.literal(true),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const MCPAuthConfigSchema = z.union([AuthValidatedSchema, AuthNoneSchema]);
|
|
21
|
+
|
|
3
22
|
export const MCPServerConfigSchema = z.object({
|
|
4
23
|
enabled: z.boolean(),
|
|
5
24
|
port: z.number().int().positive().optional(),
|
|
6
|
-
auth:
|
|
7
|
-
.object({
|
|
8
|
-
type: z.enum(["bearer", "api-key", "none"]),
|
|
9
|
-
validate: z.function()
|
|
10
|
-
.optional(),
|
|
11
|
-
})
|
|
12
|
-
.optional(),
|
|
25
|
+
auth: MCPAuthConfigSchema,
|
|
13
26
|
cors: z
|
|
14
27
|
.object({
|
|
15
28
|
enabled: z.boolean(),
|
package/src/src/mcp/server.ts
CHANGED
|
@@ -113,13 +113,69 @@ export class MCPServer {
|
|
|
113
113
|
onNotification?: (notification: { jsonrpc: "2.0"; method: string; params?: unknown }) => void;
|
|
114
114
|
|
|
115
115
|
constructor(config: MCPServerConfig) {
|
|
116
|
+
MCPServer.validateAuthConfig(config);
|
|
116
117
|
this.config = config;
|
|
117
118
|
|
|
118
|
-
if (
|
|
119
|
-
logger.warn(
|
|
119
|
+
if (config.auth.type === "none") {
|
|
120
|
+
logger.warn(
|
|
121
|
+
"MCP server started with auth.type='none' (allowUnauthenticated) — all requests will be accepted",
|
|
122
|
+
);
|
|
120
123
|
}
|
|
121
124
|
}
|
|
122
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Fail-closed validation of the auth configuration (VULN-SRV-5).
|
|
128
|
+
*
|
|
129
|
+
* Historically, an unset `auth` field — or `{ type: "none" }` — silently
|
|
130
|
+
* accepted every request with only a warning log. That meant an operator who
|
|
131
|
+
* forgot to configure auth shipped an unauthenticated JSON-RPC surface.
|
|
132
|
+
*
|
|
133
|
+
* The new contract: `auth` is required, and the only way to accept
|
|
134
|
+
* unauthenticated traffic is to explicitly set
|
|
135
|
+
* `{ type: "none", allowUnauthenticated: true }`. Any other shape is
|
|
136
|
+
* rejected at construction time.
|
|
137
|
+
*/
|
|
138
|
+
private static validateAuthConfig(config: MCPServerConfig): void {
|
|
139
|
+
const auth = (config as { auth?: unknown }).auth;
|
|
140
|
+
|
|
141
|
+
if (auth === undefined || auth === null) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
"MCP auth must be configured. For local dev, pass " +
|
|
144
|
+
"{ auth: { type: 'none', allowUnauthenticated: true } } explicitly.",
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (typeof auth !== "object") {
|
|
149
|
+
throw new Error(
|
|
150
|
+
"MCP auth must be an object. For local dev, pass " +
|
|
151
|
+
"{ auth: { type: 'none', allowUnauthenticated: true } } explicitly.",
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const type = (auth as { type?: unknown }).type;
|
|
156
|
+
|
|
157
|
+
if (type === "none") {
|
|
158
|
+
const allow = (auth as { allowUnauthenticated?: unknown }).allowUnauthenticated;
|
|
159
|
+
if (allow !== true) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
"MCP auth type 'none' requires allowUnauthenticated: true to acknowledge " +
|
|
162
|
+
"the server will accept all requests.",
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (type === "bearer") {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
throw new Error(
|
|
173
|
+
`MCP auth type '${String(type)}' is not supported. Use 'bearer' ` +
|
|
174
|
+
"or { type: 'none', allowUnauthenticated: true } for explicit opt-in to " +
|
|
175
|
+
"unauthenticated traffic.",
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
123
179
|
notifyToolsChanged(): void {
|
|
124
180
|
this.onNotification?.({ jsonrpc: "2.0", method: "notifications/tools/list_changed" });
|
|
125
181
|
}
|
|
@@ -607,7 +663,7 @@ export class MCPServer {
|
|
|
607
663
|
|
|
608
664
|
createHTTPHandler(): (request: Request) => Promise<Response> {
|
|
609
665
|
return createMCPHTTPHandler({
|
|
610
|
-
authEnabled:
|
|
666
|
+
authEnabled: this.config.auth.type !== "none",
|
|
611
667
|
getCORSHeaders: (requestOrigin) => this.getCORSHeaders(requestOrigin),
|
|
612
668
|
validateAuth: (request) => this.validateAuth(request),
|
|
613
669
|
handleRequest: (request, context) => this.handleRequest(request, context),
|
|
@@ -640,13 +696,11 @@ export class MCPServer {
|
|
|
640
696
|
|
|
641
697
|
private async validateAuth(request: Request): Promise<boolean> {
|
|
642
698
|
const auth = this.config.auth;
|
|
643
|
-
if (
|
|
699
|
+
if (auth.type === "none") return true;
|
|
644
700
|
|
|
645
701
|
const authHeader = request.headers.get("Authorization");
|
|
646
702
|
if (!authHeader) return false;
|
|
647
703
|
|
|
648
|
-
if (auth.type !== "bearer") return false;
|
|
649
|
-
|
|
650
704
|
const token = authHeader.replace("Bearer ", "");
|
|
651
705
|
|
|
652
706
|
// When bearer auth is configured without a validate function, reject all requests
|
|
@@ -15,8 +15,9 @@ import * as dntShim from "../../../_dnt.shims.js";
|
|
|
15
15
|
import { logger as baseLogger } from "../../utils/index.js";
|
|
16
16
|
import { api } from "../api.js";
|
|
17
17
|
import type { CapturedTenantContext } from "../types.js";
|
|
18
|
-
import { join, relative, resolve } from "../../../deps/jsr.io/@std/path/1.1.4/mod.js";
|
|
18
|
+
import { dirname, join, relative, resolve } from "../../../deps/jsr.io/@std/path/1.1.4/mod.js";
|
|
19
19
|
import { INITIALIZATION_ERROR, INVALID_ARGUMENT, SECURITY_VIOLATION } from "../../errors/index.js";
|
|
20
|
+
import { isWithinDirectory } from "../../utils/path-utils.js";
|
|
20
21
|
|
|
21
22
|
const logger = baseLogger.component("workspace-sync");
|
|
22
23
|
|
|
@@ -230,8 +231,8 @@ export class WorkspaceSync {
|
|
|
230
231
|
this.fileChecksums.set(path, hash);
|
|
231
232
|
|
|
232
233
|
// Write to local filesystem (use safe path resolution)
|
|
233
|
-
const localPath = this.resolveSafePath(path);
|
|
234
|
-
const dir =
|
|
234
|
+
const localPath = await this.resolveSafePath(path);
|
|
235
|
+
const dir = dirname(localPath);
|
|
235
236
|
await dntShim.Deno.mkdir(dir, { recursive: true });
|
|
236
237
|
await dntShim.Deno.writeTextFile(localPath, content);
|
|
237
238
|
|
|
@@ -295,7 +296,7 @@ export class WorkspaceSync {
|
|
|
295
296
|
// Check for deleted files
|
|
296
297
|
for (const [path, originalHash] of this.fileChecksums) {
|
|
297
298
|
try {
|
|
298
|
-
const localPath = this.resolveSafePath(path);
|
|
299
|
+
const localPath = await this.resolveSafePath(path);
|
|
299
300
|
await dntShim.Deno.stat(localPath);
|
|
300
301
|
} catch (_) {
|
|
301
302
|
// File was deleted
|
|
@@ -315,14 +316,26 @@ export class WorkspaceSync {
|
|
|
315
316
|
}
|
|
316
317
|
|
|
317
318
|
/**
|
|
318
|
-
* Recursively walk directory and detect changes
|
|
319
|
+
* Recursively walk directory and detect changes.
|
|
320
|
+
*
|
|
321
|
+
* SECURITY: Uses lstat (not stat) and skips any symlink it finds, so a
|
|
322
|
+
* symlink planted inside the workspace cannot cause us to descend into —
|
|
323
|
+
* or read the contents of — files outside the workspace (VULN-FS-4).
|
|
319
324
|
*/
|
|
320
325
|
private async walkAndDetect(
|
|
321
326
|
localPath: string,
|
|
322
327
|
relativePath: string,
|
|
323
328
|
changes: FileChange[],
|
|
324
329
|
): Promise<void> {
|
|
325
|
-
const stat = await dntShim.Deno.
|
|
330
|
+
const stat = await dntShim.Deno.lstat(localPath);
|
|
331
|
+
|
|
332
|
+
// Ignore symlinks outright — we never treat them as real files here.
|
|
333
|
+
if (stat.isSymlink) {
|
|
334
|
+
if (this.config.debug) {
|
|
335
|
+
logger.info("Skipping symlink during change detection", { localPath });
|
|
336
|
+
}
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
326
339
|
|
|
327
340
|
if (stat.isDirectory) {
|
|
328
341
|
for await (const entry of dntShim.Deno.readDir(localPath)) {
|
|
@@ -335,7 +348,7 @@ export class WorkspaceSync {
|
|
|
335
348
|
return;
|
|
336
349
|
}
|
|
337
350
|
|
|
338
|
-
// It's a file - check for changes
|
|
351
|
+
// It's a regular file - check for changes
|
|
339
352
|
const content = await dntShim.Deno.readTextFile(localPath);
|
|
340
353
|
const newHash = await checksum(content);
|
|
341
354
|
const originalHash = this.fileChecksums.get(relativePath);
|
|
@@ -390,7 +403,7 @@ export class WorkspaceSync {
|
|
|
390
403
|
}
|
|
391
404
|
|
|
392
405
|
try {
|
|
393
|
-
const localPath = this.resolveSafePath(change.path);
|
|
406
|
+
const localPath = await this.resolveSafePath(change.path);
|
|
394
407
|
const content = await dntShim.Deno.readTextFile(localPath);
|
|
395
408
|
|
|
396
409
|
if (options.onUpload) {
|
|
@@ -420,21 +433,97 @@ export class WorkspaceSync {
|
|
|
420
433
|
}
|
|
421
434
|
|
|
422
435
|
/**
|
|
423
|
-
* Safely resolve a path within the workspace, preventing path traversal
|
|
436
|
+
* Safely resolve a path within the workspace, preventing path traversal
|
|
437
|
+
* and symlink-based escapes (VULN-FS-4).
|
|
438
|
+
*
|
|
439
|
+
* - Rejects NUL bytes outright.
|
|
440
|
+
* - Rejects any intermediate path segment that is a symlink.
|
|
441
|
+
* - Re-checks containment by realpath-ing the parent directory after the
|
|
442
|
+
* segment walk, so a symlink that resolves through a non-symlink directory
|
|
443
|
+
* chain still cannot escape the workspace.
|
|
444
|
+
*
|
|
445
|
+
* Note: this deliberately rejects ALL symlinks inside the workspace — even
|
|
446
|
+
* those whose targets remain within it — because the race window between
|
|
447
|
+
* resolution and use is not worth the complexity for our use-case.
|
|
424
448
|
*/
|
|
425
|
-
private resolveSafePath(path: string): string {
|
|
426
|
-
//
|
|
449
|
+
private async resolveSafePath(path: string): Promise<string> {
|
|
450
|
+
// Reject NUL bytes — they confuse filesystem APIs and are never legitimate.
|
|
451
|
+
if (path.includes("\0")) {
|
|
452
|
+
throw SECURITY_VIOLATION.create({ detail: `NUL byte in path` });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Workspace-relative paths only. A single leading "/" is the canonical
|
|
456
|
+
// API form for "the project root" (e.g. "/src/foo.ts") and is accepted;
|
|
457
|
+
// anything that syntactically looks like a system-absolute path beyond
|
|
458
|
+
// that one-slash convention is rejected.
|
|
459
|
+
//
|
|
460
|
+
// - Windows drive letters (C:\...) — rejected.
|
|
461
|
+
// - UNC paths (//host/share) — rejected.
|
|
462
|
+
// - Unix absolute paths with a leading slash are treated as
|
|
463
|
+
// workspace-relative, but any component that tries to escape the
|
|
464
|
+
// workspace is still caught by the traversal / realpath checks below.
|
|
465
|
+
if (/^[A-Za-z]:[\\/]/.test(path)) {
|
|
466
|
+
throw SECURITY_VIOLATION.create({ detail: `Absolute path not allowed: ${path}` });
|
|
467
|
+
}
|
|
468
|
+
if (path.startsWith("//")) {
|
|
469
|
+
throw SECURITY_VIOLATION.create({ detail: `Absolute path not allowed: ${path}` });
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Normalize the input path (treat leading "/" as workspace-relative).
|
|
427
473
|
const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
|
|
428
474
|
|
|
429
|
-
//
|
|
430
|
-
|
|
475
|
+
// Empty path resolves to the workspace dir itself — writing to it would
|
|
476
|
+
// clobber the workspace as a regular file. Reject explicitly.
|
|
477
|
+
if (normalizedPath === "") {
|
|
478
|
+
throw SECURITY_VIOLATION.create({ detail: `Empty path not allowed` });
|
|
479
|
+
}
|
|
431
480
|
|
|
432
|
-
//
|
|
481
|
+
// Resolve the full path lexically first (catches literal "..").
|
|
482
|
+
const fullPath = resolve(join(this.workspaceDir, normalizedPath));
|
|
433
483
|
const relativePath = relative(this.workspaceDir, fullPath);
|
|
434
|
-
if (relativePath.startsWith("..") ||
|
|
484
|
+
if (!relativePath || relativePath.startsWith("..") || relativePath === "..") {
|
|
435
485
|
throw SECURITY_VIOLATION.create({ detail: `Path traversal detected: ${path}` });
|
|
436
486
|
}
|
|
437
487
|
|
|
488
|
+
// Walk each segment and reject any existing symlink along the way.
|
|
489
|
+
// A segment that does not yet exist is fine — it will be created later.
|
|
490
|
+
const relSegments = relativePath === "" ? [] : relativePath.split(/[\\/]/).filter(Boolean);
|
|
491
|
+
let cursor = this.workspaceDir;
|
|
492
|
+
for (const seg of relSegments) {
|
|
493
|
+
cursor = join(cursor, seg);
|
|
494
|
+
try {
|
|
495
|
+
const info = await dntShim.Deno.lstat(cursor);
|
|
496
|
+
if (info.isSymlink) {
|
|
497
|
+
throw SECURITY_VIOLATION.create({
|
|
498
|
+
detail: `Refusing to traverse symlink: ${cursor}`,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
} catch (e) {
|
|
502
|
+
if (e instanceof dntShim.Deno.errors.NotFound) {
|
|
503
|
+
// Segment doesn't exist yet — the rest of the chain will be
|
|
504
|
+
// created under a verified-non-symlink parent, so stop walking.
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
throw e;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Final containment check against the realpath of the parent directory,
|
|
512
|
+
// to defeat any symlink-in-parent we might have missed (e.g. one that
|
|
513
|
+
// appeared mid-walk). If the parent doesn't exist yet, that's fine —
|
|
514
|
+
// the segment walk above already proved every existing ancestor is real.
|
|
515
|
+
try {
|
|
516
|
+
const parentReal = await dntShim.Deno.realPath(dirname(fullPath));
|
|
517
|
+
const workspaceReal = await dntShim.Deno.realPath(this.workspaceDir);
|
|
518
|
+
if (!isWithinDirectory(workspaceReal, parentReal)) {
|
|
519
|
+
throw SECURITY_VIOLATION.create({
|
|
520
|
+
detail: `Resolved parent outside workspace: ${parentReal}`,
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
} catch (e) {
|
|
524
|
+
if (!(e instanceof dntShim.Deno.errors.NotFound)) throw e;
|
|
525
|
+
}
|
|
526
|
+
|
|
438
527
|
return fullPath;
|
|
439
528
|
}
|
|
440
529
|
|
|
@@ -442,7 +531,7 @@ export class WorkspaceSync {
|
|
|
442
531
|
* Read a file from the workspace
|
|
443
532
|
*/
|
|
444
533
|
async readFile(path: string): Promise<string> {
|
|
445
|
-
const localPath = this.resolveSafePath(path);
|
|
534
|
+
const localPath = await this.resolveSafePath(path);
|
|
446
535
|
return await dntShim.Deno.readTextFile(localPath);
|
|
447
536
|
}
|
|
448
537
|
|
|
@@ -450,10 +539,10 @@ export class WorkspaceSync {
|
|
|
450
539
|
* Write a file to the workspace
|
|
451
540
|
*/
|
|
452
541
|
async writeFile(path: string, content: string): Promise<void> {
|
|
453
|
-
const localPath = this.resolveSafePath(path);
|
|
542
|
+
const localPath = await this.resolveSafePath(path);
|
|
454
543
|
|
|
455
544
|
// Ensure directory exists
|
|
456
|
-
const dir =
|
|
545
|
+
const dir = dirname(localPath);
|
|
457
546
|
await dntShim.Deno.mkdir(dir, { recursive: true });
|
|
458
547
|
|
|
459
548
|
await dntShim.Deno.writeTextFile(localPath, content);
|
|
@@ -463,7 +552,7 @@ export class WorkspaceSync {
|
|
|
463
552
|
* Delete a file from the workspace
|
|
464
553
|
*/
|
|
465
554
|
async deleteFile(path: string): Promise<void> {
|
|
466
|
-
const localPath = this.resolveSafePath(path);
|
|
555
|
+
const localPath = await this.resolveSafePath(path);
|
|
467
556
|
await dntShim.Deno.remove(localPath);
|
|
468
557
|
}
|
|
469
558
|
|
|
@@ -472,7 +561,7 @@ export class WorkspaceSync {
|
|
|
472
561
|
*/
|
|
473
562
|
async fileExists(path: string): Promise<boolean> {
|
|
474
563
|
try {
|
|
475
|
-
const localPath = this.resolveSafePath(path);
|
|
564
|
+
const localPath = await this.resolveSafePath(path);
|
|
476
565
|
await dntShim.Deno.stat(localPath);
|
|
477
566
|
return true;
|
|
478
567
|
} catch (_) {
|