@google/gemini-cli-core 0.15.0-preview.3 → 0.16.0-nightly.20251113.ad1f0d99
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/google-gemini-cli-core-0.16.0-nightly.20251112.c961f274.tgz +0 -0
- package/dist/src/agents/codebase-investigator.test.d.ts +6 -0
- package/dist/src/agents/codebase-investigator.test.js +35 -0
- package/dist/src/agents/codebase-investigator.test.js.map +1 -0
- package/dist/src/agents/executor.test.js +181 -1
- package/dist/src/agents/executor.test.js.map +1 -1
- package/dist/src/code_assist/codeAssist.test.d.ts +6 -0
- package/dist/src/code_assist/codeAssist.test.js +99 -0
- package/dist/src/code_assist/codeAssist.test.js.map +1 -0
- package/dist/src/code_assist/experiments/client_metadata.js +2 -1
- package/dist/src/code_assist/experiments/client_metadata.js.map +1 -1
- package/dist/src/code_assist/experiments/client_metadata.test.d.ts +6 -0
- package/dist/src/code_assist/experiments/client_metadata.test.js +99 -0
- package/dist/src/code_assist/experiments/client_metadata.test.js.map +1 -0
- package/dist/src/code_assist/experiments/experiments.test.d.ts +6 -0
- package/dist/src/code_assist/experiments/experiments.test.js +92 -0
- package/dist/src/code_assist/experiments/experiments.test.js.map +1 -0
- package/dist/src/code_assist/oauth-credential-storage.test.js +49 -0
- package/dist/src/code_assist/oauth-credential-storage.test.js.map +1 -1
- package/dist/src/code_assist/server.js +5 -8
- package/dist/src/code_assist/server.js.map +1 -1
- package/dist/src/code_assist/server.test.js +109 -28
- package/dist/src/code_assist/server.test.js.map +1 -1
- package/dist/src/config/defaultModelConfigs.js +6 -0
- package/dist/src/config/defaultModelConfigs.js.map +1 -1
- package/dist/src/confirmation-bus/message-bus.d.ts +1 -1
- package/dist/src/confirmation-bus/message-bus.js +2 -2
- package/dist/src/confirmation-bus/message-bus.js.map +1 -1
- package/dist/src/confirmation-bus/message-bus.test.js +30 -24
- package/dist/src/confirmation-bus/message-bus.test.js.map +1 -1
- package/dist/src/core/loggingContentGenerator.test.d.ts +6 -0
- package/dist/src/core/loggingContentGenerator.test.js +180 -0
- package/dist/src/core/loggingContentGenerator.test.js.map +1 -0
- package/dist/src/core/tokenLimits.test.d.ts +6 -0
- package/dist/src/core/tokenLimits.test.js +26 -0
- package/dist/src/core/tokenLimits.test.js.map +1 -0
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/hooks/hookAggregator.d.ts +68 -0
- package/dist/src/hooks/hookAggregator.js +262 -0
- package/dist/src/hooks/hookAggregator.js.map +1 -0
- package/dist/src/hooks/hookAggregator.test.d.ts +6 -0
- package/dist/src/hooks/hookAggregator.test.js +387 -0
- package/dist/src/hooks/hookAggregator.test.js.map +1 -0
- package/dist/src/hooks/types.js +1 -1
- package/dist/src/hooks/types.js.map +1 -1
- package/dist/src/hooks/types.test.js +280 -2
- package/dist/src/hooks/types.test.js.map +1 -1
- package/dist/src/ide/ide-client.test.js +159 -0
- package/dist/src/ide/ide-client.test.js.map +1 -1
- package/dist/src/mcp/oauth-provider.test.js +177 -0
- package/dist/src/mcp/oauth-provider.test.js.map +1 -1
- package/dist/src/policy/config.js +3 -1
- package/dist/src/policy/config.js.map +1 -1
- package/dist/src/policy/config.test.js +118 -1
- package/dist/src/policy/config.test.js.map +1 -1
- package/dist/src/policy/policies/write.toml +10 -0
- package/dist/src/policy/policy-engine.d.ts +12 -3
- package/dist/src/policy/policy-engine.js +61 -7
- package/dist/src/policy/policy-engine.js.map +1 -1
- package/dist/src/policy/policy-engine.test.js +422 -86
- package/dist/src/policy/policy-engine.test.js.map +1 -1
- package/dist/src/policy/toml-loader.d.ts +2 -1
- package/dist/src/policy/toml-loader.js +103 -6
- package/dist/src/policy/toml-loader.js.map +1 -1
- package/dist/src/policy/toml-loader.test.js +32 -88
- package/dist/src/policy/toml-loader.test.js.map +1 -1
- package/dist/src/policy/types.d.ts +65 -0
- package/dist/src/policy/types.js +4 -0
- package/dist/src/policy/types.js.map +1 -1
- package/dist/src/prompts/mcp-prompts.test.d.ts +6 -0
- package/dist/src/prompts/mcp-prompts.test.js +40 -0
- package/dist/src/prompts/mcp-prompts.test.js.map +1 -0
- package/dist/src/prompts/prompt-registry.test.d.ts +6 -0
- package/dist/src/prompts/prompt-registry.test.js +111 -0
- package/dist/src/prompts/prompt-registry.test.js.map +1 -0
- package/dist/src/safety/built-in.d.ts +21 -0
- package/dist/src/safety/built-in.js +106 -0
- package/dist/src/safety/built-in.js.map +1 -0
- package/dist/src/safety/built-in.test.d.ts +6 -0
- package/dist/src/safety/built-in.test.js +199 -0
- package/dist/src/safety/built-in.test.js.map +1 -0
- package/dist/src/safety/checker-runner.d.ts +48 -0
- package/dist/src/safety/checker-runner.js +208 -0
- package/dist/src/safety/checker-runner.js.map +1 -0
- package/dist/src/safety/checker-runner.test.d.ts +6 -0
- package/dist/src/safety/checker-runner.test.js +238 -0
- package/dist/src/safety/checker-runner.test.js.map +1 -0
- package/dist/src/safety/context-builder.d.ts +23 -0
- package/dist/src/safety/context-builder.js +47 -0
- package/dist/src/safety/context-builder.js.map +1 -0
- package/dist/src/safety/context-builder.test.d.ts +6 -0
- package/dist/src/safety/context-builder.test.js +49 -0
- package/dist/src/safety/context-builder.test.js.map +1 -0
- package/dist/src/safety/protocol.d.ts +88 -0
- package/dist/src/safety/protocol.js +15 -0
- package/dist/src/safety/protocol.js.map +1 -0
- package/dist/src/safety/registry.d.ts +26 -0
- package/dist/src/safety/registry.js +65 -0
- package/dist/src/safety/registry.js.map +1 -0
- package/dist/src/safety/registry.test.d.ts +6 -0
- package/dist/src/safety/registry.test.js +31 -0
- package/dist/src/safety/registry.test.js.map +1 -0
- package/dist/src/services/loopDetectionService.d.ts +3 -0
- package/dist/src/services/loopDetectionService.js +81 -41
- package/dist/src/services/loopDetectionService.js.map +1 -1
- package/dist/src/services/loopDetectionService.test.js +96 -4
- package/dist/src/services/loopDetectionService.test.js.map +1 -1
- package/dist/src/services/test-data/resolved-aliases.golden.json +7 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +4 -2
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +29 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +31 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +5 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +12 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
- package/dist/src/telemetry/loggers.d.ts +2 -1
- package/dist/src/telemetry/loggers.js +11 -0
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/types.d.ts +15 -2
- package/dist/src/telemetry/types.js +42 -3
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/tools/base-tool-invocation.test.js +2 -2
- package/dist/src/tools/base-tool-invocation.test.js.map +1 -1
- package/dist/src/tools/memoryTool.js +1 -1
- package/dist/src/tools/memoryTool.js.map +1 -1
- package/dist/src/tools/memoryTool.test.js +1 -1
- package/dist/src/tools/memoryTool.test.js.map +1 -1
- package/dist/src/tools/ripGrep.d.ts +24 -7
- package/dist/src/tools/ripGrep.js +125 -145
- package/dist/src/tools/ripGrep.js.map +1 -1
- package/dist/src/tools/ripGrep.test.js +144 -20
- package/dist/src/tools/ripGrep.test.js.map +1 -1
- package/dist/src/tools/tools.js +1 -1
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/write-todos.js +1 -1
- package/dist/src/tools/write-todos.js.map +1 -1
- package/dist/src/utils/llm-edit-fixer.test.js +8 -1
- package/dist/src/utils/llm-edit-fixer.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/google-gemini-cli-core-0.15.0-preview.2.tgz +0 -0
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
+
import type { SafetyCheckInput } from '../safety/protocol.js';
|
|
6
7
|
export declare enum PolicyDecision {
|
|
7
8
|
ALLOW = "allow",
|
|
8
9
|
DENY = "deny",
|
|
@@ -13,6 +14,44 @@ export declare enum ApprovalMode {
|
|
|
13
14
|
AUTO_EDIT = "autoEdit",
|
|
14
15
|
YOLO = "yolo"
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Configuration for the built-in allowed-path checker.
|
|
19
|
+
*/
|
|
20
|
+
export interface AllowedPathConfig {
|
|
21
|
+
/**
|
|
22
|
+
* Explicitly include argument keys to be checked as paths.
|
|
23
|
+
*/
|
|
24
|
+
included_args?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Explicitly exclude argument keys from being checked as paths.
|
|
27
|
+
*/
|
|
28
|
+
excluded_args?: string[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Base interface for external checkers.
|
|
32
|
+
*/
|
|
33
|
+
export interface ExternalCheckerConfig {
|
|
34
|
+
type: 'external';
|
|
35
|
+
name: string;
|
|
36
|
+
config?: unknown;
|
|
37
|
+
required_context?: Array<keyof SafetyCheckInput['context']>;
|
|
38
|
+
}
|
|
39
|
+
export declare enum InProcessCheckerType {
|
|
40
|
+
ALLOWED_PATH = "allowed-path"
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Base interface for in-process checkers.
|
|
44
|
+
*/
|
|
45
|
+
export interface InProcessCheckerConfig {
|
|
46
|
+
type: 'in-process';
|
|
47
|
+
name: InProcessCheckerType;
|
|
48
|
+
config?: AllowedPathConfig;
|
|
49
|
+
required_context?: Array<keyof SafetyCheckInput['context']>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A discriminated union for all safety checker configurations.
|
|
53
|
+
*/
|
|
54
|
+
export type SafetyCheckerConfig = ExternalCheckerConfig | InProcessCheckerConfig;
|
|
16
55
|
export interface PolicyRule {
|
|
17
56
|
/**
|
|
18
57
|
* The name of the tool this rule applies to.
|
|
@@ -34,11 +73,37 @@ export interface PolicyRule {
|
|
|
34
73
|
*/
|
|
35
74
|
priority?: number;
|
|
36
75
|
}
|
|
76
|
+
export interface SafetyCheckerRule {
|
|
77
|
+
/**
|
|
78
|
+
* The name of the tool this rule applies to.
|
|
79
|
+
* If undefined, the rule applies to all tools.
|
|
80
|
+
*/
|
|
81
|
+
toolName?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Pattern to match against tool arguments.
|
|
84
|
+
* Can be used for more fine-grained control.
|
|
85
|
+
*/
|
|
86
|
+
argsPattern?: RegExp;
|
|
87
|
+
/**
|
|
88
|
+
* Priority of this checker. Higher numbers run first.
|
|
89
|
+
* Default is 0.
|
|
90
|
+
*/
|
|
91
|
+
priority?: number;
|
|
92
|
+
/**
|
|
93
|
+
* Specifies an external or built-in safety checker to execute for
|
|
94
|
+
* additional validation of a tool call.
|
|
95
|
+
*/
|
|
96
|
+
checker: SafetyCheckerConfig;
|
|
97
|
+
}
|
|
37
98
|
export interface PolicyEngineConfig {
|
|
38
99
|
/**
|
|
39
100
|
* List of policy rules to apply.
|
|
40
101
|
*/
|
|
41
102
|
rules?: PolicyRule[];
|
|
103
|
+
/**
|
|
104
|
+
* List of safety checkers to apply.
|
|
105
|
+
*/
|
|
106
|
+
checkers?: SafetyCheckerRule[];
|
|
42
107
|
/**
|
|
43
108
|
* Default decision when no rules match.
|
|
44
109
|
* Defaults to ASK_USER.
|
package/dist/src/policy/types.js
CHANGED
|
@@ -15,4 +15,8 @@ export var ApprovalMode;
|
|
|
15
15
|
ApprovalMode["AUTO_EDIT"] = "autoEdit";
|
|
16
16
|
ApprovalMode["YOLO"] = "yolo";
|
|
17
17
|
})(ApprovalMode || (ApprovalMode = {}));
|
|
18
|
+
export var InProcessCheckerType;
|
|
19
|
+
(function (InProcessCheckerType) {
|
|
20
|
+
InProcessCheckerType["ALLOWED_PATH"] = "allowed-path";
|
|
21
|
+
})(InProcessCheckerType || (InProcessCheckerType = {}));
|
|
18
22
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/policy/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/policy/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,CAAN,IAAY,cAIX;AAJD,WAAY,cAAc;IACxB,iCAAe,CAAA;IACf,+BAAa,CAAA;IACb,uCAAqB,CAAA;AACvB,CAAC,EAJW,cAAc,KAAd,cAAc,QAIzB;AAED,MAAM,CAAN,IAAY,YAIX;AAJD,WAAY,YAAY;IACtB,mCAAmB,CAAA;IACnB,sCAAsB,CAAA;IACtB,6BAAa,CAAA;AACf,CAAC,EAJW,YAAY,KAAZ,YAAY,QAIvB;AA2BD,MAAM,CAAN,IAAY,oBAEX;AAFD,WAAY,oBAAoB;IAC9B,qDAA6B,CAAA;AAC/B,CAAC,EAFW,oBAAoB,KAApB,oBAAoB,QAE/B"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
7
|
+
import { getMCPServerPrompts } from './mcp-prompts.js';
|
|
8
|
+
import { PromptRegistry } from './prompt-registry.js';
|
|
9
|
+
describe('getMCPServerPrompts', () => {
|
|
10
|
+
it('should return prompts from the registry for a given server', () => {
|
|
11
|
+
const mockPrompts = [
|
|
12
|
+
{
|
|
13
|
+
name: 'prompt1',
|
|
14
|
+
serverName: 'server1',
|
|
15
|
+
tool: { name: 'p1', description: '', inputSchema: {} },
|
|
16
|
+
invoke: async () => ({
|
|
17
|
+
messages: [
|
|
18
|
+
{ role: 'assistant', content: { type: 'text', text: '' } },
|
|
19
|
+
],
|
|
20
|
+
}),
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
const mockRegistry = new PromptRegistry();
|
|
24
|
+
vi.spyOn(mockRegistry, 'getPromptsByServer').mockReturnValue(mockPrompts);
|
|
25
|
+
const mockConfig = {
|
|
26
|
+
getPromptRegistry: () => mockRegistry,
|
|
27
|
+
};
|
|
28
|
+
const result = getMCPServerPrompts(mockConfig, 'server1');
|
|
29
|
+
expect(mockRegistry.getPromptsByServer).toHaveBeenCalledWith('server1');
|
|
30
|
+
expect(result).toEqual(mockPrompts);
|
|
31
|
+
});
|
|
32
|
+
it('should return an empty array if there is no prompt registry', () => {
|
|
33
|
+
const mockConfig = {
|
|
34
|
+
getPromptRegistry: () => undefined,
|
|
35
|
+
};
|
|
36
|
+
const result = getMCPServerPrompts(mockConfig, 'server1');
|
|
37
|
+
expect(result).toEqual([]);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=mcp-prompts.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-prompts.test.js","sourceRoot":"","sources":["../../../src/prompts/mcp-prompts.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,WAAW,GAA0B;YACzC;gBACE,IAAI,EAAE,SAAS;gBACf,UAAU,EAAE,SAAS;gBACrB,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;gBACtD,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;oBACnB,QAAQ,EAAE;wBACR,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;qBAC3D;iBACF,CAAC;aACH;SACF,CAAC;QAEF,MAAM,YAAY,GAAG,IAAI,cAAc,EAAE,CAAC;QAC1C,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,oBAAoB,CAAC,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;QAE1E,MAAM,UAAU,GAAG;YACjB,iBAAiB,EAAE,GAAG,EAAE,CAAC,YAAY;SACjB,CAAC;QAEvB,MAAM,MAAM,GAAG,mBAAmB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAE1D,MAAM,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC;QACxE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,UAAU,GAAG;YACjB,iBAAiB,EAAE,GAAG,EAAE,CAAC,SAAS;SACd,CAAC;QAEvB,MAAM,MAAM,GAAG,mBAAmB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAE1D,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
7
|
+
import { PromptRegistry } from './prompt-registry.js';
|
|
8
|
+
import { debugLogger } from '../utils/debugLogger.js';
|
|
9
|
+
vi.mock('../utils/debugLogger.js', () => ({
|
|
10
|
+
debugLogger: {
|
|
11
|
+
warn: vi.fn(),
|
|
12
|
+
},
|
|
13
|
+
}));
|
|
14
|
+
describe('PromptRegistry', () => {
|
|
15
|
+
let registry;
|
|
16
|
+
const prompt1 = {
|
|
17
|
+
name: 'prompt1',
|
|
18
|
+
serverName: 'server1',
|
|
19
|
+
tool: {
|
|
20
|
+
name: 'prompt1',
|
|
21
|
+
description: 'Prompt 1',
|
|
22
|
+
inputSchema: {},
|
|
23
|
+
},
|
|
24
|
+
invoke: async () => ({
|
|
25
|
+
messages: [
|
|
26
|
+
{ role: 'assistant', content: { type: 'text', text: 'response1' } },
|
|
27
|
+
],
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
30
|
+
const prompt2 = {
|
|
31
|
+
name: 'prompt2',
|
|
32
|
+
serverName: 'server1',
|
|
33
|
+
tool: {
|
|
34
|
+
name: 'prompt2',
|
|
35
|
+
description: 'Prompt 2',
|
|
36
|
+
inputSchema: {},
|
|
37
|
+
},
|
|
38
|
+
invoke: async () => ({
|
|
39
|
+
messages: [
|
|
40
|
+
{ role: 'assistant', content: { type: 'text', text: 'response2' } },
|
|
41
|
+
],
|
|
42
|
+
}),
|
|
43
|
+
};
|
|
44
|
+
const prompt3 = {
|
|
45
|
+
name: 'prompt1',
|
|
46
|
+
serverName: 'server2',
|
|
47
|
+
tool: {
|
|
48
|
+
name: 'prompt1',
|
|
49
|
+
description: 'Prompt 3',
|
|
50
|
+
inputSchema: {},
|
|
51
|
+
},
|
|
52
|
+
invoke: async () => ({
|
|
53
|
+
messages: [
|
|
54
|
+
{ role: 'assistant', content: { type: 'text', text: 'response3' } },
|
|
55
|
+
],
|
|
56
|
+
}),
|
|
57
|
+
};
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
registry = new PromptRegistry();
|
|
60
|
+
vi.clearAllMocks();
|
|
61
|
+
});
|
|
62
|
+
it('should register a prompt', () => {
|
|
63
|
+
registry.registerPrompt(prompt1);
|
|
64
|
+
expect(registry.getPrompt('prompt1')).toEqual(prompt1);
|
|
65
|
+
});
|
|
66
|
+
it('should get all prompts, sorted by name', () => {
|
|
67
|
+
registry.registerPrompt(prompt2);
|
|
68
|
+
registry.registerPrompt(prompt1);
|
|
69
|
+
expect(registry.getAllPrompts()).toEqual([prompt1, prompt2]);
|
|
70
|
+
});
|
|
71
|
+
it('should get a specific prompt by name', () => {
|
|
72
|
+
registry.registerPrompt(prompt1);
|
|
73
|
+
expect(registry.getPrompt('prompt1')).toEqual(prompt1);
|
|
74
|
+
expect(registry.getPrompt('non-existent')).toBeUndefined();
|
|
75
|
+
});
|
|
76
|
+
it('should get prompts by server, sorted by name', () => {
|
|
77
|
+
registry.registerPrompt(prompt1);
|
|
78
|
+
registry.registerPrompt(prompt2);
|
|
79
|
+
registry.registerPrompt(prompt3); // different server
|
|
80
|
+
expect(registry.getPromptsByServer('server1')).toEqual([prompt1, prompt2]);
|
|
81
|
+
expect(registry.getPromptsByServer('server2')).toEqual([
|
|
82
|
+
{ ...prompt3, name: 'server2_prompt1' },
|
|
83
|
+
]);
|
|
84
|
+
});
|
|
85
|
+
it('should handle prompt name collision by renaming', () => {
|
|
86
|
+
registry.registerPrompt(prompt1);
|
|
87
|
+
registry.registerPrompt(prompt3);
|
|
88
|
+
expect(registry.getPrompt('prompt1')).toEqual(prompt1);
|
|
89
|
+
const renamedPrompt = { ...prompt3, name: 'server2_prompt1' };
|
|
90
|
+
expect(registry.getPrompt('server2_prompt1')).toEqual(renamedPrompt);
|
|
91
|
+
expect(debugLogger.warn).toHaveBeenCalledWith('Prompt with name "prompt1" is already registered. Renaming to "server2_prompt1".');
|
|
92
|
+
});
|
|
93
|
+
it('should clear all prompts', () => {
|
|
94
|
+
registry.registerPrompt(prompt1);
|
|
95
|
+
registry.registerPrompt(prompt2);
|
|
96
|
+
registry.clear();
|
|
97
|
+
expect(registry.getAllPrompts()).toEqual([]);
|
|
98
|
+
});
|
|
99
|
+
it('should remove prompts by server', () => {
|
|
100
|
+
registry.registerPrompt(prompt1);
|
|
101
|
+
registry.registerPrompt(prompt2);
|
|
102
|
+
registry.registerPrompt(prompt3);
|
|
103
|
+
registry.removePromptsByServer('server1');
|
|
104
|
+
const renamedPrompt = { ...prompt3, name: 'server2_prompt1' };
|
|
105
|
+
expect(registry.getAllPrompts()).toEqual([renamedPrompt]);
|
|
106
|
+
expect(registry.getPrompt('prompt1')).toBeUndefined();
|
|
107
|
+
expect(registry.getPrompt('prompt2')).toBeUndefined();
|
|
108
|
+
expect(registry.getPrompt('server2_prompt1')).toEqual(renamedPrompt);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
//# sourceMappingURL=prompt-registry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-registry.test.js","sourceRoot":"","sources":["../../../src/prompts/prompt-registry.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,EAAE,CAAC,IAAI,CAAC,yBAAyB,EAAE,GAAG,EAAE,CAAC,CAAC;IACxC,WAAW,EAAE;QACX,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;KACd;CACF,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,IAAI,QAAwB,CAAC;IAE7B,MAAM,OAAO,GAAwB;QACnC,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,SAAS;QACrB,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,UAAU;YACvB,WAAW,EAAE,EAAE;SAChB;QACD,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YACnB,QAAQ,EAAE;gBACR,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;aACpE;SACF,CAAC;KACH,CAAC;IAEF,MAAM,OAAO,GAAwB;QACnC,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,SAAS;QACrB,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,UAAU;YACvB,WAAW,EAAE,EAAE;SAChB;QACD,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YACnB,QAAQ,EAAE;gBACR,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;aACpE;SACF,CAAC;KACH,CAAC;IAEF,MAAM,OAAO,GAAwB;QACnC,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,SAAS;QACrB,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,UAAU;YACvB,WAAW,EAAE,EAAE;SAChB;QACD,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YACnB,QAAQ,EAAE;gBACR,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;aACpE;SACF,CAAC;KACH,CAAC;IAEF,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,GAAG,IAAI,cAAc,EAAE,CAAC;QAChC,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjC,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvD,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB;QACrD,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;YACrD,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE;SACxC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAEjC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvD,MAAM,aAAa,GAAG,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;QAC9D,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACrE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAC3C,kFAAkF,CACnF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjC,QAAQ,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;QAE1C,MAAM,aAAa,GAAG,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;QAC9D,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QACtD,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QACtD,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import type { SafetyCheckInput, SafetyCheckResult } from './protocol.js';
|
|
7
|
+
/**
|
|
8
|
+
* Interface for all in-process safety checkers.
|
|
9
|
+
*/
|
|
10
|
+
export interface InProcessChecker {
|
|
11
|
+
check(input: SafetyCheckInput): Promise<SafetyCheckResult>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* An in-process checker to validate file paths.
|
|
15
|
+
*/
|
|
16
|
+
export declare class AllowedPathChecker implements InProcessChecker {
|
|
17
|
+
check(input: SafetyCheckInput): Promise<SafetyCheckResult>;
|
|
18
|
+
private safelyResolvePath;
|
|
19
|
+
private isPathAllowed;
|
|
20
|
+
private collectPathsToCheck;
|
|
21
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import { SafetyCheckDecision } from './protocol.js';
|
|
9
|
+
/**
|
|
10
|
+
* An in-process checker to validate file paths.
|
|
11
|
+
*/
|
|
12
|
+
export class AllowedPathChecker {
|
|
13
|
+
async check(input) {
|
|
14
|
+
const { toolCall, context } = input;
|
|
15
|
+
const config = input.config;
|
|
16
|
+
// Build list of allowed directories
|
|
17
|
+
const allowedDirs = [
|
|
18
|
+
context.environment.cwd,
|
|
19
|
+
...context.environment.workspaces,
|
|
20
|
+
];
|
|
21
|
+
// Find all arguments that look like paths
|
|
22
|
+
const includedArgs = config?.included_args ?? [];
|
|
23
|
+
const excludedArgs = config?.excluded_args ?? [];
|
|
24
|
+
const pathsToCheck = this.collectPathsToCheck(toolCall.args, includedArgs, excludedArgs);
|
|
25
|
+
// Check each path
|
|
26
|
+
for (const { path: p, argName } of pathsToCheck) {
|
|
27
|
+
const resolvedPath = this.safelyResolvePath(p, context.environment.cwd);
|
|
28
|
+
if (!resolvedPath) {
|
|
29
|
+
// If path cannot be resolved, deny it
|
|
30
|
+
return {
|
|
31
|
+
decision: SafetyCheckDecision.DENY,
|
|
32
|
+
reason: `Cannot resolve path "${p}" in argument "${argName}"`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const isAllowed = allowedDirs.some((dir) => {
|
|
36
|
+
// Also resolve allowed directories to handle symlinks
|
|
37
|
+
const resolvedDir = this.safelyResolvePath(dir, context.environment.cwd);
|
|
38
|
+
if (!resolvedDir)
|
|
39
|
+
return false;
|
|
40
|
+
return this.isPathAllowed(resolvedPath, resolvedDir);
|
|
41
|
+
});
|
|
42
|
+
if (!isAllowed) {
|
|
43
|
+
return {
|
|
44
|
+
decision: SafetyCheckDecision.DENY,
|
|
45
|
+
reason: `Path "${p}" in argument "${argName}" is outside of the allowed workspace directories.`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { decision: SafetyCheckDecision.ALLOW };
|
|
50
|
+
}
|
|
51
|
+
safelyResolvePath(inputPath, cwd) {
|
|
52
|
+
try {
|
|
53
|
+
const resolved = path.resolve(cwd, inputPath);
|
|
54
|
+
// Walk up the directory tree until we find a path that exists
|
|
55
|
+
let current = resolved;
|
|
56
|
+
// Stop at root (dirname(root) === root on many systems, or it becomes empty/'.' depending on implementation)
|
|
57
|
+
while (current && current !== path.dirname(current)) {
|
|
58
|
+
if (fs.existsSync(current)) {
|
|
59
|
+
const canonical = fs.realpathSync(current);
|
|
60
|
+
// Re-construct the full path from this canonical base
|
|
61
|
+
const relative = path.relative(current, resolved);
|
|
62
|
+
// path.join handles empty relative paths correctly (returns canonical)
|
|
63
|
+
return path.join(canonical, relative);
|
|
64
|
+
}
|
|
65
|
+
current = path.dirname(current);
|
|
66
|
+
}
|
|
67
|
+
// Fallback if nothing exists (unlikely if root exists)
|
|
68
|
+
return resolved;
|
|
69
|
+
}
|
|
70
|
+
catch (_error) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
isPathAllowed(targetPath, allowedDir) {
|
|
75
|
+
const relative = path.relative(allowedDir, targetPath);
|
|
76
|
+
return (relative === '' ||
|
|
77
|
+
(!relative.startsWith('..') && !path.isAbsolute(relative)));
|
|
78
|
+
}
|
|
79
|
+
collectPathsToCheck(args, includedArgs, excludedArgs, prefix = '') {
|
|
80
|
+
const paths = [];
|
|
81
|
+
if (typeof args !== 'object' || args === null) {
|
|
82
|
+
return paths;
|
|
83
|
+
}
|
|
84
|
+
for (const [key, value] of Object.entries(args)) {
|
|
85
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
86
|
+
if (excludedArgs.includes(fullKey)) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (typeof value === 'string') {
|
|
90
|
+
if (includedArgs.includes(fullKey) ||
|
|
91
|
+
key.includes('path') ||
|
|
92
|
+
key.includes('directory') ||
|
|
93
|
+
key.includes('file') ||
|
|
94
|
+
key === 'source' ||
|
|
95
|
+
key === 'destination') {
|
|
96
|
+
paths.push({ path: value, argName: fullKey });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else if (typeof value === 'object') {
|
|
100
|
+
paths.push(...this.collectPathsToCheck(value, includedArgs, excludedArgs, fullKey));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return paths;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=built-in.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"built-in.js","sourceRoot":"","sources":["../../../src/safety/built-in.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
7
|
+
import * as fs from 'node:fs/promises';
|
|
8
|
+
import * as os from 'node:os';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
import { AllowedPathChecker } from './built-in.js';
|
|
11
|
+
import { SafetyCheckDecision } from './protocol.js';
|
|
12
|
+
describe('AllowedPathChecker', () => {
|
|
13
|
+
let checker;
|
|
14
|
+
let testRootDir;
|
|
15
|
+
let mockCwd;
|
|
16
|
+
let mockWorkspaces;
|
|
17
|
+
beforeEach(async () => {
|
|
18
|
+
checker = new AllowedPathChecker();
|
|
19
|
+
testRootDir = await fs.mkdtemp(path.join(os.tmpdir(), 'safety-test-'));
|
|
20
|
+
mockCwd = path.join(testRootDir, 'home', 'user', 'project');
|
|
21
|
+
await fs.mkdir(mockCwd, { recursive: true });
|
|
22
|
+
mockWorkspaces = [
|
|
23
|
+
mockCwd,
|
|
24
|
+
path.join(testRootDir, 'home', 'user', 'other-project'),
|
|
25
|
+
];
|
|
26
|
+
await fs.mkdir(mockWorkspaces[1], { recursive: true });
|
|
27
|
+
});
|
|
28
|
+
afterEach(async () => {
|
|
29
|
+
await fs.rm(testRootDir, { recursive: true, force: true });
|
|
30
|
+
});
|
|
31
|
+
const createInput = (toolArgs, config) => ({
|
|
32
|
+
protocolVersion: '1.0.0',
|
|
33
|
+
toolCall: {
|
|
34
|
+
name: 'test_tool',
|
|
35
|
+
args: toolArgs,
|
|
36
|
+
},
|
|
37
|
+
context: {
|
|
38
|
+
environment: {
|
|
39
|
+
cwd: mockCwd,
|
|
40
|
+
workspaces: mockWorkspaces,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
config,
|
|
44
|
+
});
|
|
45
|
+
it('should allow paths within CWD', async () => {
|
|
46
|
+
const filePath = path.join(mockCwd, 'file.txt');
|
|
47
|
+
await fs.writeFile(filePath, 'test content');
|
|
48
|
+
const input = createInput({
|
|
49
|
+
path: filePath,
|
|
50
|
+
});
|
|
51
|
+
const result = await checker.check(input);
|
|
52
|
+
expect(result.decision).toBe(SafetyCheckDecision.ALLOW);
|
|
53
|
+
});
|
|
54
|
+
it('should allow paths within workspace roots', async () => {
|
|
55
|
+
const filePath = path.join(mockWorkspaces[1], 'data.json');
|
|
56
|
+
await fs.writeFile(filePath, 'test content');
|
|
57
|
+
const input = createInput({
|
|
58
|
+
path: filePath,
|
|
59
|
+
});
|
|
60
|
+
const result = await checker.check(input);
|
|
61
|
+
expect(result.decision).toBe(SafetyCheckDecision.ALLOW);
|
|
62
|
+
});
|
|
63
|
+
it('should deny paths outside allowed areas', async () => {
|
|
64
|
+
const outsidePath = path.join(testRootDir, 'etc', 'passwd');
|
|
65
|
+
await fs.mkdir(path.dirname(outsidePath), { recursive: true });
|
|
66
|
+
await fs.writeFile(outsidePath, 'secret');
|
|
67
|
+
const input = createInput({ path: outsidePath });
|
|
68
|
+
const result = await checker.check(input);
|
|
69
|
+
expect(result.decision).toBe(SafetyCheckDecision.DENY);
|
|
70
|
+
expect(result.reason).toContain('outside of the allowed workspace');
|
|
71
|
+
});
|
|
72
|
+
it('should deny paths using ../ to escape', async () => {
|
|
73
|
+
const secretPath = path.join(testRootDir, 'home', 'user', 'secret.txt');
|
|
74
|
+
await fs.writeFile(secretPath, 'secret');
|
|
75
|
+
const input = createInput({
|
|
76
|
+
path: path.join(mockCwd, '..', 'secret.txt'),
|
|
77
|
+
});
|
|
78
|
+
const result = await checker.check(input);
|
|
79
|
+
expect(result.decision).toBe(SafetyCheckDecision.DENY);
|
|
80
|
+
});
|
|
81
|
+
it('should check multiple path arguments', async () => {
|
|
82
|
+
const passwdPath = path.join(testRootDir, 'etc', 'passwd');
|
|
83
|
+
await fs.mkdir(path.dirname(passwdPath), { recursive: true });
|
|
84
|
+
await fs.writeFile(passwdPath, 'secret');
|
|
85
|
+
const srcPath = path.join(mockCwd, 'src.txt');
|
|
86
|
+
await fs.writeFile(srcPath, 'source content');
|
|
87
|
+
const input = createInput({
|
|
88
|
+
source: srcPath,
|
|
89
|
+
destination: passwdPath,
|
|
90
|
+
});
|
|
91
|
+
const result = await checker.check(input);
|
|
92
|
+
expect(result.decision).toBe(SafetyCheckDecision.DENY);
|
|
93
|
+
expect(result.reason).toContain(passwdPath);
|
|
94
|
+
});
|
|
95
|
+
it('should handle non-existent paths gracefully if they are inside allowed dir', async () => {
|
|
96
|
+
const input = createInput({
|
|
97
|
+
path: path.join(mockCwd, 'new-file.txt'),
|
|
98
|
+
});
|
|
99
|
+
const result = await checker.check(input);
|
|
100
|
+
expect(result.decision).toBe(SafetyCheckDecision.ALLOW);
|
|
101
|
+
});
|
|
102
|
+
it('should deny access if path contains a symlink pointing outside allowed directories', async () => {
|
|
103
|
+
const symlinkPath = path.join(mockCwd, 'symlink');
|
|
104
|
+
const targetPath = path.join(testRootDir, 'etc', 'passwd');
|
|
105
|
+
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
106
|
+
await fs.writeFile(targetPath, 'secret');
|
|
107
|
+
// Create symlink: mockCwd/symlink -> targetPath
|
|
108
|
+
await fs.symlink(targetPath, symlinkPath);
|
|
109
|
+
const input = createInput({ path: symlinkPath });
|
|
110
|
+
const result = await checker.check(input);
|
|
111
|
+
expect(result.decision).toBe(SafetyCheckDecision.DENY);
|
|
112
|
+
expect(result.reason).toContain('outside of the allowed workspace directories');
|
|
113
|
+
});
|
|
114
|
+
it('should allow access if path contains a symlink pointing INSIDE allowed directories', async () => {
|
|
115
|
+
const symlinkPath = path.join(mockCwd, 'symlink-inside');
|
|
116
|
+
const realFilePath = path.join(mockCwd, 'real-file');
|
|
117
|
+
await fs.writeFile(realFilePath, 'real content');
|
|
118
|
+
// Create symlink: mockCwd/symlink-inside -> mockCwd/real-file
|
|
119
|
+
await fs.symlink(realFilePath, symlinkPath);
|
|
120
|
+
const input = createInput({ path: symlinkPath });
|
|
121
|
+
const result = await checker.check(input);
|
|
122
|
+
expect(result.decision).toBe(SafetyCheckDecision.ALLOW);
|
|
123
|
+
});
|
|
124
|
+
it('should check explicitly included arguments', async () => {
|
|
125
|
+
const outsidePath = path.join(testRootDir, 'etc', 'passwd');
|
|
126
|
+
await fs.mkdir(path.dirname(outsidePath), { recursive: true });
|
|
127
|
+
await fs.writeFile(outsidePath, 'secret');
|
|
128
|
+
const input = createInput({ custom_arg: outsidePath }, { included_args: ['custom_arg'] });
|
|
129
|
+
const result = await checker.check(input);
|
|
130
|
+
expect(result.decision).toBe(SafetyCheckDecision.DENY);
|
|
131
|
+
expect(result.reason).toContain('outside of the allowed workspace');
|
|
132
|
+
});
|
|
133
|
+
it('should skip explicitly excluded arguments', async () => {
|
|
134
|
+
const outsidePath = path.join(testRootDir, 'etc', 'passwd');
|
|
135
|
+
await fs.mkdir(path.dirname(outsidePath), { recursive: true });
|
|
136
|
+
await fs.writeFile(outsidePath, 'secret');
|
|
137
|
+
// Normally 'path' would be checked, but we exclude it
|
|
138
|
+
const input = createInput({ path: outsidePath }, { excluded_args: ['path'] });
|
|
139
|
+
const result = await checker.check(input);
|
|
140
|
+
expect(result.decision).toBe(SafetyCheckDecision.ALLOW);
|
|
141
|
+
});
|
|
142
|
+
it('should handle both included and excluded arguments', async () => {
|
|
143
|
+
const outsidePath = path.join(testRootDir, 'etc', 'passwd');
|
|
144
|
+
await fs.mkdir(path.dirname(outsidePath), { recursive: true });
|
|
145
|
+
await fs.writeFile(outsidePath, 'secret');
|
|
146
|
+
const input = createInput({
|
|
147
|
+
path: outsidePath, // Excluded
|
|
148
|
+
custom_arg: outsidePath, // Included
|
|
149
|
+
}, {
|
|
150
|
+
excluded_args: ['path'],
|
|
151
|
+
included_args: ['custom_arg'],
|
|
152
|
+
});
|
|
153
|
+
const result = await checker.check(input);
|
|
154
|
+
expect(result.decision).toBe(SafetyCheckDecision.DENY);
|
|
155
|
+
// Should be denied because of custom_arg, not path
|
|
156
|
+
expect(result.reason).toContain(outsidePath);
|
|
157
|
+
});
|
|
158
|
+
it('should check nested path arguments', async () => {
|
|
159
|
+
const outsidePath = path.join(testRootDir, 'etc', 'passwd');
|
|
160
|
+
await fs.mkdir(path.dirname(outsidePath), { recursive: true });
|
|
161
|
+
await fs.writeFile(outsidePath, 'secret');
|
|
162
|
+
const input = createInput({
|
|
163
|
+
nested: {
|
|
164
|
+
path: outsidePath,
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
const result = await checker.check(input);
|
|
168
|
+
expect(result.decision).toBe(SafetyCheckDecision.DENY);
|
|
169
|
+
expect(result.reason).toContain(outsidePath);
|
|
170
|
+
expect(result.reason).toContain('nested.path');
|
|
171
|
+
});
|
|
172
|
+
it('should support dot notation for included_args', async () => {
|
|
173
|
+
const outsidePath = path.join(testRootDir, 'etc', 'passwd');
|
|
174
|
+
await fs.mkdir(path.dirname(outsidePath), { recursive: true });
|
|
175
|
+
await fs.writeFile(outsidePath, 'secret');
|
|
176
|
+
const input = createInput({
|
|
177
|
+
nested: {
|
|
178
|
+
custom: outsidePath,
|
|
179
|
+
},
|
|
180
|
+
}, { included_args: ['nested.custom'] });
|
|
181
|
+
const result = await checker.check(input);
|
|
182
|
+
expect(result.decision).toBe(SafetyCheckDecision.DENY);
|
|
183
|
+
expect(result.reason).toContain(outsidePath);
|
|
184
|
+
expect(result.reason).toContain('nested.custom');
|
|
185
|
+
});
|
|
186
|
+
it('should support dot notation for excluded_args', async () => {
|
|
187
|
+
const outsidePath = path.join(testRootDir, 'etc', 'passwd');
|
|
188
|
+
await fs.mkdir(path.dirname(outsidePath), { recursive: true });
|
|
189
|
+
await fs.writeFile(outsidePath, 'secret');
|
|
190
|
+
const input = createInput({
|
|
191
|
+
nested: {
|
|
192
|
+
path: outsidePath,
|
|
193
|
+
},
|
|
194
|
+
}, { excluded_args: ['nested.path'] });
|
|
195
|
+
const result = await checker.check(input);
|
|
196
|
+
expect(result.decision).toBe(SafetyCheckDecision.ALLOW);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
//# sourceMappingURL=built-in.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"built-in.test.js","sourceRoot":"","sources":["../../../src/safety/built-in.test.ts"],"names":[],"mappings":"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"}
|