Skip to content

Manage routes Gateway lifecycle in extension workflows - #672

Merged
willdavsmith merged 4 commits into
mainfrom
willdavsmith-managed-routes-gateway-lifecycle
Sep 1, 2026
Merged

Manage routes Gateway lifecycle in extension workflows#672
willdavsmith merged 4 commits into
mainfrom
willdavsmith-managed-routes-gateway-lifecycle

Conversation

@willdavsmith

Copy link
Copy Markdown
Contributor

Summary

  • Ports the managed Radius.Compute/routes Gateway lifecycle from Add managed Gateway lifecycle for routes radius#12854 at 3aa81af42ae9a0f7d8413c6b3f6dc88c4a326726 into the canonical radius-project/ai-extensions workflow tree.
  • Ensures or validates Gateway API prerequisites before deploy and safely cleans up unused, proven-owned infrastructure after application deletion.
  • Updates the extension and Radius plugin skill documentation and adds a minor changeset.

Migration decisions

  • Applied the deploy/delete changes semantically to current ai-extensions templates instead of copying stale Radius workflows, preserving the workflow migration from feat: host Repo Radius extension workflows in ai-extensions #424 and later changes.
  • All first-party lifecycle action references resolve from radius-project/ai-extensions at {{RADIUS_REF}}; Radius remains referenced only for its intentionally Radius-owned catalog data.
  • Preserves Gateway API experimental CRDs v1.2.1 (including BackendTLSPolicy), Contour chart 0.1.0 / app 1.32.0, managed defaults radius-system/radius, private ClusterIP exposure with an empty externalTrafficPolicy, controller and Programmed readiness, strict BYO preservation, null CLI-list handling, and ownership-safe cleanup.
  • The managed Contour Gateway fails closed for TCP/UDP route kinds because its fixed listeners support HTTP and TLS. BYO validation requires a compatible HTTP/HTTPS, TLS passthrough, TCP, or UDP listener for every declared route kind.
  • Lifecycle workflows use one repository-wide, non-cancelling concurrency group so different Radius environments in the repository cannot race on fixed cluster resources. Documentation establishes a single managed owner repository when multiple repositories share a cluster; consumers configure the shared Gateway as validation-only BYO infrastructure.
  • Cleanup inventories Kubernetes Ingresses and all five Contour chart-managed CRD types before Helm uninstall, preventing cascade deletion of shared Contour objects.
  • Retires the temporary Radius extension-tree parity test now that Remove duplicated Repo Radius extension workflows radius#12719 merged and removed the obsolete duplicate tree.
  • Integrates the new hermetic shell suite through the existing extension-selftests.yml automatic *_test.sh discovery rather than obsolete build/test.mk wiring.

Validation

  • Complete extension shell self-tests, standalone ShellCheck, contrib source-of-truth checks, workflow actionlint, and YAML parsing
  • Markdown table formatting and markdownlint for all changed Markdown
  • pnpm run typecheck, pnpm run lint, pnpm run format:check, pnpm run coverage, and pnpm run build
  • Coverage: 275 files passed, 7 skipped; 9,223 tests passed, 27 skipped; 92.08% statements, 89.24% branches, 87.02% functions, 92.71% lines
  • Built-extension artifact integration: 9 passed
  • Browser component: 25 passed
  • Chromium: 49 passed with no retry-only passes
  • Windows process integration skipped on macOS as designed
  • Independent code review completed; route-kind compiled-shape handling and Contour CRD cleanup findings were addressed and re-reviewed

Context

Addresses #421. This supersedes the obsolete implementation location in radius-project/radius#12854 after the extension workflow move. It is a fresh branch based on current main and does not modify or close #570 or radius-project/radius#12854.

Signed-off-by: willdavsmith <willdavsmith@gmail.com>
Copilot-Session: 90bbcc1b-c1e4-49f6-ac53-261516d66bda
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Changeset check skipped: this pull request is labelled pr/no-changeset, so it is not expected to ship anything releasable.

@willdavsmith
willdavsmith marked this pull request as ready for review September 1, 2026 17:40
@willdavsmith
willdavsmith requested review from a team as code owners September 1, 2026 17:40
Copilot AI lite review requested due to automatic review settings September 1, 2026 17:40
@willdavsmith
willdavsmith requested a review from a team as a code owner September 1, 2026 17:40

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

Ports and documents the managed Gateway API (Contour/GatewayClass/Gateway/CRDs) lifecycle needed by the default Radius.Compute/routes recipe into the canonical ai-extensions workflow templates, including validation-only BYO Gateway behavior and fail-closed, ownership-safe cleanup after application deletion.

Changes:

  • Add a new manage-routes-gateway composite action + shell implementation + hermetic shell test suite to ensure/cleanup Gateway API prerequisites on the target cluster.
  • Wire the new lifecycle into Azure/AWS deploy and application-delete provider workflows, and serialize these operations with a shared repo-wide concurrency group.
  • Update Radius plugin skill docs, workflow-tree docs, and retire the temporary extension-tree parity live test, including a minor radius changeset.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated no comments.

Show a summary per file
File Description
plugins/radius/skills/radius-environment/SKILL.md Documents new environment variables for managed/BYO routes Gateway policy.
plugins/radius/skills/radius-deploy/SKILL.md Documents pre-deploy Gateway lifecycle ensure/validation and exposure policy.
plugins/radius/skills/radius-delete/SKILL.md Documents post-delete ownership-safe Gateway cleanup behavior.
plugins/radius/skills/radius-app-bicep/SKILL.md Clarifies that ingress evidence doesn’t authorize public exposure; exposure is env policy.
packages/core/test/support/live-github.ts Updates live-test helper header comment after parity-test retirement.
packages/core/src/workflows/extension-parity.live.test.ts Removes the temporary migration parity live test.
docs/design/2026-08-port-extension-workflows-to-ai-extensions.md Updates design doc to reflect parity-test retirement and updated validation narrative.
.github/workflows/live-tests.yml Stops running the removed parity live test; updates checkout rationale comment.
.github/extension/run-rad-commands-azure.yml Adds concurrency + routes Gateway ensure step; updates target-kubeconfig handling.
.github/extension/run-rad-commands-aws.yml Adds concurrency + routes Gateway ensure step; updates routes recipe source/params and target-kubeconfig handling.
.github/extension/delete-azure.yml Adds concurrency + routes Gateway cleanup step after application delete; updates target-kubeconfig handling.
.github/extension/delete-aws.yml Adds concurrency + routes Gateway cleanup step after application delete; updates target-kubeconfig handling.
.github/extension/delete-environment-azure.yml Adds shared routes Gateway concurrency group for environment-delete lifecycle serialization.
.github/extension/README.md Documents the new manage/cleanup behavior, exposure policy, and concurrency contract.
.github/extension/actions/manage-routes-gateway/action.yml New composite action wrapper exposing ensure/cleanup inputs.
.github/extension/actions/manage-routes-gateway/routes-gateway.sh New lifecycle implementation: detect routes + default recipe, ensure/validate infra, cleanup unused owned infra.
.github/extension/actions/manage-routes-gateway/routes-gateway_test.sh New hermetic shell test suite covering detection, validation, managed/BYO paths, and workflow wiring.
.changeset/manage-routes-gateway-lifecycle.md Minor changeset announcing managed routes Gateway lifecycle behavior.
Suppressed comments (4)

.github/extension/run-rad-commands-azure.yml:75

  • The pinned actions/checkout SHA is annotated as v7.0.1 elsewhere in this repo, but this template still labels it as v4. Align the version comment with the pinned SHA to avoid confusion during audits and updates.
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4

.github/extension/run-rad-commands-aws.yml:75

  • The pinned actions/checkout SHA is annotated as v7.0.1 elsewhere in this repo, but this template still labels it as v4. Align the version comment with the pinned SHA to avoid confusion during audits and updates.
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4

.github/extension/delete-azure.yml:62

  • The pinned actions/checkout SHA is annotated as v7.0.1 elsewhere in this repo, but this template still labels it as v4. Align the version comment with the pinned SHA to avoid confusion during audits and updates.
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4

.github/extension/delete-aws.yml:62

  • The pinned actions/checkout SHA is annotated as v7.0.1 elsewhere in this repo, but this template still labels it as v4. Align the version comment with the pinned SHA to avoid confusion during audits and updates.
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@willdavsmith
willdavsmith requested a review from sk593 September 1, 2026 18:24

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

Blocking concern: cleanup must distinguish confirmed absence from failed ownership or resource discovery before continuing destructive operations.

Comment thread .github/extension/actions/manage-routes-gateway/routes-gateway.sh Outdated
Comment thread .github/extension/actions/manage-routes-gateway/routes-gateway.sh Outdated
Copilot-Session: 90bbcc1b-c1e4-49f6-ac53-261516d66bda
Signed-off-by: willdavsmith <willdavsmith@gmail.com>
Copilot-Session: 90bbcc1b-c1e4-49f6-ac53-261516d66bda
Signed-off-by: willdavsmith <willdavsmith@gmail.com>

sk593 commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Review

(Posted as a regular comment — inline diff/review comments aren't available to me here, so all six points are listed together with file/line references.)


1. .github/extension/actions/manage-routes-gateway/routes-gateway.shdesired_external_traffic_policy() (~L525-531)

When the Gateway is made public, this sets externalTrafficPolicy=Local. The private path leaves it empty (the default). Local keeps the caller's real IP address but only sends traffic to nodes that are actually running a proxy pod — so if the cloud load balancer's health checks aren't set up just right, some requests can fail intermittently. Could you confirm Local is intentional here rather than the safer Cluster? A one-line comment explaining the choice would help future readers.

2. .github/extension/run-rad-commands-azure.ymlCheckout step (~L75) (same issue applies to run-rad-commands-aws.yml, delete-azure.yml, and delete-aws.yml)

This pins actions/checkout to a commit SHA but the comment next to it says # v4, while live-tests.yml labels the exact same SHA as # v7.0.1. The SHA is what actually runs, so this isn't a bug — but a wrong version label is confusing during audits and dependency updates. Worth updating the comment to the correct version in all four provider templates.

3. .github/extension/delete-environment-azure.yml — new concurrency: block

This workflow joins the shared routes-Gateway concurrency group but, unlike the app-delete workflows, it doesn't run a Gateway cleanup step. I think that's intentional (environment deletion goes through the per-app delete path, which already handles cleanup), but it isn't obvious from the code. Could you confirm, and maybe add a short comment here explaining why no cleanup step is needed? That prevents someone later from assuming it was accidentally left out.

4. .github/extension/actions/manage-routes-gateway/routes-gateway.shresource_owned() (~L417-432)

Ownership is decided by reading a single annotation (radius-project.io/routes-gateway-lifecycle: v1). The objects are also created with a managed-by label, but cleanup only checks the annotation. If a future Helm/chart upgrade ever drops that annotation, these objects would look "not ours" and never get cleaned up, quietly leaking infrastructure. Consider also checking the managed-by label as a backup ownership signal, since both are already set at creation time.

5. .github/extension/actions/manage-routes-gateway/routes-gateway.sh — Contour Helm uninstall in cleanup_gateway() (~L1183-1187)

The other deletes re-check ownership right before deleting each object, but this Helm uninstall relies on the release_state value read earlier at the top of cleanup. If that state changed in between, we'd uninstall based on stale information. Consider re-reading the release state immediately before helm uninstall so the decision uses fresh data, matching how the other deletes work.

6. .github/extension/actions/manage-routes-gateway/routes-gateway.shshared_contour_consumers_exist() (~L1048-1062)

This checks for other users of the Contour controller by looking at Ingresses and Contour's custom resources, which is good. Just to be safe, could you confirm those object types are the only way something else could depend on this shared Contour install? If another workload could reference it some other way, we'd want to detect that too before removing it.


Copilot-Session: 90bbcc1b-c1e4-49f6-ac53-261516d66bda
Signed-off-by: willdavsmith <willdavsmith@gmail.com>
@willdavsmith

Copy link
Copy Markdown
Contributor Author

Addressed all six points in f8740e7491c3e17076b4e4eb3444efd9edd4995c:

  1. externalTrafficPolicy=Local is intentional for public Gateways so Envoy preserves client source IPs. AKS/EKS use the Kubernetes Local health-check path to route only to nodes with Envoy pods; the code now documents that choice.
  2. The four provider templates now consistently identify the pinned checkout SHA as v7.0.1 (run-rad-commands-{azure,aws}.yml and delete-{azure,aws}.yml).
  3. delete-environment-azure.yml now explains that environment deletion is allowed only after applications are gone, so app-delete has already handled Gateway cleanup; it still shares the lock to prevent cluster teardown racing deploy/app-delete Gateway mutations.
  4. I kept annotation-only ownership deliberately. The lifecycle annotation is the specific deletion capability; app.kubernetes.io/managed-by=radius-repo is a generic classification label that can collide or be copied independently. Falling back to that label could delete resources Radius cannot prove it owns. If the annotation disappears, preserving the object is the intended fail-closed result, even at the cost of manual cleanup.
  5. Cleanup now re-reads the Contour release state and ownership immediately before helm uninstall. Any lookup failure aborts, and any state transition preserves the controller and CRDs. Focused tests cover an owned-to-unowned transition and a failed fresh lookup, asserting no Helm uninstall or CRD deletion.
  6. The known Kubernetes consumer inventory is complete for the pinned Contour chart: every Gateway API object type in GATEWAY_API_OBJECTS, networking.k8s.io Ingresses, and all five Contour CRDs in CONTOUR_OBJECTS. The code now records the limitation that direct external clients of the Envoy Service are not discoverable from Kubernetes API objects; there is no safe cluster-side ownership signal for those clients.

Focused Gateway shell tests, ShellCheck, actionlint/YAML parsing, checkout-label checks, and git diff --check pass.

@willdavsmith
willdavsmith merged commit 1495112 into main Sep 1, 2026
15 checks passed
@willdavsmith
willdavsmith deleted the willdavsmith-managed-routes-gateway-lifecycle branch September 1, 2026 20:30

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.

🟡 Changes recommended

Workflow parameter defaulting can mutate the environment before failing on misconfigured BYO Gateway variables, and the new action’s diagnostics omit the provided application context.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 18/18 changed files
  • Comments generated: 3
  • Review effort level: Lite

Comment on lines 284 to +288
# Resolve every Recipe source from deploy/manifest/defaults.yaml.
CONTAINERIMAGES_SOURCE="$(radius_contrib_kube_recipe_source Radius.Compute/containerImages containerimages)"
CONTAINERS_SOURCE="$(radius_contrib_resource_git_source Radius.Compute/containers recipes/kubernetes/terraform)"
PERSISTENTVOLUMES_SOURCE="$(radius_contrib_resource_git_source Radius.Compute/persistentVolumes recipes/kubernetes/terraform)"
ROUTES_SOURCE="$(radius_contrib_resource_git_source Radius.Compute/routes recipes/kubernetes/terraform)"
ROUTES_SOURCE="$(radius_contrib_kube_recipe_source Radius.Compute/routes routes)"
Comment on lines +326 to +330
# The default routes recipe always receives a concrete Gateway reference.
# A separately-passed boolean tells the lifecycle action whether this is a
# user-owned Gateway or the Radius-managed default.
ROUTES_GATEWAY_NAME="${{ vars.RADIUS_ROUTES_GATEWAY_NAME || 'radius' }}"
ROUTES_GATEWAY_NAMESPACE="${{ vars.RADIUS_ROUTES_GATEWAY_NAMESPACE || 'radius-system' }}"
Comment on lines +80 to +83
fail() {
echo "::error::$*" >&2
exit 1
}
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.

4 participants