agent-ecosystem/test/main/services/infrastructure/ConfigManager.codexMigration.test.ts
2026-06-04 21:59:02 +03:00

398 lines
12 KiB
TypeScript

import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { afterEach, describe, expect, it, vi } from 'vitest';
describe('ConfigManager Codex migration hardening', () => {
let tempRoot: string | null = null;
afterEach(async () => {
if (tempRoot) {
fs.rmSync(tempRoot, { recursive: true, force: true });
tempRoot = null;
}
vi.resetModules();
const pathDecoder = await import('../../../../src/main/utils/pathDecoder');
pathDecoder.setClaudeBasePathOverride(null);
});
it('persists the normalized Codex auth and runtime shape after loading a legacy config', async () => {
tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'config-codex-migration-'));
const configPath = path.join(tempRoot, 'claude-devtools-config.json');
// eslint-disable-next-line security/detect-non-literal-fs-filename -- temp fixture path
fs.writeFileSync(
configPath,
JSON.stringify({
providerConnections: {
codex: {
authMode: 'oauth',
apiKeyBetaEnabled: true,
},
},
runtime: {
providerBackends: {
codex: 'api',
},
},
})
);
const { ConfigManager } = await import(
'../../../../src/main/services/infrastructure/ConfigManager'
);
const manager = new ConfigManager(configPath);
const config = manager.getConfig();
expect(config.providerConnections.codex.preferredAuthMode).toBe('chatgpt');
expect(config.runtime.providerBackends.codex).toBe('codex-native');
await vi.waitFor(() => {
// eslint-disable-next-line security/detect-non-literal-fs-filename -- temp fixture path
const persisted = JSON.parse(fs.readFileSync(configPath, 'utf8')) as {
providerConnections: { codex: Record<string, unknown> };
runtime: { providerBackends: { codex: string } };
};
expect(persisted.providerConnections.codex).toEqual({
preferredAuthMode: 'chatgpt',
customProvider: {
enabled: false,
baseUrl: '',
model: '',
},
});
expect(persisted.runtime.providerBackends.codex).toBe('codex-native');
});
});
it('deep-merges and persists Codex custom provider updates', async () => {
tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'config-codex-custom-provider-'));
const configPath = path.join(tempRoot, 'agent-teams-config.json');
const { ConfigManager } = await import(
'../../../../src/main/services/infrastructure/ConfigManager'
);
const manager = new ConfigManager(configPath);
const updated = manager.updateConfig('providerConnections', {
codex: {
preferredAuthMode: 'api_key',
customProvider: {
enabled: true,
baseUrl: ' https://gateway.example.com/v1 ',
model: ' gateway-codex-model ',
},
},
} as never);
expect(updated.providerConnections.codex).toEqual({
preferredAuthMode: 'api_key',
customProvider: {
enabled: true,
baseUrl: 'https://gateway.example.com/v1',
model: 'gateway-codex-model',
},
});
await vi.waitFor(() => {
// eslint-disable-next-line security/detect-non-literal-fs-filename -- temp fixture path
const persisted = JSON.parse(fs.readFileSync(configPath, 'utf8')) as {
providerConnections: {
codex: {
preferredAuthMode: string;
customProvider: { enabled: boolean; baseUrl: string; model: string };
};
};
};
expect(persisted.providerConnections.codex).toEqual({
preferredAuthMode: 'api_key',
customProvider: {
enabled: true,
baseUrl: 'https://gateway.example.com/v1',
model: 'gateway-codex-model',
},
});
});
const disabled = manager.updateConfig('providerConnections', {
codex: {
customProvider: {
enabled: false,
},
},
} as never);
expect(disabled.providerConnections.codex).toEqual({
preferredAuthMode: 'api_key',
customProvider: {
enabled: false,
baseUrl: 'https://gateway.example.com/v1',
model: 'gateway-codex-model',
},
});
await vi.waitFor(() => {
// eslint-disable-next-line security/detect-non-literal-fs-filename -- temp fixture path
const persisted = JSON.parse(fs.readFileSync(configPath, 'utf8')) as {
providerConnections: {
codex: {
preferredAuthMode: string;
customProvider: { enabled: boolean; baseUrl: string; model: string };
};
};
};
expect(persisted.providerConnections.codex).toEqual({
preferredAuthMode: 'api_key',
customProvider: {
enabled: false,
baseUrl: 'https://gateway.example.com/v1',
model: 'gateway-codex-model',
},
});
});
});
it('normalizes legacy Codex runtime backend updates inside ConfigManager updateConfig', async () => {
tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'config-codex-runtime-update-'));
const configPath = path.join(tempRoot, 'claude-devtools-config.json');
const { ConfigManager } = await import(
'../../../../src/main/services/infrastructure/ConfigManager'
);
const manager = new ConfigManager(configPath);
const updated = manager.updateConfig('runtime', {
providerBackends: {
codex: 'api' as never,
},
} as never);
expect(updated.runtime.providerBackends.codex).toBe('codex-native');
await vi.waitFor(() => {
// eslint-disable-next-line security/detect-non-literal-fs-filename -- temp fixture path
const persisted = JSON.parse(fs.readFileSync(configPath, 'utf8')) as {
runtime: { providerBackends: { codex: string } };
};
expect(persisted.runtime.providerBackends.codex).toBe('codex-native');
});
});
it('loads legacy Anthropic provider connections with compatible endpoint defaults', async () => {
tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'config-anthropic-compatible-default-'));
const configPath = path.join(tempRoot, 'agent-teams-config.json');
// eslint-disable-next-line security/detect-non-literal-fs-filename -- temp fixture path
fs.writeFileSync(
configPath,
JSON.stringify({
providerConnections: {
anthropic: {
authMode: 'oauth',
fastModeDefault: true,
},
},
})
);
const { ConfigManager } = await import(
'../../../../src/main/services/infrastructure/ConfigManager'
);
const manager = new ConfigManager(configPath);
const config = manager.getConfig();
expect(config.providerConnections.anthropic).toEqual({
authMode: 'oauth',
fastModeDefault: true,
compatibleEndpoint: {
enabled: false,
baseUrl: '',
},
});
await vi.waitFor(() => {
// eslint-disable-next-line security/detect-non-literal-fs-filename -- temp fixture path
const persisted = JSON.parse(fs.readFileSync(configPath, 'utf8')) as {
providerConnections: {
anthropic: {
compatibleEndpoint: { enabled: boolean; baseUrl: string };
};
};
};
expect(persisted.providerConnections.anthropic.compatibleEndpoint).toEqual({
enabled: false,
baseUrl: '',
});
});
});
it('deep-merges partial Anthropic compatible endpoint updates', async () => {
tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'config-anthropic-compatible-update-'));
const configPath = path.join(tempRoot, 'agent-teams-config.json');
const { ConfigManager } = await import(
'../../../../src/main/services/infrastructure/ConfigManager'
);
const manager = new ConfigManager(configPath);
manager.updateConfig('providerConnections', {
anthropic: {
authMode: 'oauth',
fastModeDefault: true,
},
} as never);
await vi.waitFor(() => {
// eslint-disable-next-line security/detect-non-literal-fs-filename -- temp fixture path
const persisted = JSON.parse(fs.readFileSync(configPath, 'utf8')) as {
providerConnections: {
anthropic: {
authMode: string;
fastModeDefault: boolean;
};
};
};
expect(persisted.providerConnections.anthropic.authMode).toBe('oauth');
expect(persisted.providerConnections.anthropic.fastModeDefault).toBe(true);
});
const updated = manager.updateConfig('providerConnections', {
anthropic: {
compatibleEndpoint: {
baseUrl: ' http://localhost:1234 ',
},
},
} as never);
expect(updated.providerConnections.anthropic).toEqual({
authMode: 'oauth',
fastModeDefault: true,
compatibleEndpoint: {
enabled: false,
baseUrl: 'http://localhost:1234',
},
});
await vi.waitFor(() => {
// eslint-disable-next-line security/detect-non-literal-fs-filename -- temp fixture path
const persisted = JSON.parse(fs.readFileSync(configPath, 'utf8')) as {
providerConnections: {
anthropic: {
authMode: string;
fastModeDefault: boolean;
compatibleEndpoint: { enabled: boolean; baseUrl: string };
};
};
};
expect(persisted.providerConnections.anthropic).toEqual({
authMode: 'oauth',
fastModeDefault: true,
compatibleEndpoint: {
enabled: false,
baseUrl: 'http://localhost:1234',
},
});
});
});
it('strips derived Anthropic compatible endpoint token status when loading config', async () => {
tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'config-anthropic-compatible-derived-'));
const configPath = path.join(tempRoot, 'agent-teams-config.json');
// eslint-disable-next-line security/detect-non-literal-fs-filename -- temp fixture path
fs.writeFileSync(
configPath,
JSON.stringify({
providerConnections: {
anthropic: {
authMode: 'auto',
compatibleEndpoint: {
enabled: true,
baseUrl: ' http://localhost:1234 ',
tokenConfigured: true,
tokenSource: 'stored',
tokenSourceLabel: 'Stored in app',
},
},
},
})
);
const { ConfigManager } = await import(
'../../../../src/main/services/infrastructure/ConfigManager'
);
const manager = new ConfigManager(configPath);
expect(manager.getConfig().providerConnections.anthropic.compatibleEndpoint).toEqual({
enabled: true,
baseUrl: 'http://localhost:1234',
});
await vi.waitFor(() => {
// eslint-disable-next-line security/detect-non-literal-fs-filename -- temp fixture path
const persisted = JSON.parse(fs.readFileSync(configPath, 'utf8')) as {
providerConnections: {
anthropic: {
compatibleEndpoint: Record<string, unknown>;
};
};
};
expect(persisted.providerConnections.anthropic.compatibleEndpoint).toEqual({
enabled: true,
baseUrl: 'http://localhost:1234',
});
});
});
it('strips derived Anthropic compatible endpoint token status from partial updates', async () => {
tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'config-anthropic-compatible-derived-update-'));
const configPath = path.join(tempRoot, 'agent-teams-config.json');
const { ConfigManager } = await import(
'../../../../src/main/services/infrastructure/ConfigManager'
);
const manager = new ConfigManager(configPath);
const updated = manager.updateConfig('providerConnections', {
anthropic: {
compatibleEndpoint: {
enabled: true,
baseUrl: 'http://localhost:1234',
tokenConfigured: true,
tokenSource: 'environment',
},
},
} as never);
expect(updated.providerConnections.anthropic.compatibleEndpoint).toEqual({
enabled: true,
baseUrl: 'http://localhost:1234',
});
await vi.waitFor(() => {
// eslint-disable-next-line security/detect-non-literal-fs-filename -- temp fixture path
const persisted = JSON.parse(fs.readFileSync(configPath, 'utf8')) as {
providerConnections: {
anthropic: {
compatibleEndpoint: Record<string, unknown>;
};
};
};
expect(persisted.providerConnections.anthropic.compatibleEndpoint).toEqual({
enabled: true,
baseUrl: 'http://localhost:1234',
});
});
});
});