Skip to content

Fix remaining issue 17244 items - #17507

Merged
Adam Ratzman (adamint) merged 2 commits into
microsoft:mainfrom
adamint:copilot/fix-17244-remaining
May 27, 2026
Merged

Fix remaining issue 17244 items#17507
Adam Ratzman (adamint) merged 2 commits into
microsoft:mainfrom
adamint:copilot/fix-17244-remaining

Conversation

@adamint

Copy link
Copy Markdown
Member

Description

Fixes the remaining items from #17244.

This preserves auxiliary backchannel compatibility for existing clients that deserialize ResourceSnapshot.Properties as string values. Legacy resource snapshot calls and clients that do not opt in continue to receive string/null property values, while clients that advertise the new aux.v4 capability receive JSON-valued properties for numbers, booleans, and arrays. The Aspire CLI now sends its client capabilities when using the v2 resource get/watch calls so it can opt in to the typed JSON behavior.

This also removes the dead dashboard showStartCommand menu filter. Visible Start commands are now handled like other visible resource commands instead of being filtered by a duplicate call-site flag.

User-facing behavior

Older auxiliary backchannel clients remain compatible with resource properties that contain non-string values. Newer clients can opt in to typed JSON resource properties by sending aux.v4 in ClientCapabilities on GetResourcesRequest or WatchResourcesRequest.

Dashboard resource action menus include the Start command whenever that command is visible in the resource command model.

Validation:

  • dotnet test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-launch-profile -- --filter-method "*.GetResourceSnapshotsAsync_MapsNonStringPropertiesAsStringsForLegacyCallers" --filter-method "*.GetResourcesAsync_MapsNonStringPropertiesAsJsonForV4Callers" --filter-method "*.RequestWithTraceContext_PreservesRequestProperties" --filter-method "*.GetCapabilitiesAsyncReturnsCurrentCapabilities" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"
  • dotnet test --project tests/Aspire.Cli.Tests/Aspire.Cli.Tests.csproj --no-launch-profile -- --filter-class "*.AppHostAuxiliaryBackchannelTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"
  • dotnet test --project tests/Aspire.Dashboard.Tests/Aspire.Dashboard.Tests.csproj --no-launch-profile -- --filter-class "*.ResourceMenuBuilderTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"
  • git diff --check

Fixes #17244

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

Preserve legacy auxiliary backchannel resource property serialization unless clients opt in to JSON-valued properties, and remove the unused dashboard start command filter.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented May 26, 2026

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 -- 17507

Or

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

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

Updates the auxiliary backchannel contract to add client capability negotiation (aux.v4) so callers can opt into typed JSON resource properties while preserving legacy string/null property values for callers that don’t opt in. Also removes the dead dashboard menu filtering for the Start command so Start is shown whenever it’s visible in the resource command model.

Changes:

  • Add aux.v4 capability and ClientCapabilities to v2 resource get/watch requests to enable opt-in typed JSON resource properties.
  • Update AppHost backchannel RPC target to emit legacy string-valued properties by default and typed JSON properties for aux.v4 callers.
  • Remove showStartCommand filtering in the dashboard resource menu builder and update tests accordingly.

Reviewed changes

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

