Skip to content

Exclude NuGet cache from project file search in ProjectLocator#15388

Open
MO2k4 wants to merge 4 commits intomicrosoft:mainfrom
MO2k4:fix/exclude-nuget-cache-from-project-scan
Open

Exclude NuGet cache from project file search in ProjectLocator#15388
MO2k4 wants to merge 4 commits intomicrosoft:mainfrom
MO2k4:fix/exclude-nuget-cache-from-project-scan

Conversation

@MO2k4
Copy link

@MO2k4 MO2k4 commented Mar 19, 2026

Summary

  • Fixes aspire update incorrectly surfacing immutable NuGet template packages (e.g. aspire.projecttemplates) as updatable AppHost projects when run from a broad directory like ~
  • Replaces Directory.GetFiles with FileSystemEnumerable using ShouldRecursePredicate to skip the NuGet cache directory before descending into it
  • Resolves the cache path from NUGET_PACKAGES env var or the platform-appropriate default (~/.nuget/packages)

Fixes #14055

Test plan

  • Added test: FindAppHostProjectFilesAsync_ExcludesProjectsInsideNuGetCache — verifies projects inside the NuGet cache are excluded
  • Added test: FindAppHostProjectFilesAsync_FindsProjectsOutsideNuGetCache — verifies normal project discovery still works
  • Added test: FindAppHostProjectFilesAsync_RespectsCustomNuGetPackagesEnvVar — verifies custom NUGET_PACKAGES paths are honored

When running `aspire update` from a broad directory (e.g. home), the
ProjectLocator would descend into ~/.nuget/packages and incorrectly
surface immutable template packages as updatable AppHost projects.

Replace Directory.GetFiles with FileSystemEnumerable to skip the NuGet
cache directory via ShouldRecursePredicate. The cache path is resolved
from NUGET_PACKAGES env var or the platform default. Adds three tests
covering cache exclusion, normal discovery, and custom cache paths.

Fixes microsoft#14055
@github-actions
Copy link
Contributor

github-actions bot commented Mar 19, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 15388

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 15388"

@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Mar 19, 2026
}

[Fact]
public async Task FindAppHostProjectFilesAsync_RespectsCustomNuGetPackagesEnvVar()
Copy link
Contributor

@davidfowl davidfowl Mar 19, 2026

Choose a reason for hiding this comment

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

Tests shouldn't set env variables like this, it affects the ability to run concurrently and can impact other tests.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks for the feedback, i've adjusted this and now switched to CliExecutionContext

Copy link
Member

@mitchdenny mitchdenny left a comment

Choose a reason for hiding this comment

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

Good fix for a real user-facing issue — the FileSystemEnumerable approach with ShouldRecursePredicate is the right call for skipping the NuGet cache early instead of filtering after the fact.

One bug to address: the StartsWith check in ShouldRecursePredicate lacks a trailing directory separator, which means it could false-positive on sibling directories whose names share a prefix with the cache path (e.g., .nuget/packages-extra). See inline comment for the suggested fix.

Tests are well-structured and cover the key scenarios.

Comment on lines +98 to +100
!entry.IsDirectory && FileSystemName.MatchesSimpleExpression(pattern, entry.FileName),
ShouldRecursePredicate = (ref FileSystemEntry entry) =>
nugetCachePath is null ||
Copy link
Member

Choose a reason for hiding this comment

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

Bug: StartsWith without a trailing directory separator can produce false positives. For example, if the NuGet cache path is /home/user/.nuget/packages, a sibling directory named /home/user/.nuget/packages-extra would also be incorrectly excluded because "/home/user/.nuget/packages-extra".StartsWith("/home/user/.nuget/packages") is true.

The codebase already handles this correctly in BundleService.cs (zip-slip protection) by appending Path.DirectorySeparatorChar before comparing. Suggested fix:

ShouldRecursePredicate = (ref FileSystemEntry entry) =>
{
    if (nugetCachePath is null)
    {
        return true;
    }
    var dirPath = entry.ToFullPath();
    return !dirPath.Equals(nugetCachePath, pathComparison)
        && !dirPath.StartsWith(nugetCachePath + Path.DirectorySeparatorChar, pathComparison);
}

The extra Equals check handles the exact cache root directory itself (since the StartsWith with trailing separator won't match it).

Append Path.DirectorySeparatorChar to the NuGet cache path in
ShouldRecursePredicate so sibling directories whose names share a
prefix (e.g. packages-extra vs packages) are not incorrectly excluded.

Add FindAppHostProjectFilesAsync_DoesNotExcludeSiblingDirectoriesOfNuGetCache
test to verify the fix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mitchdenny mitchdenny requested a review from JamesNK as a code owner March 25, 2026 01:16
Move FileSystemEnumerable setup (pattern matching + NuGet cache
exclusion) into a static FindMatchingFiles method, keeping
FindAppHostProjectFilesAsync focused on the higher-level flow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

aspire update offers to update its own templates

3 participants