@@ -10,14 +10,29 @@ import { randomUUID } from "node:crypto";
1010// module's exports only through `default`.
1111import dbServer from "./app/db.server" ;
1212import errorFingerprinting from "./app/utils/errorFingerprinting" ;
13+ import localHostGuard from "./app/utils/localHostGuard" ;
1314import eventCommon from "./app/v3/eventRepository/common.server" ;
1415
1516const { prisma } = dbServer ;
1617const { calculateErrorFingerprint } = errorFingerprinting ;
18+ const { isLocalHost, checkLocalOrigin } = localHostGuard ;
1719const { generateTraceId, generateSpanId } = eventCommon ;
1820
1921const APP_ORIGIN = process . env . APP_ORIGIN ?? "http://localhost:3030" ;
2022
23+ /** Every request to it carries the target's API key, so it is checked like the rest. */
24+ function appOrigin ( ) : string {
25+ const checked = checkLocalOrigin ( APP_ORIGIN ) ;
26+ if ( ! checked . ok ) {
27+ fail (
28+ checked . reason === "non_local"
29+ ? `Refusing to send an API key to a non-local host: ${ checked . hostname } `
30+ : "APP_ORIGIN isn't a URL."
31+ ) ;
32+ }
33+ return checked . origin ;
34+ }
35+
2136const DEFAULT_RUN_SECONDS = 60 ;
2237const DEFAULT_FAIL_TASK = "slow-fail" ;
2338const DEFAULT_SUCCEED_TASK = "slow-succeed" ;
@@ -174,8 +189,6 @@ type RedisLike = {
174189
175190const ZADD_BATCH = 1_000 ;
176191
177- const LOCAL_HOSTS = new Set ( [ "localhost" , "127.0.0.1" , "::1" , "0.0.0.0" ] ) ;
178-
179192function envQueueKey ( organizationId : string , environmentId : string ) : string {
180193 return `engine:runqueue:{org:${ organizationId } }:env:${ environmentId } ` ;
181194}
@@ -195,7 +208,7 @@ async function openRedis(): Promise<RedisLike> {
195208 const port = Number (
196209 process . env . RUN_ENGINE_RUN_QUEUE_REDIS_PORT ?? process . env . REDIS_PORT ?? 6379
197210 ) ;
198- if ( ! LOCAL_HOSTS . has ( host ) ) {
211+ if ( ! isLocalHost ( host ) ) {
199212 fail ( `Refusing to stage Redis on a non-local host: ${ host } ` ) ;
200213 }
201214 const { createRedisClient } = await import ( "@internal/redis" ) ;
@@ -267,7 +280,7 @@ function clickhouse(): ClickHouse {
267280 }
268281 const parsed = new URL ( url ) ;
269282 // Never echo the URL: it carries credentials.
270- if ( ! LOCAL_HOSTS . has ( parsed . hostname ) ) {
283+ if ( ! isLocalHost ( parsed . hostname ) ) {
271284 fail ( `Refusing to run against a non-local ClickHouse host: ${ parsed . hostname } ` ) ;
272285 }
273286 parsed . searchParams . delete ( "secure" ) ;
@@ -448,7 +461,8 @@ async function runScenario(
448461 taskFlag : string | undefined
449462) {
450463 const taskId = taskFlag ?? ( kind === "fail" ? DEFAULT_FAIL_TASK : DEFAULT_SUCCEED_TASK ) ;
451- const response = await fetch ( `${ APP_ORIGIN } /api/v1/tasks/${ taskId } /trigger` , {
464+ const origin = appOrigin ( ) ;
465+ const response = await fetch ( `${ origin } /api/v1/tasks/${ taskId } /trigger` , {
452466 method : "POST" ,
453467 headers : {
454468 "content-type" : "application/json" ,
@@ -457,7 +471,7 @@ async function runScenario(
457471 body : JSON . stringify ( { payload : { seconds } } ) ,
458472 } ) . catch ( ( error : unknown ) => {
459473 fail (
460- `Could not reach ${ APP_ORIGIN } (${ error instanceof Error ? error . message : error } ). ` +
474+ `Could not reach ${ origin } (${ error instanceof Error ? error . message : error } ). ` +
461475 `Is the webapp running?`
462476 ) ;
463477 } ) ;
0 commit comments