Skip to content

Add VS Code resource debugging for .NET and Go - #18602

Draft
Adam Ratzman (adamint) wants to merge 85 commits into
microsoft:mainfrom
adamint:adamint/issue18538-vscode-debug-shortcut
Draft

Add VS Code resource debugging for .NET and Go#18602
Adam Ratzman (adamint) wants to merge 85 commits into
microsoft:mainfrom
adamint:adamint/issue18538-vscode-debug-shortcut

Conversation

@adamint

@adamint Adam Ratzman (adamint) commented Jul 1, 2026

Copy link
Copy Markdown
Member

Summary

Adds resource debugger attachment for running .NET and Go resources from the Aspire view and the aspire_resource_debug Copilot tool.

Fixes #18538.
Fixes #18937.

What changed

  • Adds a shared resource-debug service, provider registry, session registry, and safe result contract for tree and language-model callers.
  • Adds .NET and Go attach providers.
  • Resolves the launched application instead of attaching to dotnet run, dotnet watch, or go run. Process discovery supports Windows, macOS, and Linux.
  • Integrates Expose a project resource child PID or evaluated AssemblyName for debugger attach #18937's launcher-child behavior: dotnet run requires the direct application child, while dotnet watch and go run support verified descendants.
  • Preserves the selected AppHost PID through fresh resolution, serialization, and session tracking so concurrent runs from the same AppHost path are not conflated.
  • Detects resource processes already owned by an Aspire-launched VS Code debug session and returns alreadyDebugging.
  • Publishes non-sensitive project.launchCommand, project.configuration, and project.targetFramework snapshot metadata. Current snapshots use exact TargetPath identity; the TargetName compatibility fallback is limited to older snapshots that do not contain the new metadata.
  • Adds classified resource-debug telemetry without resource names, paths, PIDs, arguments, environment values, or raw failures.
  • Adds tree enablement, progress, cancellation, debugger-extension guidance, and localized outcomes.
  • Adds aspire_resource_debug with input validation, explicit confirmation, invocation-time re-resolution, linked cancellation, and bounded output.
  • Adds packaged VSIX E2E coverage for package contributions, resource-debug tool behavior, privacy boundaries, and edge cases.

Evidence

Real process-tree validation covers:

  • dotnet run: the application is a direct child.
  • dotnet watch: the application is a transitive descendant.
  • go run: the application is a descendant.
  • Exact .NET target selection with same-name decoys and non-default assembly names.
  • Go/Delve attach and detach without terminating the resource.

Packaged VSIX E2E exercises registration, preparation, confirmation, cancellation, stopped/unsupported/missing-resource outcomes, and bounded output through the real Extension Host.

This PR does not claim committed end-to-end breakpoint coverage for every supported language.

Validation

extension compile, lint, and unit tests
  2206 passing
  4 pending

ResourceSnapshotBuilderTests
  22 passed

ResourceSnapshotMapperTests + DescribeCommandTests
  49 passed

ExtensionE2eWorkflowTests + TestTriggerMapTests
  17 passed

packageSurface.e2e.test.ts
  8 passed

resourceDebugTools.e2e.test.ts
  3 passed

edgeCases.e2e.test.ts
  5 passed

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
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
    • No

The language-model boundary intentionally excludes process IDs, absolute paths, arguments, environment values, and raw failures. Debug attachment also requires VS Code confirmation before invocation.

Copilot AI balanced review requested due to automatic review settings July 1, 2026 20:16
@github-actions

github-actions Bot commented Jul 1, 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 -- 18602

Or

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

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

This PR adds the first VS Code extension lane for #18538: a right-click Attach debugger action on running .NET project resources in the Aspire panel. It builds a CoreCLR attach debug configuration that targets the project's process by processName (best-effort resolving <AssemblyName> from the project file), rather than executable.pid, because DCP reports the dotnet run launcher PID rather than the child app process. The action is gated on a running top-level Project resource with a dotnet executable and a .csproj/.fsproj/.vbproj path, and only when the C# extension is installed; it re-resolves the latest resource before attaching so stale/ambiguous/missing resources fail closed with a warning.

Bundled alongside the feature is a broad telemetry overhaul: every event is renamed to its final wire name (aspire/vscode/... and aspire/dashboard/...) and routed through sendDangerousTelemetryEvent/sendDangerousTelemetryErrorEvent to bypass VS Code's automatic <extensionId>/ prefix, with manual opt-in gating (telemetryLevel), manual common properties, and explicit value sanitization.

Changes:

  • Add aspire-vscode.attachDebuggerToResource command, menu contribution (canAttachDebugger context value), attachability helpers, and the attach execution flow with latest-resource re-resolution.
  • Rename all telemetry events to final wire names and route them through the "dangerous" send path with explicit gating/sanitization and manually-added common properties.
  • Add localized strings and extensive unit tests for both the attach flow and the telemetry changes.
