Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 1 addition & 24 deletions containers/api-proxy/guards/effective-token-guard.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

const { parsePositiveInteger } = require('./guard-utils');
const { parsePositiveInteger, parseModelMultipliers, parsePositiveNumber } = require('./guard-utils');
const { logRequest, sanitizeForLog } = require('../logging');

const ET_WARNING_THRESHOLDS = [80, 90, 95, 99];
Expand Down Expand Up @@ -38,29 +38,6 @@ const effectiveTokenConfigCache = {
parsed: { max: null, multipliers: {}, defaultMultiplier: 1 },
};

function parseModelMultipliers(raw) {
if (!raw || String(raw).trim() === '') return {};
try {
const parsed = JSON.parse(raw);
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return {};
const result = {};
for (const [model, value] of Object.entries(parsed)) {
const num = Number(value);
if (Number.isFinite(num) && num > 0) {
result[model] = num;
}
}
return result;
} catch {
return {};
}
}

function parsePositiveNumber(raw) {
const value = Number(raw);
return Number.isFinite(value) && value > 0 ? value : null;
}

function getEffectiveTokenConfig() {
const rawMax = process.env.AWF_MAX_EFFECTIVE_TOKENS;
const rawMultipliers = process.env.AWF_EFFECTIVE_TOKEN_MODEL_MULTIPLIERS;
Expand Down
25 changes: 25 additions & 0 deletions containers/api-proxy/guards/guard-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,31 @@ function parsePositiveInteger(raw) {
return parsed;
}

function parseModelMultipliers(raw) {
if (!raw || String(raw).trim() === '') return {};
try {
const parsed = JSON.parse(raw);
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return {};
const result = {};
for (const [model, value] of Object.entries(parsed)) {
const num = Number(value);
if (Number.isFinite(num) && num > 0) {
result[model] = num;
}
}
return result;
} catch {
return {};
}
}

function parsePositiveNumber(raw) {
const value = Number(raw);
return Number.isFinite(value) && value > 0 ? value : null;
}

module.exports = {
parsePositiveInteger,
parseModelMultipliers,
parsePositiveNumber,
};
43 changes: 42 additions & 1 deletion containers/api-proxy/guards/guard-utils.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { parsePositiveInteger } = require('./guard-utils');
const { parsePositiveInteger, parseModelMultipliers, parsePositiveNumber } = require('./guard-utils');

describe('guard-utils', () => {
describe('parsePositiveInteger', () => {
Expand All @@ -25,4 +25,45 @@ describe('guard-utils', () => {
expect(parsePositiveInteger(raw)).toBe(expected);
});
});

describe('parseModelMultipliers', () => {
it.each([undefined, null, '', ' ', 'invalid-json', '[]', '42'])(
'returns empty object for %p',
(raw) => {
expect(parseModelMultipliers(raw)).toEqual({});
}
);

it('parses only finite positive multipliers', () => {
expect(
parseModelMultipliers(
JSON.stringify({
valid: 2,
stringValid: '3.5',
zero: 0,
negative: -1,
notANumber: 'abc',
infinity: Infinity,
})
)
).toEqual({
valid: 2,
stringValid: 3.5,
});
});
});

describe('parsePositiveNumber', () => {
it.each([undefined, null, '', 'abc', 0, -1, Infinity])('returns null for %p', (raw) => {
expect(parsePositiveNumber(raw)).toBeNull();
});

it.each([
[1, 1],
['2.5', 2.5],
[' 3 ', 3],
])('for raw value %p returns %p', (raw, expected) => {
expect(parsePositiveNumber(raw)).toBe(expected);
});
});
});
24 changes: 1 addition & 23 deletions containers/api-proxy/guards/max-model-multiplier-guard.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const { sanitizeForLog } = require('../logging');
const { parseModelMultipliers, parsePositiveNumber } = require('./guard-utils');

const maxModelMultiplierConfigCache = {
rawCap: undefined,
Expand All @@ -9,29 +10,6 @@ const maxModelMultiplierConfigCache = {
parsed: { cap: null, multipliers: {}, defaultMultiplier: 1 },
};

function parseModelMultipliers(raw) {
if (!raw || String(raw).trim() === '') return {};
try {
const parsed = JSON.parse(raw);
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return {};
const result = {};
for (const [model, value] of Object.entries(parsed)) {
const num = Number(value);
if (Number.isFinite(num) && num > 0) {
result[model] = num;
}
}
return result;
} catch {
return {};
}
}

function parsePositiveNumber(raw) {
const value = Number(raw);
return Number.isFinite(value) && value > 0 ? value : null;
}

function getMaxModelMultiplierConfig() {
const rawCap = process.env.AWF_MAX_MODEL_MULTIPLIER;
const rawMultipliers = process.env.AWF_EFFECTIVE_TOKEN_MODEL_MULTIPLIERS;
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/blocked-domains.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ describe('Block Domains Deny-List (--block-domains)', () => {

test('should still allow non-blocked subdomains when parent is allowed', async () => {
const result = await runner.runWithSudo(
'curl -f --max-time 10 https://github.com',
'curl -f --retry 3 --retry-all-errors --retry-delay 1 --max-time 10 https://github.com',
{
allowDomains: ['github.com'],
blockDomains: ['api.github.com'],
Expand Down
Loading