feat(stack): run the complete native service graph - #6385
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d1515d4700
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c912c31e38
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3a0834d944
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5fe089ab55
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Automated review convergence checkpoint after three batched fix rounds:
The automated loop is now capped per AGENTS.md because new findings are primarily in code introduced by prior bot-driven rounds. Please provide human review, especially on whether Storage restart persistence should be folded into CLI-2141 before merge or tracked separately. |
| nativeRunService({ | ||
| name: "pgmeta", | ||
| command: `${opts.binPath}/bin/pgmeta`, | ||
| env: pgmetaEnv(opts), |
There was a problem hiding this comment.
🟠 Severity: HIGH
Native PgMeta is launched without PG_META_HOST; postgres-meta defaults that host to 0.0.0.0 (https://github.com/supabase/postgres-meta/blob/master/src/server/constants.ts). The newly enabled host process therefore exposes its unauthenticated schema and query API to LAN clients, bypassing the loopback API-proxy boundary and permitting database metadata reads or mutations.
Helpful? Add 👍 / 👎
💡 Fix Suggestion
Suggestion: Add PG_META_HOST: "127.0.0.1" to the returned object in the pgmetaEnv function (around line 32). This restricts the postgres-meta HTTP server to bind only on the loopback interface, consistent with the pattern used by other native services in this codebase (e.g., SERVER_HOST: "127.0.0.1" in storage.ts, HOSTNAME: "127.0.0.1" in studio.ts, MP_UI_BIND_ADDR: "127.0.0.1:..." in mailpit.ts). Without this, postgres-meta defaults to 0.0.0.0, exposing its unauthenticated schema/query API to all LAN clients and bypassing the loopback API-proxy boundary. The fix is: in pgmetaEnv, add PG_META_HOST: "127.0.0.1" alongside the other PG_META_* environment variables.
| const bootstrap = nativeRunService({ | ||
| name: "pooler-bootstrap", | ||
| command: `${opts.binPath}/bin/supavisor`, | ||
| args: ["eval", tenantScript({ ...opts, dbHost: "127.0.0.1" })], |
There was a problem hiding this comment.
🟠 Severity: HIGH
Native pooler bootstrap passes tenantId from stack configuration into supavisor eval as interpolated Elixir source. A crafted tenant ID can break out of the quoted external_id value and execute arbitrary Elixir or OS commands in the host process with the CLI user's privileges.
Helpful? Add 👍 / 👎
💡 Fix Suggestion
Suggestion: The root cause is in the tenantScript function (lines 82–94) where opts.tenantId (and opts.poolMode) are directly interpolated into an Elixir source string without escaping. A tenant ID containing " or \ can break out of the Elixir string literal and execute arbitrary Elixir code.
Two complementary fixes are needed:
-
Input validation guard (immediate, at the call site): Before calling
tenantScript, validate thattenantIdcontains only safe characters using an allowlist regex such as/^[a-zA-Z0-9._-]+$/. Throw an error early if the value fails the check. In the native path,poolModeis constrained by TypeScript's literal union type ("transaction" | "session") so it is safe at compile time, anddbHostis hardcoded to"127.0.0.1", sotenantIdis the primary injection vector. -
String escaping in
tenantScript(defense-in-depth, in the function at lines 82 and 94): Add an escape helper such asconst esc = (s: string) => s.replace(/\\/g, '\\\\').replace(/"/g, '\\"');and apply it to every string value interpolated inside Elixir double-quoted strings:"external_id" => "${esc(opts.tenantId)}"and"mode_type" => "${esc(opts.poolMode)}". Note that numeric values (dbPort,maxClientConn,defaultPoolSize) do not need escaping because they are not placed inside Elixir string literals.
⚠️ Experimental Feature: This code suggestion is automatically generated. Please review carefully.
| const bootstrap = nativeRunService({ | |
| name: "pooler-bootstrap", | |
| command: `${opts.binPath}/bin/supavisor`, | |
| args: ["eval", tenantScript({ ...opts, dbHost: "127.0.0.1" })], | |
| if (!/^[a-zA-Z0-9._-]+$/.test(opts.tenantId)) { | |
| throw new Error( | |
| `Pooler bootstrap: tenantId "${opts.tenantId}" contains characters unsafe for Elixir source interpolation`, | |
| ); | |
| } | |
| const bootstrap = nativeRunService({ | |
| name: "pooler-bootstrap", | |
| command: `${opts.binPath}/bin/supavisor`, | |
| args: ["eval", tenantScript({ ...opts, dbHost: "127.0.0.1" })], | |
| env, | |
| dependencies: [{ service: migrate.name, condition: "completed" }], | |
| restart: "no", | |
| }); |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 69acdd0e84
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const bootstrap = nativeRunService({ | ||
| name: "pooler-bootstrap", | ||
| command: `${opts.binPath}/bin/supavisor`, | ||
| args: ["eval", tenantScript({ ...opts, dbHost: "127.0.0.1" })], |
There was a problem hiding this comment.
Encode tenant IDs before building the bootstrap script
When a native caller supplies a pooler.tenantId containing an Elixir string metacharacter such as " or \, tenantScript inserts it verbatim into the quoted external_id literal passed here. PoolerConfig accepts an unrestricted string, so the bootstrap command then either fails to parse or creates a tenant with a different ID, preventing the native Pooler server from starting. Encode the value as a valid Elixir literal or pass it through the environment instead of interpolating it into source.
Useful? React with 👍 / 👎.
| const realtimeNativeHealthCheck = (port: number, tenantId: string): ServiceDef["healthCheck"] => | ||
| hostHttpHealthCheck(port, "/api/ping", { | ||
| ...stackHealthBudgets.realtime, | ||
| headers: { Host: tenantId }, |
There was a problem hiding this comment.
Send the tenant Host header in Node health probes
When the public Node entrypoint runs a native stack with Realtime enabled, FetchHttpClient ultimately uses Node's built-in fetch, which replaces a caller-supplied Host header with the URL authority. The Realtime probe therefore sends Host: 127.0.0.1:<port> instead of the tenant ID required by /api/ping, so Realtime never becomes healthy and stack readiness fails. The new header test avoids this behavior by replacing fetch with a node:http adapter; use such an adapter for this probe or otherwise ensure the actual Node transport preserves the tenant host.
Useful? React with 👍 / 👎.
Summary
Extends the strict native stack runtime from the Postgres/Auth/PostgREST core to the complete service graph using the frozen slim-services releases.
Adds native launch, configuration, lifecycle, and private companion ownership for Edge Runtime, Realtime, Storage/imgproxy, PgMeta/Studio, Analytics/Vector, Pooler, and Mailpit. Native logs remain supervisor-owned and isolated per stack, while the public package surface preserves eager, lazy, and explicit preparation closure semantics.
The representative consumer journey covers the public service graph and exact resource ownership. This change does not add per-service Docker fallback or absorb unrelated proxy hardening.