proxyMode "direct" was a security hole (leaked secrets as plaintext env vars in .mcp.json) and bypassed all mcplocal features (gating, audit, RBAC, content pipeline, namespacing). Removed from schema, API, CLI, and all tests. Old configs with proxyMode are accepted but silently stripped via Zod .transform() for backward compatibility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
98 lines
3.2 KiB
TypeScript
98 lines
3.2 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { createCreateCommand } from '../../src/commands/create.js';
|
|
import { createGetCommand } from '../../src/commands/get.js';
|
|
import { createDescribeCommand } from '../../src/commands/describe.js';
|
|
import { type ApiClient, ApiError } from '../../src/api-client.js';
|
|
|
|
function mockClient(): ApiClient {
|
|
return {
|
|
get: vi.fn(async () => []),
|
|
post: vi.fn(async () => ({ id: 'new-id', name: 'test' })),
|
|
put: vi.fn(async () => ({})),
|
|
delete: vi.fn(async () => {}),
|
|
} as unknown as ApiClient;
|
|
}
|
|
|
|
describe('project with new fields', () => {
|
|
let client: ReturnType<typeof mockClient>;
|
|
let output: string[];
|
|
const log = (...args: unknown[]) => output.push(args.map(String).join(' '));
|
|
|
|
beforeEach(() => {
|
|
client = mockClient();
|
|
output = [];
|
|
});
|
|
|
|
describe('create project with enhanced options', () => {
|
|
it('creates project with servers', async () => {
|
|
const cmd = createCreateCommand({ client, log });
|
|
await cmd.parseAsync([
|
|
'project', 'smart-home',
|
|
'-d', 'Smart home project',
|
|
'--server', 'my-grafana',
|
|
'--server', 'my-ha',
|
|
], { from: 'user' });
|
|
|
|
expect(client.post).toHaveBeenCalledWith('/api/v1/projects', expect.objectContaining({
|
|
name: 'smart-home',
|
|
description: 'Smart home project',
|
|
servers: ['my-grafana', 'my-ha'],
|
|
}));
|
|
});
|
|
});
|
|
|
|
describe('get projects shows new columns', () => {
|
|
it('shows SERVERS column', async () => {
|
|
const deps = {
|
|
output: [] as string[],
|
|
fetchResource: vi.fn(async () => [{
|
|
id: 'proj-1',
|
|
name: 'smart-home',
|
|
description: 'Test',
|
|
ownerId: 'user-1',
|
|
servers: [{ server: { name: 'grafana' } }, { server: { name: 'ha' } }],
|
|
}]),
|
|
log: (...args: string[]) => deps.output.push(args.join(' ')),
|
|
};
|
|
const cmd = createGetCommand(deps);
|
|
await cmd.parseAsync(['node', 'test', 'projects']);
|
|
|
|
const text = deps.output.join('\n');
|
|
expect(text).toContain('SERVERS');
|
|
expect(text).toContain('smart-home');
|
|
});
|
|
});
|
|
|
|
describe('describe project shows full detail', () => {
|
|
it('shows servers and LLM config', async () => {
|
|
const deps = {
|
|
output: [] as string[],
|
|
client: mockClient(),
|
|
fetchResource: vi.fn(async () => ({
|
|
id: 'proj-1',
|
|
name: 'smart-home',
|
|
description: 'Smart home',
|
|
llmProvider: 'gemini-cli',
|
|
llmModel: 'gemini-2.0-flash',
|
|
ownerId: 'user-1',
|
|
servers: [
|
|
{ server: { name: 'my-grafana' } },
|
|
{ server: { name: 'my-ha' } },
|
|
],
|
|
createdAt: '2025-01-01',
|
|
updatedAt: '2025-01-01',
|
|
})),
|
|
log: (...args: string[]) => deps.output.push(args.join(' ')),
|
|
};
|
|
const cmd = createDescribeCommand(deps);
|
|
await cmd.parseAsync(['node', 'test', 'project', 'proj-1']);
|
|
|
|
const text = deps.output.join('\n');
|
|
expect(text).toContain('=== Project: smart-home ===');
|
|
expect(text).toContain('gemini-cli');
|
|
expect(text).toContain('my-grafana');
|
|
expect(text).toContain('my-ha');
|
|
});
|
|
});
|
|
});
|