Show a summary per file
File Description
tests/Aspire.Hosting.Tests/Backchannel/BackchannelContractTests.cs Extends contract test helpers to handle string[] properties.
tests/Aspire.Hosting.Tests/Backchannel/AuxiliaryBackchannelTests.cs Updates capability assertions to include aux.v4.
tests/Aspire.Hosting.Tests/Backchannel/AuxiliaryBackchannelRpcTargetTests.cs Adds tests validating legacy string mapping vs v4 typed JSON mapping for properties.
tests/Aspire.Dashboard.Tests/Model/ResourceMenuBuilderTests.cs Updates test expectations to include Start as a normal visible command.
tests/Aspire.Cli.Tests/TestServices/TestAppHostAuxiliaryBackchannel.cs Adds SupportsV4 to the CLI backchannel test double.
tests/Aspire.Cli.Tests/Backchannel/AppHostAuxiliaryBackchannelTests.cs Adds tests ensuring CLI sends ClientCapabilities including aux.v4 for v2 get/watch calls.
src/Aspire.Hosting/Backchannel/BackchannelDataTypes.cs Adds aux.v4 constant and ClientCapabilities fields to v2 resource request types.
src/Aspire.Hosting/Backchannel/AuxiliaryBackchannelRpcTarget.cs Implements opt-in typed JSON properties and legacy string property conversion.
src/Aspire.Dashboard/Model/ResourceMenuBuilder.cs Removes showStartCommand parameter and filtering; treats Start like other visible commands.
src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor.cs Updates call site after removing showStartCommand parameter.
src/Aspire.Cli/Backchannel/IAppHostAuxiliaryBackchannel.cs Adds SupportsV4 capability property to the CLI backchannel interface.
src/Aspire.Cli/Backchannel/AppHostAuxiliaryBackchannel.cs Sends client capabilities on v2 resource get/watch requests to opt in to typed JSON properties.

Comment on lines +36 to +46
var snapshots = new List<ResourceSnapshot>();
await foreach (var snapshot in backchannel.WatchResourceSnapshotsAsync(includeHidden: true).DefaultTimeout())
{
snapshots.Add(snapshot);
}

var resource = Assert.Single(snapshots);
Assert.Equal("api", resource.Name);
Assert.NotNull(server.Target.WatchResourcesRequest);
Assert.Contains(AuxiliaryBackchannelCapabilities.V4, server.Target.WatchResourcesRequest.ClientCapabilities);
}
@adamint

Copy link
Copy Markdown
Member Author

PR Testing Report

PR Information

CLI Version Verification

  • Expected Commit: ad60ed8
  • Installed Version: 13.4.0-pr.17507.gad60ed80
  • Status: ✅ Verified (ad60ed8 matches PR head)

Changes Analyzed

Files Changed

  • src/Aspire.Cli/Backchannel/AppHostAuxiliaryBackchannel.cs
  • src/Aspire.Cli/Backchannel/IAppHostAuxiliaryBackchannel.cs
  • src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor.cs
  • src/Aspire.Dashboard/Model/ResourceMenuBuilder.cs
  • src/Aspire.Hosting/Backchannel/AuxiliaryBackchannelRpcTarget.cs
  • src/Aspire.Hosting/Backchannel/BackchannelDataTypes.cs
  • Backchannel, CLI, and dashboard tests

Change Categories

  • CLI changes detected - CLI advertises auxiliary backchannel client capabilities on resource get/watch calls.
  • Hosting changes detected - AppHost gates typed JSON resource properties behind aux.v4 client capability.
  • Dashboard changes detected - removes dead showStartCommand filter from resource menu building.
  • Template changes
  • Client/Component changes
  • Test changes detected

Test Scenarios Executed

Scenario 1: Dogfood CLI install and version verification

Objective: Confirm the PR dogfood CLI artifact is available and matches the PR head commit.
Coverage Type: Happy path
Status: ✅ Passed

Steps:

  1. Waited for the macOS arm64 native CLI artifact after the first install attempt reported it was not available yet.
  2. Installed the PR CLI with get-aspire-cli-pr.sh into a fresh temp directory using --install-path, --skip-path, and --skip-extension.
  3. Ran the installed binary directly with --version.

Evidence:

  • /Users/adamratzman/.copilot/session-state/07fa9b16-c557-4cf9-90e3-b2a5571b252a/files/pr-17507-testing/version.txt

Observations:

  • Installed CLI version was 13.4.0-pr.17507.gad60ed80, matching PR head ad60ed8.

Scenario 2: CLI/AppHost backchannel typed resource properties

Objective: Verify a real AppHost created with the PR templates can start under the PR CLI and that aspire describe receives typed JSON resource properties through the changed auxiliary backchannel path.
Coverage Type: Happy path / boundary for non-string property values
Status: ✅ Passed

