Skip to content

Fix Helm cleanup ordering for AKS destroy - #19243

Merged
Sébastien Ros (sebastienros) merged 13 commits into
mainfrom
sebros/fix-aks-helm-destroy
Sep 4, 2026
Merged

Sébastien Ros (sebastienros) merged 13 commits into
mainfrom
sebros/fix-aks-helm-destroy

Conversation

@sebastienros

Copy link
Copy Markdown
Contributor

Description

aspire destroy could fail for AKS deployments when the caller did not already have the cluster selected in their ambient kubeconfig. Helm cleanup ran without first acquiring AKS credentials, while Azure resource-group deletion could start concurrently and race the cluster teardown.

This change adds a destroy-specific AKS credential step that stays separate from the provisioning-dependent deploy credential step. Kubernetes cleanup steps are tagged per environment so the pipeline can order the main Helm release, opted-in external charts, and cert-manager resources after credential acquisition. Azure resource-group deletion now waits for all cluster cleanup to finish. Credential acquisition uses persisted Azure state so retries after partial teardown continue to target the correct cluster.

User-facing usage

AKS deployments can now be destroyed without relying on the caller's current Kubernetes context:

KUBECONFIG="$(mktemp)" aspire destroy \
  --apphost MyApp.AppHost/MyApp.AppHost.csproj \
  --environment my-environment \
  --non-interactive \
  --yes

The regression coverage verifies the complete destroy dependency graph, including multiple AKS environments, and the deployment scenario replaces its ambient kubeconfig before running destroy.

Fixes: #19206

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 AI balanced review requested due to automatic review settings August 11, 2026 18:37
@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 -- 19243

Or

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

@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

Adds AKS destroy ordering so Kubernetes cleanup acquires credentials before Helm/cert-manager teardown and Azure deletion runs last.

Changes:

  • Tags and orders Kubernetes cleanup steps per AKS environment.
  • Adds destroy-specific credential acquisition.
  • Expands dependency-graph and deployment E2E coverage.

Reviewed changes

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

Show a summary per file
File Description
AzureKubernetesInfrastructureTests.cs Tests destroy dependency graphs.
AksWithHelmChartDeploymentTests.cs Tests destroy with an empty kubeconfig.
KubernetesHelmChartExtensions.cs Tags external-chart cleanup.
HelmDeploymentEngine.cs Defines destroy tags for Helm cleanup.
CertManagerExtensions.cs Tags issuer cleanup.
AzureKubernetesEnvironmentResource.cs Orders credentials, cleanup, and Azure deletion.
AzureKubernetesEnvironmentResource.AksPipeline.cs Adds destroy credential acquisition.
Suppressed comments (2)

src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.AksPipeline.cs:312

  • This call cannot complete in a destroy-only graph. Pipeline step creation initializes this resource's ProvisioningTaskCompletionSource, but the new credential step deliberately does not depend on the provisioning step; GetAksCredentialsAsync then calls NameOutputReference.GetValueAsync, which waits on that never-completed task. Read/hydrate the saved AKS name output directly for destroy (without awaiting provisioning) and pass it into the credential routine.
        await GetAksCredentialsAsync(context).ConfigureAwait(false);

src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.AksPipeline.cs:304

  • Azure state can still exist after the resource-group delete has started because that step uses WaitUntil.Started, and the original Helm failure leaves overall state uncleared. On a retry after AKS has disappeared, this check enters credential acquisition and fails before the idempotent Azure destroy step can report that the group is already gone. Treat a missing AKS cluster/resource group as a successful no-op in the destroy credential step so partial-teardown retries can finish.
        if (string.IsNullOrEmpty(resourceGroupName) || string.IsNullOrEmpty(subscriptionId))

@sebastienros

Copy link
Copy Markdown
Contributor Author

PR Testing Report

PR Information

Artifact Version Verification

  • Expected Commit: 5b9b1eb5af77f842e0b5cd321da14296f46da914
  • Installed Version: 13.6.0-pr.19243.g5b9b1eb5
  • Installed Binary: /var/folders/qn/lq74424935j69rxktvp5tqwc0000gn/T/aspire-pr-test-19243-XXXXXX.9jH8mvMb7i/dogfood/pr-19243/bin/aspire
  • Status: Verified

The CLI was installed from the PR's cli-native-archives-osx-arm64 artifact after that artifact became available.

Changes Analyzed

Files Changed

  • src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.AksPipeline.cs
  • src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.cs
  • src/Aspire.Hosting.Kubernetes/CertManagerExtensions.cs
  • src/Aspire.Hosting.Kubernetes/Deployment/HelmDeploymentEngine.cs
  • src/Aspire.Hosting.Kubernetes/KubernetesHelmChartExtensions.cs
  • tests/Aspire.Deployment.EndToEnd.Tests/AksWithHelmChartDeploymentTests.cs
  • tests/Aspire.Hosting.Azure.Kubernetes.Tests/AzureKubernetesInfrastructureTests.cs

Change Categories

  • CLI changes
  • Hosting integration changes
  • Dashboard changes
  • Client/component changes
  • Template changes
  • VS Code extension changes
  • Test changes
  • CI infrastructure changes

Test Scenarios Executed

Scenario 1: PR artifact identity and fresh AKS AppHost

Objective: Verify that testing uses the artifact containing the PR changes and that a fresh AppHost can consume the PR AKS package.

Coverage Type: Artifact and build validation

Status: Passed

Steps:

  1. Installed PR Fix Helm cleanup ordering for AKS destroy #19243 with the repository dogfood installer into an isolated temp directory.
  2. Verified the installed binary reports 13.6.0-pr.19243.g5b9b1eb5.
  3. Created a fresh C# aspire-empty AppHost from the PR package hive.
  4. Added Aspire.Hosting.Azure.Kubernetes version 13.6.0-pr.19243.g5b9b1eb5.
  5. Built and evaluated the AppHost through aspire destroy --list-steps.

Evidence:

  • version.txt
  • install-retry.log
  • scenario-no-state/new-retry.log
  • scenario-no-state/add-aks.log
  • scenario-no-state/list-steps-cleanup.log

Observations:

  • The installed CLI short SHA matches the PR head.
  • The fresh AppHost restored and loaded the PR SDK and AKS integration successfully.

Scenario 2: Safe AKS destroy without deployment state

Objective: Verify that a never-deployed AKS AppHost can be destroyed safely without ambient Kubernetes credentials or Azure deployment state.

Coverage Type: Unhappy path

Status: Passed

Steps:

  1. Created a new empty kubeconfig file and set KUBECONFIG to it.
  2. Ran aspire destroy non-interactively for a unique environment that had never been deployed.
  3. Captured debug-level pipeline output.

Evidence:

  • scenario-no-state/destroy.log

Expected Unhappy-Path Outcome: Credential acquisition, Helm teardown, and Azure deletion should each recognize missing persisted state and complete safely.

Observations:

  • aks-get-credentials-for-destroy-aks reported no Azure deployment state and skipped credential acquisition.
  • destroy-helm-aks reported no Helm deployment state.
  • destroy-azure-azure-environment reported no Azure deployment state.
  • The destroy pipeline completed with 12 of 12 steps successful.

Scenario 3: AKS cluster-cleanup dependency graph

Objective: Verify the dogfood artifact exposes the intended destroy topology for the main release, an opted-in external Helm chart, and cert-manager resources.

Coverage Type: Boundary and topology validation

Status: Passed

Steps:

  1. Added an AKS environment, the podinfo external Helm chart with .WithDestroy(), and a cert-manager issuer to the fresh AppHost.
  2. Ran aspire destroy --list-steps with an empty kubeconfig.
  3. Inspected direct dependencies and environment-scoped cleanup tags.

Evidence:

  • scenario-no-state/apphost.cs
  • scenario-no-state/list-steps-cleanup.log

Observations:

  • Deploy credentials remain isolated behind provision-azure-bicep-resources.
  • aks-get-credentials-for-destroy-aks depends only on destroy-prereq.
  • destroy-helm-aks, helm-uninstall-podinfo, helm-uninstall-cert-manager-chart, and cm-issuer-delete-letsencrypt are tagged kubernetes-destroy-aks and depend on destroy credential acquisition.
  • Cert-manager chart removal also waits for issuer deletion.
  • destroy-azure-azure-environment waits for all four cluster-facing cleanup steps.

Scenario 4: Focused source regression suites

Objective: Verify the PR source passes the affected Azure Kubernetes and Kubernetes hosting test projects.

Coverage Type: Automated regression

Status: Passed

Steps:

  1. Ran Aspire.Hosting.Azure.Kubernetes.Tests excluding quarantined and outerloop tests.
  2. Ran Aspire.Hosting.Kubernetes.Tests excluding quarantined and outerloop tests.

Evidence:

  • source-tests/azure-kubernetes.log
  • source-tests/kubernetes.log

Observations:

  • Azure Kubernetes: 69 passed, 0 failed, 0 skipped.
  • Kubernetes: 270 passed, 0 failed, 0 skipped.

Scenario Not Executed

Live AKS deploy and destroy with empty kubeconfig

Status: Not run

This scenario provisions billable Azure resources and requires explicit approval. No user was available to approve cloud provisioning, so testing stopped short of the live deployment. The updated deployment E2E test remains the appropriate end-to-end validation for this path.

Summary

Scenario Status Notes
PR artifact identity and fresh AKS AppHost Passed Artifact matches PR head
Safe AKS destroy without deployment state Passed 12/12 pipeline steps succeeded
AKS cluster-cleanup dependency graph Passed All cleanup precedes Azure deletion
Focused source regression suites Passed 339 tests passed
Live AKS deploy/destroy Not run Explicit approval required for billable Azure resources

Overall Result

PARTIALLY VERIFIED

All non-provisioning artifact and source scenarios passed. The live AKS deployment scenario is still required to verify the original failure against a real cluster with an empty ambient kubeconfig.

@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 App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a5fbe5fe-6726-431d-af32-692b54aa1c2b
Copilot AI review requested due to automatic review settings August 11, 2026 22:04
@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 8 out of 8 changed files in this pull request and generated 1 comment.

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

Copilot-Session: a5fbe5fe-6726-431d-af32-692b54aa1c2b
Copilot AI review requested due to automatic review settings August 11, 2026 23:14
@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 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.AksPipeline.cs:344

  • When persisted AKS state is incomplete, returning here leaves KubernetesEnvironment.KubeConfigPath unset, but all tagged cleanup steps still run. External chart uninstall falls back to its configured release name, and cert-manager issuer deletion always invokes kubectl, so both will use the caller's ambient kubeconfig and can delete resources from an unrelated cluster—the behavior this change is intended to eliminate. Fail this prerequisite (or otherwise prevent the downstream cleanup steps from executing) instead of continuing without an isolated kubeconfig.
            context.Logger.LogInformation(
                "No complete Azure deployment state found for AKS environment '{EnvironmentName}'. Skipping credential acquisition.",
                Name);
            return;

@sebastienros
Sébastien Ros (sebastienros) marked this pull request as ready for review August 11, 2026 23:25
@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.

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.

Two destroy-path correctness issues remain at 3bb5670509: incomplete persisted state can send cleanup to the ambient Kubernetes context, and adopted AKS resources ignore their persisted resource-specific Azure scope. The existing --clear-cache E2E coverage issue is already tracked in a separate thread and was not duplicated.

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

Copilot-Session: a5fbe5fe-6726-431d-af32-692b54aa1c2b
Copilot AI review requested due to automatic review settings August 12, 2026 18:26
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a5fbe5fe-6726-431d-af32-692b54aa1c2b
@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 7 out of 7 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.AksPipeline.cs:345

  • The destroy path always uses the app-wide Azure subscription/resource group, but AKS can target an existing cluster in a different scope via AsExistingInResourceGroup or Scope. In that supported scenario, credential acquisition now targets the app resource group (or skips when global Azure state is absent) instead of the cluster scope, so Helm cleanup still fails or reaches the wrong cluster. Apply the same explicit-scope precedence used by the deploy credential path, while using persisted state only as its fallback.
        var resourceGroupName = stateSection.Data["ResourceGroup"]?.ToString();
        var subscriptionId = stateSection.Data["SubscriptionId"]?.ToString();

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

Suppressed comments (1)

src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.AksPipeline.cs:428

  • A malformed persisted Scope aborts the credential prerequisite, which also prevents the dependent destroy-azure-* step from deleting the resource group. Scope is optional cached state elsewhere, and the already-validated clusterResourceId contains the exact subscription and resource group, so use it as the safe fallback instead of blocking aggregate destroy.
            catch (Exception ex) when (ex is not OperationCanceledException)
            {
                throw new InvalidOperationException(
                    $"The Azure deployment state for AKS environment '{Name}' contains an invalid scope.",
                    ex);

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

@mitchdenny Mitch Denny (mitchdenny) 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.

Looks good — the destroy ordering fix is sound: tagging cluster-scoped cleanup steps and making destroy-azure-* depend on them is the right shape, and the destroy-only credential step correctly avoids pulling provisioning into the destroy graph.

Three non-blocking follow-ups:

  1. AzureKubernetesEnvironmentResource.cs uses .Single() for the AzureEnvironmentResource and the destroy-azure-* step. Every other call site in the repo uses SingleOrDefault/FirstOrDefault with a guard — safe in practice since AddAzureProvisioning always adds it, but a mis-shaped model would surface an opaque "Sequence contains no elements".
  2. AksResourceExistsAsync throws on any nonzero az resource list exit. If the resource group itself was deleted out-of-band, that's ResourceGroupNotFound, which fails the credential step and blocks the entire destroy including Azure cleanup. Probably worth treating a missing RG the same as a missing cluster.
  3. The E2E test dropped the helm list -n podinfo assertion, so destroy is now only verified by pipeline success. Understandable given the cluster is gone by then, but it's lost coverage on the WithDestroy() contract.

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

Copilot-Session: a5fbe5fe-6726-431d-af32-692b54aa1c2b
Copilot AI review requested due to automatic review settings September 4, 2026 15:15
@sebastienros

Copy link
Copy Markdown
Contributor Author

Addressed the three follow-ups from review 5108517925 in c303691:

  1. Added guarded Azure environment and destroy-step lookups with actionable errors.
  2. Treat (ResourceGroupNotFound) from the scoped AKS existence query as an already-absent cluster while preserving failures for unrelated Azure CLI errors.
  3. Restored E2E coverage for WithDestroy() by asserting that helm-uninstall-podinfo participates in the successful aggregate destroy pipeline.

The Azure Kubernetes suite passes 110/110, and the deployment E2E project builds with no warnings or errors.

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Tests selector

5 / 99 PR test projects · 2 PR jobs · 2 advisory-only targets, from 14 changed files.

Selected PR test projects (5 / 99)

Aspire.Hosting.Azure.Kubernetes.Tests, Aspire.Hosting.Azure.Tests, Aspire.Hosting.CodeGeneration.TypeScript.Tests, Aspire.Hosting.Docker.Tests, Aspire.Hosting.Kubernetes.Tests

Selected PR jobs (2)

extension-e2e, typescript-api-compat

Advisory workflow impact (2)

  • Aspire.Deployment.EndToEnd.Tests (deployment workflow-only)
  • deployment-e2e (schedule/dispatch-only)

How these were chosen — grouped by what changed

🔧 src/Aspire.Hosting.Kubernetes/CertManagerExtensions.cs (changed source)
→ 1 directly: Aspire.Hosting.Kubernetes.Tests
→ 2 via the project graph: Aspire.Hosting.CodeGeneration.TypeScript.Tests, Aspire.Hosting.Docker.Tests

🔧 src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.AksPipeline.cs (changed source)
→ 2 directly: Aspire.Hosting.Azure.Kubernetes.Tests, Aspire.Hosting.Azure.Tests

🔧 src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.cs (changed source)
→ 2 directly: Aspire.Hosting.Azure.Kubernetes.Tests, Aspire.Hosting.Azure.Tests

🔧 src/Aspire.Hosting.Kubernetes/Deployment/HelmDeploymentEngine.cs (changed source)
→ 1 directly: Aspire.Hosting.Kubernetes.Tests

🔧 src/Aspire.Hosting.Kubernetes/KubernetesEnvironmentResource.cs (changed source)
→ 1 directly: Aspire.Hosting.Kubernetes.Tests

🔧 src/Aspire.Hosting.Kubernetes/KubernetesHelmChartExtensions.cs (changed source)
→ 1 directly: Aspire.Hosting.Kubernetes.Tests

🧪 tests/Aspire.Deployment.EndToEnd.Tests/AksWithHelmChartDeploymentTests.cs (changed test)
→ 1 directly: Aspire.Deployment.EndToEnd.Tests

🧪 tests/Aspire.Hosting.Azure.Kubernetes.Tests/Aspire.Hosting.Azure.Kubernetes.Tests.csproj (changed test)
→ 1 directly: Aspire.Hosting.Azure.Kubernetes.Tests

🧪 tests/Aspire.Hosting.Azure.Kubernetes.Tests/AzureKubernetesInfrastructureTests.cs (changed test)
→ 1 directly: Aspire.Hosting.Azure.Kubernetes.Tests

🧪 tests/Aspire.Hosting.Kubernetes.Tests/Aspire.Hosting.Kubernetes.Tests.csproj (changed test)
→ 1 directly: Aspire.Hosting.Kubernetes.Tests

🧪 tests/Aspire.Hosting.Kubernetes.Tests/FakeHelmRunner.cs (changed test)
→ 1 directly: Aspire.Hosting.Kubernetes.Tests

🧪 tests/Aspire.Hosting.Kubernetes.Tests/HelmVersionValidatorTests.cs (changed test)
→ 1 directly: Aspire.Hosting.Kubernetes.Tests

🧪 tests/Aspire.Hosting.Kubernetes.Tests/KubernetesDeployTests.cs (changed test)
→ 1 directly: Aspire.Hosting.Kubernetes.Tests

Job reasons

Job Triggered by
deployment-e2e • tests/Aspire.Deployment.EndToEnd.Tests/AksWithHelmChartDeploymentTests.cs
• affected project Aspire.Hosting.Azure.Kubernetes
extension-e2e • src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.AksPipeline.cs, src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.cs, src/Aspire.Hosting.Kubernetes/CertManagerExtensions.cs, src/Aspire.Hosting.Kubernetes/Deployment/HelmDeploymentEngine.cs, src/Aspire.Hosting.Kubernetes/KubernetesEnvironmentResource.cs, src/Aspire.Hosting.Kubernetes/KubernetesHelmChartExtensions.cs
• affected project Aspire.Hosting.Azure.Kubernetes
typescript-api-compat affected project Aspire.Hosting.Azure.Kubernetes

Selection computed for commit c303691.

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.

🟢 Approval recommended

The destroy graph, persisted-state handling, retry behavior, and real deployment scenario are comprehensively covered.

Review details
  • Files reviewed: 13/13 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@github-actions

github-actions Bot commented Sep 4, 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 Sep 4, 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.

@sebastienros
Sébastien Ros (sebastienros) merged commit ff714af into main Sep 4, 2026
247 of 254 checks passed
@sebastienros
Sébastien Ros (sebastienros) deleted the sebros/fix-aks-helm-destroy branch September 4, 2026 17:52
@microsoft-github-policy-service microsoft-github-policy-service Bot added this to the 13.6 milestone Sep 4, 2026
aspire-repo-bot Bot added a commit to microsoft/aspire.dev that referenced this pull request Sep 4, 2026
Documents the new destroy-specific AKS credential acquisition from
microsoft/aspire#19243, which lets 'aspire destroy' tear down AKS
deployments without relying on the caller's ambient kubectl context.

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

Copy link
Copy Markdown
Contributor

Pull request created: #1620

Generated by PR Documentation Check · auto · 63.4 AIC · ⌖ 7.73 AIC · ⊞ 19.7K

@aspire-repo-bot

Copy link
Copy Markdown
Contributor

📝 Documentation has been drafted in microsoft/aspire.dev#1620 targeting release/13.6.

Added a "Clean up resources" section to the AKS deployment doc covering aspire destroy, the new independent AKS credential acquisition, and the non-interactive CI/CD example from the PR body.

  • Modified: src/frontend/src/content/docs/deployment/kubernetes/aks.mdx

Note

This draft PR needs human review before merging.

@github-actions

github-actions Bot commented Sep 4, 2026

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.Components.Tests.Pages.MetricsTests.ChangeResource_MeterAndInstrumentNotOnNewResources_InstrumentCleared in job Tests / No-package tests (regular, Aspire.Dashboard.Components.Tests, Dashboard.Components, Dashboard.Components (windows-latest))
    • Error: Microsoft.Data.Sqlite.SqliteException : SQLite Error 1: 'expected 0 columns for '' but got 18'.
    • Stack Trace (first frames):
      at Microsoft.Data.Sqlite.SqliteCommand.PrepareAndEnumerateStatements()+MoveNext()
         at Microsoft.Data.Sqlite.SqliteCommand.GetStatements()+MoveNext()
         at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
         at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
         at Aspire.Dashboard.Otlp.Storage.SqliteTelemetryRepository.MaterializeMetricDimensions(...) in SqliteTelemetryRepository.Metrics.Reads.cs:line 206
      
    • Why likely flaky: Matches prior cause 'dashboard-components-sqlite-column-count-mismatch' (issue [CI Failure] Flaky: MetricsTests.ChangeResource_MeterAndInstrumentNotOnNewResources_InstrumentCleared fails with SQLite 'expected 0 columns' error on Windows #19742, 4 prior occurrences). PR does not touch Dashboard or SQLite storage code.
  • Aspire.Templates.Tests.NewUpAndBuildStandaloneTemplateTests.CanNewAndBuild(templateName: "aspire-ts-cs-starter", extraArgs: "", sdk: Net11, tfm: Net10, error: null) in job Tests / Package tests - Windows (class, Aspire.Templates.Tests, Templates-NewUpAndBuildStandaloneTemplateTests (windows-latest))
    • Error: Aspire.Templates.Tests.ToolCommandException : Expected 0 exit code but got 1: dotnet.exe build ... /p:TreatWarningsAsErrors=true -c Debug /p:AspireUseCliBundle=false
    • Stack Trace (first frames):
      at Aspire.Templates.Tests.CommandResult.EnsureExitCode(...) in CommandResult.cs:line 36
         at Aspire.Templates.Tests.CommandResult.EnsureSuccessful(...) in CommandResult.cs:line 20
         at Aspire.Templates.Tests.AspireProject.BuildAsync(...) in AspireProject.cs:line 347
         at Aspire.Templates.Tests.NewUpAndBuildStandaloneTemplateTests.CanNewAndBuild(...) in NewUpAndBuildStandaloneTemplateTests.cs:line 46
      
    • Why likely flaky: Template build failure on a newly-generated aspire-ts-cs-starter project using preview .NET 11 SDK; unrelated to PR's Kubernetes/Helm hosting changes. No matching test file in PR changed files.

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.

David Pine (IEvangelist) added a commit to microsoft/aspire.dev that referenced this pull request Sep 28, 2026
…ps (#1780)

## Summary

<!-- Describe what this pull request changes and why. -->

Reconcile the 13.6 wiki audit and **all 25 open `docs-from-code`
proposals targeting `release/13.6`** against the actual release source.
Add missing canonical guidance rather than putting all coverage in
What's new. This is a new, isolated feature PR into `release/13.6`; it
does not update the release rollup #1599, merge or close another
proposal, or push directly to a release branch.

**Draft with explicit remaining packaging/validation gates:** the six
REPL walkthroughs are source-verified, but current publicly available
13.6 packages do not contain the late `WithRepl` exports. Generated API
catalogs have deliberately not been fabricated or refreshed from 14.x.
See the open checklist below.

### Evidence baseline

- Documentation base: `717442f6666948bcf77f3d704dc2dadf7c080ec2`.
- Product source of truth:
[`microsoft/aspire@e8fd6fbb954f50ccd2e66479538392f65e13e71d`](https://github.com/microsoft/aspire/tree/e8fd6fbb954f50ccd2e66479538392f65e13e71d),
current `release/13.6` at audit time. Source was read from that Git
object, not the stale source working directory.
- [13.6 wiki](https://github.com/microsoft/aspire/wiki/13.6-Change-log)
snapshot `8e01a371d4f16a1306e48174d4cf1fdeca714348`, whose cutoff is
product PR 20511. Later backports 20541/20546/20548 are included here.
- Proposal base branches alone were **not** used as proof of release
membership. Direct ancestry and known release backports were checked.
Four fallback-targeted proposals are excluded below.
- Wiki link corrections: its REPL link #1752 actually covers Sandboxes;
the REPL proposal is #1740. Its AOT link #1714 covers PFX certificates,
not AOT.

### Complete audit-gap checklist

Checked items mean documentation coverage is implemented, not that cloud
deployment or every product runtime scenario was executed.

- [x] **1. Dotnet API graduation:** correct removal to **13.6**, not
14.0, in What's new, both Dotnet guides, and the diagnostic page;
preserve the prerelease package caveat. This applies to core
`AddDotnetProject`, `DotnetProjectResource`, and related
`WithBuildEnvironment` overloads, not all uses of the diagnostic.
Source: microsoft/aspire#20496.
- [x] **2. Sandboxes:** remove obsolete API suppressions in the article
and deployment guide while preserving Azure service preview/access and
prerelease package limitations. Source: microsoft/aspire#20483.
- [x] **3. Docked REPL documentation:** all six
PostgreSQL/MySQL/MongoDB/SQL Server/Redis/Valkey guides plus the article
now cover opt-in `WithRepl`/`withRepl`, run-only availability, actual
client privileges, credential handling, and explicit exit versus closing
a viewer. Source: microsoft/aspire#20419, backport of
microsoft/aspire#20231. Package-backed checks remain open below.
- [x] **4. Terminal CLI flag:** update current 13.6 article,
`with-terminal`, and all three terminal command references. Preserve
`terminals.v1` and experimental hosting API distinctions. Current
configuration/schema data had no flag entry to remove; historical 13.5
notes remain historical. Source: microsoft/aspire#20548.
- [x] **5. First-party Rust:** rewrite both canonical Rust guides around
`Aspire.Hosting.Rust`; document Cargo versus application arguments,
typed targets, debugging, generated Dockerfiles, workspace context, ABI
constraints, and Toolkit migration. Bacon remains explicitly
Toolkit-only. Add exact first-party package mapping. Source:
microsoft/aspire#18906 and current Rust README.
- [x] **6. Agent setup:** align command reference, skills guide,
AI-agent guide, and article on MCP opt-in, `--mcp`,
chained/non-interactive behavior, seven-skill catalog, Project v2
migration, and Copilot app detection. Also fix stale default-selection
text: all applicable bundle skills are preselected; companion tools
remain opt-in. Sources: microsoft/aspire#19893, microsoft/aspire#20405,
microsoft/aspire#19820.
- [x] **7. Deno AppHost runtime:** document Deno 2+ detection, commands,
permissions, native watch/type checking, doctor, and `DENO_CERT`,
separately from Deno guest hosting. Source: microsoft/aspire#18627,
distinct from microsoft/aspire#18628.
- [x] **8. Native AOT / Fluent UI v5:** concise article, dashboard
exploration, and standalone guidance; automatic packaged-dashboard
selection, no invented performance figures. Source:
microsoft/aspire#19565 and release packaging sources.
- [x] **9. NuGet:** document bundled in-process operations, credential
providers, non-interactive authentication, and realistic
troubleshooting. Correct the proposal's `dotnet nuget locals`
authentication advice: cache commands do not authenticate a feed.
Source: microsoft/aspire#20391.
- [x] **10. Multithreaded builds:** article and coordinated-build guide
explain `-mt`, SDK detection, distinct project/file-based SDK floors,
and fallback. Source: microsoft/aspire#20441.
- [x] **11. Radius:** add a real deployment guide with C#/TypeScript
setup, recipe-backed connections versus local endpoints, per-resource
credential behavior, unauthenticated Redis limitation, secret exposure
boundaries, and actionable runtime diagnostics 070–091. Wire navigation
and exact package mapping. Source: microsoft/aspire#19555 and release
README.
- [x] **12. Connection aliases:** replace contradictory no-encoding
guidance, retain composed logical-key-first lookup and portable-target
behavior, explain collision detection and custom-publisher metadata.
Source: microsoft/aspire#19729.
- [x] **13. Connector Namespace / Toolbox / provisioning:** add
Connector Namespace walkthrough, security/consent/revocation limits and
mapping/sidebar; add Foundry Toolbox walkthrough, connection properties,
roles, index prerequisites, approval enforcement boundaries, immutable
versions, and existing-resource behavior. Extend existing Azure
provisioning guide without a duplicate page. Sources:
microsoft/aspire#19024, microsoft/aspire#17742, microsoft/aspire#20131.
- [x] **14. Remaining high-impact items:** article covers opt-in
manifest-aware DNX and new-template CLI bundling (existing SDK guides
retained), migration skill and Copilot app detection; canonical inline
`CsiVolumeSourceV1`/`VolumeV1.Csi` example, management links, Cosmos
vNext telemetry, and AI Inference `GetModelInfoAsync`/`/info` health
checks with `DisableHealthChecks`. No Azure OpenAI health-check claim.
Sources: microsoft/aspire#19310, microsoft/aspire#19076,
microsoft/aspire#19826, microsoft/aspire#20070, microsoft/aspire#15671,
microsoft/aspire#15969.
- [x] **15. All 25 proposal dispositions:** listed below, including
newer dashboard backports and four exclusions. Existing Sandbox
inference coverage is retained rather than copied from a stale draft.
- [ ] **16. Refresh generated API/catalog/Twoslash data from an official
post-backport 13.6 build.** Existing `26473.12`/`a11eca96` data remains
untouched. The newest public `dotnet9` feed package checked,
`13.6.0-preview.1.26474.10` at
`43496a2a306c81c862c947b11b4f4e5494b6fe08`, still has no Redis
`WithRepl` in its actual package XML. Do not use 14.x, hand-edit
declarations, or attribute source changes to older binaries.
- [ ] **Validate the six REPL examples against that actual post-backport
SDK and running clients.** Their new TypeScript fences are plain
TypeScript, not annotated with unsupported Twoslash data. No existing
diagnostics are allowlisted or suppressed; no generated API exports are
fabricated. Enable Twoslash when the genuine catalog catches up.

### All 25 open proposal dispositions and provenance

Text is selectively adapted from these proposals, not merged wholesale.
#1778 and #1748 are authored by @sebastienros; the other proposals are
authored by the Aspire repo bot. The table credits the associated
product-change authors where supplied by the proposals. Existing PRs
remain open and unchanged.

| Docs PR | Release source / credited product author | Disposition |
| --- | --- | --- |
| #1778 | microsoft/aspire#19729 — @sebastienros | **Adopted:**
canonical connection-string alias correction, including logical-first
resolution and migration. |
| #1771 | microsoft/aspire#20481 — @sebastienros | **Excluded:** flat
polyglot feature keys are not in the audited release tip; no verified
backport. Preserve release key names. |
| #1770 | microsoft/aspire#20525 → microsoft/aspire#20548 — @mitchdenny
| **Corrected/adopted:** command guides plus the still-current 13.6
article, which the proposal incorrectly treats as historical. |
| #1769 | microsoft/aspire#20416 — @JamesNK | **Excluded:** brand hover
change has no verified 13.6 membership/backport. |
| #1768 | microsoft/aspire#20523 → microsoft/aspire#20546 — @JamesNK |
**Adopted:** run pin/unpin preserves selector and current selection. |
| #1766 | microsoft/aspire#20537 → microsoft/aspire#20541 — @mitchdenny
| **Adopted:** terminal dock empty state. |
| #1761 | microsoft/aspire#20490 → microsoft/aspire#20496 — @eerhardt |
**Corrected:** graduation is 13.6, package remains prerelease,
Blazor-specific exception retained. |
| #1760 | microsoft/aspire#20436 — @eerhardt | **Excluded:** CLI
net11/tools-any retarget is not in the audited release; no fallback-base
inference. |
| #1748 | microsoft/aspire#20131 — @sebastienros | **Adopted:** extend
existing provisioning guide with service-specific models/lookups and
projection limits. |
| #1744 | microsoft/aspire#20337 → microsoft/aspire#20441 — @karolz-ms |
**Adopted:** precise SDK-conditional multithreaded build coverage. |
| #1740 | microsoft/aspire#20231 → microsoft/aspire#20419 — @mitchdenny
| **Adapted:** all six guides; TypeScript-first tabs, source-verified
lifecycle/security. Actual post-backport SDK/runtime gate is open above.
|
| #1738 | microsoft/aspire#20158 → microsoft/aspire#20405 — @karolz-ms |
**Partly already covered / completed:** existing seven-skill catalog
retained; add project migration guidance and correct command
catalog/defaults. Do not misclassify the bundled skill as a companion
tool. |
| #1735 | microsoft/aspire#20334 — @karolz-ms | **Excluded:** enhanced
startup errors are not in the audited release; no verified backport. |
| #1731 | microsoft/aspire#19847 → microsoft/aspire#20391 — @eerhardt |
**Corrected/adopted:** in-process NuGet and real authenticated-restore
troubleshooting, not cache-command authentication. |
| #1719 | microsoft/aspire#20299 → microsoft/aspire#20407 — @JamesNK |
**Corrected/adopted:** cookie naming/scoping; identical names can
collide but do not guarantee cross-dashboard cookie decryptability or
shared sign-in. |
| #1664 | microsoft/aspire#20011 — @maddymontaquila | **Adopted:**
concise Azure environment icon release note. |
| #1628 | microsoft/aspire#17742 — @davidfowl | **Adapted/expanded:**
canonical Toolbox examples, consumer contract, role/index prerequisites,
approval/security and concurrency limits. |
| #1623 | microsoft/aspire#19810 — @mitchdenny | **Already covered:**
current Sandbox guide/article already describe compute inference,
explicit selection and external endpoints. Preserve that guidance while
removing obsolete suppressions. |
| #1620 | microsoft/aspire#19243 — @sebastienros | **Adapted:** AKS
credential-before-Helm cleanup and destructive-operation warning; omit
misleading ambient-context workaround. |
| #1614 | microsoft/aspire#19870 — @sebastienros | **Adopted:** typed
callback handle behavior in extension authoring and article. |
| #1574 | microsoft/aspire#19430 — @mitchdenny | **Adapted:** canonical
hostname inheritance, explicit-host precedence, catch-all default
backend. |
| #1570 | microsoft/aspire#19590 — @karolz-ms | **Adopted:** Dev Tunnel
URL regression troubleshooting. |
| #1565 | microsoft/aspire#19429 — @mitchdenny | **Corrected/adopted:**
Helm embedded parameters with real `refExpr` and `addParameter(name, {
value })`, not stringifying a handle or using an invalid actual-SDK
overload. |
| #1564 | microsoft/aspire#19026 — @karolz-ms | **Corrected/adopted:**
C#/TypeScript Dotnet gateway walkthrough. Retain both experimental
diagnostics; remove obsolete run-only restriction after
microsoft/aspire#19997 publishing support. Avoid imported ambiguous API
reference. |
| #1499 | microsoft/aspire#19248 — @IEvangelist | **Adopted:** describe
exact secret-value redaction and embedded-secret limit; release article
already covered the fix. |

### Important source-verified corrections to proposals / earlier audit
assumptions

-
[`BlazorGatewayExtensions.cs`](https://github.com/microsoft/aspire/blob/e8fd6fbb954f50ccd2e66479538392f65e13e71d/src/Aspire.Hosting.Blazor/BlazorGatewayExtensions.cs):
`AddDotnetProjectBlazorGateway` and the Dotnet `WithBlazorClientApp`
overload still carry `ASPIREDOTNETPROJECT001`; the class carries
`ASPIREBLAZOR001`. They share `WithBlazorClientAppCore`/`WithBlazorApp`
and the publish-companion path. Thus neither blanket diagnostic
retirement nor the proposal's old run-only claim is correct.
-
[`SkillDefinition.cs`](https://github.com/microsoft/aspire/blob/e8fd6fbb954f50ccd2e66479538392f65e13e71d/src/Aspire.Cli/Agents/SkillDefinition.cs)
sets bundled skills' `IsDefault=true`;
[`AgentInitCommand.cs`](https://github.com/microsoft/aspire/blob/e8fd6fbb954f50ccd2e66479538392f65e13e71d/src/Aspire.Cli/Commands/AgentInitCommand.cs)
selects the applicable catalog defaults for both flows. MCP has its own
standalone-only binding.
-
[`TypeScriptAppHostToolchainResolver.cs`](https://github.com/microsoft/aspire/blob/e8fd6fbb954f50ccd2e66479538392f65e13e71d/src/Aspire.Cli/Projects/TypeScriptAppHostToolchainResolver.cs)
is the source for Deno flags and certificate variable; guest Deno
hosting is separate.
- [`Radius
README`](https://github.com/microsoft/aspire/blob/e8fd6fbb954f50ccd2e66479538392f65e13e71d/src/Aspire.Hosting.Radius/README.md)
supplies the resource-specific credential rules and publish diagnostics,
not assumptions about local endpoints.

## Third-party links and affiliations

<!-- List third-party links and disclose material affiliations. -->

Links point to official Microsoft Learn, VS Code Marketplace debugger
extensions, Rust/Cargo/Bacon documentation, Radius documentation, and
source repositories. No sponsorship, commercial endorsement, or
affiliation claim is introduced. Maintainers should supply any personal
affiliation disclosure required by policy; automation has not inferred
one.

## Validation

<!-- List the checks you ran or explain why validation isn't needed. -->

- **97 passing focused unit checks** across API-reference
authoring/rendering, Twoslash blocks, file-tree formatting, CLI
configuration schema, SEO lengths, and resource catalog.
- **82 passing structured-data checks**, including exact integration
mapping uniqueness and page resolution.
- **11 C# samples compile**, zero warnings/errors, using genuine
`13.6.0-preview.1.26473.12` packages. Scope: Rust, Connector Namespace,
Radius, Toolbox, inline CSI, Helm, Blazor gateway, and provisioning.
`Projects.Api/Worker/Client` use compile-only `IProjectMetadata`
stand-ins; no claim of running those apps or provisioning cloud
resources.
- **10 TypeScript samples pass `tsc`** under `strict`, `NodeNext`, and
`ES2022` against three **unmodified actual SDK files**, not just the
site's declaration bundle. The fixture uses the exact `e8fd6fbb` release
`AtsCapabilityScanner` and genuine `26473.12`
TypeSystem/code-generator/integration binaries, whose informational
source is `a11eca96`. This is an isolated local generation fixture,
**not** a claim that official CLI generation or a new packaged release
was tested. An attempted restore with the older handed-off local CLI
could not discover an AppHost server; the bounded direct generator
fixture was used instead.
- The SDK scan is **not globally warning-free**: it reports a Radius
`withContainerImage` collision on `CSharpAppResource` and an App
Configuration `createRoleAssignment` overload collision. None of the
compiled examples calls those colliding methods; the warnings are
retained in evidence, not suppressed, and no generated declarations were
edited.
- Browser: Connector Namespace, Radius, both Rust pages, Foundry
hosting, and What's new return **HTTP 200**, correct headings, and no
rendered Twoslash errors. New guide/article page-local anchors and the
cross-page Blazor anchor resolve. Connector/Radius mobile layouts have
no horizontal overflow; Connector language-tab interaction works.
Standalone Astro preview emits expected `/api/live` 404s because
StaticHost is not running.
- `git diff --check` passes. No production `pnpm build`, cloud
deployment, REPL runtime session, full product suite, or blanket
validation of every pre-existing example was performed.
- Generated C#/TypeScript API data, declaration bundles, integration
catalogs, image catalogs, and contributor data are unchanged. Only the
authored package-to-guide mapping is updated.

**Before merging:** complete the two packaging/REPL checkboxes above,
inspect CI, and obtain human review. This PR intentionally does not
close or merge the source documentation proposals.

---------

Co-authored-by: David Pine <7679720+IEvangelist@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Mitch Denny (mitchdenny) added a commit to microsoft/aspire.dev that referenced this pull request Sep 29, 2026
Documents changes from microsoft/aspire#19243

`@sebastienros`

Targeting `release/13.6` based on the source PR milestone `13.6`.

## Why

The source PR fixes `aspire destroy` for AKS deployments so it no longer
depends on the caller's ambient `kubectl` context: it now acquires AKS
credentials for the target cluster itself before running Helm cleanup,
and orders Helm release removal, opted-in external charts, and
cert-manager teardown before the Azure resource group is deleted. The PR
body includes a "User-facing usage" section and a
`--apphost`/`--environment` CLI example, but the AKS docs page had no
"Clean up resources" / destroy section at all — only a deploy-time
reference to destroy-time uninstall behavior for external charts.

## What changed

Added a new **Clean up resources** section to
`deployment/kubernetes/aks.mdx` (after "Publish AKS artifacts", before
"Azure-specific considerations") that:
- Shows the basic `aspire destroy` command.
- Explains that AKS credential acquisition is now independent of the
ambient kubeconfig, and that Helm/cert-manager cleanup completes before
the resource group is deleted.
- Reproduces the PR's non-interactive `KUBECONFIG=$(mktemp) aspire
destroy --apphost ... --environment ... --non-interactive --yes` example
for CI/CD usage.
- Cross-references the existing `aspire destroy` CLI command reference
page.

## Files modified

- `src/frontend/src/content/docs/deployment/kubernetes/aks.mdx`

> Generated by [PR Documentation
Check](https://github.com/microsoft/aspire/actions/runs/33902845128) for
#19243 · auto · 63.4 AIC · ⌖ 7.73 AIC · ⊞ 19.7K ·
[◷](https://github.com/search?q=repo%3Amicrosoft%2Faspire.dev+%22gh-aw-workflow-id%3A+pr-docs-check%22&type=pullrequests)

<!-- gh-aw-agentic-workflow: PR Documentation Check, engine: copilot,
model: auto, id: 33902845128, workflow_id: pr-docs-check, run:
https://github.com/microsoft/aspire/actions/runs/33902845128 -->

<!-- gh-aw-workflow-id: pr-docs-check -->
<!-- gh-aw-workflow-call-id: microsoft/aspire/pr-docs-check -->

---------

Co-authored-by: aspire-repo-bot[bot] <268009190+aspire-repo-bot[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Mitch Denny <midenn@microsoft.com>
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.

aspire destroy fails to uninstall Helm release for AKS deployments

4 participants