fix: restrict local runtime readiness probes

This commit is contained in:
Kai (Tam Nhu) Tran
2026-05-30 15:19:38 -04:00
committed by Tam Nhu Tran
parent 62a4d44b58
commit 9a7b26eab7
2 changed files with 52 additions and 1 deletions
+9 -1
View File
@@ -6,6 +6,7 @@
*/
import { Router, Request, Response } from 'express';
import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware';
import { isReservedName, RESERVED_PROFILE_NAMES } from '../../config/reserved-names';
import {
createApiProfile,
@@ -30,6 +31,9 @@ import { isAnthropicDirectProfile, updateSettingsFile, parseTarget } from './rou
const router = Router();
const LOCAL_RUNTIME_READINESS_LOCAL_ACCESS_ERROR =
'Local runtime readiness requires localhost access when dashboard auth is disabled.';
function isDenylistError(message: string | undefined): boolean {
return typeof message === 'string' && message.toLowerCase().includes('denylist');
}
@@ -87,7 +91,11 @@ router.get('/cliproxy-bridge/providers', (_req: Request, res: Response): void =>
}
});
router.get('/local-runtime-readiness', async (_req: Request, res: Response): Promise<void> => {
router.get('/local-runtime-readiness', async (req: Request, res: Response): Promise<void> => {
if (!requireLocalAccessWhenAuthDisabled(req, res, LOCAL_RUNTIME_READINESS_LOCAL_ACCESS_ERROR)) {
return;
}
try {
res.json({ runtimes: await getLocalRuntimeReadiness() });
} catch (error) {
@@ -6,11 +6,20 @@ import profileRoutes from '../../../src/web-server/routes/profile-routes';
describe('profile-routes local runtime readiness', () => {
let server: Server;
let baseUrl = '';
let forcedRemoteAddress = '127.0.0.1';
let originalDashboardAuthEnabled: string | undefined;
const originalFetch = globalThis.fetch;
beforeAll(async () => {
const app = express();
app.use(express.json());
app.use((req, _res, next) => {
Object.defineProperty(req.socket, 'remoteAddress', {
value: forcedRemoteAddress,
configurable: true,
});
next();
});
app.use('/api/profiles', profileRoutes);
await new Promise<void>((resolve, reject) => {
@@ -36,6 +45,10 @@ describe('profile-routes local runtime readiness', () => {
});
beforeEach(() => {
originalDashboardAuthEnabled = process.env.CCS_DASHBOARD_AUTH_ENABLED;
process.env.CCS_DASHBOARD_AUTH_ENABLED = 'false';
forcedRemoteAddress = '127.0.0.1';
globalThis.fetch = (async (input: RequestInfo | URL) => {
const url = String(input);
@@ -73,6 +86,12 @@ describe('profile-routes local runtime readiness', () => {
afterEach(() => {
globalThis.fetch = originalFetch;
if (originalDashboardAuthEnabled !== undefined) {
process.env.CCS_DASHBOARD_AUTH_ENABLED = originalDashboardAuthEnabled;
} else {
delete process.env.CCS_DASHBOARD_AUTH_ENABLED;
}
});
it('reports local runtimes as ready when their endpoints respond with models', async () => {
@@ -103,6 +122,30 @@ describe('profile-routes local runtime readiness', () => {
);
});
it('blocks remote readiness probes when dashboard auth is disabled', async () => {
let probeCount = 0;
forcedRemoteAddress = '10.10.0.24';
globalThis.fetch = (async (input: RequestInfo | URL) => {
const url = String(input);
if (url.startsWith(baseUrl)) {
return originalFetch(input);
}
probeCount += 1;
return new Response(JSON.stringify({ models: [{ name: 'gemma4:e4b' }] }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
}) as typeof fetch;
const response = await fetch(`${baseUrl}/api/profiles/local-runtime-readiness`);
expect(response.status).toBe(403);
expect(await response.json()).toEqual({
error: 'Local runtime readiness requires localhost access when dashboard auth is disabled.',
});
expect(probeCount).toBe(0);
});
it('reports setup guidance when local endpoints are unavailable', async () => {
globalThis.fetch = (async (input: RequestInfo | URL) => {
const url = String(input);