Repository navigation
fix(env): serve pgweb and db-mcp only under a path each gateway deploy draws - #455
earakely-scale wants to merge 2 commits into
Conversation
…y draws pgweb and db-mcp hold the servicedb's superuser DSN and take any SQL. Their ports are published, on a remote VM on every interface and through public tunnels, and the agent's website browser shares their compose network, so the agent, or anyone with the tunnel URL, could run SQL around the gateway. Each gateway deploy now draws a random path for them, and the URLs it records carry it: - pgweb reads it from PGWEB_URL_PREFIX, in the compose file and in container mode alike, and answers 404 outside it. - db-mcp serves MCP at /<path>/mcp on the VM path. postgres-mcp has no option for it, so compose starts it through a two-line shim that sets FastMCP's streamable_http_path; it runs on the db-mcp images already promoted. Container mode, whose entrypoint can't be changed, keeps /mcp. - Without a path, as every render outside a deploy has (exports), both serve at their roots, as before. - The logged compose redacts both settings, the deploy logs the URLs and the consoles' own output with the path masked, and run_code hands a script on the env's host its DB MCP URL with the path, as it does its MCP URL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| else LocalPostgresStateProvider() | ||
| ) | ||
| if isinstance(self._state_provider, LocalPostgresStateProvider): | ||
| self._state_provider.console_path = secrets.token_urlsafe(18) |
There was a problem hiding this comment.
The new secrets.token_urlsafe(18) leaves the path's random size as an unexplained inline number. The repository requires magic numbers to live in descriptively named class or instance variables. Move 18 into a named variable that makes its byte unit clear. This repository requirement must be satisfied before merging.
Rule Used: Store magic numbers as class or instance variables with descriptive names rather than using them inline in the code. (source)
Learned From
scaleapi/scaleapi#126388
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/providers/env_providers/env_gateway_provider.py
Line: 1377
Comment:
**Token size lacks a name**
The new `secrets.token_urlsafe(18)` leaves the path's random size as an unexplained inline number. The repository requires magic numbers to live in descriptively named class or instance variables. Move `18` into a named variable that makes its byte unit clear. This repository requirement must be satisfied before merging.
**Rule Used:** Store magic numbers as class or instance variables with descriptive names rather than using them inline in the code. ([source](https://app.greptile.com/-/switch-tenant?tenant=scale-ai&next=%2Fcustom-context%3Fmemory%3D002e0051-41ad-46c1-9098-47433c580150))
**Learned From**
[scaleapi/scaleapi#126388](https://github.com/scaleapi/scaleapi/pull/126388)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
Fixed in 80b2e10: _CONSOLE_PATH_BYTES = 18, next to the module's other constants.
A caller's existing VM may lack the pgweb tunnel; masking the log line then read None. The path's size gets a name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Closing unmerged. Instead of a secret path, the SQL consoles will move behind the gateway and be gated by the operator credential the gateway work adds. The branch stays for reference. |
What
Each gateway deploy now draws a random path for pgweb and db-mcp, and the URLs it records carry that path.
PGWEB_URL_PREFIX, in compose and in container mode. It answers 404 outside the path./<path>/mcpon the VM path. postgres-mcp has no option for its path, so compose starts it through a two-line shim that sets FastMCP'sstreamable_http_path.default-dbv8 has the same build digest as main, so the shim runs on the images prod uses today./mcpthere.LocalPostgresStateProvider.console_pathdefaults to None, and_launchdraws a path for each deploy attempt. Every other render, such as the SDK's exports, is byte-identical to today.PGWEB_URL_PREFIXandDB_MCP_PATH.run_codegives a script on the env's hostinput["env"]["db_mcp_url"], with the path, as it already givesmcp_url.Why
Both consoles hold the servicedb's superuser DSN and accept any SQL.
So the agent, or anyone with a tunnel URL, could run SQL around the gateway. Measured on main: the browser's same-origin
POST /api/queryreturned rows, by name and by the VM's host IP.Moving the browser onto its own network was tried first. A container on another network still reaches a port published on all interfaces through its gateway IP, docker0 or the VM IP, so that would have left every prod VM open. The path closes all three routes: by name, by host address and through the tunnel.
Design and full test record: https://claude.ai/artifact/L6Hm3t52JuTkRzxKYTgwNG
Compatibility
A consumer audit covered 145 sites across this repo, the Scale monorepo and synthetic-pipelines. 113 use the recorded URL as given and keep working.
Two consumers rebuild the URL from a port. They get fixes in their own PRs, and those fixes work with old and new URLs alike:
qc_e2e.Records from older deploys keep their old shape, and every consumer reads what is recorded.
Not covered
/triggersexecutor, which the agent can make POST to any URL onenv-network. Without the path, the consoles answer it 404 too; closing that request source needs the gateway control token.Tests
Unit: compose renders with and without a path, the container spec, container-mode URLs, the redaction, and
run_code's DB MCP URL. All fail on main. The unit suite passes (11,567).Integration: the website test now checks that the browser gets
not foundfrom both consoles, and that the operator's recorded URLs work while the bare hosts return 404.EC2 box: the full gateway integration suite (27 passed) and the env, artifact and bundle suites (81 passed).
Chaos run on EC2, main vs this branch. It covered:
/api/query, db-mcp tools andexecute_sql, directly and through a path-prefix proxy;Every route closes and every legitimate flow keeps working. The second box run caught a regression: the local provider rewrites
/apppaths, which broke the shim's first form. It is fixed and covered.Real Modal:
modal_vm: the browser is refused by name and via the VM's host IPs, and everything the operator uses works at the recorded URLs.create_containerwith onlyPGWEB_URL_PREFIX: 404 outside the path, 200 inside it.🤖 Generated with Claude Code


Confidence Score: 5/5
The follow-up changes appear safe to merge; both previous findings are fixed.Summary
Gateway deploys give SQL consoles a random path and record that path in their URLs.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Gateway deploy draws a random path] --> B{Deployment mode} B -->|VM| C[pgweb and db-mcp use the path] B -->|Containers| D[pgweb uses the path; db-mcp keeps /mcp] C --> E[Record console URLs] D --> E E --> F[Give run_code the DB MCP URL] A --> G[Mask the path in deploy logs]Reviews (2) · Last reviewed commit: "fix(env): log a deploy's console URLs wh..." · Reviewed by Greptile