Files
OpenShell/.github/workflows/e2e-label-help.yml
Taylor Mutch 59475aabf4 ci(kubernetes): add kube gateway e2e tests and gated CI workflow (#1251)
* test(helm): Add kube gateway e2e tests

Signed-off-by: Taylor Mutch <taylormutch@gmail.com>

* ci(helm): add Branch Helm E2E workflow gated on test:e2e-helm

Adds a label-gated GitHub Actions workflow that exercises the Helm
chart end-to-end against the Rust e2e suite via `mise run e2e:helm`.

Pipeline:
- pr_metadata gates on the `test:e2e-helm` label via the pr-gate action.
- build-gateway / build-supervisor build and push Docker images using
  the reusable docker-build.yml workflow.
- helm-e2e (bare runner): apt-installs z3 build deps so cargo can
  compile the openshell-policy crate's z3-sys backend, creates a kind
  cluster via helm/kind-action, materializes the kind kubeconfig at the
  path mise's [env] block expects, side-loads the freshly built
  gateway/supervisor images, applies
  deploy/kube/manifests/agent-sandbox.yaml so the
  sandboxes.agents.x-k8s.io CRD and reconciling StatefulSet are in
  place, and finally runs `mise run e2e:helm`.

Also expands the `e2e:helm` task to run the full Rust e2e suite
(matching `e2e:podman`) instead of only the smoke test, with
OPENSHELL_E2E_KUBE_TEST as an opt-in single-test override for local
debugging.

Extends the e2e-label-help workflow so applying `test:e2e-helm` posts
the next-step hint pointing at this workflow.

Signed-off-by: Taylor Mutch <taylormutch@gmail.com>

* test(helm-e2e): run host-gateway tests on the kube driver

Six tests previously skipped on the kubernetes driver — three in
host_gateway_alias.rs plus the forward_proxy_l7 + graphql_l7 cases —
relied on `host.openshell.internal` reaching either a host process or a
sibling docker container. The Helm chart already supports this via
`server.hostGatewayIP`, but the e2e wrapper never set it.

- with-kube-gateway.sh: auto-detect the host-routable IP (CoreDNS
  `host.k3d.internal` first to handle Docker Desktop, docker network
  gateway as a fallback for kind on Linux CI) and pass it to helm
  install. Also import locally-built images into existing k3d clusters
  and wait for namespace deletion to complete before exit.
- e2e/rust/Cargo.toml + e2e-helm.sh: add an `e2e-host-gateway` feature
  that gates the three test files; docker and podman runs imply it,
  helm runs opt in by default (overridable via
  OPENSHELL_E2E_HELM_FEATURES for remote clusters where the test host
  is unreachable from pods).
- Drop the `skip_if_kube` helper and its callers — feature gating now
  decides whether the tests compile in.

Verified against a local k3d cluster: all six previously-skipped tests
pass, smoke regression intact.

* refactor(e2e): rename e2e:helm to e2e:kubernetes

The runner exercises the gateway on Kubernetes; helm is just the
deployment mechanism. Names now describe the target environment.

- mise task: `e2e:helm` -> `e2e:kubernetes`
- script: e2e/rust/e2e-helm.sh -> e2e/rust/e2e-kubernetes.sh
- env var: OPENSHELL_E2E_HELM_FEATURES -> OPENSHELL_E2E_KUBERNETES_FEATURES
- workflow: branch-helm-e2e.yml -> branch-kubernetes-e2e.yml
  (display name "Branch Kubernetes E2E", job "kubernetes-e2e")
- PR gate label: test:e2e-helm -> test:e2e-kubernetes (e2e-label-help
  hint workflow updated to match)

PR #1251 needs the new label applied; the old label can be removed.

* fix(e2e): prefer IPv4 host-gateway IP from dual-stack docker networks

kind dual-stacks its network; the wrapper's awk picked the first
non-empty gateway, which was the IPv6 entry (fc00:...). Sandbox pods
can't reach the test host's IPv4 listener through that, so the L7 and
host-gateway-alias tests failed in CI even though they passed locally
against k3d (where host.k3d.internal in CoreDNS short-circuits the
docker-network fallback).

Restrict the awk filter to IPv4 octets.

---------

Signed-off-by: Taylor Mutch <taylormutch@gmail.com>
2026-05-11 12:57:23 -07:00

69 lines
3.6 KiB
YAML

name: E2E Label Help
# When a `test:e2e` / `test:e2e-gpu` label is applied, post a PR comment
# telling the maintainer the next manual step. We don't dispatch the workflow
# ourselves: a workflow_dispatch-triggered run does not surface in the PR's
# Checks tab, so we'd lose in-progress visibility. Instead we point the
# maintainer at either the existing run (re-run from the UI) or the
# `/ok to test <SHA>` command needed to refresh the mirror.
#
# Uses `pull_request_target` so forked PRs get a token capable of posting
# comments. The job never checks out PR code; it only calls the GitHub API.
on:
pull_request_target:
types: [labeled]
permissions: {}
jobs:
hint:
name: Post next-step hint for E2E label
if: github.event.label.name == 'test:e2e' || github.event.label.name == 'test:e2e-gpu' || github.event.label.name == 'test:e2e-kubernetes'
runs-on: ubuntu-latest
permissions:
pull-requests: write
actions: read
contents: read
steps:
- name: Post comment
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
LABEL_NAME: ${{ github.event.label.name }}
shell: bash
run: |
set -euo pipefail
case "$LABEL_NAME" in
test:e2e) workflow_file=branch-e2e.yml; workflow_name="Branch E2E Checks" ;;
test:e2e-gpu) workflow_file=test-gpu.yml; workflow_name="GPU Test" ;;
test:e2e-kubernetes) workflow_file=branch-kubernetes-e2e.yml; workflow_name="Branch Kubernetes E2E" ;;
*) echo "Unrecognized label $LABEL_NAME"; exit 1 ;;
esac
mirror_ref="pull-request/$PR_NUMBER"
mirror_sha=$(gh api "repos/$GH_REPO/branches/$mirror_ref" --jq '.commit.sha' 2>/dev/null || echo "")
short_pr=${PR_HEAD_SHA:0:7}
if [ -z "$mirror_sha" ]; then
body="Label \`$LABEL_NAME\` applied, but \`$mirror_ref\` does not exist yet. A maintainer needs to comment \`/ok to test $PR_HEAD_SHA\` to mirror this PR. Once the mirror exists, re-apply the label or re-run [$workflow_name](https://github.com/$GH_REPO/actions/workflows/$workflow_file) from the Actions tab."
elif [ "$mirror_sha" != "$PR_HEAD_SHA" ]; then
short_mirror=${mirror_sha:0:7}
body="Label \`$LABEL_NAME\` applied, but \`$mirror_ref\` is at \`$short_mirror\` while the PR head is \`$short_pr\`. A maintainer needs to comment \`/ok to test $PR_HEAD_SHA\` to refresh the mirror. Once the mirror catches up, re-run [$workflow_name](https://github.com/$GH_REPO/actions/workflows/$workflow_file) from the Actions tab."
else
run_id=$(gh api "repos/$GH_REPO/actions/workflows/$workflow_file/runs?head_sha=$PR_HEAD_SHA&event=push" \
--jq '.workflow_runs | sort_by(.created_at) | reverse | .[0].id // empty')
if [ -n "$run_id" ]; then
instructions="Open [the existing run](https://github.com/$GH_REPO/actions/runs/$run_id) and click **Re-run all jobs** to execute with the label set."
else
workflow_link="[$workflow_name](https://github.com/$GH_REPO/actions/workflows/$workflow_file)"
instructions="Open $workflow_link, find the run for commit \`$short_pr\`, and click **Re-run all jobs** to execute with the label set."
fi
body="Label \`$LABEL_NAME\` applied for \`$short_pr\`. $instructions The \`E2E Gate\` check on this PR will flip green automatically once the run finishes."
fi
gh pr comment "$PR_NUMBER" --body "$body"