Skip to content

Commit 95c0116

Browse files
committed
chore(perf): add gateway perf runner
1 parent 0c229fe commit 95c0116

4 files changed

Lines changed: 2354 additions & 0 deletions

File tree

scripts/dev/gateway-perf-guard.sh

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
5+
cd "$ROOT_DIR"
6+
7+
PERF_ENV_PATH="${CODEX_POOLER_PERF_ENV:-tmp/gateway-perf/bootstrap/perf.env}"
8+
PERF_POOL_SLUG="${CODEX_POOLER_PERF_POOL_SLUG:-dev-perf-pool}"
9+
10+
usage() {
11+
cat <<'EOF'
12+
Usage: scripts/dev/gateway-perf-guard.sh --check
13+
14+
Validates gateway performance upstream targets before traffic starts. The guard
15+
checks URL hosts from CODEX_POOLER_PERF_* environment variables and DB-backed
16+
metadata for the dev perf Pool.
17+
18+
Allowed hosts:
19+
localhost, 127.0.0.1, ::1, *.svc, *.svc.cluster.local, CODEX_POOLER_PERF_ALLOW_HOSTS
20+
EOF
21+
}
22+
23+
fail() {
24+
printf 'error: %s\n' "$*" >&2
25+
exit 1
26+
}
27+
28+
load_perf_env() {
29+
if [[ -f "$PERF_ENV_PATH" ]]; then
30+
set -a
31+
source "$PERF_ENV_PATH"
32+
set +a
33+
fi
34+
35+
PERF_POOL_SLUG="${CODEX_POOLER_PERF_POOL_SLUG:-$PERF_POOL_SLUG}"
36+
}
37+
38+
env_targets() {
39+
local name value
40+
for name in \
41+
CODEX_POOLER_PERF_HTTP_URL \
42+
CODEX_POOLER_PERF_BASE_URL \
43+
CODEX_POOLER_PERF_UPSTREAM_BASE_URL \
44+
CODEX_POOLER_PERF_WEBSOCKET_URL \
45+
CODEX_POOLER_PERF_WS_URL
46+
do
47+
value="${!name:-}"
48+
if [[ -n "$value" ]]; then
49+
printf 'env:%s\t%s\n' "$name" "$value"
50+
fi
51+
done
52+
}
53+
54+
db_targets() {
55+
MIX_ENV="${MIX_ENV:-dev}" CODEX_POOLER_PERF_POOL_SLUG="$PERF_POOL_SLUG" mix run -e '
56+
import Ecto.Query
57+
58+
alias CodexPooler.Pools.Pool
59+
alias CodexPooler.Repo
60+
alias CodexPooler.Upstreams.Schemas.{PoolUpstreamAssignment, UpstreamIdentity}
61+
62+
pool_slug = System.fetch_env!("CODEX_POOLER_PERF_POOL_SLUG")
63+
http_keys = ~w(base_url api_base_url upstream_base_url cluster_base_url usage_base_url codex_usage_base_url)
64+
websocket_keys = ~w(websocket_url ws_url cluster_websocket_url)
65+
66+
rows =
67+
Repo.all(
68+
from assignment in PoolUpstreamAssignment,
69+
join: pool in Pool,
70+
on: pool.id == assignment.pool_id,
71+
join: identity in UpstreamIdentity,
72+
on: identity.id == assignment.upstream_identity_id,
73+
where: pool.slug == ^pool_slug and assignment.status != "deleted",
74+
select: {assignment.assignment_label, assignment.metadata, identity.metadata}
75+
)
76+
77+
for {label, assignment_metadata, identity_metadata} <- rows,
78+
{scope, metadata} <- [{"assignment", assignment_metadata || %{}}, {"identity", identity_metadata || %{}}],
79+
{kind, keys} <- [{"http", http_keys}, {"websocket", websocket_keys}],
80+
key <- keys,
81+
url = Map.get(metadata, key),
82+
is_binary(url) and String.trim(url) != "" do
83+
IO.puts(["db:", scope, ":", label, ":", kind, ":", key, "\t", url])
84+
end
85+
'
86+
}
87+
88+
append_db_targets() {
89+
if [[ "${CODEX_POOLER_PERF_GUARD_DB:-1}" == "0" ]]; then
90+
return 0
91+
fi
92+
93+
db_targets
94+
}
95+
96+
validate_targets() {
97+
local target_file allowed_hosts
98+
target_file="$(mktemp)"
99+
trap 'rm -f "${target_file:-}"' RETURN
100+
101+
env_targets > "$target_file"
102+
append_db_targets >> "$target_file"
103+
104+
allowed_hosts="${CODEX_POOLER_PERF_ALLOW_HOSTS:-}"
105+
106+
python3 - "$target_file" "$allowed_hosts" <<'PY'
107+
import ipaddress
108+
import sys
109+
from pathlib import Path
110+
from urllib.parse import urlparse
111+
112+
target_path = Path(sys.argv[1])
113+
extra_hosts = {host.strip().lower() for host in sys.argv[2].split(",") if host.strip()}
114+
allowed_fixed = {"localhost", "127.0.0.1", "::1"}
115+
allowed_schemes = {"http", "https", "ws", "wss"}
116+
violations = []
117+
checked = 0
118+
119+
def allowed_host(host):
120+
normalized = host.strip("[]").lower()
121+
if normalized in allowed_fixed or normalized in extra_hosts:
122+
return True
123+
if normalized.endswith(".svc") or normalized.endswith(".svc.cluster.local"):
124+
return True
125+
try:
126+
return ipaddress.ip_address(normalized).is_loopback
127+
except ValueError:
128+
return False
129+
130+
for raw_line in target_path.read_text().splitlines():
131+
line = raw_line.strip()
132+
if not line or "\t" not in line:
133+
continue
134+
source, url = line.split("\t", 1)
135+
source = source.strip()
136+
if not (source.startswith("env:") or source.startswith("db:")):
137+
continue
138+
parsed = urlparse(url.strip())
139+
checked += 1
140+
if parsed.scheme not in allowed_schemes or not parsed.hostname:
141+
violations.append((source, "invalid-url", url))
142+
continue
143+
if not allowed_host(parsed.hostname):
144+
violations.append((source, parsed.hostname, url))
145+
146+
if violations:
147+
print(f"gateway perf guard failed: {len(violations)} unsafe target(s)", file=sys.stderr)
148+
for source, host, url in violations:
149+
print(f"unsafe target source={source} host={host} url={url}", file=sys.stderr)
150+
sys.exit(1)
151+
152+
print(f"gateway perf guard ok: checked {checked} target(s)")
153+
PY
154+
}
155+
156+
main() {
157+
case "${1:-}" in
158+
--check)
159+
load_perf_env
160+
validate_targets
161+
;;
162+
--help|-h)
163+
usage
164+
;;
165+
*)
166+
usage >&2
167+
exit 1
168+
;;
169+
esac
170+
}
171+
172+
main "$@"

0 commit comments

Comments
 (0)