Skip to content

Commit 94a5bd2

Browse files
authored
fix BYOK OpenCode permission bypass (#5701)
1 parent 86f18d0 commit 94a5bd2

4 files changed

Lines changed: 58 additions & 10 deletions

File tree

apps/daemon/src/runtimes/defs/byok-opencode.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import { opencodeByokModelId } from '../byok-opencode.js';
2+
import {
3+
OPENCODE_PERMISSION_CAPABILITY,
4+
appendOpenCodePermissionBypass,
5+
} from '../opencode-permissions.js';
26
import { DEFAULT_MODEL_OPTION } from './shared.js';
37
import type { RuntimeAgentDef } from '../types.js';
48

@@ -8,9 +12,11 @@ export const byokOpenCodeAgentDef = {
812
bin: 'opencode-cli',
913
fallbackBins: ['opencode'],
1014
versionArgs: ['--version'],
15+
...OPENCODE_PERMISSION_CAPABILITY,
1116
fallbackModels: [DEFAULT_MODEL_OPTION],
1217
buildArgs: (_prompt, _imagePaths, _extra, options = {}) => {
1318
const args = ['run', '--format', 'json'];
19+
appendOpenCodePermissionBypass(args, 'byok-opencode');
1420
const model = opencodeByokModelId(options.model);
1521
if (model) args.push('-m', model);
1622
return args;

apps/daemon/src/runtimes/defs/opencode.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
import { DEFAULT_MODEL_OPTION, parseLineSeparatedModels } from './shared.js';
2-
import { agentCapabilities } from '../capabilities.js';
2+
import {
3+
OPENCODE_PERMISSION_CAPABILITY,
4+
appendOpenCodePermissionBypass,
5+
} from '../opencode-permissions.js';
36
import type { RuntimeAgentDef } from '../types.js';
47

5-
const SKIP_PERMISSIONS_FLAG = '--dangerously-skip-permissions';
6-
78
export const opencodeAgentDef = {
89
id: 'opencode',
910
name: 'OpenCode',
1011
bin: 'opencode-cli',
1112
fallbackBins: ['opencode'],
1213
versionArgs: ['--version'],
13-
helpArgs: ['run', '--help'],
14-
capabilityFlags: {
15-
[SKIP_PERMISSIONS_FLAG]: 'skipPermissions',
16-
},
14+
...OPENCODE_PERMISSION_CAPABILITY,
1715
// `opencode models` prints `provider/model` per line. Real-world
1816
// `opencode models` calls can take >8s (network round-trip to the
1917
// provider registry), so the previous 8s budget timed out and fell back
@@ -50,9 +48,7 @@ export const opencodeAgentDef = {
5048
'--format',
5149
'json',
5250
];
53-
if (agentCapabilities.get('opencode')?.skipPermissions) {
54-
args.push(SKIP_PERMISSIONS_FLAG);
55-
}
51+
appendOpenCodePermissionBypass(args, 'opencode');
5652
// Capture-style resume: OpenCode mints its own session id (reported on
5753
// the stream as `sessionID`, e.g. `ses_...`). On a follow-up turn the
5854
// daemon continues that session with `-s <id>` instead of re-sending the
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { agentCapabilities } from './capabilities.js';
2+
import type { RuntimeAgentDef } from './types.js';
3+
4+
export const OPENCODE_SKIP_PERMISSIONS_FLAG = '--dangerously-skip-permissions';
5+
6+
export const OPENCODE_PERMISSION_CAPABILITY = {
7+
helpArgs: ['run', '--help'],
8+
capabilityFlags: {
9+
[OPENCODE_SKIP_PERMISSIONS_FLAG]: 'skipPermissions',
10+
},
11+
} satisfies Pick<RuntimeAgentDef, 'helpArgs' | 'capabilityFlags'>;
12+
13+
export function appendOpenCodePermissionBypass(args: string[], agentId: string): void {
14+
if (agentCapabilities.get(agentId)?.skipPermissions) {
15+
args.push(OPENCODE_SKIP_PERMISSIONS_FLAG);
16+
}
17+
}

apps/daemon/tests/runtimes/byok-opencode.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,42 @@
11
import { describe, expect, it } from 'vitest';
22

3+
import { agentCapabilities } from '../../src/runtimes/capabilities.js';
34
import {
45
BYOK_OPENCODE_API_KEY_ENV,
56
BYOK_OPENCODE_PROVIDER_ID,
67
buildOpenCodeByokProviderConfig,
78
opencodeByokModelId,
89
} from '../../src/runtimes/byok-opencode.js';
10+
import { byokOpenCodeAgentDef } from '../../src/runtimes/defs/byok-opencode.js';
911

1012
describe('byok-opencode runtime config', () => {
13+
it('gates non-interactive permission bypass on the installed OpenCode capability', () => {
14+
agentCapabilities.delete('byok-opencode');
15+
expect(byokOpenCodeAgentDef.helpArgs).toEqual(['run', '--help']);
16+
expect(byokOpenCodeAgentDef.capabilityFlags).toEqual({
17+
'--dangerously-skip-permissions': 'skipPermissions',
18+
});
19+
expect(byokOpenCodeAgentDef.buildArgs('', [], [], {})).toEqual([
20+
'run',
21+
'--format',
22+
'json',
23+
]);
24+
25+
agentCapabilities.set('byok-opencode', { skipPermissions: true });
26+
try {
27+
expect(byokOpenCodeAgentDef.buildArgs('', [], [], { model: 'gpt-5.5' })).toEqual([
28+
'run',
29+
'--format',
30+
'json',
31+
'--dangerously-skip-permissions',
32+
'-m',
33+
'open-design-byok/gpt-5.5',
34+
]);
35+
} finally {
36+
agentCapabilities.delete('byok-opencode');
37+
}
38+
});
39+
1140
it('prefixes raw BYOK models with the run-scoped OpenCode provider id', () => {
1241
expect(opencodeByokModelId('gpt-4o-mini')).toBe('open-design-byok/gpt-4o-mini');
1342
expect(opencodeByokModelId('open-design-byok/gpt-4o-mini')).toBe('open-design-byok/gpt-4o-mini');

0 commit comments

Comments
 (0)