Skip to content

ENG-3613: Remove GitPython dependency, reimplement dirty check with subprocess#8237

Merged
thabofletcher merged 6 commits into
mainfrom
fix/gitpython-vulnerable-dep
May 20, 2026
Merged

ENG-3613: Remove GitPython dependency, reimplement dirty check with subprocess#8237
thabofletcher merged 6 commits into
mainfrom
fix/gitpython-vulnerable-dep

Conversation

@thabofletcher
Copy link
Copy Markdown
Contributor

@thabofletcher thabofletcher commented May 19, 2026

Ticket ENG-3613

Description Of Changes

GitPython was declared as a runtime dependency in pyproject.toml despite only being used by git_is_dirty(), a CLI helper in fides pull that warns operators if they are running from a dirty git working tree. This caused three High-severity CVEs (CVE-2026-42215, CVE-2026-42284, CVE-2026-44243) to apply to the production fidesplus slim image against code that never executes in the deployed server.

Rather than bumping the pinned version (which would only defer the problem — GitPython shipped 3 patch releases in 8 days), we remove the dependency entirely by reimplementing git_is_dirty() using stdlib subprocess and os.path. The git CLI is always available on machines running fides pull (git is required to clone the repo in the first place).

Behavior is identical to before:

  • Dirty working tree → warns the operator and returns True
  • Clean working tree → returns False
  • No .git/ directory → prints "No git repo detected", returns False
  • git binary not found → prints "Git executable not detected", returns False

GitPython and its transitive dependency gitdb are fully removed from the dependency tree.

Code Changes

  • src/fides/core/utils.py — replace GitPython-based git_is_dirty() with subprocess.run(["git", "status", ...]) + os.path.isdir(".git/") check
  • pyproject.toml — remove GitPython==3.1.41 from [project.dependencies] and from [dependency-groups] dev
  • uv.lock — updated to reflect removed packages

Steps to Confirm

  1. In a local fides git repo with uncommitted changes, run fides pull — confirm the dirty-tree warning appears as before
  2. In a clean repo, run fides pull — confirm no dirty warning
  3. Build the slim image and confirm GitPython is absent:
docker run --rm ethyca/fidesplus:local pip show GitPython
# Expected: WARNING: Package(s) not found: GitPython

Pre-Merge Checklist

  • Issue requirements met
  • All CI pipelines succeeded
  • CHANGELOG.md updated
  • UX feedback:
    • No UX review needed
  • Followup issues:
    • No followup issues
  • Database migrations:
    • No migrations
  • Documentation:
    • No documentation updates required

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
fides-plus-nightly Ready Ready Preview, Comment May 20, 2026 3:53pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
fides-privacy-center Ignored Ignored May 20, 2026 3:53pm

Request Review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 19, 2026

Dependency Review

✅ No vulnerabilities found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA e9f0040.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

  • pyproject.toml
  • uv.lock

@codecov
Copy link
Copy Markdown

codecov Bot commented May 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.14%. Comparing base (b9acbc8) to head (e9f0040).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8237      +/-   ##
==========================================
+ Coverage   85.12%   85.14%   +0.01%     
==========================================
  Files         670      670              
  Lines       43415    43413       -2     
  Branches     5081     5081              
==========================================
+ Hits        36957    36962       +5     
+ Misses       5351     5345       -6     
+ Partials     1107     1106       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@thabofletcher thabofletcher force-pushed the fix/gitpython-vulnerable-dep branch from da715fa to 18ecf8a Compare May 19, 2026 17:24
GitPython shipped as a runtime dep despite only being used by git_is_dirty(),
a CLI helper in fides pull. Three High-severity CVEs (CVE-2026-42215,
CVE-2026-42284, CVE-2026-44243) applied to the pinned version (3.1.41),
triggering C1 SLA requirements against code never executed in the server.

Replace the GitPython-based implementation with subprocess + os.path:
- os.path.isdir(".git/") replaces is_git_dir()
- subprocess.run(["git", "status", ...]) replaces Repo/git_session.status()
- FileNotFoundError on missing git binary replaces ImportError fallback

