Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/cli/print.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4592,7 +4592,7 @@ function handleSetPermissionMode(
subtype: 'error',
request_id: requestId,
error:
'Cannot set permission mode to bypassPermissions because the session was not launched with --dangerously-skip-permissions',
'Cannot set permission mode to bypassPermissions. Enable it with --allow-dangerously-skip-permissions or set permissions.allowBypassPermissionsMode in settings.json',
},
})
return toolPermissionContext
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useReplBridge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ export function useReplBridge(messages: Message[], setMessages: (action: React.S
if (!store.getState().toolPermissionContext.isBypassPermissionsModeAvailable) {
return {
ok: false,
error: 'Cannot set permission mode to bypassPermissions because the session was not launched with --dangerously-skip-permissions'
error: 'Cannot set permission mode to bypassPermissions. Enable it with --allow-dangerously-skip-permissions or set permissions.allowBypassPermissionsMode in settings.json'
};
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/utils/permissions/permissionSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
getSettings_DEPRECATED,
getSettingsFilePathForSource,
getUseAutoModeDuringPlan,
hasAllowBypassPermissionsMode,
hasAutoModeOptIn,
} from '../settings/settings.js'
import {
Expand Down Expand Up @@ -936,9 +937,11 @@ export async function initializeToolPermissionContext({
const settings = getSettings_DEPRECATED() || {}
const settingsDisableBypassPermissionsMode =
settings.permissions?.disableBypassPermissionsMode === 'disable'
const settingsAllowBypassPermissionsMode = hasAllowBypassPermissionsMode()
const isBypassPermissionsModeAvailable =
(permissionMode === 'bypassPermissions' ||
allowDangerouslySkipPermissions) &&
allowDangerouslySkipPermissions ||
settingsAllowBypassPermissionsMode) &&
!growthBookDisableBypassPermissionsMode &&
!settingsDisableBypassPermissionsMode
Comment thread
Flo5k5 marked this conversation as resolved.
Comment thread
Flo5k5 marked this conversation as resolved.

Expand Down
27 changes: 27 additions & 0 deletions src/utils/settings/allowBypassPermissionsMode.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { describe, test, expect } from 'bun:test'

describe('SettingsSchema allowBypassPermissionsMode', () => {
test('accepts allowBypassPermissionsMode: true', async () => {
const { SettingsSchema } = await import('./types.js')
const result = SettingsSchema().safeParse({
permissions: { allowBypassPermissionsMode: true },
})
expect(result.success).toBe(true)
})

test('accepts allowBypassPermissionsMode: false', async () => {
const { SettingsSchema } = await import('./types.js')
const result = SettingsSchema().safeParse({
permissions: { allowBypassPermissionsMode: false },
})
expect(result.success).toBe(true)
})

test('rejects non-boolean allowBypassPermissionsMode', async () => {
const { SettingsSchema } = await import('./types.js')
const result = SettingsSchema().safeParse({
permissions: { allowBypassPermissionsMode: 'yes' },
})
expect(result.success).toBe(false)
})
})
19 changes: 19 additions & 0 deletions src/utils/settings/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ export function getManagedSettingsKeysForLogging(
'ask',
'defaultMode',
'disableBypassPermissionsMode',
'allowBypassPermissionsMode',
...(feature('TRANSCRIPT_CLASSIFIER') ? ['disableAutoMode'] : []),
'additionalDirectories',
]),
Expand Down Expand Up @@ -888,6 +889,24 @@ export function hasSkipDangerousModePermissionPrompt(): boolean {
)
}

/**
* Returns true if any trusted settings source has enabled bypass permissions
* mode availability. projectSettings is intentionally excluded — a malicious
* project could otherwise enable bypass mode (security risk).
*/
export function hasAllowBypassPermissionsMode(): boolean {
return !!(
getSettingsForSource('userSettings')?.permissions
?.allowBypassPermissionsMode ||
getSettingsForSource('localSettings')?.permissions
?.allowBypassPermissionsMode ||
getSettingsForSource('flagSettings')?.permissions
?.allowBypassPermissionsMode ||
getSettingsForSource('policySettings')?.permissions
?.allowBypassPermissionsMode
)
}

/**
* Returns true if any trusted settings source has accepted the auto
* mode opt-in dialog. projectSettings is intentionally excluded —
Expand Down
6 changes: 6 additions & 0 deletions src/utils/settings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ export const PermissionsSchema = lazySchema(() =>
.enum(['disable'])
.optional()
.describe('Disable the ability to bypass permission prompts'),
allowBypassPermissionsMode: z
.boolean()
.optional()
.describe(
'Allow bypass permissions mode to appear in the mode list without requiring the CLI flag',
),
Comment thread
Flo5k5 marked this conversation as resolved.
...(feature('TRANSCRIPT_CLASSIFIER')
? {
disableAutoMode: z
Expand Down
Loading