Validate extensions.targeting assets value in include-assets-step#7504
Validate extensions.targeting assets value in include-assets-step#7504JoshuaWhite1 wants to merge 1 commit into
Conversation
64c1e3a to
6ef723c
Compare
6ef723c to
6feec59
Compare
| for (const entry of config.inclusions) { | ||
| if (entry.type !== 'configKey') continue | ||
|
|
||
| if (entry.key === 'extension_points[].assets') { |
There was a problem hiding this comment.
We can't hard code checks like this. These steps are generic. Isn't there a better place for this inside copyConfigKeyEntry? If the trimmed value configured is an empty string we should fail early with an error.
6feec59 to
92326e8
Compare
|
| Changeset | Package |
|---|---|
thin-webs-notice.md |
'@shopify/plugin-did-you-mean': major |
thin-webs-notice.md |
'@shopify/plugin-cloudflare': major |
thin-webs-notice.md |
'@shopify/create-app': major |
thin-webs-notice.md |
'@shopify/cli-kit': major |
thin-webs-notice.md |
'@shopify/store': major |
thin-webs-notice.md |
'@shopify/theme': major |
thin-webs-notice.md |
'@shopify/app': major |
thin-webs-notice.md |
'@shopify/cli': major |
thin-webs-notice.md |
'@shopify/e2e': major |
There was a problem hiding this comment.
Pull request overview
This PR adds early validation for configKey-resolved include-assets paths (notably extension_points[].assets) to fail builds before copying/bundling when an extension config points to an empty, root, or out-of-root assets path. This prevents expensive/incorrect bundling attempts and surfaces a more direct error to the developer.
Changes:
- Add an up-front guard in
copyConfigKeyEntryto reject empty/whitespace values and paths that resolve to the extension root or outside it. - Add a focused test suite covering the new guard behavior (empty, whitespace, root-ish values, parent traversal, and allowed
..round-trip). - Minor formatting change in
include-assets-step.ts(no behavior change).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/app/src/cli/services/build/steps/include-assets/copy-config-key-entry.ts | Adds validation for configKey-derived paths using resolvePath + isSubpath before copying. |
| packages/app/src/cli/services/build/steps/include-assets/copy-config-key-entry.test.ts | Adds tests covering rejection/acceptance cases for the new value guard. |
| packages/app/src/cli/services/build/steps/include-assets-step.ts | Minor whitespace-only change. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const trimmed = sourcePath.trim() | ||
| if (trimmed === '') { | ||
| throw new Error(`'${fieldName}' can't be empty.`) | ||
| } | ||
| const resolved = resolvePath(baseDir, trimmed) | ||
| if (resolved === baseDir || !isSubpath(baseDir, resolved)) { | ||
| throw new Error(`'${fieldName}' is not a valid path: '${sourcePath}'`) | ||
| } |

WHY are these changes introduced?
closes https://github.com/shop/issues-admin-extensibility/issues/2521
When a developer sets an invalid assets value in [[extensions.targeting]] (empty string, ., ./, ../foo, etc.), the CLI currently builds the extension, compresses the bundle, and uploads it to GCS before the server rejects the deployment. When we pivoted to the extensions approach for hosted apps, we lost the contract validations from the admin module. That included: empty static_root (now called assets), length limit of 80 char, root path
./,., and parent directories like../.The app will still currently fail, but with an incorrect error message, and further downstream. i.e. defining assets =
./, it is attempting to upload the entire project directory which contains node modules and fails the file limit validation:WHAT is this pull request doing?
Adds a build-time guard in the include_assets step that validates assets values before bundling. Specifically:
The guard fires before copyConfigKeyEntry runs, so a misconfigured value short-circuits the build instead of producing a bundle that the server later rejects.
How to test your changes?
shopify app init --template https://github.com/Shopify/shopify-app-template-extension-onlyassetsvalue underextensions.targetinginextensions/app-home/shopify.extension.toml../../shopify app dev+shopify app deployin your local CLI, pointing to your app template:SHOPIFY_CLI_NEVER_USE_PARTNERS_API=1 SHOPIFY_SERVICE_ENV=local pnpm run shopify app dev --path="<PATH_TO_APP>"assetsvalue in your toml back to valid casesassets./assetsConsiderations
Considered applying this in two alternative layers:
cli/models/extensions/schemas.tsassets: zod.string().optional()Checklist
patchfor bug fixes ·minorfor new features ·majorfor breaking changes) and added a changeset withpnpm changeset add