@google/gemini-cli-core 0.36.0-preview.8 → 0.37.0-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/docs/CONTRIBUTING.md +10 -7
- package/dist/docs/assets/theme-tokyonight-dark.png +0 -0
- package/dist/docs/changelogs/index.md +24 -0
- package/dist/docs/changelogs/latest.md +366 -459
- package/dist/docs/changelogs/preview.md +362 -356
- package/dist/docs/cli/acp-mode.md +126 -0
- package/dist/docs/cli/cli-reference.md +1 -1
- package/dist/docs/cli/notifications.md +5 -5
- package/dist/docs/cli/plan-mode.md +12 -8
- package/dist/docs/cli/sandbox.md +1 -1
- package/dist/docs/cli/settings.md +14 -13
- package/dist/docs/cli/themes.md +5 -0
- package/dist/docs/core/index.md +2 -2
- package/dist/docs/core/subagents.md +134 -23
- package/dist/docs/get-started/gemini-3.md +1 -1
- package/dist/docs/get-started/index.md +127 -1
- package/dist/docs/ide-integration/index.md +99 -24
- package/dist/docs/index.md +0 -2
- package/dist/docs/redirects.json +1 -0
- package/dist/docs/reference/commands.md +1 -3
- package/dist/docs/reference/configuration.md +182 -91
- package/dist/docs/reference/keyboard-shortcuts.md +14 -6
- package/dist/docs/reference/policy-engine.md +16 -30
- package/dist/docs/reference/tools.md +56 -23
- package/dist/docs/resources/quota-and-pricing.md +23 -9
- package/dist/docs/sidebar.json +11 -4
- package/dist/docs/tools/planning.md +6 -4
- package/dist/src/agents/agentLoader.d.ts +12 -12
- package/dist/src/agents/agentLoader.js +1 -0
- package/dist/src/agents/agentLoader.js.map +1 -1
- package/dist/src/agents/browser/automationOverlay.js +2 -10
- package/dist/src/agents/browser/automationOverlay.js.map +1 -1
- package/dist/src/agents/browser/browserAgentDefinition.js +10 -3
- package/dist/src/agents/browser/browserAgentDefinition.js.map +1 -1
- package/dist/src/agents/browser/browserAgentFactory.d.ts +4 -4
- package/dist/src/agents/browser/browserAgentFactory.js +15 -29
- package/dist/src/agents/browser/browserAgentFactory.js.map +1 -1
- package/dist/src/agents/browser/browserAgentFactory.test.js +41 -24
- package/dist/src/agents/browser/browserAgentFactory.test.js.map +1 -1
- package/dist/src/agents/browser/browserAgentInvocation.d.ts +1 -0
- package/dist/src/agents/browser/browserAgentInvocation.js +60 -27
- package/dist/src/agents/browser/browserAgentInvocation.js.map +1 -1
- package/dist/src/agents/browser/browserAgentInvocation.test.js +59 -5
- package/dist/src/agents/browser/browserAgentInvocation.test.js.map +1 -1
- package/dist/src/agents/browser/browserManager.d.ts +51 -8
- package/dist/src/agents/browser/browserManager.js +242 -70
- package/dist/src/agents/browser/browserManager.js.map +1 -1
- package/dist/src/agents/browser/browserManager.test.js +384 -17
- package/dist/src/agents/browser/browserManager.test.js.map +1 -1
- package/dist/src/agents/browser/inputBlocker.d.ts +4 -4
- package/dist/src/agents/browser/inputBlocker.js +8 -18
- package/dist/src/agents/browser/inputBlocker.js.map +1 -1
- package/dist/src/agents/browser/inputBlocker.test.js +31 -3
- package/dist/src/agents/browser/inputBlocker.test.js.map +1 -1
- package/dist/src/agents/browser/mcpToolWrapper.d.ts +1 -1
- package/dist/src/agents/browser/mcpToolWrapper.js +9 -6
- package/dist/src/agents/browser/mcpToolWrapper.js.map +1 -1
- package/dist/src/agents/browser/mcpToolWrapper.test.js +2 -2
- package/dist/src/agents/browser/mcpToolWrapper.test.js.map +1 -1
- package/dist/src/agents/browser/snapshotSuperseder.d.ts +31 -0
- package/dist/src/agents/browser/snapshotSuperseder.js +101 -0
- package/dist/src/agents/browser/snapshotSuperseder.js.map +1 -0
- package/dist/src/agents/browser/snapshotSuperseder.test.js +158 -0
- package/dist/src/agents/browser/snapshotSuperseder.test.js.map +1 -0
- package/dist/src/agents/local-executor.d.ts +4 -0
- package/dist/src/agents/local-executor.js +46 -19
- package/dist/src/agents/local-executor.js.map +1 -1
- package/dist/src/agents/local-executor.test.js +118 -18
- package/dist/src/agents/local-executor.test.js.map +1 -1
- package/dist/src/agents/local-invocation.d.ts +1 -0
- package/dist/src/agents/local-invocation.js +19 -9
- package/dist/src/agents/local-invocation.js.map +1 -1
- package/dist/src/agents/local-invocation.test.js +24 -0
- package/dist/src/agents/local-invocation.test.js.map +1 -1
- package/dist/src/agents/registry.js +16 -1
- package/dist/src/agents/registry.js.map +1 -1
- package/dist/src/agents/registry.test.js +67 -0
- package/dist/src/agents/registry.test.js.map +1 -1
- package/dist/src/agents/types.d.ts +9 -0
- package/dist/src/agents/types.js.map +1 -1
- package/dist/src/code_assist/oauth2.js +8 -3
- package/dist/src/code_assist/oauth2.js.map +1 -1
- package/dist/src/code_assist/oauth2.test.js +57 -0
- package/dist/src/code_assist/oauth2.test.js.map +1 -1
- package/dist/src/code_assist/setup.js +5 -2
- package/dist/src/code_assist/setup.js.map +1 -1
- package/dist/src/code_assist/setup.test.js +27 -1
- package/dist/src/code_assist/setup.test.js.map +1 -1
- package/dist/src/code_assist/types.d.ts +80 -80
- package/dist/src/config/agent-loop-context.d.ts +2 -0
- package/dist/src/config/config.d.ts +81 -16
- package/dist/src/config/config.js +146 -50
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +89 -2
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/defaultModelConfigs.js +9 -0
- package/dist/src/config/defaultModelConfigs.js.map +1 -1
- package/dist/src/config/memory.d.ts +1 -0
- package/dist/src/config/memory.js +6 -0
- package/dist/src/config/memory.js.map +1 -1
- package/dist/src/config/storage.d.ts +1 -0
- package/dist/src/config/storage.js +4 -0
- package/dist/src/config/storage.js.map +1 -1
- package/dist/src/config/storage.test.js +5 -0
- package/dist/src/config/storage.test.js.map +1 -1
- package/dist/src/config/topicState.d.ts +21 -0
- package/dist/src/config/topicState.js +41 -0
- package/dist/src/config/topicState.js.map +1 -0
- package/dist/src/confirmation-bus/types.d.ts +9 -2
- package/dist/src/confirmation-bus/types.js +1 -0
- package/dist/src/confirmation-bus/types.js.map +1 -1
- package/dist/src/context/agentHistoryProvider.d.ts +45 -0
- package/dist/src/context/agentHistoryProvider.js +298 -0
- package/dist/src/context/agentHistoryProvider.js.map +1 -0
- package/dist/src/context/agentHistoryProvider.test.d.ts +6 -0
- package/dist/src/context/agentHistoryProvider.test.js +394 -0
- package/dist/src/context/agentHistoryProvider.test.js.map +1 -0
- package/dist/src/context/chatCompressionService.js.map +1 -0
- package/dist/src/context/chatCompressionService.test.js.map +1 -0
- package/dist/src/{services → context}/contextManager.d.ts +2 -0
- package/dist/src/{services → context}/contextManager.js +18 -9
- package/dist/src/context/contextManager.js.map +1 -0
- package/dist/src/{services → context}/contextManager.test.js +21 -6
- package/dist/src/context/contextManager.test.js.map +1 -0
- package/dist/src/context/toolDistillationService.d.ts +38 -0
- package/dist/src/context/toolDistillationService.js +170 -0
- package/dist/src/context/toolDistillationService.js.map +1 -0
- package/dist/src/context/toolDistillationService.test.d.ts +6 -0
- package/dist/src/context/toolDistillationService.test.js +83 -0
- package/dist/src/context/toolDistillationService.test.js.map +1 -0
- package/dist/src/{services → context}/toolOutputMaskingService.d.ts +2 -2
- package/dist/src/{services → context}/toolOutputMaskingService.js +7 -7
- package/dist/src/context/toolOutputMaskingService.js.map +1 -0
- package/dist/src/context/toolOutputMaskingService.test.d.ts +6 -0
- package/dist/src/{services → context}/toolOutputMaskingService.test.js +4 -5
- package/dist/src/context/toolOutputMaskingService.test.js.map +1 -0
- package/dist/src/context/truncation.d.ts +26 -0
- package/dist/src/context/truncation.js +102 -0
- package/dist/src/context/truncation.js.map +1 -0
- package/dist/src/core/client.d.ts +3 -1
- package/dist/src/core/client.js +23 -13
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +29 -34
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +0 -1
- package/dist/src/core/contentGenerator.js +2 -28
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/contentGenerator.test.js +1 -101
- package/dist/src/core/contentGenerator.test.js.map +1 -1
- package/dist/src/core/geminiChat.js +4 -5
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/geminiChat.test.js +71 -18
- package/dist/src/core/geminiChat.test.js.map +1 -1
- package/dist/src/core/prompts-substitution.test.js +5 -0
- package/dist/src/core/prompts-substitution.test.js.map +1 -1
- package/dist/src/core/prompts.test.js +3 -0
- package/dist/src/core/prompts.test.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/index.d.ts +7 -3
- package/dist/src/index.js +9 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/policy/config.d.ts +1 -1
- package/dist/src/policy/config.js +5 -2
- package/dist/src/policy/config.js.map +1 -1
- package/dist/src/policy/policies/discovered.toml +7 -0
- package/dist/src/policy/policies/non-interactive.toml +7 -0
- package/dist/src/policy/policies/plan.toml +25 -0
- package/dist/src/policy/policies/read-only.toml +6 -0
- package/dist/src/policy/policies/sandbox-default.toml +3 -2
- package/dist/src/policy/policies/write.toml +21 -0
- package/dist/src/policy/policies/yolo.toml +1 -1
- package/dist/src/policy/policy-engine.d.ts +2 -4
- package/dist/src/policy/policy-engine.js +24 -37
- package/dist/src/policy/policy-engine.js.map +1 -1
- package/dist/src/policy/policy-engine.test.js +107 -29
- package/dist/src/policy/policy-engine.test.js.map +1 -1
- package/dist/src/policy/topic-policy.test.d.ts +6 -0
- package/dist/src/policy/topic-policy.test.js +48 -0
- package/dist/src/policy/topic-policy.test.js.map +1 -0
- package/dist/src/policy/types.d.ts +3 -6
- package/dist/src/policy/types.js.map +1 -1
- package/dist/src/prompts/promptProvider.js +20 -4
- package/dist/src/prompts/promptProvider.js.map +1 -1
- package/dist/src/prompts/promptProvider.test.js +84 -1
- package/dist/src/prompts/promptProvider.test.js.map +1 -1
- package/dist/src/prompts/snippets-memory-manager.test.js +1 -1
- package/dist/src/prompts/snippets-memory-manager.test.js.map +1 -1
- package/dist/src/prompts/snippets.d.ts +3 -4
- package/dist/src/prompts/snippets.js +33 -51
- package/dist/src/prompts/snippets.js.map +1 -1
- package/dist/src/prompts/snippets.legacy.d.ts +6 -4
- package/dist/src/prompts/snippets.legacy.js +32 -7
- package/dist/src/prompts/snippets.legacy.js.map +1 -1
- package/dist/src/sandbox/linux/LinuxSandboxManager.d.ts +11 -1
- package/dist/src/sandbox/linux/LinuxSandboxManager.js +261 -27
- package/dist/src/sandbox/linux/LinuxSandboxManager.js.map +1 -1
- package/dist/src/sandbox/linux/LinuxSandboxManager.test.js +430 -125
- package/dist/src/sandbox/linux/LinuxSandboxManager.test.js.map +1 -1
- package/dist/src/sandbox/macos/MacOsSandboxManager.d.ts +7 -22
- package/dist/src/sandbox/macos/MacOsSandboxManager.js +58 -57
- package/dist/src/sandbox/macos/MacOsSandboxManager.js.map +1 -1
- package/dist/src/sandbox/macos/MacOsSandboxManager.test.js +148 -103
- package/dist/src/sandbox/macos/MacOsSandboxManager.test.js.map +1 -1
- package/dist/src/sandbox/macos/baseProfile.d.ts +1 -1
- package/dist/src/sandbox/macos/baseProfile.js +0 -6
- package/dist/src/sandbox/macos/baseProfile.js.map +1 -1
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.d.ts +10 -10
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.js +80 -92
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.js.map +1 -1
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.test.js +135 -99
- package/dist/src/sandbox/macos/seatbeltArgsBuilder.test.js.map +1 -1
- package/dist/src/sandbox/{macos → utils}/commandSafety.d.ts +11 -0
- package/dist/src/sandbox/{macos → utils}/commandSafety.js +47 -14
- package/dist/src/sandbox/utils/commandSafety.js.map +1 -0
- package/dist/src/sandbox/utils/commandUtils.d.ts +9 -0
- package/dist/src/sandbox/utils/commandUtils.js +57 -0
- package/dist/src/sandbox/utils/commandUtils.js.map +1 -0
- package/dist/src/sandbox/utils/fsUtils.d.ts +11 -0
- package/dist/src/sandbox/utils/fsUtils.js +82 -0
- package/dist/src/sandbox/utils/fsUtils.js.map +1 -0
- package/dist/src/sandbox/utils/sandboxDenialUtils.d.ts +12 -0
- package/dist/src/sandbox/utils/sandboxDenialUtils.js +68 -0
- package/dist/src/sandbox/utils/sandboxDenialUtils.js.map +1 -0
- package/dist/src/sandbox/utils/sandboxDenialUtils.test.d.ts +6 -0
- package/dist/src/sandbox/utils/sandboxDenialUtils.test.js +37 -0
- package/dist/src/sandbox/utils/sandboxDenialUtils.test.js.map +1 -0
- package/dist/src/sandbox/utils/sandboxReadWriteUtils.d.ts +5 -0
- package/dist/src/sandbox/utils/sandboxReadWriteUtils.js +60 -0
- package/dist/src/sandbox/utils/sandboxReadWriteUtils.js.map +1 -0
- package/dist/src/sandbox/windows/GeminiSandbox.cs +257 -216
- package/dist/src/sandbox/windows/WindowsSandboxManager.d.ts +12 -2
- package/dist/src/sandbox/windows/WindowsSandboxManager.js +250 -38
- package/dist/src/sandbox/windows/WindowsSandboxManager.js.map +1 -1
- package/dist/src/sandbox/windows/WindowsSandboxManager.test.js +326 -9
- package/dist/src/sandbox/windows/WindowsSandboxManager.test.js.map +1 -1
- package/dist/src/sandbox/windows/commandSafety.d.ts +19 -0
- package/dist/src/sandbox/windows/commandSafety.js +128 -0
- package/dist/src/sandbox/windows/commandSafety.js.map +1 -0
- package/dist/src/sandbox/windows/commandSafety.test.d.ts +6 -0
- package/dist/src/sandbox/windows/commandSafety.test.js +42 -0
- package/dist/src/sandbox/windows/commandSafety.test.js.map +1 -0
- package/dist/src/sandbox/windows/windowsSandboxDenialUtils.d.ts +12 -0
- package/dist/src/sandbox/windows/windowsSandboxDenialUtils.js +68 -0
- package/dist/src/sandbox/windows/windowsSandboxDenialUtils.js.map +1 -0
- package/dist/src/sandbox/windows/windowsSandboxDenialUtils.test.d.ts +6 -0
- package/dist/src/sandbox/windows/windowsSandboxDenialUtils.test.js +68 -0
- package/dist/src/sandbox/windows/windowsSandboxDenialUtils.test.js.map +1 -0
- package/dist/src/scheduler/scheduler.js +12 -2
- package/dist/src/scheduler/scheduler.js.map +1 -1
- package/dist/src/scheduler/scheduler.test.js +52 -0
- package/dist/src/scheduler/scheduler.test.js.map +1 -1
- package/dist/src/scheduler/scheduler_hooks.test.js +1 -0
- package/dist/src/scheduler/scheduler_hooks.test.js.map +1 -1
- package/dist/src/scheduler/state-manager.js +1 -1
- package/dist/src/scheduler/state-manager.js.map +1 -1
- package/dist/src/scheduler/state-manager.test.js +10 -0
- package/dist/src/scheduler/state-manager.test.js.map +1 -1
- package/dist/src/scheduler/tool-executor.js +7 -2
- package/dist/src/scheduler/tool-executor.js.map +1 -1
- package/dist/src/scheduler/tool-executor.test.js +38 -0
- package/dist/src/scheduler/tool-executor.test.js.map +1 -1
- package/dist/src/scheduler/types.d.ts +4 -2
- package/dist/src/services/chatRecordingService.d.ts +1 -13
- package/dist/src/services/chatRecordingService.js +45 -46
- package/dist/src/services/chatRecordingService.js.map +1 -1
- package/dist/src/services/chatRecordingService.test.js +79 -10
- package/dist/src/services/chatRecordingService.test.js.map +1 -1
- package/dist/src/services/executionLifecycleService.d.ts +43 -6
- package/dist/src/services/executionLifecycleService.js +49 -12
- package/dist/src/services/executionLifecycleService.js.map +1 -1
- package/dist/src/services/executionLifecycleService.test.js +157 -3
- package/dist/src/services/executionLifecycleService.test.js.map +1 -1
- package/dist/src/services/fileDiscoveryService.d.ts +17 -2
- package/dist/src/services/fileDiscoveryService.js +84 -20
- package/dist/src/services/fileDiscoveryService.js.map +1 -1
- package/dist/src/services/fileDiscoveryService.test.js +67 -1
- package/dist/src/services/fileDiscoveryService.test.js.map +1 -1
- package/dist/src/services/modelConfigService.d.ts +11 -0
- package/dist/src/services/modelConfigService.js +67 -0
- package/dist/src/services/modelConfigService.js.map +1 -1
- package/dist/src/services/modelConfigService.test.js +30 -0
- package/dist/src/services/modelConfigService.test.js.map +1 -1
- package/dist/src/services/sandboxManager.d.ts +90 -8
- package/dist/src/services/sandboxManager.integration.test.js +438 -0
- package/dist/src/services/sandboxManager.integration.test.js.map +1 -0
- package/dist/src/services/sandboxManager.js +156 -13
- package/dist/src/services/sandboxManager.js.map +1 -1
- package/dist/src/services/sandboxManager.test.js +373 -117
- package/dist/src/services/sandboxManager.test.js.map +1 -1
- package/dist/src/services/sandboxManagerFactory.d.ts +2 -3
- package/dist/src/services/sandboxManagerFactory.js +10 -17
- package/dist/src/services/sandboxManagerFactory.js.map +1 -1
- package/dist/src/services/sandboxedFileSystemService.d.ts +1 -0
- package/dist/src/services/sandboxedFileSystemService.js +32 -3
- package/dist/src/services/sandboxedFileSystemService.js.map +1 -1
- package/dist/src/services/sandboxedFileSystemService.test.js +83 -12
- package/dist/src/services/sandboxedFileSystemService.test.js.map +1 -1
- package/dist/src/services/shellExecutionService.d.ts +2 -0
- package/dist/src/services/shellExecutionService.js +45 -16
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/services/shellExecutionService.test.js +5 -4
- package/dist/src/services/shellExecutionService.test.js.map +1 -1
- package/dist/src/services/test-data/resolved-aliases-retry.golden.json +4 -0
- package/dist/src/services/test-data/resolved-aliases.golden.json +4 -0
- package/dist/src/services/types.d.ts +14 -0
- package/dist/src/services/types.js +7 -0
- package/dist/src/services/types.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +6 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +5 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +2 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +3 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
- package/dist/src/telemetry/loggers.js +1 -1
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +8 -3
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/metrics.d.ts +10 -1
- package/dist/src/telemetry/metrics.js +19 -4
- package/dist/src/telemetry/metrics.js.map +1 -1
- package/dist/src/telemetry/metrics.test.js +44 -0
- package/dist/src/telemetry/metrics.test.js.map +1 -1
- package/dist/src/telemetry/types.d.ts +3 -3
- package/dist/src/telemetry/types.js +9 -4
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/test-utils/mock-message-bus.d.ts +1 -1
- package/dist/src/test-utils/mock-message-bus.js +1 -1
- package/dist/src/test-utils/mock-message-bus.js.map +1 -1
- package/dist/src/tools/definitions/base-declarations.d.ts +6 -0
- package/dist/src/tools/definitions/base-declarations.js +7 -0
- package/dist/src/tools/definitions/base-declarations.js.map +1 -1
- package/dist/src/tools/definitions/coreTools.d.ts +2 -1
- package/dist/src/tools/definitions/coreTools.js +9 -3
- package/dist/src/tools/definitions/coreTools.js.map +1 -1
- package/dist/src/tools/definitions/dynamic-declaration-helpers.d.ts +4 -0
- package/dist/src/tools/definitions/dynamic-declaration-helpers.js +29 -2
- package/dist/src/tools/definitions/dynamic-declaration-helpers.js.map +1 -1
- package/dist/src/tools/definitions/model-family-sets/default-legacy.js +11 -6
- package/dist/src/tools/definitions/model-family-sets/default-legacy.js.map +1 -1
- package/dist/src/tools/definitions/model-family-sets/gemini-3.js +10 -4
- package/dist/src/tools/definitions/model-family-sets/gemini-3.js.map +1 -1
- package/dist/src/tools/definitions/trackerTools.js +3 -3
- package/dist/src/tools/definitions/trackerTools.js.map +1 -1
- package/dist/src/tools/definitions/types.d.ts +1 -0
- package/dist/src/tools/enter-plan-mode.js +15 -0
- package/dist/src/tools/enter-plan-mode.js.map +1 -1
- package/dist/src/tools/enter-plan-mode.test.js +25 -0
- package/dist/src/tools/enter-plan-mode.test.js.map +1 -1
- package/dist/src/tools/grep-utils.d.ts +2 -1
- package/dist/src/tools/grep-utils.js +22 -3
- package/dist/src/tools/grep-utils.js.map +1 -1
- package/dist/src/tools/grep.js +16 -3
- package/dist/src/tools/grep.js.map +1 -1
- package/dist/src/tools/grep.test.js +34 -6
- package/dist/src/tools/grep.test.js.map +1 -1
- package/dist/src/tools/ls.js +6 -4
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/ls.test.js +22 -7
- package/dist/src/tools/ls.test.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.js +6 -3
- package/dist/src/tools/mcp-client-manager.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.test.js +35 -0
- package/dist/src/tools/mcp-client-manager.test.js.map +1 -1
- package/dist/src/tools/memoryTool.d.ts +9 -2
- package/dist/src/tools/memoryTool.js +39 -15
- package/dist/src/tools/memoryTool.js.map +1 -1
- package/dist/src/tools/memoryTool.test.js +61 -2
- package/dist/src/tools/memoryTool.test.js.map +1 -1
- package/dist/src/tools/read-many-files.js +12 -4
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/read-many-files.test.js +17 -17
- package/dist/src/tools/read-many-files.test.js.map +1 -1
- package/dist/src/tools/ripGrep.js +14 -1
- package/dist/src/tools/ripGrep.js.map +1 -1
- package/dist/src/tools/ripGrep.test.js +9 -9
- package/dist/src/tools/ripGrep.test.js.map +1 -1
- package/dist/src/tools/shell.d.ts +10 -0
- package/dist/src/tools/shell.js +97 -124
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/shell.test.js +22 -3
- package/dist/src/tools/shell.test.js.map +1 -1
- package/dist/src/tools/tool-names.d.ts +4 -4
- package/dist/src/tools/tool-names.js +5 -3
- package/dist/src/tools/tool-names.js.map +1 -1
- package/dist/src/tools/tool-registry.js +11 -1
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tool-registry.test.js +43 -1
- package/dist/src/tools/tool-registry.test.js.map +1 -1
- package/dist/src/tools/tools.d.ts +12 -1
- package/dist/src/tools/tools.js +15 -0
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/tools.test.js +42 -1
- package/dist/src/tools/tools.test.js.map +1 -1
- package/dist/src/tools/topicTool.d.ts +29 -0
- package/dist/src/tools/topicTool.js +72 -0
- package/dist/src/tools/topicTool.js.map +1 -0
- package/dist/src/tools/topicTool.test.d.ts +6 -0
- package/dist/src/tools/topicTool.test.js +105 -0
- package/dist/src/tools/topicTool.test.js.map +1 -0
- package/dist/src/tools/web-fetch.js +38 -20
- package/dist/src/tools/web-fetch.js.map +1 -1
- package/dist/src/tools/web-fetch.test.js +28 -0
- package/dist/src/tools/web-fetch.test.js.map +1 -1
- package/dist/src/utils/checkpointUtils.d.ts +4 -4
- package/dist/src/utils/errors.d.ts +3 -0
- package/dist/src/utils/errors.js +28 -6
- package/dist/src/utils/errors.js.map +1 -1
- package/dist/src/utils/errors.test.js +23 -0
- package/dist/src/utils/errors.test.js.map +1 -1
- package/dist/src/utils/getFolderStructure.js +1 -1
- package/dist/src/utils/getFolderStructure.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.d.ts +2 -2
- package/dist/src/utils/gitIgnoreParser.js +28 -50
- package/dist/src/utils/gitIgnoreParser.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.test.js +51 -185
- package/dist/src/utils/gitIgnoreParser.test.js.map +1 -1
- package/dist/src/utils/ignoreFileParser.d.ts +2 -2
- package/dist/src/utils/ignoreFileParser.js +6 -17
- package/dist/src/utils/ignoreFileParser.js.map +1 -1
- package/dist/src/utils/ignoreFileParser.test.js +40 -132
- package/dist/src/utils/ignoreFileParser.test.js.map +1 -1
- package/dist/src/utils/ignorePathUtils.d.ts +11 -0
- package/dist/src/utils/ignorePathUtils.js +39 -0
- package/dist/src/utils/ignorePathUtils.js.map +1 -0
- package/dist/src/utils/ignorePathUtils.test.d.ts +6 -0
- package/dist/src/utils/ignorePathUtils.test.js +70 -0
- package/dist/src/utils/ignorePathUtils.test.js.map +1 -0
- package/dist/src/utils/memoryDiscovery.d.ts +6 -4
- package/dist/src/utils/memoryDiscovery.js +66 -41
- package/dist/src/utils/memoryDiscovery.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.test.js +40 -0
- package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
- package/dist/src/utils/memoryImportProcessor.d.ts +1 -1
- package/dist/src/utils/memoryImportProcessor.js +24 -15
- package/dist/src/utils/memoryImportProcessor.js.map +1 -1
- package/dist/src/utils/sessionOperations.d.ts +19 -0
- package/dist/src/utils/sessionOperations.js +101 -0
- package/dist/src/utils/sessionOperations.js.map +1 -0
- package/dist/src/utils/sessionOperations.test.d.ts +6 -0
- package/dist/src/utils/sessionOperations.test.js +92 -0
- package/dist/src/utils/sessionOperations.test.js.map +1 -0
- package/dist/src/utils/shell-utils.d.ts +15 -0
- package/dist/src/utils/shell-utils.js +43 -2
- package/dist/src/utils/shell-utils.js.map +1 -1
- package/dist/src/utils/textUtils.d.ts +8 -0
- package/dist/src/utils/textUtils.js +16 -0
- package/dist/src/utils/textUtils.js.map +1 -1
- package/dist/src/utils/tokenCalculation.d.ts +2 -0
- package/dist/src/utils/tokenCalculation.js +2 -2
- package/dist/src/utils/tokenCalculation.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/docs/get-started/examples.md +0 -141
- package/dist/google-gemini-cli-core-0.36.0-preview.7.tgz +0 -0
- package/dist/src/sandbox/macos/MacOsSandboxManager.integration.test.js +0 -164
- package/dist/src/sandbox/macos/MacOsSandboxManager.integration.test.js.map +0 -1
- package/dist/src/sandbox/macos/commandSafety.js.map +0 -1
- package/dist/src/services/chatCompressionService.js.map +0 -1
- package/dist/src/services/chatCompressionService.test.js.map +0 -1
- package/dist/src/services/contextManager.js.map +0 -1
- package/dist/src/services/contextManager.test.js.map +0 -1
- package/dist/src/services/toolOutputMaskingService.js.map +0 -1
- package/dist/src/services/toolOutputMaskingService.test.js.map +0 -1
- /package/dist/src/{services/toolOutputMaskingService.test.d.ts → agents/browser/snapshotSuperseder.test.d.ts} +0 -0
- /package/dist/src/{services → context}/chatCompressionService.d.ts +0 -0
- /package/dist/src/{services → context}/chatCompressionService.js +0 -0
- /package/dist/src/{services → context}/chatCompressionService.test.d.ts +0 -0
- /package/dist/src/{services → context}/chatCompressionService.test.js +0 -0
- /package/dist/src/{services → context}/contextManager.test.d.ts +0 -0
- /package/dist/src/{sandbox/macos/MacOsSandboxManager.integration.test.d.ts → services/sandboxManager.integration.test.d.ts} +0 -0
|
@@ -133,12 +133,6 @@ export const BASE_SEATBELT_PROFILE = `(version 1)
|
|
|
133
133
|
(literal "/dev/zero")
|
|
134
134
|
(subpath "/tmp")
|
|
135
135
|
(subpath "/private/tmp")
|
|
136
|
-
(subpath (param "TMPDIR"))
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
; Workspace access using parameterized paths
|
|
140
|
-
(allow file-read*
|
|
141
|
-
(subpath (param "WORKSPACE"))
|
|
142
136
|
)
|
|
143
137
|
|
|
144
138
|
`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baseProfile.js","sourceRoot":"","sources":["../../../../src/sandbox/macos/baseProfile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG
|
|
1
|
+
{"version":3,"file":"baseProfile.js","sourceRoot":"","sources":["../../../../src/sandbox/macos/baseProfile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6HpC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BvC,CAAC"}
|
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { type SandboxPermissions } from '../../services/sandboxManager.js';
|
|
7
7
|
/**
|
|
8
|
-
* Options for building macOS Seatbelt
|
|
8
|
+
* Options for building macOS Seatbelt profile.
|
|
9
9
|
*/
|
|
10
10
|
export interface SeatbeltArgsOptions {
|
|
11
11
|
/** The primary workspace path to allow access to. */
|
|
12
12
|
workspace: string;
|
|
13
13
|
/** Additional paths to allow access to. */
|
|
14
|
-
allowedPaths
|
|
14
|
+
allowedPaths: string[];
|
|
15
15
|
/** Absolute paths to explicitly deny read/write access to (overrides allowlists). */
|
|
16
|
-
forbiddenPaths
|
|
16
|
+
forbiddenPaths: string[];
|
|
17
17
|
/** Whether to allow network access. */
|
|
18
18
|
networkAccess?: boolean;
|
|
19
19
|
/** Granular additional permissions. */
|
|
@@ -22,11 +22,11 @@ export interface SeatbeltArgsOptions {
|
|
|
22
22
|
workspaceWrite?: boolean;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
26
|
-
* It relies on parameters passed to sandbox-exec via the -D flag to avoid
|
|
27
|
-
* string interpolation vulnerabilities, and normalizes paths against symlink escapes.
|
|
28
|
-
*
|
|
29
|
-
* Returns arguments up to the end of sandbox-exec configuration (e.g. ['-p', '<profile>', '-D', ...])
|
|
30
|
-
* Does not include the final '--' separator or the command to run.
|
|
25
|
+
* Escapes a string for use within a Scheme string literal "..."
|
|
31
26
|
*/
|
|
32
|
-
export declare function
|
|
27
|
+
export declare function escapeSchemeString(str: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Builds a complete macOS Seatbelt profile string using a strict allowlist.
|
|
30
|
+
* It embeds paths directly into the profile, properly escaped for Scheme.
|
|
31
|
+
*/
|
|
32
|
+
export declare function buildSeatbeltProfile(options: SeatbeltArgsOptions): string;
|
|
@@ -7,48 +7,29 @@ import fs from 'node:fs';
|
|
|
7
7
|
import os from 'node:os';
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import { BASE_SEATBELT_PROFILE, NETWORK_SEATBELT_PROFILE, } from './baseProfile.js';
|
|
10
|
-
import {
|
|
10
|
+
import { GOVERNANCE_FILES, SECRET_FILES, } from '../../services/sandboxManager.js';
|
|
11
|
+
import { tryRealpath, resolveGitWorktreePaths } from '../utils/fsUtils.js';
|
|
11
12
|
/**
|
|
12
|
-
*
|
|
13
|
-
* If a file does not exist (ENOENT), it recursively resolves the parent directory.
|
|
14
|
-
* Other errors (e.g. EACCES) are re-thrown.
|
|
13
|
+
* Escapes a string for use within a Scheme string literal "..."
|
|
15
14
|
*/
|
|
16
|
-
function
|
|
17
|
-
|
|
18
|
-
return fs.realpathSync(p);
|
|
19
|
-
}
|
|
20
|
-
catch (e) {
|
|
21
|
-
if (e instanceof Error && 'code' in e && e.code === 'ENOENT') {
|
|
22
|
-
const parentDir = path.dirname(p);
|
|
23
|
-
if (parentDir === p) {
|
|
24
|
-
return p;
|
|
25
|
-
}
|
|
26
|
-
return path.join(tryRealpath(parentDir), path.basename(p));
|
|
27
|
-
}
|
|
28
|
-
throw e;
|
|
29
|
-
}
|
|
15
|
+
export function escapeSchemeString(str) {
|
|
16
|
+
return str.replace(/[\\"]/g, '\\$&');
|
|
30
17
|
}
|
|
31
18
|
/**
|
|
32
|
-
* Builds
|
|
33
|
-
* It
|
|
34
|
-
* string interpolation vulnerabilities, and normalizes paths against symlink escapes.
|
|
35
|
-
*
|
|
36
|
-
* Returns arguments up to the end of sandbox-exec configuration (e.g. ['-p', '<profile>', '-D', ...])
|
|
37
|
-
* Does not include the final '--' separator or the command to run.
|
|
19
|
+
* Builds a complete macOS Seatbelt profile string using a strict allowlist.
|
|
20
|
+
* It embeds paths directly into the profile, properly escaped for Scheme.
|
|
38
21
|
*/
|
|
39
|
-
export function
|
|
22
|
+
export function buildSeatbeltProfile(options) {
|
|
40
23
|
let profile = BASE_SEATBELT_PROFILE + '\n';
|
|
41
|
-
const args = [];
|
|
42
24
|
const workspacePath = tryRealpath(options.workspace);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
profile += `(allow file-read* (subpath (param "WORKSPACE_RAW")))\n`;
|
|
46
|
-
if (options.workspaceWrite) {
|
|
47
|
-
profile += `(allow file-write* (subpath (param "WORKSPACE_RAW")))\n`;
|
|
48
|
-
}
|
|
25
|
+
profile += `(allow file-read* (subpath "${escapeSchemeString(options.workspace)}"))\n`;
|
|
26
|
+
profile += `(allow file-read* (subpath "${escapeSchemeString(workspacePath)}"))\n`;
|
|
49
27
|
if (options.workspaceWrite) {
|
|
50
|
-
profile += `(allow file-write* (subpath (
|
|
28
|
+
profile += `(allow file-write* (subpath "${escapeSchemeString(options.workspace)}"))\n`;
|
|
29
|
+
profile += `(allow file-write* (subpath "${escapeSchemeString(workspacePath)}"))\n`;
|
|
51
30
|
}
|
|
31
|
+
const tmpPath = tryRealpath(os.tmpdir());
|
|
32
|
+
profile += `(allow file-read* file-write* (subpath "${escapeSchemeString(tmpPath)}"))\n`;
|
|
52
33
|
// Add explicit deny rules for governance files in the workspace.
|
|
53
34
|
// These are added after the workspace allow rule to ensure they take precedence
|
|
54
35
|
// (Seatbelt evaluates rules in order, later rules win for same path).
|
|
@@ -67,51 +48,48 @@ export function buildSeatbeltArgs(options) {
|
|
|
67
48
|
// Ignore errors, use default guess
|
|
68
49
|
}
|
|
69
50
|
const ruleType = isDirectory ? 'subpath' : 'literal';
|
|
70
|
-
|
|
71
|
-
profile += `(deny file-write* (${ruleType} (param "GOVERNANCE_FILE_${i}")))\n`;
|
|
51
|
+
profile += `(deny file-write* (${ruleType} "${escapeSchemeString(governanceFile)}"))\n`;
|
|
72
52
|
if (realGovernanceFile !== governanceFile) {
|
|
73
|
-
|
|
74
|
-
profile += `(deny file-write* (${ruleType} (param "REAL_GOVERNANCE_FILE_${i}")))\n`;
|
|
53
|
+
profile += `(deny file-write* (${ruleType} "${escapeSchemeString(realGovernanceFile)}"))\n`;
|
|
75
54
|
}
|
|
76
55
|
}
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
//
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
args.push('-D', `MAIN_GIT_DIR=${mainGitDir}`);
|
|
98
|
-
profile += `(allow file-read* file-write* (subpath (param "MAIN_GIT_DIR")))\n`;
|
|
99
|
-
}
|
|
56
|
+
// Add explicit deny rules for secret files (.env, .env.*) in the workspace and allowed paths.
|
|
57
|
+
// We use regex rules to avoid expensive file discovery scans.
|
|
58
|
+
// Anchoring to workspace/allowed paths to avoid over-blocking.
|
|
59
|
+
const searchPaths = [options.workspace, ...options.allowedPaths];
|
|
60
|
+
for (const basePath of searchPaths) {
|
|
61
|
+
const resolvedBase = tryRealpath(basePath);
|
|
62
|
+
for (const secret of SECRET_FILES) {
|
|
63
|
+
// Map pattern to Seatbelt regex
|
|
64
|
+
let regexPattern;
|
|
65
|
+
const escapedBase = escapeRegex(resolvedBase);
|
|
66
|
+
if (secret.pattern.endsWith('*')) {
|
|
67
|
+
// .env.* -> .env\..+ (match .env followed by dot and something)
|
|
68
|
+
// We anchor the secret file name to either a directory separator or the start of the relative path.
|
|
69
|
+
const basePattern = secret.pattern.slice(0, -1).replace(/\./g, '\\\\.');
|
|
70
|
+
regexPattern = `^${escapedBase}/(.*/)?${basePattern}[^/]+$`;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// .env -> \.env$
|
|
74
|
+
const basePattern = secret.pattern.replace(/\./g, '\\\\.');
|
|
75
|
+
regexPattern = `^${escapedBase}/(.*/)?${basePattern}$`;
|
|
100
76
|
}
|
|
77
|
+
profile += `(deny file-read* file-write* (regex #"${regexPattern}"))\n`;
|
|
101
78
|
}
|
|
102
79
|
}
|
|
103
|
-
|
|
104
|
-
|
|
80
|
+
// Auto-detect and support git worktrees by granting read and write access to the underlying git directory
|
|
81
|
+
const { worktreeGitDir, mainGitDir } = resolveGitWorktreePaths(workspacePath);
|
|
82
|
+
if (worktreeGitDir) {
|
|
83
|
+
profile += `(allow file-read* file-write* (subpath "${escapeSchemeString(worktreeGitDir)}"))\n`;
|
|
84
|
+
}
|
|
85
|
+
if (mainGitDir) {
|
|
86
|
+
profile += `(allow file-read* file-write* (subpath "${escapeSchemeString(mainGitDir)}"))\n`;
|
|
105
87
|
}
|
|
106
|
-
const tmpPath = tryRealpath(os.tmpdir());
|
|
107
|
-
args.push('-D', `TMPDIR=${tmpPath}`);
|
|
108
88
|
const nodeRootPath = tryRealpath(path.dirname(path.dirname(process.execPath)));
|
|
109
|
-
|
|
110
|
-
profile += `(allow file-read* (subpath (param "NODE_ROOT")))\n`;
|
|
89
|
+
profile += `(allow file-read* (subpath "${escapeSchemeString(nodeRootPath)}"))\n`;
|
|
111
90
|
// Add PATH directories as read-only to support nvm, homebrew, etc.
|
|
112
91
|
if (process.env['PATH']) {
|
|
113
92
|
const paths = process.env['PATH'].split(':');
|
|
114
|
-
let pathIndex = 0;
|
|
115
93
|
const addedPaths = new Set();
|
|
116
94
|
for (const p of paths) {
|
|
117
95
|
if (!p.trim())
|
|
@@ -126,9 +104,7 @@ export function buildSeatbeltArgs(options) {
|
|
|
126
104
|
}
|
|
127
105
|
if (!addedPaths.has(resolved)) {
|
|
128
106
|
addedPaths.add(resolved);
|
|
129
|
-
|
|
130
|
-
profile += `(allow file-read* (subpath (param "SYS_PATH_${pathIndex}")))\n`;
|
|
131
|
-
pathIndex++;
|
|
107
|
+
profile += `(allow file-read* (subpath "${escapeSchemeString(resolved)}"))\n`;
|
|
132
108
|
}
|
|
133
109
|
}
|
|
134
110
|
catch (_e) {
|
|
@@ -137,20 +113,17 @@ export function buildSeatbeltArgs(options) {
|
|
|
137
113
|
}
|
|
138
114
|
}
|
|
139
115
|
// Handle allowedPaths
|
|
140
|
-
const allowedPaths =
|
|
116
|
+
const allowedPaths = options.allowedPaths;
|
|
141
117
|
for (let i = 0; i < allowedPaths.length; i++) {
|
|
142
118
|
const allowedPath = tryRealpath(allowedPaths[i]);
|
|
143
|
-
|
|
144
|
-
profile += `(allow file-read* file-write* (subpath (param "ALLOWED_PATH_${i}")))\n`;
|
|
119
|
+
profile += `(allow file-read* file-write* (subpath "${escapeSchemeString(allowedPath)}"))\n`;
|
|
145
120
|
}
|
|
146
121
|
// Handle granular additional permissions
|
|
147
122
|
if (options.additionalPermissions?.fileSystem) {
|
|
148
123
|
const { read, write } = options.additionalPermissions.fileSystem;
|
|
149
124
|
if (read) {
|
|
150
|
-
read.
|
|
151
|
-
const resolved = tryRealpath(
|
|
152
|
-
const paramName = `ADDITIONAL_READ_${i}`;
|
|
153
|
-
args.push('-D', `${paramName}=${resolved}`);
|
|
125
|
+
for (let i = 0; i < read.length; i++) {
|
|
126
|
+
const resolved = tryRealpath(read[i]);
|
|
154
127
|
let isFile = false;
|
|
155
128
|
try {
|
|
156
129
|
isFile = fs.statSync(resolved).isFile();
|
|
@@ -159,18 +132,16 @@ export function buildSeatbeltArgs(options) {
|
|
|
159
132
|
// Ignore error
|
|
160
133
|
}
|
|
161
134
|
if (isFile) {
|
|
162
|
-
profile += `(allow file-read* (literal
|
|
135
|
+
profile += `(allow file-read* (literal "${escapeSchemeString(resolved)}"))\n`;
|
|
163
136
|
}
|
|
164
137
|
else {
|
|
165
|
-
profile += `(allow file-read* (subpath
|
|
138
|
+
profile += `(allow file-read* (subpath "${escapeSchemeString(resolved)}"))\n`;
|
|
166
139
|
}
|
|
167
|
-
}
|
|
140
|
+
}
|
|
168
141
|
}
|
|
169
142
|
if (write) {
|
|
170
|
-
write.
|
|
171
|
-
const resolved = tryRealpath(
|
|
172
|
-
const paramName = `ADDITIONAL_WRITE_${i}`;
|
|
173
|
-
args.push('-D', `${paramName}=${resolved}`);
|
|
143
|
+
for (let i = 0; i < write.length; i++) {
|
|
144
|
+
const resolved = tryRealpath(write[i]);
|
|
174
145
|
let isFile = false;
|
|
175
146
|
try {
|
|
176
147
|
isFile = fs.statSync(resolved).isFile();
|
|
@@ -179,25 +150,42 @@ export function buildSeatbeltArgs(options) {
|
|
|
179
150
|
// Ignore error
|
|
180
151
|
}
|
|
181
152
|
if (isFile) {
|
|
182
|
-
profile += `(allow file-read* file-write* (literal
|
|
153
|
+
profile += `(allow file-read* file-write* (literal "${escapeSchemeString(resolved)}"))\n`;
|
|
183
154
|
}
|
|
184
155
|
else {
|
|
185
|
-
profile += `(allow file-read* file-write* (subpath
|
|
156
|
+
profile += `(allow file-read* file-write* (subpath "${escapeSchemeString(resolved)}"))\n`;
|
|
186
157
|
}
|
|
187
|
-
}
|
|
158
|
+
}
|
|
188
159
|
}
|
|
189
160
|
}
|
|
190
161
|
// Handle forbiddenPaths
|
|
191
|
-
const forbiddenPaths =
|
|
162
|
+
const forbiddenPaths = options.forbiddenPaths;
|
|
192
163
|
for (let i = 0; i < forbiddenPaths.length; i++) {
|
|
193
164
|
const forbiddenPath = tryRealpath(forbiddenPaths[i]);
|
|
194
|
-
|
|
195
|
-
profile += `(deny file-read* file-write* (subpath (param "FORBIDDEN_PATH_${i}")))\n`;
|
|
165
|
+
profile += `(deny file-read* file-write* (subpath "${escapeSchemeString(forbiddenPath)}"))\n`;
|
|
196
166
|
}
|
|
197
167
|
if (options.networkAccess || options.additionalPermissions?.network) {
|
|
198
168
|
profile += NETWORK_SEATBELT_PROFILE;
|
|
199
169
|
}
|
|
200
|
-
|
|
201
|
-
|
|
170
|
+
return profile;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Escapes a string for use within a Seatbelt regex literal #"..."
|
|
174
|
+
*/
|
|
175
|
+
function escapeRegex(str) {
|
|
176
|
+
return str.replace(/[.*+?^${}()|[\]\\"]/g, (c) => {
|
|
177
|
+
if (c === '"') {
|
|
178
|
+
// Escape double quotes for the Scheme string literal
|
|
179
|
+
return '\\"';
|
|
180
|
+
}
|
|
181
|
+
if (c === '\\') {
|
|
182
|
+
// A literal backslash needs to be \\ in the regex.
|
|
183
|
+
// To get \\ in the regex engine, we need \\\\ in the Scheme string literal.
|
|
184
|
+
return '\\\\\\\\';
|
|
185
|
+
}
|
|
186
|
+
// For other regex special characters (like .), we need \c in the regex.
|
|
187
|
+
// To get \c in the regex engine, we need \\c in the Scheme string literal.
|
|
188
|
+
return '\\\\' + c;
|
|
189
|
+
});
|
|
202
190
|
}
|
|
203
191
|
//# sourceMappingURL=seatbeltArgsBuilder.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seatbeltArgsBuilder.js","sourceRoot":"","sources":["../../../../src/sandbox/macos/seatbeltArgsBuilder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,
|
|
1
|
+
{"version":3,"file":"seatbeltArgsBuilder.js","sourceRoot":"","sources":["../../../../src/sandbox/macos/seatbeltArgsBuilder.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,116 +3,152 @@
|
|
|
3
3
|
* Copyright 2026 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
7
|
-
import {
|
|
6
|
+
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
7
|
+
import { buildSeatbeltProfile, escapeSchemeString, } from './seatbeltArgsBuilder.js';
|
|
8
|
+
import * as fsUtils from '../utils/fsUtils.js';
|
|
8
9
|
import fs from 'node:fs';
|
|
9
|
-
|
|
10
|
+
vi.mock('../utils/fsUtils.js', async () => {
|
|
11
|
+
const actual = await vi.importActual('../utils/fsUtils.js');
|
|
12
|
+
return {
|
|
13
|
+
...actual,
|
|
14
|
+
tryRealpath: vi.fn((p) => p),
|
|
15
|
+
resolveGitWorktreePaths: vi.fn(() => ({})),
|
|
16
|
+
};
|
|
17
|
+
});
|
|
10
18
|
describe('seatbeltArgsBuilder', () => {
|
|
11
|
-
|
|
12
|
-
// Mock realpathSync to just return the path for testing
|
|
13
|
-
vi.spyOn(fs, 'realpathSync').mockImplementation((p) => p);
|
|
14
|
-
const args = buildSeatbeltArgs({ workspace: '/Users/test/workspace' });
|
|
15
|
-
expect(args[0]).toBe('-p');
|
|
16
|
-
const profile = args[1];
|
|
17
|
-
expect(profile).toContain('(version 1)');
|
|
18
|
-
expect(profile).toContain('(deny default)');
|
|
19
|
-
expect(profile).toContain('(allow process-exec)');
|
|
20
|
-
expect(profile).toContain('(subpath (param "WORKSPACE"))');
|
|
21
|
-
expect(profile).not.toContain('(allow network*)');
|
|
22
|
-
expect(args).toContain('-D');
|
|
23
|
-
expect(args).toContain('WORKSPACE=/Users/test/workspace');
|
|
24
|
-
expect(args).toContain(`TMPDIR=${os.tmpdir()}`);
|
|
19
|
+
afterEach(() => {
|
|
25
20
|
vi.restoreAllMocks();
|
|
26
21
|
});
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
});
|
|
32
|
-
it('should parameterize allowed paths and normalize them', () => {
|
|
33
|
-
vi.spyOn(fs, 'realpathSync').mockImplementation((p) => {
|
|
34
|
-
if (p === '/test/symlink')
|
|
35
|
-
return '/test/real_path';
|
|
36
|
-
return p;
|
|
22
|
+
describe('escapeSchemeString', () => {
|
|
23
|
+
it('escapes quotes and backslashes', () => {
|
|
24
|
+
expect(escapeSchemeString('path/to/"file"')).toBe('path/to/\\"file\\"');
|
|
25
|
+
expect(escapeSchemeString('path\\to\\file')).toBe('path\\\\to\\\\file');
|
|
37
26
|
});
|
|
38
|
-
const args = buildSeatbeltArgs({
|
|
39
|
-
workspace: '/test',
|
|
40
|
-
allowedPaths: ['/custom/path1', '/test/symlink'],
|
|
41
|
-
});
|
|
42
|
-
const profile = args[1];
|
|
43
|
-
expect(profile).toContain('(subpath (param "ALLOWED_PATH_0"))');
|
|
44
|
-
expect(profile).toContain('(subpath (param "ALLOWED_PATH_1"))');
|
|
45
|
-
expect(args).toContain('-D');
|
|
46
|
-
expect(args).toContain('ALLOWED_PATH_0=/custom/path1');
|
|
47
|
-
expect(args).toContain('ALLOWED_PATH_1=/test/real_path');
|
|
48
|
-
vi.restoreAllMocks();
|
|
49
27
|
});
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
28
|
+
describe('buildSeatbeltProfile', () => {
|
|
29
|
+
it('should build a strict allowlist profile allowing the workspace', () => {
|
|
30
|
+
vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => p);
|
|
31
|
+
const profile = buildSeatbeltProfile({
|
|
32
|
+
workspace: '/Users/test/workspace',
|
|
33
|
+
allowedPaths: [],
|
|
34
|
+
forbiddenPaths: [],
|
|
35
|
+
});
|
|
36
|
+
expect(profile).toContain('(version 1)');
|
|
37
|
+
expect(profile).toContain('(deny default)');
|
|
38
|
+
expect(profile).toContain('(allow process-exec)');
|
|
39
|
+
expect(profile).toContain(`(subpath "/Users/test/workspace")`);
|
|
40
|
+
expect(profile).not.toContain('(allow network*)');
|
|
61
41
|
});
|
|
62
|
-
|
|
63
|
-
|
|
42
|
+
it('should allow network when networkAccess is true', () => {
|
|
43
|
+
vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => p);
|
|
44
|
+
const profile = buildSeatbeltProfile({
|
|
45
|
+
workspace: '/test',
|
|
46
|
+
allowedPaths: [],
|
|
47
|
+
forbiddenPaths: [],
|
|
48
|
+
networkAccess: true,
|
|
49
|
+
});
|
|
50
|
+
expect(profile).toContain('(allow network-outbound)');
|
|
64
51
|
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
52
|
+
describe('governance files', () => {
|
|
53
|
+
it('should inject explicit deny rules for governance files', () => {
|
|
54
|
+
vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => p.toString());
|
|
55
|
+
vi.spyOn(fs, 'existsSync').mockReturnValue(true);
|
|
56
|
+
vi.spyOn(fs, 'lstatSync').mockImplementation((p) => ({
|
|
57
|
+
isDirectory: () => p.toString().endsWith('.git'),
|
|
58
|
+
isFile: () => !p.toString().endsWith('.git'),
|
|
59
|
+
}));
|
|
60
|
+
const profile = buildSeatbeltProfile({
|
|
61
|
+
workspace: '/test/workspace',
|
|
62
|
+
allowedPaths: [],
|
|
63
|
+
forbiddenPaths: [],
|
|
64
|
+
});
|
|
65
|
+
expect(profile).toContain(`(deny file-write* (literal "/test/workspace/.gitignore"))`);
|
|
66
|
+
expect(profile).toContain(`(deny file-write* (subpath "/test/workspace/.git"))`);
|
|
67
|
+
});
|
|
68
|
+
it('should protect both the symlink and the real path if they differ', () => {
|
|
69
|
+
vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => {
|
|
70
|
+
if (p === '/test/workspace/.gitignore')
|
|
71
|
+
return '/test/real/.gitignore';
|
|
72
|
+
return p.toString();
|
|
73
|
+
});
|
|
74
|
+
vi.spyOn(fs, 'existsSync').mockReturnValue(true);
|
|
75
|
+
vi.spyOn(fs, 'lstatSync').mockImplementation(() => ({
|
|
76
|
+
isDirectory: () => false,
|
|
77
|
+
isFile: () => true,
|
|
78
|
+
}));
|
|
79
|
+
const profile = buildSeatbeltProfile({
|
|
80
|
+
workspace: '/test/workspace',
|
|
81
|
+
allowedPaths: [],
|
|
82
|
+
forbiddenPaths: [],
|
|
83
|
+
});
|
|
84
|
+
expect(profile).toContain(`(deny file-write* (literal "/test/workspace/.gitignore"))`);
|
|
85
|
+
expect(profile).toContain(`(deny file-write* (literal "/test/real/.gitignore"))`);
|
|
86
|
+
});
|
|
73
87
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// .gitignore should be a literal deny
|
|
90
|
-
expect(args).toContain('-D');
|
|
91
|
-
expect(args).toContain('GOVERNANCE_FILE_0=/Users/test/workspace/.gitignore');
|
|
92
|
-
expect(profile).toContain('(deny file-write* (literal (param "GOVERNANCE_FILE_0")))');
|
|
93
|
-
// .git should be a subpath deny
|
|
94
|
-
expect(args).toContain('GOVERNANCE_FILE_2=/Users/test/workspace/.git');
|
|
95
|
-
expect(profile).toContain('(deny file-write* (subpath (param "GOVERNANCE_FILE_2")))');
|
|
96
|
-
vi.restoreAllMocks();
|
|
88
|
+
describe('allowedPaths', () => {
|
|
89
|
+
it('should embed allowed paths and normalize them', () => {
|
|
90
|
+
vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => {
|
|
91
|
+
if (p === '/test/symlink')
|
|
92
|
+
return '/test/real_path';
|
|
93
|
+
return p;
|
|
94
|
+
});
|
|
95
|
+
const profile = buildSeatbeltProfile({
|
|
96
|
+
workspace: '/test',
|
|
97
|
+
allowedPaths: ['/custom/path1', '/test/symlink'],
|
|
98
|
+
forbiddenPaths: [],
|
|
99
|
+
});
|
|
100
|
+
expect(profile).toContain(`(subpath "/custom/path1")`);
|
|
101
|
+
expect(profile).toContain(`(subpath "/test/real_path")`);
|
|
102
|
+
});
|
|
97
103
|
});
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
describe('forbiddenPaths', () => {
|
|
105
|
+
it('should explicitly deny forbidden paths', () => {
|
|
106
|
+
vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => p);
|
|
107
|
+
const profile = buildSeatbeltProfile({
|
|
108
|
+
workspace: '/test',
|
|
109
|
+
allowedPaths: [],
|
|
110
|
+
forbiddenPaths: ['/secret/path'],
|
|
111
|
+
});
|
|
112
|
+
expect(profile).toContain(`(deny file-read* file-write* (subpath "/secret/path"))`);
|
|
113
|
+
});
|
|
114
|
+
it('resolves forbidden symlink paths to their real paths', () => {
|
|
115
|
+
vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => {
|
|
116
|
+
if (p === '/test/symlink' || p === '/test/missing-dir') {
|
|
117
|
+
return '/test/real_path';
|
|
118
|
+
}
|
|
119
|
+
return p;
|
|
120
|
+
});
|
|
121
|
+
const profile = buildSeatbeltProfile({
|
|
122
|
+
workspace: '/test',
|
|
123
|
+
allowedPaths: [],
|
|
124
|
+
forbiddenPaths: ['/test/symlink'],
|
|
125
|
+
});
|
|
126
|
+
expect(profile).toContain(`(deny file-read* file-write* (subpath "/test/real_path"))`);
|
|
127
|
+
});
|
|
128
|
+
it('explicitly denies non-existent forbidden paths to prevent creation', () => {
|
|
129
|
+
vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => p);
|
|
130
|
+
const profile = buildSeatbeltProfile({
|
|
131
|
+
workspace: '/test',
|
|
132
|
+
allowedPaths: [],
|
|
133
|
+
forbiddenPaths: ['/test/missing-dir/missing-file.txt'],
|
|
134
|
+
});
|
|
135
|
+
expect(profile).toContain(`(deny file-read* file-write* (subpath "/test/missing-dir/missing-file.txt"))`);
|
|
136
|
+
});
|
|
137
|
+
it('should override allowed paths if a path is also in forbidden paths', () => {
|
|
138
|
+
vi.mocked(fsUtils.tryRealpath).mockImplementation((p) => p);
|
|
139
|
+
const profile = buildSeatbeltProfile({
|
|
140
|
+
workspace: '/test',
|
|
141
|
+
allowedPaths: ['/custom/path1'],
|
|
142
|
+
forbiddenPaths: ['/custom/path1'],
|
|
143
|
+
});
|
|
144
|
+
const allowString = `(allow file-read* file-write* (subpath "/custom/path1"))`;
|
|
145
|
+
const denyString = `(deny file-read* file-write* (subpath "/custom/path1"))`;
|
|
146
|
+
expect(profile).toContain(allowString);
|
|
147
|
+
expect(profile).toContain(denyString);
|
|
148
|
+
const allowIndex = profile.indexOf(allowString);
|
|
149
|
+
const denyIndex = profile.indexOf(denyString);
|
|
150
|
+
expect(denyIndex).toBeGreaterThan(allowIndex);
|
|
103
151
|
});
|
|
104
|
-
vi.spyOn(fs, 'existsSync').mockReturnValue(true);
|
|
105
|
-
vi.spyOn(fs, 'lstatSync').mockImplementation(() => ({
|
|
106
|
-
isDirectory: () => false,
|
|
107
|
-
isFile: () => true,
|
|
108
|
-
}));
|
|
109
|
-
const args = buildSeatbeltArgs({ workspace: '/test/workspace' });
|
|
110
|
-
const profile = args[1];
|
|
111
|
-
expect(args).toContain('GOVERNANCE_FILE_0=/test/workspace/.gitignore');
|
|
112
|
-
expect(args).toContain('REAL_GOVERNANCE_FILE_0=/test/real/.gitignore');
|
|
113
|
-
expect(profile).toContain('(deny file-write* (literal (param "GOVERNANCE_FILE_0")))');
|
|
114
|
-
expect(profile).toContain('(deny file-write* (literal (param "REAL_GOVERNANCE_FILE_0")))');
|
|
115
|
-
vi.restoreAllMocks();
|
|
116
152
|
});
|
|
117
153
|
});
|
|
118
154
|
});
|