Show a summary per file
File Description
extension/src/views/AspireAppHostTreeProvider.ts Core attach logic: attachability helpers, process-name derivation, attachDebuggerToResource, latest-resource resolution; propagates appHostPath through tree items.
extension/src/extension.ts Registers the new attach command; renames the extension/activated telemetry event.
extension/package.json Contributes the command, hidden palette entry, and view/item/context menu item; reorders action groups.
extension/package.nls.json / extension/src/loc/strings.ts / extension/loc/xlf/aspire-vscode.xlf Adds/regenerates localized strings for the attach action.
extension/src/utils/telemetry.ts Switches to dangerous-send path, adds manual gating, common properties, and value sanitization; hard-codes telemetry client version.
extension/src/utils/telemetryRegistry.ts Renames event schema keys to final aspire/vscode/... and aspire/dashboard/... wire names; documents the convention.
extension/telemetry.json Updates classification inventory keys to the new wire names.
extension/src/dcp/DashboardTelemetryPassthrough.ts / AspireDcpServer.ts / AspireDebugSession.ts / AppHostLaunchService.ts / AppHostsViewTelemetry.ts / meaningfulEngagement.ts / appHostDiscovery.ts / workspace.ts / interactionService.ts Update event-name call sites and passthrough comments to the new namespaces.
extension/src/test/*.test.ts, extension/src/test-e2e/packageSurface.e2e.test.ts Extensive tests for the attach flow, telemetry gating/sanitization/naming, and the manifest/surface contributions.

Review details

  • Files reviewed: 29/29 changed files
  • Comments generated: 3
  • Review effort level: Medium

Comment thread extension/src/utils/telemetryRegistry.ts Outdated
Comment thread extension/src/test/appHostTreeView.test.ts Outdated
Comment thread extension/src/utils/telemetry.ts Outdated
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Copilot AI review requested due to automatic review settings July 1, 2026 23:36

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.

Review details

  • Files reviewed: 30/30 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread extension/src/utils/telemetry.ts Outdated
Copilot AI review requested due to automatic review settings July 1, 2026 23:45

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.

Review details

  • Files reviewed: 30/30 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread extension/src/dcp/AspireDcpServer.ts Outdated
@adamint

Adam Ratzman (adamint) commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

I tried to place these as inline tracking comments, but GitHub rejected new inline comments because there is already a pending review draft for this user on the PR. I kept the tracking here instead while the branch was fixed:

  1. The handled attach guard failures in attachDebuggerToResource should return a failure result for command telemetry instead of plain void, otherwise withCommandTelemetry records user-visible attach failures as successful invocations.
  2. The home-directory sanitizer needed coverage and a fix for usernames with spaces; paths like /Users/Alice Smith/project or C:\Users\Alice Smith\project could leave part of the username in telemetry after the dangerous-send path.

These were fixed before the later Windows punctuation redaction follow-up. This is a top-level tracking comment, so there is no review thread to resolve; final tracking is in #18602 (comment).

@adamint

Adam Ratzman (adamint) commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

Pushed 8f4fe85 with the Windows telemetry redaction fix. Windows CI caught that the home-directory sanitizer could cross punctuation/text between two C:\Users\... paths; the parser now keeps punctuation boundaries intact and the regression is covered.

Validation on the live head passed locally: compile-tests, lint, compile, and full telemetry.test (31 passing). gh pr checks is green on 8f4fe85 (328 success / 0 pending / 3 skipped / 0 failed), and the review/test fleet found no blocking agent-owned follow-up.

Remaining non-agent gates: live CoreCLR attach/manual readiness pass, plus telemetry/reviewer sign-off for the common.* properties and dangerous-send sanitizer parity.

Copilot AI review requested due to automatic review settings July 2, 2026 20:14

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.

Review details

  • Files reviewed: 30/30 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Copilot AI review requested due to automatic review settings July 3, 2026 02:09

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.

Review details

  • Files reviewed: 30/30 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Copilot AI review requested due to automatic review settings July 3, 2026 02:46

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.

Review details

  • Files reviewed: 30/30 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Copilot AI review requested due to automatic review settings July 4, 2026 15:42

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.

Review details

  • Files reviewed: 30/30 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Copilot AI review requested due to automatic review settings July 4, 2026 16:36

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.

Review details

  • Files reviewed: 30/30 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Adam Ratzman and others added 7 commits August 15, 2026 06:31
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Preserve AppHost process identity, detect Aspire-owned debuggee processes, and publish non-sensitive .NET launch metadata for exact attach target resolution.

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

Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7

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.

Review details

  • Files reviewed: 62/62 changed files
  • Comments generated: 3
  • Review effort level: Balanced

Comment on lines +743 to +744
function isAppHostProcessForTarget(process: LaunchedChildProcess, appHostPaths: readonly string[]): boolean {
return appHostPaths.some(appHostPath => areProcessPathsEqual(process.executable, appHostPath));
Comment on lines +193 to +195
resources = await this._dependencies.appHostRepository.fetchAppHostResourcesOnce(
resolvedTarget.absolutePath,
request.cancellationToken);
*/
function toContainedPosixRelativePath(folderPath: string, candidate: string): string | undefined {
const relative = path.relative(folderPath, candidate);
if (relative.length === 0 || relative.startsWith('..') || path.isAbsolute(relative)) {
@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Adam Ratzman and others added 13 commits August 15, 2026 12:33
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7

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.

Review details

Suppressed comments (2)

extension/src/debugger/languages/dotnet.ts:764

  • On macOS, ps -o comm= supplies only the executable name, but the current-snapshot path uses the exact TargetPath branch and this matcher compares that basename with the full apphost path. Because UseAppHost is normally true for executable .NET projects, their candidate is never recognized and attach times out on macOS. Also match the program parsed from process.command, which is populated from ps -o args= with the launched path.
function isAppHostProcessForTarget(process: LaunchedChildProcess, appHostPaths: readonly string[]): boolean {
    return appHostPaths.some(appHostPath => areProcessPathsEqual(process.executable, appHostPath));
}

extension/src/lm/appHostTargetResolverService.ts:241

  • This containment check rejects valid in-workspace paths whose first segment merely starts with .., such as ..cache/AppHost.csproj. Those AppHosts can be discovered and shown by the extension but can never be selected by either language-model tool. Restrict the escape check to the actual parent segment.
function toContainedPosixRelativePath(folderPath: string, candidate: string): string | undefined {
    const relative = path.relative(folderPath, candidate);
    if (relative.length === 0 || relative.startsWith('..') || path.isAbsolute(relative)) {
        return undefined;
  • Files reviewed: 63/63 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment on lines +132 to +142
assert.deepStrictEqual(invocation.results, [{
tool: resourceDebugToolName,
success: false,
outcome: 'debuggerExtensionMissing',
appHost: relativeAppHostPath,
resourceName: worker.name,
requestedStrategy: 'auto',
effectiveStrategy: 'none',
controller: 'none',
debuggerExtensions: [{ id: 'ms-dotnettools.csharp', label: 'C#' }],
}]);
Comment thread extension/CHANGELOG.md

### Features

- Add an Attach debugger action for running .NET project resources in the Aspire pane when the C# extension is installed ([#18602](https://github.com/microsoft/aspire/pull/18602)).
@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

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

Copilot-Session: daf7d04c-3dfd-4f43-927d-830d288b9bf7

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.

Review details

Suppressed comments (3)

extension/src/debugger/resourceDebugService.ts:195

  • The selected AppHost PID is dropped during the fresh resource refresh. aspire describe --apphost <path> cannot distinguish overlapping runs; AppHostConnectionResolver.ResolveConnectionAsync iterates matching sockets and returns the first connection (src/Aspire.Cli/Backchannel/AppHostConnectionResolver.cs:138-155). Thus a tree item for PID 2222 can fetch PID 1111's resource metadata and attach to the wrong process while session tracking records 2222. Carry the resolved PID/socket identity into the describe call, or fetch the snapshot through the exact resolved AppHost connection.
            resources = await this._dependencies.appHostRepository.fetchAppHostResourcesOnce(
                resolvedTarget.absolutePath,
                request.cancellationToken);

extension/src/lm/appHostTargetResolverService.ts:240

  • This containment check also rejects legitimate in-workspace paths whose first segment merely begins with .., such as ..services/AppHost.csproj. Check for the parent segment itself (..) or ..${path.sep} instead of any .. prefix.
    if (relative.length === 0 || relative.startsWith('..') || path.isAbsolute(relative)) {

extension/src/test-e2e/resourceDebugTools.e2e.test.ts:142

  • The running-resource E2E stops at debuggerExtensionMissing, so it never exercises process discovery, startDebugging, breakpoint binding, detach, or verifies that the resource survives detach. No committed E2E covers Go attachment either. This leaves the central new behavior unprotected and does not meet issue #18538's explicit .NET and non-.NET attach/breakpoint/detach completion criterion; add packaged-VSIX scenarios with the debugger extensions installed for both providers.
  • Files reviewed: 63/63 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose a project resource child PID or evaluated AssemblyName for debugger attach [VS Code] Attach a debugger to resources in a running AppHost

3 participants