Skip to content

fix(cli): follow symlinks in function source directories during deploy - #6087

Draft
avallete wants to merge 2 commits into
developfrom
claude/slack-thread-investigation-wdymqd
Draft

fix(cli): follow symlinks in function source directories during deploy#6087
avallete wants to merge 2 commits into
developfrom
claude/slack-thread-investigation-wdymqd

Conversation

@avallete

@avallete avallete commented Aug 5, 2026

Copy link
Copy Markdown
Member

Summary

Fixes a regression where symlinked function source directories (or the supabase/functions directory itself) whose targets lie outside the git root were silently skipped during deploy, causing the API to reject the request with "Entrypoint path does not exist".

The Go CLI follows symlinks unconditionally when walking function sources. The TypeScript implementation was enforcing a git-root containment boundary that excluded symlink targets, even though the uploaded file names and metadata paths remained anchored inside the workdir.

The fix widens the containment boundary to include the real (symlink-resolved) paths of:

  • The supabase/functions directory
  • Each function's entrypoint directory

This mirrors the existing resolveImportMapAllowedRoots pattern and restores parity with Go's behavior.

Changes

  • apps/cli/src/shared/functions/deploy.ts: Added withRealSourceDirs() helper to expand containment roots with the real paths of function source directories. Updated writeSourceDeployForm() and buildDockerBinds() to use this helper when validating asset paths.
  • apps/cli/src/legacy/commands/functions/deploy/deploy.integration.test.ts: Added integration test covering symlinked function directories outside the git root, verifying that sources upload correctly with workdir-anchored names.
  • apps/cli/src/legacy/commands/functions/deploy/SIDE_EFFECTS.md: Updated documentation to explain the expanded containment boundary.

Linked issue

  • The linked issue is open and carries the open-for-contribution label (or I'm a Supabase maintainer).

Checklist

  • The PR title follows Conventional Commits (e.g. fix(cli): …).
  • Tests added or updated for the change.
  • pnpm check:all and pnpm test pass for the workspace(s) I touched.

https://claude.ai/code/session_0142Gar1VCPkaW3jWBNxg9SP

…the git root (INC-699)

An API deploy whose supabase/functions dir (or a single function dir) is a
symlink pointing outside the nearest git root uploaded no file parts at all:
the realpath-based containment boundary silently skipped the entrypoint with
only a stderr WARN ("Skipping import path outside source root"), the request
went out metadata-only, and the Management API rejected it with 400
"Entrypoint path does not exist - .../source/supabase/functions/<slug>/index.ts"
(reported in the INC-699 incident channel on 2026-08-05, SupabaseCLI/2.111.0).

The Go CLI follows symlinks unconditionally (pkg/function/deno.go "Assume no
file is symlinked"), so the skip was a TS-only regression introduced with the
#5755 containment boundary. Widen the boundary with the real (symlink-resolved)
directories of supabase/functions and the function entrypoint, mirroring the
existing resolveImportMapAllowedRoots precedent for out-of-root import maps.
Uploaded names and recorded metadata stay anchored at the workdir per CLI-1985;
the same widening applies to the Docker bundler's module roots so symlinked
sources get their read-only binds.

Non-symlinked layouts are byte-for-byte unchanged, and the Go-parity `..`-name
rejection (hasParentPathSegment) still guards genuinely escaping names.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0142Gar1VCPkaW3jWBNxg9SP
@avallete
avallete requested a review from a team as a code owner August 5, 2026 14:06
@avallete
avallete marked this pull request as draft August 5, 2026 14:08
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Supabase CLI preview

npx --yes https://pkg.pr.new/supabase/cli/supabase@ac3c117407f387772cf2d4d7a450bac96ffb245f

Preview package for commit ac3c117.

@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: ac3c117407

ℹ️ 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 on lines +1213 to +1214
[hostFunctionsDir, dirname(resolve(config.entrypoint))],
);

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 Include symlink roots when binding static files

When a single function directory is symlinked outside the git root and the function declares static_files, this widened root list is only used for moduleRoots. The later static-file loop still goes through appendProjectBind, which checks only [realSourceRoot], so real paths under the symlink target are silently omitted from the Docker -v binds while the bundler still receives --static for the symlinked path. That leaves --use-docker deploys and serve/start unable to read those assets even though Go follows the symlink; use the same widened asset roots for static-file binds too.

AGENTS.md reference: apps/cli/AGENTS.md:L247-L257

Useful? React with 👍 / 👎.

@avallete avallete closed this Aug 6, 2026
@avallete avallete reopened this Aug 6, 2026
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.

2 participants