122 lines
4.6 KiB
TypeScript
122 lines
4.6 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import {
|
|
assertProviderAccess,
|
|
decideProviderAccess,
|
|
ServerManagedProviderRequiredError,
|
|
} from '@/lib/server/provider-access-policy';
|
|
|
|
describe('provider access policy', () => {
|
|
it('rejects an unmanaged provider on a dedicated server deployment', () => {
|
|
expect(decideProviderAccess('server', false)).toEqual({
|
|
allowed: false,
|
|
reason: 'server-managed-provider-required',
|
|
});
|
|
expect(() => assertProviderAccess('server', false)).toThrow(ServerManagedProviderRequiredError);
|
|
});
|
|
|
|
it('allows a managed provider but never accepts client connection configuration', () => {
|
|
expect(decideProviderAccess('server', true)).toEqual({
|
|
allowed: true,
|
|
acceptClientConfiguration: false,
|
|
});
|
|
});
|
|
|
|
it.each(['all', 'ops', 'learner'] as const)(
|
|
'keeps unmanaged provider compatibility for role=%s',
|
|
(role) => {
|
|
expect(decideProviderAccess(role, false)).toEqual({
|
|
allowed: true,
|
|
acceptClientConfiguration: true,
|
|
});
|
|
},
|
|
);
|
|
});
|
|
|
|
describe('provider-config deployment integration', () => {
|
|
beforeEach(() => {
|
|
vi.resetModules();
|
|
vi.unstubAllEnvs();
|
|
vi.stubEnv('NODE_ENV', 'test');
|
|
});
|
|
|
|
it('server + unmanaged rejects client key and base URL before model construction', async () => {
|
|
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'server');
|
|
const { resolveApiKey, resolveBaseUrl } = await import('@/lib/server/provider-config');
|
|
|
|
// `vi.resetModules()` intentionally reloads the policy class together with
|
|
// provider-config, so assert the stable public error contract rather than
|
|
// identity against the pre-reset constructor.
|
|
expect(() => resolveApiKey('unmanaged-provider', 'forged-client-key')).toThrow(
|
|
/only permits providers configured by the server operator/,
|
|
);
|
|
expect(() => resolveBaseUrl('unmanaged-provider', 'https://client.invalid/v1')).toThrow(
|
|
/only permits providers configured by the server operator/,
|
|
);
|
|
});
|
|
|
|
it('the shared LLM resolver rejects server-role BYOK before creating a provider client', async () => {
|
|
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'server');
|
|
const { resolveModel } = await import('@/lib/server/resolve-model');
|
|
|
|
await expect(
|
|
resolveModel({
|
|
modelString: 'caller-owned-provider:test-model',
|
|
apiKey: 'forged-client-key',
|
|
baseUrl: 'https://attacker.invalid/v1',
|
|
}),
|
|
).rejects.toThrow(/only permits providers configured by the server operator/);
|
|
});
|
|
|
|
it('server + managed ignores forged client values, including operator self-hosted URLs', async () => {
|
|
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'server');
|
|
vi.stubEnv('OLLAMA_BASE_URL', 'http://ollama.operator.internal:11434');
|
|
const { resolveApiKey, resolveBaseUrl } = await import('@/lib/server/provider-config');
|
|
|
|
expect(resolveApiKey('ollama', 'forged-client-key')).toBe('');
|
|
expect(resolveBaseUrl('ollama', 'https://attacker.invalid/v1')).toBe(
|
|
'http://ollama.operator.internal:11434',
|
|
);
|
|
});
|
|
|
|
it('server keeps the intrinsic local PDF parser without accepting caller connection data', async () => {
|
|
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'server');
|
|
const { requireProviderAccess, resolvePDFApiKey, resolvePDFBaseUrl } =
|
|
await import('@/lib/server/provider-config');
|
|
|
|
expect(requireProviderAccess('pdf', 'unpdf')).toEqual({
|
|
isServerConfigured: false,
|
|
acceptClientConfiguration: false,
|
|
});
|
|
expect(resolvePDFApiKey('unpdf', 'forged-client-key')).toBe('');
|
|
expect(resolvePDFBaseUrl('unpdf', 'https://attacker.invalid')).toBeUndefined();
|
|
});
|
|
|
|
it('the shared LLM resolver keeps operator self-hosted configuration authoritative', async () => {
|
|
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'server');
|
|
vi.stubEnv('OLLAMA_BASE_URL', 'http://ollama.operator.internal:11434');
|
|
const { resolveModel } = await import('@/lib/server/resolve-model');
|
|
|
|
const resolved = await resolveModel({
|
|
modelString: 'ollama:llama3.3',
|
|
apiKey: 'forged-client-key',
|
|
baseUrl: 'https://attacker.invalid/v1',
|
|
});
|
|
|
|
expect(resolved.apiKey).toBe('');
|
|
expect(resolved.baseUrl).toBe('http://ollama.operator.internal:11434');
|
|
});
|
|
|
|
it.each(['all', 'ops', 'learner'] as const)(
|
|
'role=%s keeps existing unmanaged BYOK resolution',
|
|
async (role) => {
|
|
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', role);
|
|
const { resolveApiKey, resolveBaseUrl } = await import('@/lib/server/provider-config');
|
|
|
|
expect(resolveApiKey('custom-provider', 'client-key')).toBe('client-key');
|
|
expect(resolveBaseUrl('custom-provider', 'https://client.example/v1')).toBe(
|
|
'https://client.example/v1',
|
|
);
|
|
},
|
|
);
|
|
});
|