Steps:

  1. Created a fresh C# aspire-empty app using the PR hive and installed PR template version.
  2. Added a custom resource with initial properties: number 42, boolean true, and string array ["one", "two"].
  3. Started the AppHost with aspire start --format Json --isolated --non-interactive.
  4. Queried resources with aspire describe --format Json --include-hidden --non-interactive.
  5. Asserted with jq that typed-props was Running/Healthy and properties were JSON number, boolean, and array values.
  6. Captured a dashboard screenshot showing the running custom resource.
  7. Stopped the AppHost with aspire stop --apphost ... --non-interactive.

Evidence:

  • /Users/adamratzman/.copilot/session-state/07fa9b16-c557-4cf9-90e3-b2a5571b252a/files/pr-17507-testing/new-output.txt
  • /Users/adamratzman/.copilot/session-state/07fa9b16-c557-4cf9-90e3-b2a5571b252a/files/pr-17507-testing/start-output.json
  • /Users/adamratzman/.copilot/session-state/07fa9b16-c557-4cf9-90e3-b2a5571b252a/files/pr-17507-testing/describe-output.json
  • /Users/adamratzman/.copilot/session-state/07fa9b16-c557-4cf9-90e3-b2a5571b252a/files/pr-17507-testing/describe-typed-table.txt
  • /Users/adamratzman/.copilot/session-state/07fa9b16-c557-4cf9-90e3-b2a5571b252a/files/pr-17507-testing/assertions.txt
  • /Users/adamratzman/.copilot/session-state/07fa9b16-c557-4cf9-90e3-b2a5571b252a/files/pr-17507-testing/dashboard-resources.png
  • /Users/adamratzman/.copilot/session-state/07fa9b16-c557-4cf9-90e3-b2a5571b252a/files/pr-17507-testing/stop-output.txt

Observations:

  • aspire describe returned number: 42, flag: true, and list: ["one", "two"] for the custom resource.
  • Dashboard loaded and showed the typed-props resource in Running state.

Scenario 3: Non-empty output directory rejection

Objective: Verify template creation still fails safely for an invalid non-empty output directory while using the PR CLI/hive.
Coverage Type: Unhappy path
Status: ✅ Passed

Steps:

  1. Created a fresh output directory containing an existing file.
  2. Ran aspire new aspire-starter with non-interactive prompt-suppressing flags against that output directory.
  3. Verified the command exited non-zero and printed a clear validation error.

Evidence:

  • /Users/adamratzman/.copilot/session-state/07fa9b16-c557-4cf9-90e3-b2a5571b252a/files/pr-17507-testing/nonempty-output.txt

Expected Unhappy-Path Outcome:

  • Non-zero exit code with a safe validation error explaining that the output directory already exists and is not empty.

Observations:

  • Command exited with code 4 and reported that the output directory already exists and is not empty.

Summary

Scenario Status Notes
Dogfood CLI install/version ✅ Passed Artifact initially unavailable; succeeded after CI artifact completed.
Backchannel typed properties smoke ✅ Passed Real PR CLI/AppHost returned typed JSON properties through aspire describe.
Non-empty output directory rejection ✅ Passed Safe non-zero validation error.

Overall Result

✅ PR VERIFIED

The PR dogfood CLI installed successfully after waiting for artifacts, matched the PR head commit, and passed targeted real-command scenarios covering the changed CLI/AppHost backchannel behavior plus dashboard resource visibility evidence.

PR Comment Status

Not posted. Posting requires explicit confirmation.

Cleanup / Inspection Status

Artifacts copied to /Users/adamratzman/.copilot/session-state/07fa9b16-c557-4cf9-90e3-b2a5571b252a/files/pr-17507-testing. The temp dogfood workspace can be removed after final reporting.

public bool SupportsV3 => _capabilities.Contains(AuxiliaryBackchannelCapabilities.V3);

/// <inheritdoc />
public bool SupportsV4 => _capabilities.Contains(AuxiliaryBackchannelCapabilities.V4);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No. V3 is new. Use it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good. Before merging, can you run the PR tester with an older released CLI against the new app host to verify backward compatibility? Specifically, confirm that an old CLI (without V4 capability) can still get resource data from the new app host — i.e., properties are serialized as strings for legacy callers.

Use the existing auxiliary backchannel V3 capability for typed resource properties and stop advertising a new V4 capability. Also limit the watch-resource capability test to the first streamed snapshot so it does not wait for a never-ending watch stream.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@adamint

Copy link
Copy Markdown
Member Author

James Newton-King (@JamesNK) I ran the backward-compatibility PR-tester scenario you requested.

PR Testing Report

PR Information

Version Verification

  • Released CLI under test: 13.3.5+70b33bcb5f64c75e3ab6f57616545f35bd43dc81
  • PR AppHost SDK/package: 13.4.0-pr.17507.g9fa7f3ea
  • PR package source: /var/folders/jt/y4c1v32j5hg8gg47g4m_ztvr0000gn/T/aspire-pr-17507-compat-XXXXXX.hHJZgGDzKs/pr-nugets
  • Status: Verified current PR AppHost package version on the running AppHost log: Aspire AppHost version: 13.4.0-pr.17507.g9fa7f3ea

Changes Analyzed

This PR changes the Aspire CLI/AppHost auxiliary backchannel resource snapshot contract. James requested a backward-compatibility PR-tester pass confirming an older released CLI/client without the typed-property capability can still get resource data from the new AppHost with properties serialized as strings.

Release tag evidence for the tested old CLI line is captured in v13.3.5-legacy-client-evidence.txt: Aspire 13.3.5 only defines auxiliary capabilities aux.v1 and aux.v2, and its GetResourcesAsync call sends the request as-is without clientCapabilities.

Test Scenarios Executed

Scenario 1: Legacy released CLI with PR AppHost packages

Objective: Create/run an app with the released Aspire CLI while pinning the AppHost SDK/package to the PR build, then confirm the new AppHost starts successfully.
Coverage Type: Backward compatibility / Happy path
Status: Passed

Steps:

  1. Installed released CLI with get-aspire-cli.sh --quality release into an isolated temp directory.
  2. Created an aspire-empty file-based app using that released CLI.
  3. Added a local NuGet source for PR built-nugets and pinned the generated AppHost SDK/package to 13.4.0-pr.17507.g9fa7f3ea.
  4. Added a custom typed-props resource with number, bool, array, and object properties.
  5. Ran the app with the released CLI and confirmed the AppHost log reports 13.4.0-pr.17507.g9fa7f3ea.

Evidence:

  • Generated AppHost: /Users/adamratzman/.copilot/session-state/5a48d002-fc06-4be3-8f15-ddb45c7353b9/files/pr-17507-compat-testing/apphost.cs
  • NuGet config: /Users/adamratzman/.copilot/session-state/5a48d002-fc06-4be3-8f15-ddb45c7353b9/files/pr-17507-compat-testing/nuget.config
  • Run output: /Users/adamratzman/.copilot/session-state/5a48d002-fc06-4be3-8f15-ddb45c7353b9/files/pr-17507-compat-testing/run-protocol-output.txt
  • App root used for testing: /var/folders/jt/y4c1v32j5hg8gg47g4m_ztvr0000gn/T/aspire-pr-17507-compat-XXXXXX.hHJZgGDzKs/scenario-legacy-cli-new-apphost/LegacyCompat

Scenario 2: Legacy resource snapshot request gets string properties

Objective: Confirm a legacy caller using the old 13.3.5 request shape receives string-valued properties from the new PR AppHost.
Coverage Type: Backward compatibility / Protocol boundary
Status: Passed

Steps:

  1. Connected to the running AppHost auxiliary JSON-RPC socket.
  2. Called GetResourcesAsync with the old 13.3.5 null-request shape: params: [null].
  3. Also called GetResourcesAsync with only aux.v1/aux.v2 client capabilities.
  4. Asserted the typed-props resource properties are serialized as strings.

Observed legacy properties:

{
  "number": "42",
  "flag": "True",
  "list": "one,two",
  "json": "{\"name\":\"value\"}"
}

Evidence:

  • Full null-request RPC response: /Users/adamratzman/.copilot/session-state/5a48d002-fc06-4be3-8f15-ddb45c7353b9/files/pr-17507-compat-testing/rpc-resources-legacy-null-request.json
  • Null-request assertion: /Users/adamratzman/.copilot/session-state/5a48d002-fc06-4be3-8f15-ddb45c7353b9/files/pr-17507-compat-testing/rpc-legacy-null-assertions.txt
  • V1/V2 capabilities response: /Users/adamratzman/.copilot/session-state/5a48d002-fc06-4be3-8f15-ddb45c7353b9/files/pr-17507-compat-testing/rpc-resources-legacy-v1v2.json
  • V1/V2 assertion: /Users/adamratzman/.copilot/session-state/5a48d002-fc06-4be3-8f15-ddb45c7353b9/files/pr-17507-compat-testing/rpc-legacy-v1v2-assertions.txt

Scenario 3: V3-capable request still gets typed JSON

Objective: Sanity-check that typed properties remain available when the caller advertises the current typed-property capability.
Coverage Type: Positive capability-gating check
Status: Passed

Steps:

  1. Called GetResourcesAsync with clientCapabilities: ["aux.v1", "aux.v2", "aux.v3"].
  2. Asserted the same typed-props resource returns native JSON values.

Observed V3 properties:

{
  "number": 42,
  "flag": true,
  "list": ["one", "two"],
  "json": { "name": "value" }
}

Evidence:

  • Full V3 RPC response: /Users/adamratzman/.copilot/session-state/5a48d002-fc06-4be3-8f15-ddb45c7353b9/files/pr-17507-compat-testing/rpc-resources-v3.json
  • V3 assertion: /Users/adamratzman/.copilot/session-state/5a48d002-fc06-4be3-8f15-ddb45c7353b9/files/pr-17507-compat-testing/rpc-v3-assertions.txt

Harness Notes

  • The PR-native macOS arm64 CLI artifact was not ready while testing, but James's requested scenario was specifically old released CLI compatibility against the new AppHost. I used the released CLI plus the available PR built-nugets AppHost package, which directly exercises that compatibility boundary.
  • The released CLI's detached aspire start path timed out while polling dashboard URLs against this PR AppHost. Foreground aspire run successfully launched the AppHost, so I used the live auxiliary socket from that run for the compatibility assertions. The timeout output is captured in start-stderr.txt and start-noisolated-stderr.txt.

Summary

Scenario Status Notes
Released CLI runs PR AppHost package Passed AppHost version 13.4.0-pr.17507.g9fa7f3ea confirmed in logs
Legacy GetResources request returns strings Passed number/bool/array/object properties all stringified
V3-capable GetResources request returns typed JSON Passed typed JSON still available for capable callers

Overall Result

PR verified for James's backward-compatibility scenario. An older released Aspire CLI/client shape can get resource data from the new PR AppHost, and resource properties are serialized as strings for legacy callers.

@adamint
Adam Ratzman (adamint) enabled auto-merge (squash) May 27, 2026 03:49
@adamint
Adam Ratzman (adamint) merged commit f984d4f into microsoft:main May 27, 2026
616 of 619 checks passed
@microsoft-github-policy-service microsoft-github-policy-service Bot modified the milestones: 13.4, 13.5 May 27, 2026
@davidfowl

Copy link
Copy Markdown
Collaborator

Adam Ratzman (@adamint) main is 13.5, now if you want this in 13.4 then you need to backport.

@adamint

Copy link
Copy Markdown
Member Author

/backport to release/13.4

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/13.4 (link to workflow run)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Follow-up: Unresolved issues from PR #17089 (waiting dependency details in dashboard)

4 participants