Skip to content

Guard CLI bundle upload against oversized and out-of-app paths#7542

Draft
isaacroldan wants to merge 1 commit into
mainfrom
05-13-cli_bundle_guard_size_and_path
Draft

Guard CLI bundle upload against oversized and out-of-app paths#7542
isaacroldan wants to merge 1 commit into
mainfrom
05-13-cli_bundle_guard_size_and_path

Conversation

@isaacroldan
Copy link
Copy Markdown
Contributor

@isaacroldan isaacroldan commented May 13, 2026

WHY are these changes introduced?

Follow-up from the Slack discussion in #app-management around uploaded bundle size (thread). Today the CLI has no guard rails on the asset zip we upload to GCS: an asset path pointing outside the app folder (e.g. source = "../../" or an absolute home directory) silently copies whatever it resolves to, and the resulting bundle is then uploaded regardless of size. Josh confirmed a 2GB end-to-end upload, with the byproduct that a failed deploy still leaves a giant zip in .shopify/.

Server-side enforcement (#713307, capping ProcessBundle at 100MB) is the security boundary. This PR adds the CLI-side fail-fast for the accidental-misuse cases so developers don't OOM their own machine or wait through a multi-GB upload before being told no.

WHAT is this pull request doing?

Two guards in the bundle pipeline:

  1. Asset paths must resolve inside the app directory. include_assets entries (configKey, static, pattern) now reject sources that resolve outside the app folder (where shopify.app.toml lives). Sibling-extension paths still work (the boundary is the app, not the extension). Implemented via a small assertPathWithinAppDir helper plus a threaded appDirectory param through the three entry handlers and include-assets-step.ts.

  2. uploadToGCS aborts when the compressed bundle exceeds 100MB. Single chokepoint covers both deploy (services/deploy/upload.ts) and dev session (services/dev/processes/dev-session/dev-session.ts). The cap matches the new server-side check so the CLI and server agree on the limit. Error message points the developer at their asset config.

Out of scope on purpose: file-count limits, streaming the upload, and any opt-in GCS-side header — those were debated in the thread but defer cleanly.

How to test your changes?

Unit tests cover both guards:

  • packages/app/src/cli/services/build/steps/include-assets/assert-path-within-app.test.ts
  • packages/app/src/cli/services/build/steps/include-assets/*.test.ts (existing tests adjusted; behaviour preserved when paths stay inside the app dir)
  • packages/app/src/cli/services/bundle.test.ts (new uploadToGCS describe block — happy path + 101MB rejection)

Manual repro of the path bound: in any app, set an asset entry to source = "../../" or tools = "/Users/me/some/dir" and run shopify app build/deploy — you should get a clear Asset path '...' resolves outside the app directory error instead of a silent home-directory copy.

Manual repro of the size guard: temporarily lower MAX_BUNDLE_SIZE_MB to 1 in bundle.ts, then run deploy — the CLI should abort before the GCS PUT.

Post-release steps

None.

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows) — path check uses relativePath from cli-kit which normalises both POSIX and Windows separators
  • I've considered possible documentation changes — no public flag/config surface changed; the only new behaviour is a fail-fast error that didn't have docs before
  • I've considered analytics changes to measure impact — not adding metrics; if we want a counter for "rejected oversized bundle" we can add it in a follow-up
  • Added a changeset (patch bump for @shopify/app)

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@github-actions github-actions Bot added the Area: @shopify/app @shopify/app package issues label May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: @shopify/app @shopify/app package issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant