Skip to content

Conversation

brettfo
Copy link
Contributor

@brettfo brettfo commented Jun 26, 2025

Problem

More mature .NET repos with NuGet packages are commonly only built on Windows with a case-insensitive filesystem. This can cause issues with the dependabot updater if there is a mismatch between the files in the repo and their casing in import statements. Consider a .csproj with a line like <Import Project="build/versions.props" /> but in the repo and on disk the file is named build/Versions.props (notice the upper-case V). Since dependabot runs in a Linux host, all operations will fail because the requested files could not be loaded. This same issue can arise if a NuGet package consumed by a repo has package-internal <Import> elements that don't match the casing of the file in the package. All of these scenarios have been encountered.

The Fix

To address this, dependabot needs to run on a case-insensitive filesystem, but that would add certain requirements for the Docker host that's running the update job. To avoid this, we can use some functionality built into Docker itself, namely its ability to natively mount SMB/CIFS shares for use as volumes to bind to another container. The SMB/CIFS sharing protocol was picked because it has an optional nocase mount option that makes all operations case-insensitive.

To accomplish this, the Docker host needs access to a SMB/CIFS share, but to again not impose additional requirements on the Docker host, a separate image is used, ghcr.io.dependabot/dependabot-storage. That container only hosts a SMB/CIFS share on the default ports with a hardcoded username and password. The default Docker configuration doesn't allow guest access so user/pass had to be used isntead.

The changes to this codebase

Immediately before the updater container is created (e.g., from the dependabot-updater-nuget image), a new container is created from the dependabot-storage image and it is given no external internet access. The host (this code) then mounts the SMB/CIFS share twice. The first mount is with the standard options which is then given to the updater in the environment variable $DEPENDABOT_REPO_CONTENTS_PATH. The second mount is exactly the same as the first, except with the nocase option and it is exposed to the updater in the environment variable $DEPENDABOT_CASE_INSENSITIVE_REPO_CONTENTS_PATH.

The job the proceeds as normal and the container cleanup operations have been amended to also remove the storage container and both volume mounts.

All of this work is behind a new feature flag use_case_insensitive_filesystem.

This experiment is not expected to be enabled for non-NuGet jobs, but I've done some testing anyway and found no change in behavior because the updater reads its version of $DEPENDABOT_REPO_CONTENTS_PATH and proceeds as normal. Nothing is done with the ..._CASE_INSENSITIVE_... variable.

The changes here will also require a change to dependabot/dependabot-core (PR pending) where the updater is aware of both directory paths. It performs all update work against the case-insensitive one then normalizes all file paths (e.g. the contents of create_pull_request) using the case-sensitive one.

@jakecoffman
Copy link
Member

Is there any way we can test this? For instance making one of these script tests we could test it's possible to mount a case-insensitive filesystem, but more importantly ensure it doesn't break going forward.

@JamieMagee JamieMagee requested a review from Copilot June 26, 2025 21:47
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces support for case-insensitive file operations during NuGet updates by leveraging SMB/CIFS mounts. The key changes include:

  • Adding a new method to Job to check the "use_case_insensitive_filesystem" experiment flag.
  • Creating a storage container and volumes in the updater to mount SMB/CIFS shares with optional case-insensitive behavior.
  • Adjusting environment variables and clone directory paths based on the case-sensitivity setting.

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
internal/model/job.go Adds a method to check the case insensitivity experimental feature.
internal/infra/updater.go Implements storage container and volume setups for case-insensitive mounts and updates environment variables accordingly.
internal/infra/run.go Updates cloning and shell execution to account for different container mount paths.

@brettfo brettfo force-pushed the dev/brettfo/cifs-storage branch 2 times, most recently from cb6c77d to ac2e2e2 Compare June 26, 2025 23:00
@brettfo brettfo force-pushed the dev/brettfo/cifs-storage branch from 659dcc8 to 61cc328 Compare June 26, 2025 23:16
@brettfo
Copy link
Contributor Author

brettfo commented Jun 26, 2025

@jakecoffman I added smb-mount.txt that writes a file to the case-sensitive share then reads it back with different casing from the case insensitive share. Good catch on this, turns out I also forgot to add the code to pull the storage image, but this caught it. "Works on my machine!"

@schmittjoseph Addressed feedback in additional commit.

Current smoke failures are due to a rate limit, I'll see what I can do to get those cleared.

ByAgenT
ByAgenT previously approved these changes Jun 27, 2025
Copy link
Contributor

@kbukum1 kbukum1 left a comment

Choose a reason for hiding this comment

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

LGTM

@brettfo brettfo added this pull request to the merge queue Jun 30, 2025
Merged via the queue into main with commit 5feadd9 Jun 30, 2025
78 checks passed
@brettfo brettfo deleted the dev/brettfo/cifs-storage branch June 30, 2025 16:31
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.

5 participants