Add token refresh endpoints to agent server#2018
Conversation
Adds a `set_token` command (also aliased as `posthog/set_token`) that updates `GH_TOKEN` / `GITHUB_TOKEN` on the agent process, so Claude-based agents pick up a refreshed token without restart. Adds a localhost-only `POST /gh` route that runs an arbitrary `gh` CLI invocation with the agent's current env, giving isolated Codex sandboxes a way to apply the new token via a shell wrapper. Generated-By: PostHog Code Task-Id: 2cbfd9f1-a4ff-4d49-a526-1184b909a373
|
| }); | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
| const LOOPBACK_ADDRESSES = new Set([ | ||
| "127.0.0.1", | ||
| "::1", | ||
| "::ffff:127.0.0.1", | ||
| "localhost", | ||
| ]); | ||
|
|
||
| export function isLoopbackAddress(address: string | undefined): boolean { |
There was a problem hiding this comment.
isLoopbackAddress only recognises a four-value fixed set, not the full loopback range
IPv4 reserves the entire 127.0.0.0/8 subnet as loopback, and IPv4-mapped loopback in IPv6 covers ::ffff:127.0.0.0/104. The set currently contains only 127.0.0.1 and ::ffff:127.0.0.1, so a connection arriving on any other address in those ranges (e.g. 127.0.0.2, ::ffff:127.1.2.3) is silently rejected with 403. A safer check would be a proper prefix test for 127. and ::ffff:127..
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/agent/src/server/gh-exec.ts
Line: 88-100
Comment:
**`isLoopbackAddress` only recognises a four-value fixed set, not the full loopback range**
IPv4 reserves the entire `127.0.0.0/8` subnet as loopback, and IPv4-mapped loopback in IPv6 covers `::ffff:127.0.0.0/104`. The set currently contains only `127.0.0.1` and `::ffff:127.0.0.1`, so a connection arriving on any other address in those ranges (e.g. `127.0.0.2`, `::ffff:127.1.2.3`) is silently rejected with 403. A safer check would be a proper prefix test for `127.` and `::ffff:127.`.
How can I resolve this? If you propose a fix, please make it concise.- isLoopbackAddress: match the full 127.0.0.0/8 range (and the IPv4-mapped ::ffff:127.0.0.0/104 prefix) instead of a fixed four-value set, so legitimate loopback connections on 127.0.0.x are not silently rejected with 403. - Parameterise the duplicated /gh 400-validation tests and the two set_token command tests with it.each to remove identical scaffolding. Generated-By: PostHog Code Task-Id: 2cbfd9f1-a4ff-4d49-a526-1184b909a373
|
Make sure to not allow the caller to specify the binary. |
Drops the binary option from runGh's public type so callers — including the /gh HTTP route — cannot specify which binary is executed. The route already only forwards args/cwd/timeoutMs from the body schema, but removing the option makes that guarantee structural rather than incidental. Tests now exercise the underlying spawnAndCollect helper directly when they need to inject a stand-in binary. Generated-By: PostHog Code Task-Id: 2cbfd9f1-a4ff-4d49-a526-1184b909a373
Replaces the direct gh-bin invocation in the sandbox `gh` wrapper with a curl call to the agent-server's loopback `/gh` endpoint, so gh runs with the agent-server's freshly-rotated GH_TOKEN instead of whatever token was baked into this child process at spawn time. Pairs with the periodic `posthog/set_token` refresh and the agent-server endpoint added in PostHog/code#2018. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
runGh now reads POSTHOG_GH_BINARY from the server process env, falling back to "gh". Lets dev and test setups (where `gh` isn't on PATH or a stand-in is needed) point the /gh route at a different binary without changing code. The HTTP body schema still strips unknowns, so untrusted clients can't pick the binary — only the operator running the server. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
scripts/dev-server.ts boots AgentServer with msw mocks for the PostHog API, generates an ephemeral RSA keypair, and stamps a fake session so /command's session guard passes — enough surface to exercise /health, /gh, and the new set_token route from curl without spinning up a real agent runtime or backend. Prints a copy-paste curl playbook on startup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
joshsny
left a comment
There was a problem hiding this comment.
interestring trick to get this to work, lgtm from the code side, worth testing this properly in a modal sandbox with the modal docker setup before shipping it
|
|
||
| return new Promise<GhExecResult>((resolve, reject) => { | ||
| const child = spawn(binary, args, { | ||
| cwd: options.cwd, |
There was a problem hiding this comment.
do we really need to put all envs? we know what gh needs from us here right? would like to avoid subprocesses seeing everything if not strictly needed
Summary
set_tokencommand (also aliased asposthog/set_token) to the agent server that updatesGH_TOKENandGITHUB_TOKENon the agent process so Claude-based agents pick up a refreshed token without restart.POST /ghroute that runs an arbitraryghCLI invocation using the agent's current env. Codex-based agents run in an isolated sandbox, so a shell-script wrapper hits this endpoint to apply the new token throughgh.gh-exechelper (runGh+isLoopbackAddress) that spawnsghdirectly (no shell), inherits the agent'sprocess.env, and supports timeouts. The/ghroute reuses it; tests exercise both happy/error paths.Test plan
pnpm --filter agent test— full agent server suite passes (149/149), including 15 newgh-exectests and 6 newagent-servertests covering bothset_tokenaliases,/ghbody validation, and that/ghdoes not require JWT.pnpm --filter agent typecheck— clean.POST /commandwith{"command":"set_token","params":{"token":"…"}}— verifyGH_TOKENupdates in the agent process.POST /ghwith the wrapper script — verifyghruns with the new token.