Skip to content

Make polyglot integration restores consistent and cache-safe - #19763

Draft
David Negstad (danegsta) wants to merge 4 commits into
danegsta/apphost-path-normalizationfrom
danegsta/shared-integration-closure
Draft

Make polyglot integration restores consistent and cache-safe#19763
David Negstad (danegsta) wants to merge 4 commits into
danegsta/apphost-path-normalizationfrom
danegsta/shared-integration-closure

Conversation

@danegsta

@danegsta David Negstad (danegsta) commented Aug 28, 2026

Copy link
Copy Markdown
Member

Description

Polyglot AppHosts can load .NET integrations from both NuGet packages and project references. Those paths need to honor the same package channels, source mappings, central package management isolation, output layout, and closure-manifest contract; otherwise a generated restore can select the wrong feed, inherit repository package versions, or produce an incomplete runtime closure.

Generated integration projects now share one C# project model, restore-source resolver, closure builder, cache layout, and runtime environment setup. This makes the existing prebuilt AppHost path consistent across package and project-reference integrations, including explicit channels, source overrides, staging-feed cache isolation, and project-reference assembly discovery.

Fixes # (issue)

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 2dd71101-249d-428b-81e7-9b247b9b3a2a
@danegsta David Negstad (danegsta) changed the title Share generated integration closure infrastructure Aug 28, 2026
@danegsta
David Negstad (danegsta) requested a balanced review from Copilot August 28, 2026 00:17

Copilot AI left a comment

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.

Pull request overview

Unifies polyglot integration restore behavior across generated AppHost projects, including source resolution, closure generation, cache layout, and runtime configuration.

Changes:

  • Adds shared C# project, restore-source, closure, and environment helpers.
  • Updates prebuilt and repository-mode AppHost generation.
  • Expands restore fingerprinting and project-reference tests.

Reviewed changes

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

Show a summary per file
File Description
tests/Aspire.Cli.Tests/Projects/PrebuiltAppHostServerTests.cs Tests restore configuration, closure outputs, and cache normalization.
src/Aspire.Cli/Utils/CliPathHelper.cs Adds path and staging-cache helpers.
src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs Adopts shared restore and closure infrastructure.
src/Aspire.Cli/Projects/IntegrationRestoreSourceResolver.cs Centralizes channel and source resolution.
src/Aspire.Cli/Projects/IntegrationClosureEnvironment.cs Centralizes runtime integration environment variables.
src/Aspire.Cli/Projects/IntegrationClosureBuilder.cs Centralizes closure project generation and manifest reading.
src/Aspire.Cli/Projects/DotNetBasedAppHostServerProject.cs Uses the shared C# project model.
src/Aspire.Cli/Projects/CSharpProjectFile.cs Introduces a generated C# project model.
Comment thread src/Aspire.Cli/Projects/DotNetBasedAppHostServerProject.cs Outdated
Comment thread src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs
Comment thread src/Aspire.Cli/Projects/IntegrationRestoreSourceResolver.cs Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d38799a7-a99c-48c5-b45b-9d6594dd1830
Copilot AI review requested due to automatic review settings August 28, 2026 01:47
@github-actions

Copy link
Copy Markdown
Contributor

🚀 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 -- 19763

Or

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

This comment has been minimized.

Copilot AI left a comment

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.

Pull request overview

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

Suppressed comments (1)

src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs:750

  • This only checks PackageSourceMappings, but the no-channel path returns all explicit channel URLs in AdditionalSources while leaving PackageSourceMappings null. If one of those channels contains a SAS/user-info URL, it is written into the long-lived IntegrationRestore.csproj as RestoreAdditionalProjectSources, and restore-cache skipping remains enabled. Include all effective sources in the credential check and keep the generated project/config ephemeral (or reject the ambiguous no-channel case) so credentials are never persisted.
        var hasCredentialBearingRestoreSource = restoreSources.PackageSourceMappings?.Any(
            static mapping => PackageSourceOverrideMappings.HasCredentialMaterial(mapping.Source)) == true;