Behavior is identical. The git CLI is always present on machines running
fides pull (git is required to have the repo). GitPython and its transitive
dep gitdb are fully removed from the dependency tree.
@thabofletcher thabofletcher force-pushed the fix/gitpython-vulnerable-dep branch from 18ecf8a to 74b90b9 Compare May 19, 2026 18:56
@thabofletcher
Copy link
Copy Markdown
Contributor Author

/code-review

@thabofletcher thabofletcher force-pushed the fix/gitpython-vulnerable-dep branch from ca8a774 to ff3530d Compare May 19, 2026 19:10
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

Code Review: Remove GitPython dependency, reimplement dirty check with subprocess

The core approach here is correct and well-motivated — replacing a third-party library with stdlib subprocess to eliminate three CVEs from the production image is the right call. The changelog entry is accurate and the uv.lock update is clean.

The main concerns are in the new subprocess-based implementation of git_is_dirty.

Critical (should fix before merge)

1. NameError if subprocess.run raises a non-FileNotFoundError exception

The return bool(result.stdout.strip()) is outside the try block, so if subprocess.run raises anything other than FileNotFoundError (e.g. PermissionError, OSError, or TimeoutExpired once a timeout is added), result will be unbound and the function will raise NameError. Moving the return inside the try block fixes this. See inline comment on line 163.

2. No timeout on subprocess.run — can hang indefinitely

git status on a network-mounted filesystem or a repo with a slow/timing-out remote can stall. Adding timeout=10 and catching subprocess.TimeoutExpired prevents the CLI from blocking indefinitely. See inline comment on lines 153–158.

Minor

3. os.path.exists(".git") vs os.path.isdir(".git")

os.path.exists returns True for a .git file (present in worktrees and submodules), making the guard pass and the error message misleading. os.path.isdir is more semantically correct. Also, the old is_git_dir validated internal git structure (HEAD, objects, refs); the new check will proceed to git status even on a corrupt .git dir — the exit-code check (suggestion 4) would catch that case.

Suggestions

4. Silent failure on non-zero git status exit code

With check=False, a code-128 exit (corrupt repo, etc.) produces empty stdout and silently returns False — indistinguishable from a clean tree. Checking result.returncode and logging on failure makes errors visible. See inline comment on line 157.

5. Unpinned GitPython>=3.1.50 in dev dependencies

Every other dev dependency is pinned to an exact version for reproducibility. Since the CVE concern is about the runtime dependency (now removed), pinning the dev entry to ==3.1.50 (matching the resolved lock) avoids silent float on future uv lock --upgrade. See inline comment on line 147 of pyproject.toml.

6. Docstring says "unstaged changes" but --porcelain also catches untracked files — minor wording nit on line 145.


Overall: two small but real bugs (NameError, missing timeout) should be addressed before merge. The other items are low-risk suggestions. The security goal of removing GitPython from the production image is achieved cleanly.

🔬 Codegraph: unavailable


💡 Write /code-review in a comment to re-run this review.

Comment thread src/fides/core/utils.py Outdated
Comment thread src/fides/core/utils.py
Comment thread src/fides/core/utils.py
Comment thread src/fides/core/utils.py
Comment thread pyproject.toml Outdated
Comment thread src/fides/core/utils.py Outdated
@thabofletcher thabofletcher force-pushed the fix/gitpython-vulnerable-dep branch from ed12b5d to 76b8e77 Compare May 19, 2026 21:31
@thabofletcher thabofletcher marked this pull request as ready for review May 19, 2026 22:02
@thabofletcher thabofletcher requested a review from a team as a code owner May 19, 2026 22:02
@thabofletcher thabofletcher requested review from galvana and removed request for a team May 19, 2026 22:02
Comment thread pyproject.toml
"Faker==14.1.0",
"freezegun==1.5.5",
"GitPython==3.1.41",
"GitPython==3.1.50",
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.

This adds as a dev dependency only and updates it to the latest version (for tests)

@thabofletcher thabofletcher added this pull request to the merge queue May 20, 2026
Merged via the queue into main with commit 1c97e0d May 20, 2026
69 of 70 checks passed
@thabofletcher thabofletcher deleted the fix/gitpython-vulnerable-dep branch May 20, 2026 18:42
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