Merge pull request #1315 from kaitranntt/kai/fix/1275-codex-diagnostics-redaction

fix: redact Codex diagnostics metadata
This commit is contained in:
Kai (Tam Nhu) Tran authored and GitHub committed 2026-05-22 11:25:10 -04:00
commit 9aeb1c1e99
3 files changed
+116 -5

No files matched your search

@@ -20,6 +20,7 @@ describe('api-routes remote write guard', () => {
let tempHome = '';
let originalDashboardAuthEnabled: string | undefined;
let originalCcsHome: string | undefined;
let originalCodexHome: string | undefined;
beforeAll(async () => {
const app = express();
@@ -53,8 +54,10 @@ describe('api-routes remote write guard', () => {
beforeEach(() => {
originalDashboardAuthEnabled = process.env.CCS_DASHBOARD_AUTH_ENABLED;
originalCcsHome = process.env.CCS_HOME;
originalCodexHome = process.env.CODEX_HOME;
tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-api-routes-remote-write-guard-'));
process.env.CCS_HOME = tempHome;
process.env.CODEX_HOME = path.join(tempHome, '.codex');
process.env.CCS_DASHBOARD_AUTH_ENABLED = 'false';
forcedRemoteAddress = '10.10.0.24';
});
@@ -72,6 +75,12 @@ describe('api-routes remote write guard', () => {
delete process.env.CCS_HOME;
}
if (originalCodexHome !== undefined) {
process.env.CODEX_HOME = originalCodexHome;
} else {
delete process.env.CODEX_HOME;
}
if (tempHome && fs.existsSync(tempHome)) {
fs.rmSync(tempHome, { recursive: true, force: true });
tempHome = '';
@@ -99,6 +108,44 @@ describe('api-routes remote write guard', () => {
expect(response.status).toBe(200);
});
it('redacts sensitive Codex diagnostics data while preserving remote access', async () => {
const codexHome = process.env.CODEX_HOME;
if (!codexHome) throw new Error('CODEX_HOME was not initialized');
fs.mkdirSync(codexHome, { recursive: true });
fs.writeFileSync(
path.join(codexHome, 'config.toml'),
`model_provider = "private"
[model_providers.private]
base_url = "https://llm.internal.example.test/v1/responses?tenant=alpha"
env_key = "PRIVATE_PROVIDER_TOKEN"
wire_api = "responses"
[projects."/Users/someone/CloudPersonal/private-workspace"]
trust_level = "trusted"
`
);
const response = await fetch(`${baseUrl}/api/codex/diagnostics`);
const body = await response.json();
const serialized = JSON.stringify(body);
expect(response.status).toBe(200);
expect(body.config.projectTrust).toEqual([
{ path: 'private-workspace', trustLevel: 'trusted' },
]);
expect(body.config.modelProviders).toEqual([
expect.objectContaining({
name: 'private',
baseUrl: '[redacted:https]',
envKey: '[set]',
}),
]);
expect(serialized).not.toContain('/Users/someone');
expect(serialized).not.toContain('llm.internal.example.test');
expect(serialized).not.toContain('PRIVATE_PROVIDER_TOKEN');
});
it('blocks remote profile creation when dashboard auth is disabled', async () => {
const response = await fetch(`${baseUrl}/api/profiles`, {
method: 'POST',
@@ -105,11 +105,33 @@ describe('codex-dashboard-service', () => {
expect(summary.length).toBe(2);
expect(summary[0].name).toBe('cliproxy');
expect(summary[0].envKey).toBe('CLIPROXY_API_KEY');
expect(summary[0].baseUrl).toBe('[redacted:http]');
expect(summary[0].envKey).toBe('[set]');
expect(summary[0].hasHttpHeaders).toBe(true);
expect(summary[1].usesExperimentalBearerToken).toBe(true);
});
it('redacts custom provider URLs and env var names from diagnostics summaries', () => {
const summary = summarizeCodexModelProviders({
private: {
base_url: 'https://llm.internal.example.test/v1/responses?tenant=alpha',
env_key: 'PRIVATE_PROVIDER_TOKEN',
wire_api: 'responses',
},
});
expect(summary).toEqual([
expect.objectContaining({
name: 'private',
baseUrl: '[redacted:https]',
envKey: '[set]',
wireApi: 'responses',
}),
]);
expect(JSON.stringify(summary)).not.toContain('llm.internal.example.test');
expect(JSON.stringify(summary)).not.toContain('PRIVATE_PROVIDER_TOKEN');
});
it('summarizes feature flags, project trust, and mcp servers', () => {
const features = summarizeCodexFeatureFlags({
multi_agent: true,
@@ -136,11 +158,26 @@ describe('codex-dashboard-service', () => {
expect(features.disabled.map((feature) => feature.name)).toEqual(['shell_snapshot']);
expect(features.all.find((feature) => feature.name === 'custom_mode')?.state).toBe('custom');
expect(projects.length).toBe(2);
expect(projects[0].path).toBe('a');
expect(projects[0].trustLevel).toBe('trusted');
expect(servers[0].transport).toBe('streamable-http');
expect(servers[0].usesInlineBearerToken).toBe(true);
});
it('redacts project trust paths to basenames in diagnostics summaries', () => {
const summary = summarizeCodexProjectTrust({
'/Users/someone/CloudPersonal/private-workspace': { trust_level: 'trusted' },
'/var/tmp/other-workspace/': { trust_level: 'untrusted' },
});
expect(summary).toEqual([
{ path: 'other-workspace', trustLevel: 'untrusted' },
{ path: 'private-workspace', trustLevel: 'trusted' },
]);
expect(JSON.stringify(summary)).not.toContain('/Users/someone');
expect(JSON.stringify(summary)).not.toContain('/var/tmp');
});
it('returns raw config payload for missing config.toml', async () => {
const raw = await getCodexRawConfig();
@@ -404,7 +441,7 @@ bearer_token = "secret"
expect(diagnostics.config.modelAutoCompactTokenLimit).toBe(700000);
expect(diagnostics.config.toolOutputTokenLimit).toBe(12000);
expect(diagnostics.config.personality).toBe('friendly');
expect(diagnostics.config.projectTrust[0]?.path).toBe('/tmp/workspace-a');
expect(diagnostics.config.projectTrust[0]?.path).toBe('workspace-a');
expect(result.rawText).toContain('model = "gpt-5.4"');
expect(result.rawText).toContain('model_context_window = 800000');
expect(result.rawText).toContain('model_auto_compact_token_limit = 700000');