Comment thread src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs
Comment thread src/Aspire.Cli/Projects/CSharpProjectFile.cs
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d38799a7-a99c-48c5-b45b-9d6594dd1830
Copilot AI review requested due to automatic review settings August 28, 2026 02:05
@github-actions

This comment has been minimized.

Copilot AI left a comment

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.

Pull request overview

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

Comment thread src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs Outdated
Comment thread src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d38799a7-a99c-48c5-b45b-9d6594dd1830
Copilot AI review requested due to automatic review settings August 28, 2026 02:39
@github-actions

Copy link
Copy Markdown
Contributor

Tests selector (audit mode)

The full test matrix and all jobs still run in audit mode. The tests and jobs below are what selective CI would run under enforcement.

2 / 102 test projects · 4 jobs, from 12 changed files.

Selected test projects (2 / 102)

Aspire.Cli.EndToEnd.Tests, Aspire.Cli.Tests

Selected jobs (4)

deployment-e2e, extension-e2e, polyglot, typescript-api-compat


How these were chosen — grouped by what changed

📦 affected project Aspire.Cli
1 test: Aspire.Cli.EndToEnd.Tests

🧪 tests/Aspire.Cli.Tests/Packaging/TemporaryNuGetConfigTests.cs (changed test)
1 directly: Aspire.Cli.Tests

🧪 tests/Aspire.Cli.Tests/Projects/AppHostServerProjectTests.cs (changed test)
1 directly: Aspire.Cli.Tests

🧪 tests/Aspire.Cli.Tests/Projects/PrebuiltAppHostServerTests.cs (changed test)
1 directly: Aspire.Cli.Tests

Job reasons

Job Triggered by
deployment-e2e affected project Aspire.Cli
extension-e2e src/Aspire.Cli/Packaging/NuGetConfigComposer.cs, src/Aspire.Cli/Packaging/TemporaryNuGetConfig.cs, src/Aspire.Cli/Projects/CSharpProjectFile.cs, src/Aspire.Cli/Projects/DotNetBasedAppHostServerProject.cs, src/Aspire.Cli/Projects/IntegrationClosureBuilder.cs, src/Aspire.Cli/Projects/IntegrationClosureEnvironment.cs, src/Aspire.Cli/Projects/IntegrationRestoreSourceResolver.cs, src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs, src/Aspire.Cli/Utils/CliPathHelper.cs, tests/Aspire.Cli.Tests/Packaging/TemporaryNuGetConfigTests.cs, tests/Aspire.Cli.Tests/Projects/AppHostServerProjectTests.cs, tests/Aspire.Cli.Tests/Projects/PrebuiltAppHostServerTests.cs
• affected project Aspire.Cli
polyglot affected project Aspire.Cli
typescript-api-compat affected project Aspire.Cli

Selection computed for commit c9c2ea5.

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

src/Aspire.Cli/Projects/DotNetBasedAppHostServerProject.cs:164

  • This set now stores project paths, but OrdinalIgnoreCase collapses distinct paths such as /src/Foo/Foo.csproj and /src/foo/foo.csproj on case-sensitive Linux/macOS filesystems, silently omitting one valid ProjectReference. Use ordinal path identity here; the restore graph uses the same rule specifically to avoid dropping distinct paths (PrebuiltAppHostServer.cs:378-380).
        var addedProjects = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
Comment on lines +153 to +165
var identityAttribute =
string.Equals(itemName, "author", StringComparison.OrdinalIgnoreCase) ||
string.Equals(itemName, "repository", StringComparison.OrdinalIgnoreCase)
? "name"
: string.Equals(itemName, "certificate", StringComparison.OrdinalIgnoreCase)
? "fingerprint"
: string.Equals(itemName, "fileCert", StringComparison.OrdinalIgnoreCase) ||
string.Equals(itemName, "storeCert", StringComparison.OrdinalIgnoreCase)
? "packageSource"
: null;

return identityAttribute is null ||
string.Equals(GetAttributeValue(first, identityAttribute), GetAttributeValue(second, identityAttribute), StringComparison.OrdinalIgnoreCase);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants