mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-10 04:19:29 +00:00
fix(image-analysis): reject unknown backend mappings
This commit is contained in:
@@ -40,6 +40,13 @@ const IMAGE_ANALYSIS_PROVIDER_ALIASES = Object.freeze(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function isConfiguredImageAnalysisBackend(
|
||||||
|
backend: string | null,
|
||||||
|
providerModels: Record<string, string>
|
||||||
|
): backend is string {
|
||||||
|
return Boolean(backend && Object.prototype.hasOwnProperty.call(providerModels, backend));
|
||||||
|
}
|
||||||
|
|
||||||
function parseArgs(args: string[]): ImageAnalysisCommandOptions {
|
function parseArgs(args: string[]): ImageAnalysisCommandOptions {
|
||||||
const options: ImageAnalysisCommandOptions = {
|
const options: ImageAnalysisCommandOptions = {
|
||||||
enable: hasAnyFlag(args, ['--enable']),
|
enable: hasAnyFlag(args, ['--enable']),
|
||||||
@@ -296,7 +303,7 @@ export async function handleConfigImageAnalysisCommand(args: string[]): Promise<
|
|||||||
options.setFallback,
|
options.setFallback,
|
||||||
Object.keys(imageConfig.provider_models)
|
Object.keys(imageConfig.provider_models)
|
||||||
);
|
);
|
||||||
if (!normalizedBackend) {
|
if (!isConfiguredImageAnalysisBackend(normalizedBackend, imageConfig.provider_models)) {
|
||||||
console.error(fail(`Invalid fallback backend: ${options.setFallback}`));
|
console.error(fail(`Invalid fallback backend: ${options.setFallback}`));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@@ -314,7 +321,7 @@ export async function handleConfigImageAnalysisCommand(args: string[]): Promise<
|
|||||||
console.error(fail('Profile name cannot be empty'));
|
console.error(fail('Profile name cannot be empty'));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
if (!normalizedBackend) {
|
if (!isConfiguredImageAnalysisBackend(normalizedBackend, imageConfig.provider_models)) {
|
||||||
console.error(fail(`Invalid backend: ${options.setProfileBackend.backend}`));
|
console.error(fail(`Invalid backend: ${options.setProfileBackend.backend}`));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* Unit tests for ccs config image-analysis subcommand.
|
* Unit tests for ccs config image-analysis subcommand.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { describe, it, expect, beforeEach, afterEach, spyOn, mock } from 'bun:test';
|
import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
@@ -33,6 +33,13 @@ function createConfigYaml(content: string): void {
|
|||||||
fs.writeFileSync(path.join(testDir, 'config.yaml'), content, 'utf8');
|
fs.writeFileSync(path.join(testDir, 'config.yaml'), content, 'utf8');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadHandleConfigImageAnalysisCommand() {
|
||||||
|
const mod = await import(
|
||||||
|
`../../../src/commands/config-image-analysis-command?test=${Date.now()}-${Math.random()}`
|
||||||
|
);
|
||||||
|
return mod.handleConfigImageAnalysisCommand;
|
||||||
|
}
|
||||||
|
|
||||||
describe('config image-analysis command', () => {
|
describe('config image-analysis command', () => {
|
||||||
describe('config file parsing', () => {
|
describe('config file parsing', () => {
|
||||||
it('should parse enabled status from config.yaml', () => {
|
it('should parse enabled status from config.yaml', () => {
|
||||||
@@ -152,6 +159,56 @@ image_analysis:
|
|||||||
expect(validProviders.includes(provider)).toBe(false);
|
expect(validProviders.includes(provider)).toBe(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('rejects invalid fallback backends that are not configured', async () => {
|
||||||
|
const handleConfigImageAnalysisCommand = await loadHandleConfigImageAnalysisCommand();
|
||||||
|
const originalProcessExit = process.exit;
|
||||||
|
|
||||||
|
process.exit = ((code?: number) => {
|
||||||
|
throw new Error(`process.exit(${code ?? 0})`);
|
||||||
|
}) as typeof process.exit;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await expect(
|
||||||
|
handleConfigImageAnalysisCommand(['--set-fallback', 'unknown-provider'])
|
||||||
|
).rejects.toThrow('process.exit(1)');
|
||||||
|
} finally {
|
||||||
|
process.exit = originalProcessExit;
|
||||||
|
}
|
||||||
|
|
||||||
|
const configPath = path.join(testDir, 'config.yaml');
|
||||||
|
if (fs.existsSync(configPath)) {
|
||||||
|
const content = fs.readFileSync(configPath, 'utf8');
|
||||||
|
expect(content).not.toContain('fallback_backend: unknown-provider');
|
||||||
|
} else {
|
||||||
|
expect(fs.existsSync(configPath)).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects invalid profile backend mappings that are not configured', async () => {
|
||||||
|
const handleConfigImageAnalysisCommand = await loadHandleConfigImageAnalysisCommand();
|
||||||
|
const originalProcessExit = process.exit;
|
||||||
|
|
||||||
|
process.exit = ((code?: number) => {
|
||||||
|
throw new Error(`process.exit(${code ?? 0})`);
|
||||||
|
}) as typeof process.exit;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await expect(
|
||||||
|
handleConfigImageAnalysisCommand(['--set-profile-backend', 'orq', 'unknown-provider'])
|
||||||
|
).rejects.toThrow('process.exit(1)');
|
||||||
|
} finally {
|
||||||
|
process.exit = originalProcessExit;
|
||||||
|
}
|
||||||
|
|
||||||
|
const configPath = path.join(testDir, 'config.yaml');
|
||||||
|
if (fs.existsSync(configPath)) {
|
||||||
|
const content = fs.readFileSync(configPath, 'utf8');
|
||||||
|
expect(content).not.toContain('unknown-provider');
|
||||||
|
} else {
|
||||||
|
expect(fs.existsSync(configPath)).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('default configuration', () => {
|
describe('default configuration', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user