Files
shockbot/utils/apiUrl.ts
T
Colin McDonnell b0274e3265 local proxy-key testing via x-dev-repo bypass (#629)
* local proxy-key testing via x-dev-repo bypass

`pnpm play` previously couldn't exercise the proxy/router/oss code path
— `resolveProxyModel` early-exits without OIDC credentials, and
`mintProxyKey` always sends an OIDC bearer to `/api/proxy-token`. since
GitHub Actions OIDC only exists in real workflow runs, billing flows
(auto-reload, balance gates, key rotation, OSS subsidy) had no local
feedback loop.

a server-side dev bypass already exists at `app/api/proxy-token/route.ts`
that accepts an `x-dev-repo: owner/repo` header instead of an OIDC bearer
when `NODE_ENV === "development"`. wire the action side so it sends that
header when there are no OIDC credentials AND `API_URL` resolves to
localhost (i.e. the developer is talking to their own `pnpm dev`
server). production is unreachable through this path because vercel
never sets `NODE_ENV=development`.

document the affordance in `wiki/action-tests.md` so the next person
doesn't have to re-discover it (the server bypass had been sitting
there undocumented since the WIP billing rewrite).

verified end-to-end: `PLAY_LOCAL=1 GITHUB_REPOSITORY=pullfrog/app
API_URL=http://localhost:3100 pnpm play …` now logs `» proxy: dev
bypass (x-dev-repo) for pullfrog/app` → `» proxy: router → openrouter/
anthropic/claude-opus-4.7` → `» model: …(proxy)`, mints a real
OpenRouter key against the dev DB, and the agent runs through the
proxy.

* wiki: cross-reference dev proxy-key affordance from main/e2e/stripe

action-tests.md already documents the localhost+x-dev-repo path; mention
it from the natural discovery points so the next person finds it without
spelunking through git history again:

- main.md: resolveProxyModel row in the dependencies table notes the
  two auth paths (OIDC bearer in prod, x-dev-repo in dev).
- e2e-testing.md: "When to use this" calls out the lighter-weight
  alternative for proxy-only changes.
- stripe.md: new "Loop including the action" subsection in the Dev
  workflow section, alongside the existing dev-script and cron-endpoint
  loops.
2026-05-08 23:35:58 +00:00

43 lines
1.3 KiB
TypeScript

import { log } from "./cli.ts";
function isLocalUrl(url: URL): boolean {
return url.hostname === "localhost" || url.hostname === "127.0.0.1";
}
/**
* resolve the Pullfrog API base URL.
*
* in the action: API_URL is not explicitly set, so this falls back to https://pullfrog.com.
* in local dev: API_URL=http://localhost:3000 (from .env).
*
* enforces https:// for non-local URLs to prevent cleartext credential transmission.
*/
export function getApiUrl(): string {
const raw = process.env.API_URL || "https://pullfrog.com";
const parsed = new URL(raw);
if (parsed.protocol !== "https:" && !isLocalUrl(parsed)) {
throw new Error(
`API_URL must use https:// (got ${parsed.protocol}). only localhost is exempt.`
);
}
log.debug(`resolved API_URL: ${raw}`);
return raw;
}
/**
* true when the action is configured to talk to a localhost API server (i.e.
* `pnpm dev` running on the developer's box). signals we can use dev-only
* affordances like the `x-dev-repo` proxy-token bypass — the corresponding
* server-side dev gates (`NODE_ENV === "development"`) ensure these paths
* never activate against prod regardless of what the action does.
*/
export function isLocalApiUrl(): boolean {
try {
return isLocalUrl(new URL(getApiUrl()));
} catch {
return false;
}
}