mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-07 07:55:13 +02:00
docs: disclose codex isolation limits
This commit is contained in:
parent
5966a09c49
commit
27bedb2879
8 changed files with 68 additions and 2 deletions
|
|
@ -61,6 +61,12 @@ For `llm.provider.backend: codex`, `ktx status` runs a minimal non-interactive
|
|||
Codex request. If the probe fails, authenticate Codex locally with the Codex CLI
|
||||
and verify the Codex CLI installation.
|
||||
|
||||
When `llm.provider.backend: codex` is configured, `ktx status` also prints a
|
||||
warning when the installed public Codex SDK and CLI surface cannot prove full
|
||||
Claude-Code-style isolation. The warning does not block authenticated Codex
|
||||
usage, but it marks the project status as partial so you can make an explicit
|
||||
runtime-isolation decision.
|
||||
|
||||
A `Local data` section summarises what the project has accumulated locally:
|
||||
ingest run counts, last completed timestamp per connection, knowledge page
|
||||
counts by scope, semantic-layer source and dictionary value counts, and the
|
||||
|
|
|
|||
|
|
@ -74,8 +74,15 @@ enrichment, memory, and other LLM-backed work through Codex.
|
|||
|
||||
During runtime loops, **ktx** starts a temporary loopback MCP server for the
|
||||
current run, exposes only the tools passed to that run, asks Codex to use a
|
||||
read-only sandbox with approval disabled, auto-approves only those run-scoped
|
||||
MCP tools, and disables Codex web search.
|
||||
read-only sandbox, sets `approval_policy=never`, auto-approves only those
|
||||
run-scoped MCP tools, and disables Codex web search.
|
||||
|
||||
Codex backend isolation is currently limited by the public Codex SDK and CLI
|
||||
surface. Codex may still load user Codex config and built-in command execution
|
||||
or read-only file capabilities. Use `llm.provider.backend: claude-code` when
|
||||
you need stricter Claude-Code-style runtime tool isolation, or remove host
|
||||
Codex MCP and tool config before running untrusted prompts through the `codex`
|
||||
backend.
|
||||
|
||||
## Prompt caching
|
||||
|
||||
|
|
|
|||
9
packages/cli/src/context/llm/codex-isolation.ts
Normal file
9
packages/cli/src/context/llm/codex-isolation.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export const CODEX_ISOLATION_WARNING =
|
||||
'Codex backend isolation is limited by the public Codex SDK/CLI surface: ktx restricts the runtime MCP server to the current ktx tool set, disables Codex web search, asks for a read-only sandbox, and sets approval_policy=never, but Codex may still load user Codex config and built-in command execution or read-only file capabilities.';
|
||||
|
||||
export const CODEX_ISOLATION_WARNING_FIX =
|
||||
'Use llm.provider.backend: claude-code when you need stricter Claude-Code-style runtime tool isolation, or remove host Codex MCP/tool config before running untrusted prompts through the codex backend.';
|
||||
|
||||
export function formatCodexIsolationWarning(): string {
|
||||
return `${CODEX_ISOLATION_WARNING} ${CODEX_ISOLATION_WARNING_FIX}`;
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import { execFile } from 'node:child_process';
|
|||
import { writeFile } from 'node:fs/promises';
|
||||
import { promisify } from 'node:util';
|
||||
import { runClaudeCodeAuthProbe } from './context/llm/claude-code-runtime.js';
|
||||
import { formatCodexIsolationWarning } from './context/llm/codex-isolation.js';
|
||||
import { runCodexAuthProbe } from './context/llm/codex-runtime.js';
|
||||
import { resolveLocalKtxLlmConfig } from './context/llm/local-config.js';
|
||||
import { resolveKtxConfigReference } from './context/core/config-reference.js';
|
||||
|
|
@ -1113,6 +1114,7 @@ export async function runKtxSetupAnthropicModelStep(
|
|||
io.stderr.write(`${health.message}\n`);
|
||||
return { status: 'failed', projectDir: args.projectDir };
|
||||
}
|
||||
io.stderr.write(`${formatCodexIsolationWarning()}\n`);
|
||||
await persistLlmConfig(args.projectDir, { backend: 'codex' }, model.model);
|
||||
io.stdout.write(`│ LLM ready: yes (codex, ${model.model})\n`);
|
||||
return { status: 'ready', projectDir: args.projectDir };
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
import { stat as statAsync, readdir as readdirAsync } from 'node:fs/promises';
|
||||
import { basename, join } from 'node:path';
|
||||
import { runClaudeCodeAuthProbe } from './context/llm/claude-code-runtime.js';
|
||||
import {
|
||||
CODEX_ISOLATION_WARNING,
|
||||
CODEX_ISOLATION_WARNING_FIX,
|
||||
} from './context/llm/codex-isolation.js';
|
||||
import { runCodexAuthProbe } from './context/llm/codex-runtime.js';
|
||||
import type { KtxConfigIssue, KtxProjectConfig, KtxProjectConnectionConfig, KtxProjectEmbeddingConfig, KtxProjectLlmConfig } from './context/project/config.js';
|
||||
import type { KtxLocalProject } from './context/project/project.js';
|
||||
|
|
@ -609,6 +613,13 @@ function buildWarnings(
|
|||
});
|
||||
}
|
||||
|
||||
if (llm.backend === 'codex') {
|
||||
warnings.push({
|
||||
message: CODEX_ISOLATION_WARNING,
|
||||
fix: CODEX_ISOLATION_WARNING_FIX,
|
||||
});
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
|
|
|
|||
19
packages/cli/test/context/llm/codex-isolation.test.ts
Normal file
19
packages/cli/test/context/llm/codex-isolation.test.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
CODEX_ISOLATION_WARNING,
|
||||
CODEX_ISOLATION_WARNING_FIX,
|
||||
formatCodexIsolationWarning,
|
||||
} from '../../../src/context/llm/codex-isolation.js';
|
||||
|
||||
describe('Codex isolation warning', () => {
|
||||
it('documents the enforced and unenforced Codex isolation boundaries', () => {
|
||||
expect(CODEX_ISOLATION_WARNING).toContain('runtime MCP server to the current ktx tool set');
|
||||
expect(CODEX_ISOLATION_WARNING).toContain('disables Codex web search');
|
||||
expect(CODEX_ISOLATION_WARNING).toContain('may still load user Codex config');
|
||||
expect(CODEX_ISOLATION_WARNING).toContain('built-in command execution');
|
||||
expect(CODEX_ISOLATION_WARNING_FIX).toContain('claude-code');
|
||||
expect(formatCodexIsolationWarning()).toBe(
|
||||
`${CODEX_ISOLATION_WARNING} ${CODEX_ISOLATION_WARNING_FIX}`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -240,6 +240,8 @@ describe('setup Anthropic model step', () => {
|
|||
models: { default: 'gpt-5.3-codex' },
|
||||
});
|
||||
expect(codexAuthProbe).toHaveBeenCalledWith(expect.objectContaining({ projectDir: tempDir, model: 'gpt-5.3-codex' }));
|
||||
expect(io.stderr()).toContain('Codex backend isolation is limited');
|
||||
expect(io.stderr()).toContain('may still load user Codex config');
|
||||
});
|
||||
|
||||
it('prompts for the Claude Code model during interactive setup', async () => {
|
||||
|
|
|
|||
|
|
@ -415,6 +415,16 @@ describe('buildProjectStatus codex', () => {
|
|||
status: 'ok',
|
||||
detail: 'local Codex session authenticated',
|
||||
});
|
||||
expect(status.warnings).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
message: expect.stringContaining('Codex backend isolation is limited'),
|
||||
fix: expect.stringContaining('claude-code'),
|
||||
}),
|
||||
]),
|
||||
);
|
||||
const rendered = renderProjectStatus(status, { verbose: false, useColor: false });
|
||||
expect(rendered).toContain('Codex backend isolation is limited');
|
||||
});
|
||||
|
||||
it('skips Codex auth probe with --fast', async () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue