Skip to content

Harden Azure Functions VS Code launch lifecycle - #19205

Merged
Adam Ratzman (adamint) merged 9 commits into
mainfrom
ellahathaway-harden-functions-launch-lifecycle
Aug 19, 2026
Merged

Adam Ratzman (adamint) merged 9 commits into
mainfrom
ellahathaway-harden-functions-launch-lifecycle

Conversation

@ellahathaway

@ellahathaway Ella Hathaway (ellahathaway) commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Description

Issue #19138 tracked seven follow-up gaps in the Azure Functions VS Code launch lifecycle and E2E coverage. Since the issue was filed, #19313 replaced the startFuncProcess API path with an Aspire-owned, registered func task. That current main implementation now owns the exact task execution, reports task exits, and avoids signalling a worker PID after natural task exit.

This PR completes the remaining follow-up work against that registered-task design:

  • Validates and quotes caller-provided launch arguments before building the Functions project.
  • Supports POSIX-compatible bash, dash, ash, zsh, fish, and ksh task shells while continuing to reject shells whose quoting rules are unsupported.
  • Accepts only positive worker PIDs within Node's signed 32-bit process range and reports malformed Core Tools NDJSON through a localized error.
  • Exercises real shell quoting in the Azure Functions E2E fixture with a shell-sensitive HTTPS certificate password.
  • Invokes the Windows func.cmd preflight through ComSpec, which Node requires for .cmd files.
  • Targets every generated extension E2E project at .NET 10 and verifies the workflow installs the SDK from global.json before Azure Functions prerequisites.

User-facing behavior

Unsupported shell arguments and invalid launch data now fail directly, before a project build or debugger attachment. dash and ash configurations work like other POSIX shells. The resulting registered-task lifecycle reports Azure Functions exits and stops the exact task without risking termination of a recycled worker PID.

Validation

  • TypeScript test compilation passed.
  • ESLint passed.
  • Azure Functions debugger suite: 42 passing.
  • Azure Functions E2E toolchain and launch-profile contract coverage passed.

The real Azure Functions E2E shard is exercised by the pull request workflow with pinned Core Tools and VS Code extension prerequisites.

Fixes #19138

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

Validate shell arguments and worker PIDs, adopt reused Functions tasks, improve process cleanup, and strengthen .NET 10 E2E coverage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3eabf6e8-5e26-4877-9f92-2265293a6b0f
Copilot AI balanced review requested due to automatic review settings August 10, 2026 22:03
@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 -- 19205

Or

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

@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

Hardens Azure Functions launch validation, task adoption, PID handling, and process-exit cleanup in the VS Code extension.

Changes:

  • Validates shell arguments and worker PIDs before launch.
  • Tracks reused tasks and polls worker liveness when task capture fails.
  • Expands lifecycle tests and updates E2E fixtures to .NET 10.

Reviewed changes

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

Show a summary per file
File Description
extension/src/debugger/languages/azureFunctions.ts Hardens launch and cleanup lifecycle.
extension/src/test/azureFunctionsDebugger.test.ts Adds lifecycle, shell, and PID tests.
extension/src/test/e2eLaunchProfile.test.ts Extends E2E source contracts.
extension/src/test-e2e/helpers/fixtures.ts Targets .NET 10.
extension/scripts/run-e2e.js Updates fixtures and shell-sensitive HTTPS arguments.
extension/src/loc/strings.ts Adds localized invalid-PID error.
extension/package.nls.json Registers the localization string.
extension/loc/xlf/aspire-vscode.xlf Updates generated localization data.
extension/CONTRIBUTING.md Documents updated E2E prerequisites and behavior.

Comment thread extension/src/test/e2eLaunchProfile.test.ts Outdated
Comment thread extension/src/test/azureFunctionsDebugger.test.ts Outdated
@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.

Reject worker process IDs outside Node's signed 32-bit process range and cover the first invalid boundary.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3eabf6e8-5e26-4877-9f92-2265293a6b0f
Replace the natural-exit flag with explicit completion reasons and cover the full Functions-to-DCP lifecycle for task exit, worker disappearance, and explicit stop.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3eabf6e8-5e26-4877-9f92-2265293a6b0f
Copilot AI review requested due to automatic review settings August 11, 2026 16:42
@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 no new comments.

