Skip to content

feat(stack): run the complete native service graph - #6385

Open
jgoux wants to merge 24 commits into
juliengoux/cli-2121-stack-qualify-the-native-postgres-auth-and-postgrest-corefrom
juliengoux/cli-2141-stack-run-the-remaining-native-service-graph-from-slim
Open

feat(stack): run the complete native service graph#6385
jgoux wants to merge 24 commits into
juliengoux/cli-2121-stack-qualify-the-native-postgres-auth-and-postgrest-corefrom
juliengoux/cli-2141-stack-run-the-remaining-native-service-graph-from-slim

Conversation

@jgoux

@jgoux jgoux commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

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.

@jgoux
jgoux requested a review from a team as a code owner August 28, 2026 18:01
Comment thread packages/stack/src/services/imgproxy.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/stack/src/StackBuilder.ts
Comment thread packages/stack/src/ServiceCatalog.ts Outdated
Comment thread packages/stack/src/services/analytics.ts Outdated
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 29, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-29T15:49:36.446863Z 69acdd0 New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Comment thread packages/stack/src/services/pooler.ts
Comment thread packages/stack/src/ServiceCatalog.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/stack/src/ServiceCatalog.ts Outdated
Comment thread packages/stack/src/versions.ts
Comment thread packages/stack/src/services/imgproxy.ts
Comment thread packages/stack/src/services/realtime.ts
Comment thread packages/stack/vitest.config.ts Outdated
Comment thread packages/stack/src/services/analytics.ts
Comment thread packages/stack/src/services/realtime.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/stack/src/PortCatalog.ts
Comment thread packages/stack/src/managed/document.ts
Comment thread packages/stack/src/services/edge-runtime.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/stack/src/services/storage.ts
Comment thread apps/cli/src/next/commands/services/services.handler.ts
Comment thread apps/cli/src/next/commands/link/link.handler.ts
@jgoux

jgoux commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Automated review convergence checkpoint after three batched fix rounds:

  • Fixed the in-scope, reproduced findings through 69acdd0, including runtime-specific version planning, normal integration parallelism, Analytics loopback binding, and the CliConfig Pooler-port projection.
  • Deferred direct-listener/proxy confinement that the frozen runtimes cannot currently express (Pooler and Realtime), plus coordinated imgproxy hardening, to CLI-2227. Edge Runtime loopback binding belongs with that same direct-listener audit rather than another isolated patch.
  • Reproduced the Storage cleanup concern: the child supervisor currently runs configured cleanup actions on requested shutdown as well as owner loss, so auto-managed Storage data can be removed on restart. This is a valid lifecycle question and may be a merge blocker; it needs a human scope decision rather than a fourth automated patch round.
  • Fresh-stack stack services runtime selection and partial linked-version fallback are CLI-consumer semantics outside the authoritative CLI-2141 public @supabase/stack scope. They arose in code expanded during the previous review round and are deferred for separate CLI follow-up.
  • Rejected migration support for the unreleased managed db.pooler.port key per the explicit no-backward-compatibility direction.

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),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 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.

Comment on lines +179 to +182
const bootstrap = nativeRunService({
name: "pooler-bootstrap",
command: `${opts.binPath}/bin/supavisor`,
args: ["eval", tenantScript({ ...opts, dbHost: "127.0.0.1" })],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 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:

  1. Input validation guard (immediate, at the call site): Before calling tenantScript, validate that tenantId contains 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, poolMode is constrained by TypeScript's literal union type ("transaction" | "session") so it is safe at compile time, and dbHost is hardcoded to "127.0.0.1", so tenantId is the primary injection vector.

  2. String escaping in tenantScript (defense-in-depth, in the function at lines 82 and 94): Add an escape helper such as const 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.

Suggested change
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",
});

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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" })],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant