blob: 2fd2e9117341a5bf5406998091665759e128452b [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import assert from 'node:assert/strict';
import { test } from 'node:test';
import {
createDefaultRuntimePolicy,
decodeCanonicalConnectionCatalogEntry,
decodeCanonicalRuntimePolicy,
decodeModelOverridesTable,
normalizeCreateCatalogConnectionInput,
normalizeConnectionCatalogEntryUpdate,
normalizeConnectionCatalogEntryUpdateForProvider,
normalizeConnectionModelDiscoveryResult,
normalizeRuntimePolicyMutation,
normalizeSetCredentialInput,
RuntimePolicyDomainDecodeError,
} from '../runtime-policy.js';
test('normalizes policy input while canonical policy decode rejects producer drift', () => {
const mutation = normalizeRuntimePolicyMutation({
expectedRevision: 0,
operation: {
kind: 'set_network_proxy',
value: { ...createDefaultRuntimePolicy().networkProxy, enabled: true, host: ' proxy.local ' },
},
});
assert.equal(mutation.operation.kind, 'set_network_proxy');
if (mutation.operation.kind !== 'set_network_proxy') return;
assert.equal(mutation.operation.value.host, 'proxy.local');
assert.throws(
() =>
decodeCanonicalRuntimePolicy({
...createDefaultRuntimePolicy(),
networkProxy: { ...mutation.operation.value, host: ' proxy.local ' },
}),
RuntimePolicyDomainDecodeError,
);
assert.doesNotThrow(() =>
decodeCanonicalRuntimePolicy({
...createDefaultRuntimePolicy(),
networkProxy: { ...mutation.operation.value, host: 'proxy.local' },
}),
);
});
test('Code Mode is opt-in and survives policy decoding', () => {
const policy = createDefaultRuntimePolicy();
assert.notEqual(decodeCanonicalRuntimePolicy(policy).chatDefaults.codeModeEnabled, true);
assert.equal(
decodeCanonicalRuntimePolicy({
...policy,
chatDefaults: { ...policy.chatDefaults, codeModeEnabled: true },
}).chatDefaults.codeModeEnabled,
true,
);
assert.throws(
() =>
decodeCanonicalRuntimePolicy({
...policy,
chatDefaults: { ...policy.chatDefaults, codeModeEnabled: 'true' },
}),
RuntimePolicyDomainDecodeError,
);
});
test('preserves a valid default thinking level and rejects unknown levels', () => {
const policy = {
...createDefaultRuntimePolicy(),
chatDefaults: { permissionMode: 'ask' as const, thinkingLevel: 'high' as const },
};
assert.deepEqual(decodeCanonicalRuntimePolicy(policy).chatDefaults, policy.chatDefaults);
assert.throws(
() =>
normalizeRuntimePolicyMutation({
expectedRevision: 0,
operation: {
kind: 'set_chat_defaults',
value: { permissionMode: 'ask', thinkingLevel: 'unbounded' },
},
}),
RuntimePolicyDomainDecodeError,
);
});
test('keeps user-approved subagent presets canonical in Runtime Policy', () => {
const preset = {
id: 'fast-reader',
name: 'Fast reader',
description: 'Cheap scans',
profile: 'local_read' as const,
connectionSlug: 'openrouter',
model: 'openrouter/free',
enabled: true,
};
const policy = { ...createDefaultRuntimePolicy(), subagents: { presets: [preset] } };
assert.deepEqual(decodeCanonicalRuntimePolicy(policy).subagents.presets, [preset]);
assert.deepEqual(
normalizeRuntimePolicyMutation({
expectedRevision: 2,
operation: { kind: 'set_subagents', value: { presets: [preset] } },
}),
{ expectedRevision: 2, operation: { kind: 'set_subagents', value: { presets: [preset] } } },
);
});
test('normalizes the explicit Git Bash preference and rejects arbitrary shell kinds', () => {
assert.deepEqual(
normalizeRuntimePolicyMutation({
expectedRevision: 3,
operation: {
kind: 'set_shell',
value: {
preference: 'git_bash',
executable: ' C:\\Program Files\\Git\\bin\\bash.exe ',
},
},
}),
{
expectedRevision: 3,
operation: {
kind: 'set_shell',
value: {
preference: 'git_bash',
executable: 'C:\\Program Files\\Git\\bin\\bash.exe',
},
},
},
);
assert.throws(
() =>
normalizeRuntimePolicyMutation({
expectedRevision: 3,
operation: {
kind: 'set_shell',
value: { preference: 'custom', executable: 'C:\\tools\\fish.exe' },
},
}),
RuntimePolicyDomainDecodeError,
);
});
test('normalizes only the bounded agent settings patch surface', () => {
assert.deepEqual(
normalizeRuntimePolicyMutation({
expectedRevision: 4,
operation: {
kind: 'patch_agent_settings',
value: {
personalization: { assistantTone: 'Be direct.' },
memory: { agentReadEnabled: true },
webSearch: { enabled: true },
},
},
}),
{
expectedRevision: 4,
operation: {
kind: 'patch_agent_settings',
value: {
personalization: { assistantTone: 'Be direct.' },
memory: { agentReadEnabled: true },
webSearch: { enabled: true },
},
},
},
);
assert.throws(
() =>
normalizeRuntimePolicyMutation({
expectedRevision: 4,
operation: {
kind: 'patch_agent_settings',
value: { networkProxy: { enabled: false } },
},
}),
RuntimePolicyDomainDecodeError,
);
});
test('normalizes catalog inputs while canonical entries reject noncanonical endpoints', () => {
const input = normalizeCreateCatalogConnectionInput({
expectedCatalogRevision: 0,
connection: {
slug: 'openai-main',
name: 'OpenAI',
providerType: 'openai',
baseUrl: 'https://proxy.example:443/v1',
enabled: true,
enabledModelIds: [],
},
});
assert.equal(input.connection.baseUrl, 'https://proxy.example/v1');
assert.throws(
() =>
normalizeCreateCatalogConnectionInput({
expectedCatalogRevision: 0,
connection: {
slug: 'unicode-relay',
name: 'Unicode relay',
providerType: 'openai-compatible',
baseUrl: `https://example.test/${'界'.repeat(2_000)}`,
enabled: true,
enabledModelIds: [],
},
}),
/must not exceed 2048 bytes/,
);
assert.throws(
() =>
decodeCanonicalConnectionCatalogEntry({
...input.connection,
connectionId: '123e4567-e89b-42d3-a456-426614174000',
revision: 1,
baseUrl: 'https://proxy.example:443/v1',
models: [],
}),
RuntimePolicyDomainDecodeError,
);
});
for (const [slug, detail] of [
['', 'Slug is required'],
['Not A Slug', 'Slug must be lowercase letters, digits, and hyphens'],
['a'.repeat(65), 'Slug must be 64 characters or fewer'],
]) {
test(`catalog decoding preserves the diagnostic: ${detail}`, () => {
assert.throws(
() =>
decodeCanonicalConnectionCatalogEntry({
connectionId: '123e4567-e89b-42d3-a456-426614174000',
revision: 1,
slug,
name: 'OpenAI',
providerType: 'openai',
enabled: true,
enabledModelIds: [],
models: [],
}),
{ name: 'RuntimePolicyDomainDecodeError', message: `connection slug: ${detail}` },
);
});
}
test('rejects new connections for the retired Gemini CLI account provider', () => {
assert.throws(
() =>
normalizeCreateCatalogConnectionInput({
expectedCatalogRevision: 0,
connection: {
slug: 'gemini-account',
name: 'Gemini account',
providerType: 'gemini-cli',
enabled: true,
enabledModelIds: [],
},
}),
/provider type is not registered/,
);
});
test('relay model profiles round-trip canonical entries and drafts, strictly', () => {
const table = {
'relay-reasoner': {
thinkingLevels: ['minimal', 'low'],
vision: true,
contextWindow: 128_000,
serviceTier: 'fast',
},
};
const draft = normalizeCreateCatalogConnectionInput({
expectedCatalogRevision: 0,
connection: {
slug: 'relay',
name: 'Relay',
providerType: 'openai-compatible',
baseUrl: 'https://relay.example/v1',
enabled: true,
enabledModelIds: ['relay-reasoner'],
modelOverrides: table,
},
});
assert.deepEqual(draft.connection.modelOverrides, table);
const responsesDraft = normalizeCreateCatalogConnectionInput({
expectedCatalogRevision: 0,
connection: {
slug: 'responses-relay',
name: 'Responses Relay',
providerType: 'openai-responses-compatible',
baseUrl: 'https://responses.example/v1',
enabled: true,
enabledModelIds: ['relay-reasoner'],
modelOverrides: table,
},
});
assert.deepEqual(responsesDraft.connection.modelOverrides, table);
// The canonical path re-decodes the same table (entry = draft + identity).
const entry = decodeCanonicalConnectionCatalogEntry({
...draft.connection,
connectionId: '123e4567-e89b-42d3-a456-426614174000',
revision: 1,
models: [],
});
assert.deepEqual(entry.modelOverrides, table);
// An empty table is never a state: drafts omit the key, updates read it as
// the same clear-instruction `null` gives.
const emptyDraft = normalizeCreateCatalogConnectionInput({
expectedCatalogRevision: 0,
connection: {
slug: 'relay',
name: 'Relay',
providerType: 'openai-compatible',
enabled: true,
enabledModelIds: [],
modelOverrides: {},
},
});
assert.equal(emptyDraft.connection.modelOverrides, undefined);
const emptyUpdate = normalizeConnectionCatalogEntryUpdate({
name: 'Relay',
enabled: true,
enabledModelIds: [],
modelOverrides: {},
});
assert.equal(emptyUpdate.modelOverrides, null);
// The update input is tri-state: null (or the equivalent {}) clears, a
// table replaces, and an ABSENT key means untouched — absent must never
// materialize into a clear, which is what keeps profile-blind writers
// safe.
const update = normalizeConnectionCatalogEntryUpdate({
name: 'Relay',
enabled: true,
enabledModelIds: [],
modelOverrides: null,
});
assert.equal(update.modelOverrides, null);
const absentUpdate = normalizeConnectionCatalogEntryUpdate({
name: 'Relay',
enabled: true,
enabledModelIds: [],
});
assert.deepEqual(absentUpdate, {
name: 'Relay',
enabled: true,
enabledModelIds: [],
});
// The write seam splits the table by FIELD, not by provider (#1584).
// `contextWindow` and `vision` state facts about a model, and a user has
// them when Maka does not — a model newer than the bundled snapshot, or any
// model on a provider with no model-list endpoint — so they are legal
// everywhere.
const facts = { 'relay-reasoner': { vision: true, contextWindow: 128_000 } };
assert.deepEqual(
normalizeCreateCatalogConnectionInput({
expectedCatalogRevision: 0,
connection: {
slug: 'not-a-relay',
name: 'Other',
providerType: 'openai',
enabled: true,
enabledModelIds: ['relay-reasoner'],
modelOverrides: facts,
},
}).connection.modelOverrides,
facts,
);
assert.deepEqual(
normalizeConnectionCatalogEntryUpdateForProvider(
{
name: 'Other',
enabled: true,
enabledModelIds: ['relay-reasoner'],
modelOverrides: facts,
},
'anthropic',
).modelOverrides,
facts,
);
// `thinkingLevels` and `serviceTier` name a wire feature only the
// OpenAI-compatible relays accept, so they stay relay-only on both write
// paths: elsewhere they are a request Maka would never send.
for (const wireShaped of [
{ 'relay-reasoner': { thinkingLevels: ['low'] } },
{ 'relay-reasoner': { serviceTier: 'fast' } },
]) {
assert.throws(
() =>
normalizeCreateCatalogConnectionInput({
expectedCatalogRevision: 0,
connection: {
slug: 'not-a-relay',
name: 'Other',
providerType: 'openai',
enabled: true,
enabledModelIds: ['relay-reasoner'],
modelOverrides: wireShaped,
},
}),
/require[s]? an OpenAI-compatible connection/,
JSON.stringify(wireShaped),
);
assert.throws(
() =>
normalizeConnectionCatalogEntryUpdateForProvider(
{
name: 'Other',
enabled: true,
enabledModelIds: ['relay-reasoner'],
modelOverrides: wireShaped,
},
'anthropic',
),
/require[s]? an OpenAI-compatible connection/,
JSON.stringify(wireShaped),
);
}
assert.equal(
normalizeConnectionCatalogEntryUpdateForProvider(
{ name: 'Other', enabled: true, enabledModelIds: [], modelOverrides: null },
'anthropic',
).modelOverrides,
null,
);
assert.deepEqual(
normalizeConnectionCatalogEntryUpdate({
name: 'Relay',
enabled: true,
enabledModelIds: [],
modelOverrides: { 'disabled-model': { vision: true } },
}).modelOverrides,
{ 'disabled-model': { vision: true } },
);
// Model ids are relay-supplied strings; __proto__/constructor/toString
// must survive the table as ordinary own keys — the decode builds the
// table with fromEntries precisely so '__proto__' cannot poison the result
// object's prototype and quietly drop the entry.
const hostileTable = decodeModelOverridesTable(
// An object literal could not even express `__proto__` as an own key —
// the deserialized document is the realistic carrier of a hostile id.
JSON.parse(
'{"__proto__":{"vision":true},"constructor":{"vision":false},"toString":{"contextWindow":8192}}',
),
);
assert.deepEqual(Object.keys(hostileTable).sort(), ['__proto__', 'constructor', 'toString']);
assert.equal(JSON.stringify(hostileTable).includes('"__proto__"'), true);
// Strictness: writers emit normalized tables, so anything else is corrupt.
for (const bad of [
'nope',
[],
{ m: { thinkingLevels: ['turbo'] } }, // unknown level
{ m: { thinkingLevels: ['off'] } }, // disable wire, not a declarable tier
{ m: { thinkingLevels: ['low', 'low'] } }, // duplicate
{ m: { thinkingLevels: [] } }, // empty level list
{ m: { vision: 'yes' } },
{ m: { contextWindow: 0 } },
{ m: { contextWindow: 1.5 } },
{ m: { contextWindow: 2 ** 60 } }, // not within 1..MAX_SAFE_INTEGER
{ m: { vision: true, extra: 1 } }, // unknown key in the entry
]) {
assert.throws(
() => decodeModelOverridesTable(bad),
RuntimePolicyDomainDecodeError,
JSON.stringify(bad),
);
}
});
test('normalizes exact bounded model discovery results', () => {
assert.deepEqual(
normalizeConnectionModelDiscoveryResult({
models: [{ id: 'gpt-5', capabilities: { chat: true, parallelToolCalls: false } }],
source: 'fetched',
fetchedAt: 42,
}),
{
models: [{ id: 'gpt-5', capabilities: { chat: true, parallelToolCalls: false } }],
source: 'fetched',
fetchedAt: 42,
},
);
for (const invalid of [
{ models: [{ id: 'duplicate' }, { id: 'duplicate' }], source: 'fetched', fetchedAt: 42 },
{ models: [{ id: 'invalid', contextWindow: 0 }], source: 'fetched', fetchedAt: 42 },
{
models: Array.from({ length: 2049 }, (_, i) => ({ id: `model-${i}` })),
source: 'fetched',
fetchedAt: 42,
},
{ models: [{ id: 'gpt-5' }], source: 'unknown', fetchedAt: 42 },
{ models: [{ id: 'gpt-5' }], source: 'fetched', fetchedAt: 42, rawBody: 'secret' },
]) {
assert.throws(
() => normalizeConnectionModelDiscoveryResult(invalid),
RuntimePolicyDomainDecodeError,
);
}
});
test('normalizes extended model facts used by the runtime host catalog', () => {
const result = normalizeConnectionModelDiscoveryResult({
models: [
{
id: 'custom-model',
description: 'A custom model',
inputLimit: 120_000,
knowledgeCutoff: '2025-01',
structuredOutput: true,
lastUpdated: '2026-01-01',
modalities: { input: ['text', 'image'], output: ['text'] },
},
],
source: 'fetched',
fetchedAt: 42,
});
assert.deepEqual(result.models[0], {
id: 'custom-model',
description: 'A custom model',
inputLimit: 120_000,
knowledgeCutoff: '2025-01',
structuredOutput: true,
lastUpdated: '2026-01-01',
modalities: { input: ['text', 'image'], output: ['text'] },
});
});
test('carries the video and pdf modalities models.dev declares', () => {
const modalities = {
input: ['text', 'image', 'video'],
output: ['text', 'pdf', 'video'],
};
const result = normalizeConnectionModelDiscoveryResult({
models: [{ id: 'custom-model', modalities }],
source: 'fetched',
fetchedAt: 42,
});
assert.deepEqual(result.models[0], { id: 'custom-model', modalities });
});
test('rejects sparse model modality arrays', () => {
assert.throws(
() =>
normalizeConnectionModelDiscoveryResult({
models: [
{
id: 'custom-model',
modalities: { input: Array(1), output: ['text'] },
},
],
source: 'fetched',
fetchedAt: 42,
}),
RuntimePolicyDomainDecodeError,
);
});
test('credential domain validation requires material but leaves capacity to callers', () => {
const input = normalizeSetCredentialInput({
locator: {
scope: 'connection',
connectionId: '123e4567-e89b-42d3-a456-426614174000',
kind: 'api_key',
},
expected: null,
secret: 's'.repeat(20 * 1024),
});
assert.equal(input.secret.length, 20 * 1024);
assert.throws(
() => normalizeSetCredentialInput({ ...input, secret: '' }),
RuntimePolicyDomainDecodeError,
);
});