Make the Azure Functions E2E contract assert each generated project TFM instead of accepting a single net10.0 match.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3eabf6e8-5e26-4877-9f92-2265293a6b0f
Copilot AI review requested due to automatic review settings August 11, 2026 16:48

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 no new comments.

@github-actions

This comment has been minimized.

Invoke the Azure Functions Core Tools .cmd shim through ComSpec so the E2E runner can validate it on Windows.

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

Copilot-Session: 3eabf6e8-5e26-4877-9f92-2265293a6b0f
Copilot AI review requested due to automatic review settings August 11, 2026 18:17
@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 no new comments.

@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.

@ellahathaway

Copy link
Copy Markdown
Contributor Author

Waiting on #19237

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 19, 2026 16:58
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 19, 2026 17:06

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 no new comments.

Suppressed comments (1)

extension/src/debugger/languages/azureFunctions.ts:507

  • JSON.parse can return null for a syntactically valid NDJSON line. Dereferencing event.name then throws an unlocalized TypeError, so malformed Core Tools output can still bypass the localized launch error. Parse as unknown and narrow to a non-null object before reading name; add a regression case containing null\n.
        if (event.name !== 'dotnet-worker-startup') {

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 19, 2026 17:17
@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 no new comments.

Suppressed comments (2)

extension/src/test/e2eLaunchProfile.test.ts:524

  • This contract still misses a generated E2E project: extension/src/test-e2e/appHostLifecycleTools.e2e.test.ts:749 writes LinkedAppHost.csproj with net8.0, and that spec runs in the workflow matrix. Consequently, installing only the SDK from global.json does not remove the suite's implicit .NET 8 dependency, contrary to this PR's stated goal. Update that generator to net10.0 and include it in this contract.
        assert.deepStrictEqual(fixtureTargetFrameworks, ['net10.0']);

extension/CONTRIBUTING.md:136

  • This statement is not yet accurate: extension/src/test-e2e/appHostLifecycleTools.e2e.test.ts:749 still generates a linked-worktree AppHost targeting net8.0, and that spec is part of the E2E workflow matrix. Either move that fixture to .NET 10 as intended by this PR or document the remaining .NET 8 prerequisite.
The E2E fixtures target .NET 10, matching the SDK pinned by the repository's `global.json`. The Azure Functions shard additionally requires Azure Functions Core Tools v4 (`func`) on `PATH`. It installs the real .NET Install Tool, C#, Azure Resource Groups, and Azure Functions extensions into the isolated VS Code instance, generates a dedicated HTTPS certificate with shell-sensitive arguments, and activates the Azure Functions extension so it registers its `func` task definition and listeners. Aspire then creates and runs a registered `func: host start` task for the generated .NET isolated Functions resource; the shard probes its HTTPS endpoint and verifies that stopping the Aspire resource ends the same VS Code task. CI runs this shard on Linux with pinned, checksum-verified copies of Core Tools 4.12.1, .NET Install Tool 3.1.0, C# 2.148.23 for Linux x64, Azure Resource Groups 0.12.7, and Azure Functions 1.22.0.

@github-actions

This comment has been minimized.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 19, 2026 17:41

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 10 out of 10 changed files in this pull request and generated no new comments.

Suppressed comments (1)

extension/src/debugger/languages/azureFunctions.ts:504

  • This catch treats every JSON parse failure as an in-flight final record, including malformed records that are already newline-terminated. Such a record is silently skipped, so the launch can time out or attach using a later event instead of reporting the malformed Core Tools NDJSON directly. Only suppress the parse error for the final unterminated line; complete malformed records should fail with a localized error.
        } catch {
            // The final NDJSON line may still be in flight.
            continue;

@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.

0 / 102 test projects · 2 jobs, from 9 changed files.

Selected test projects (0 / 102)

none — no .NET test projects run for this change.

Selected jobs (2)

extension-e2e, extension-unit


How these were chosen — grouped by what changed

Job reasons

Job Triggered by
extension-e2e extension/loc/xlf/aspire-vscode.xlf, extension/package.nls.json, extension/scripts/run-e2e.js, extension/src/debugger/languages/azureFunctions.ts, extension/src/loc/strings.ts, extension/src/test-e2e/appHostLifecycleTools.e2e.test.ts, extension/src/test-e2e/helpers/fixtures.ts, extension/src/test/azureFunctionsDebugger.test.ts, extension/src/test/e2eLaunchProfile.test.ts
extension-unit extension/loc/xlf/aspire-vscode.xlf, extension/package.nls.json, extension/scripts/run-e2e.js, extension/src/debugger/languages/azureFunctions.ts, extension/src/loc/strings.ts, extension/src/test-e2e/appHostLifecycleTools.e2e.test.ts, extension/src/test-e2e/helpers/fixtures.ts, extension/src/test/azureFunctionsDebugger.test.ts, extension/src/test/e2eLaunchProfile.test.ts

Selection computed for commit e88fbc3.

@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.

@adamint Adam Ratzman (adamint) left a comment

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.

The current-head malformed-NDJSON finding is still unresolved and blocks approval. I didn't find a separate issue beyond that existing review note.

@adamint
Adam Ratzman (adamint) merged commit ef44893 into main Aug 19, 2026
754 of 757 checks passed
@adamint
Adam Ratzman (adamint) deleted the ellahathaway-harden-functions-launch-lifecycle branch August 19, 2026 19:34
@microsoft-github-policy-service microsoft-github-policy-service Bot added this to the 13.6 milestone Aug 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ CI Failure Analysis: Possible Flaky Test(s)

The CI build failed due to test failure(s) that appear unrelated to the PR changes. These may be flaky tests.

Suspected flaky test(s):

  • Aspire.Dashboard.Tests.Model.DashboardClientTests.SubscribeResources_ReplicaStartedAtChanged_EmitsParentChange in job Tests / Dashboard / Dashboard (ubuntu-latest)
    • Error: Assert.Single() Failure: The collection contained 2 matching items
      Expected: (predicate expression)
      Collection: [ResourceViewModelChange { ChangeType = Upsert, Resource = Aspire.Dashboard.Model.ResourceViewModel }, ResourceViewModelChange { ChangeType = Upsert, Resource = Aspire.Dashboard.Model.ResourceViewModel }, ResourceViewModelChange { ChangeType = Upsert, Resource = Aspire.Dashboard.Model.ResourceViewModel }, ResourceViewModelChange { ChangeType = Upsert, Resource = Aspire.Dashboard.Model.ResourceViewModel }]
      Match indices: 0, 3
    • Stack Trace (first frames):
      at Aspire.Dashboard.Tests.Model.DashboardClientTests.SubscribeResources_ReplicaStartedAtChanged_EmitsParentChange() in /_/tests/Aspire.Dashboard.Tests/Model/DashboardClientTests.cs:line 567
         at Aspire.Dashboard.Tests.Model.DashboardClientTests.SubscribeResources_ReplicaStartedAtChanged_EmitsParentChange() in /_/tests/Aspire.Dashboard.Tests/Model/DashboardClientTests.cs:line 569
      
    • Why likely flaky: The test asserts exactly one matching change event, but two matching upsert events were emitted (indices 0 and 3), indicating a timing/ordering race in the resource change subscription stream rather than an assertion tied to any PR-modified code. PR Harden Azure Functions VS Code launch lifecycle #19205 only modifies files under extension/ (VS Code extension), not Aspire.Dashboard or its tests.

Suggested actions:

  • Re-run the failed CI jobs to confirm if the failure is intermittent
  • If the test continues to fail, consider quarantining it using /quarantine-test <test name> <issue URL>
  • Search existing issues to see if this test is already known to be flaky

You can re-run the failed jobs from the workflow run page.

@aspire-repo-bot

Copy link
Copy Markdown
Contributor

⚠️ Documentation drafting was attempted but the draft PR could not be confirmed.

See the workflow run for details: https://github.com/microsoft/aspire/actions/runs/32293779350

Added a note to the VS Code extension docs (get-started/aspire-vscode-extension.mdx) explaining that Azure Functions debugging now runs via a registered VS Code task with upfront validation of launch arguments, and listing the supported POSIX shells (bash, dash, ash, zsh, fish, ksh).

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.

Harden Azure Functions VS Code launch lifecycle and E2E coverage

3 participants