Skip to content

Only read from Git in app security check - #8841

Merged
jek merged 1 commit into
mainfrom
app-security/git-fsmonitor
Oct 9, 2026
Merged

jek merged 1 commit into
mainfrom
app-security/git-fsmonitor

Conversation

@jek

@jek jek commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

WHY are these changes introduced?

shopify app security check asks Git which files are tracked, which are ignored, and where a repository's top level is. Answering doesn't need Git to:

  • Run a file-system monitor (core.fsmonitor). ls-files and check-ignore start one whenever they read the index.
  • Fetch a missing object. A partial clone does this through its transport command (core.sshCommand, remote.<name>.uploadpack), for example when a skip-worktree .gitignore isn't in the object store.
  • Use a bare repository found in the working directory, such as one committed as ordinary files (HEAD, config, objects/, refs/), instead of the repository that contains the app.

Git takes the settings behind all three from the repository being scanned, so a scanned repository could make the check run a program or get its answers from the wrong place. The check now overrides them.

WHAT is this pull request doing?

Every Git command in the engine now goes through one runGit helper (scanners/git.ts). It applies four protections, kept in a named table:

Protection Turns off
-c core.fsmonitor= The file-system monitor, which only speeds up reading the index. The empty value turns it off on every Git version; older versions would run false as the program's name.
-c safe.bareRepository=explicit Using a bare repository found in the working directory. Older Git versions ignore it; the other protections still apply.
GIT_NO_LAZY_FETCH=1 Fetching a missing object, which would use the network and write to the repository.
GIT_ALLOW_PROTOCOL= (empty) Every transport, which also covers Git versions without GIT_NO_LAZY_FETCH.

path-rules.ts and secret-rules.ts lose their private copies of runGit.

Behaviour changes:

  • Where Git's built-in file-system monitor is enabled globally (core.fsmonitor=true), scans no longer start a git fsmonitor--daemon for each scanned directory.
  • If a scanned directory is itself a committed bare repository, Git refuses it. Secrets found there stay reported, because Git can't confirm they're untracked or ignored.

Tests (tests/untrusted-repository.test.ts):

  • There is one fixture per case: a repository whose own .git/config names a monitor, a bare repository committed into a clone, and a partial clone missing an object. Each fixture first shows that plain Git runs the program it names, so a fixture that stops doing so fails instead of passing.
  • Each protection is tested on its own against its fixture, and a protection added without a fixture fails type-checking.
  • An end-to-end scan of each fixture runs nothing. For the first fixture, the scan still gets normal answers from Git.
  • The tests run on Windows, which keeps checking that Git for Windows honours each protection, including the empty GIT_ALLOW_PROTOCOL.

How to manually test your changes?

  1. Create a repository whose own settings name a file-system monitor:

    mkdir /tmp/untrusted && cd /tmp/untrusted && git init -q
    printf 'name = "x"\nclient_id = "abc123"\napplication_url = "https://example.com"\n' > shopify.app.toml
    git add . && git commit -qm init
    git config core.fsmonitor "echo ran >> /tmp/untrusted-marker; false"
  2. Run git ls-files. /tmp/untrusted-marker appears, which shows the program runs.

  3. Delete the marker. Run shopify app security check --path /tmp/untrusted. The marker doesn't appear.

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

@github-actions github-actions Bot added the Area: @shopify/cli @shopify/cli package issues label Oct 8, 2026
app security check asks Git which files are tracked, which are ignored
and where a repository's top level is. Answering doesn't need Git to
run a program, start a background file-system monitor or fetch
anything, and the answers should come from the repository that
contains the app, not from repository files committed inside it. Git
takes the settings behind all of these from the repository being
scanned, so the check now overrides them.

Every Git command in the engine goes through one runGit helper that
applies four protections:

- `-c core.fsmonitor=` turns off the file-system monitor, which only
  speeds up reading the index.
- `-c safe.bareRepository=explicit` refuses a bare repository found in
  the working directory, such as one committed as ordinary files.
  Older Git versions ignore it; the other protections still apply.
- `GIT_NO_LAZY_FETCH=1` stops a partial clone from fetching a missing
  object, which would use the network and write to the repository.
- `GIT_ALLOW_PROTOCOL=` refuses every transport, which also covers Git
  versions without GIT_NO_LAZY_FETCH.

The tests build a repository for each case and show that plain Git
runs a program it names. They then show that each protection on its
own stops that program and that a scan runs nothing. A protection
added without a test fixture fails type-checking. The tests also run
on Windows.
@jek
jek force-pushed the app-security/git-fsmonitor branch from 95961f0 to 0c17a82 Compare October 8, 2026 17:12
@jek
jek marked this pull request as ready for review October 8, 2026 17:33
@jek
jek requested a review from a team as a code owner October 8, 2026 17:33
@jek
jek requested a review from jplhomer October 8, 2026 17:34
@jek
jek added this pull request to the merge queue Oct 9, 2026
Merged via the queue into main with commit f08dbe5 Oct 9, 2026
30 checks passed
@jek
jek deleted the app-security/git-fsmonitor branch October 9, 2026 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants