Skip to content

Scan extension and web directories outside the app directory - #8767

Merged
jek merged 1 commit into
app-security/nested-app-configsfrom
app-security/extension-directories
Oct 6, 2026
Merged

jek merged 1 commit into
app-security/nested-app-configsfrom
app-security/extension-directories

Conversation

@jek

@jek jek commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

WHY are these changes introduced?

The selected app configuration file can point extension_directories and web_directories outside the app directory, for example ../shared-extensions/*. dev and deploy load those extensions and webs as part of the app, but app security check only scanned the app directory, so their files were skipped unless they were passed with --include-dir.

WHAT is this pull request doing?

  • Scans the directory of each extension and web TOML that the selected configuration file's globs match, when it's outside the app directory, the same way as an --include-dir directory. The matching is the CLI loader's own (extensionFilesForConfig and webFilesForConfig), so only module directories are added, not every directory a glob starts from. A glob that matches no TOML adds nothing.
  • Adds nothing for an absolute entry, since the CLI never loads anything from one.
  • Leaves out a directory reached through a symbolic link outside the app directory. These directories are implicit, so they follow the gathering rule that symbolic links aren't followed, unlike a directory passed with --include-dir.
  • Records these directories with a new scan-directory origin, app_config_directory, in the --json selection and in coverage. The scope and the generated commands don't change, since running the same command again finds the same directories.

Stacked on #8763: extensions in these directories count as this app's, and only another shopify.app*.toml triggers its warning.

image image

How to manually test your changes?

mkdir -p /tmp/ext-dirs/app /tmp/ext-dirs/shared-extensions/theme/assets /tmp/ext-dirs/not-extensions/tools
cat > /tmp/ext-dirs/app/shopify.app.toml <<'TOML'
extension_directories = ["../shared-extensions/*", "../not-extensions/*"]

name = "Demo"
client_id = "demo-client-id"
application_url = "https://example.com"
embedded = true

[auth]
redirect_urls = ["https://example.com/auth/callback"]

[webhooks]
api_version = "2025-07"
TOML
printf 'name = "theme"\ntype = "theme"\n' > /tmp/ext-dirs/shared-extensions/theme/shopify.extension.toml
printf 'export const theme = true\n' > /tmp/ext-dirs/shared-extensions/theme/assets/theme.js
printf 'Shared extensions\n' > /tmp/ext-dirs/shared-extensions/README.md
printf 'export const build = true\n' > /tmp/ext-dirs/not-extensions/tools/build.ts
pnpm --dir <path to this checkout> shopify app security check --path /tmp/ext-dirs/app --list-files

The output lists ../shared-extensions/theme/assets/theme.js and ../shared-extensions/theme/shopify.extension.toml. It doesn't list ../shared-extensions/README.md, which isn't in an extension directory, or ../not-extensions/tools/build.ts, whose glob matches no TOML.

Run the same command with --json --skip-instructions instead of --list-files: selection.scan_directories lists the shared-extensions/theme directory with the origin app_config_directory.

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes
  • I've considered analytics changes to measure impact
  • The change is user-facing — I've identified the correct bump type (patch for bug fixes · minor for new features · major for breaking changes) and added a changeset with pnpm changeset add

@jek
jek requested a review from a team as a code owner October 5, 2026 22:00
@jek
jek added this pull request to stack #8768 October 5, 2026 22:01
@github-actions github-actions Bot added the no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users. label Oct 5, 2026
@jek
jek requested a review from jplhomer October 5, 2026 22:07
@jek
jek force-pushed the app-security/extension-directories branch from 9e1f196 to 8f4ba0d Compare October 5, 2026 22:24
@jek
jek requested a review from a team as a code owner October 5, 2026 22:24
@jek
jek force-pushed the app-security/extension-directories branch 2 times, most recently from a0178fc to 406163b Compare October 6, 2026 02:55
}
const {scanDirectories, requestedScanDirectories} = mergeScanDirectories(appDirectory, includeDirectories)
const appConfigDirectories = selection.kind === 'config' ? (selection.appConfigDirectories ?? []) : []
const {scanDirectories, requestedScanDirectories} = mergeScanDirectories(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same issue of the previous PR. With web_directories = ["../backend"], running with --exclude '../backend' still scans that directory’s files. The walker checks exclusions against entries inside each scan root, so it never matches the root itself

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed downstack in 53a0db3 (#8763): declared directories are scan directories, and --exclude now tests a scan directory and the directories above it, so web_directories = ["../backend"] with --exclude ../backend gathers nothing from ../backend.

@jek
jek force-pushed the app-security/extension-directories branch from 406163b to 26edd8f Compare October 6, 2026 13:19
The selected app configuration file can point extension_directories and
web_directories outside the app directory, for example
"../shared-extensions/*". The CLI loads those extensions and webs as part
of the app, but App Security only scanned the app directory, so their
files were skipped unless they were passed with --include-dir.

Add the directory of each extension and web TOML that the selected file's
globs match, as the CLI's loader matches them, when it's outside the app
directory. A glob that matches no TOML adds nothing, and neither does an
absolute entry, which the CLI never loads from. These directories are
implicit, so unlike an --include-dir directory, one reached through a
symbolic link outside the app directory is left out.

Coverage records them with a new scan-directory origin,
app_config_directory. The scope and the generated commands don't change,
since running the same command again finds the same directories.
@jek
jek force-pushed the app-security/extension-directories branch from 26edd8f to 9cb585b Compare October 6, 2026 13:27
@jek
jek added this pull request to the merge queue Oct 6, 2026
Merged via the queue into main with commit a3c8b2a Oct 6, 2026
30 checks passed
@jek
jek deleted the app-security/extension-directories branch October 6, 2026 13:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants