@@ -5,6 +5,101 @@ images. This fixture exercises the listener without discovery or the reference
55proxy. The opt-in Helm values are
66` deploy/helm/openshell/ci/values-app-listener.yaml ` .
77
8+ ## Repeatable local checks
9+
10+ The local and CI entry point creates an isolated Helm release, temporary TLS
11+ Secret and client resources, runs the checks, and removes the release/namespace:
12+
13+ ``` shell
14+ KUBECONFIG=" $PWD /kubeconfig" \
15+ IMAGE_TAG=dev OPENSHELL_REGISTRY=openshell \
16+ OPENSHELL_E2E_APP_TOPOLOGY=shared \
17+ OPENSHELL_E2E_APP_TAKEOVER=abrupt \
18+ mise run e2e:kubernetes:app-listener
19+ ```
20+
21+ Build and import matching ` openshell/gateway:dev ` , ` openshell/supervisor:dev ` ,
22+ and ` openshell/sandbox:dev ` images first, or set the registry/tag to images
23+ already loaded into the cluster. Build the CLI or set ` OPENSHELL_BIN ` to it.
24+ Set ` OPENSHELL_E2E_KUBE_CONTEXT ` to select a context explicitly. The cluster must
25+ enforce NetworkPolicy; the local k3s default does. The task installs the pinned
26+ Agent Sandbox controller only when its CRD is absent.
27+ Set ` OPENSHELL_E2E_KUBECONFIG ` when testing a separate cluster whose kubeconfig
28+ differs from the repository's mise environment.
29+
30+ ` OPENSHELL_E2E_APP_TOPOLOGY ` accepts ` dedicated ` (default) or ` shared ` ;
31+ ` OPENSHELL_E2E_APP_DELIVERY ` accepts ` push ` (default) or ` poll ` ;
32+ ` OPENSHELL_E2E_APP_TAKEOVER ` accepts ` graceful ` (default) or ` abrupt ` for shared
33+ supervisors. Dedicated runs include gateway-outage expiry. Every run also
34+ disables the listener and verifies absent app sockets/TLS mounts/Services and
35+ continued gateway application ingress. Logs, events, and resource summaries
36+ are written under ` results/app-listener/ ` , without TLS private keys or Secrets.
37+
38+ GitHub Actions runs four matrix cases under the existing ` test:e2e ` label:
39+ dedicated push/poll and shared graceful/abrupt takeover. These jobs use the
40+ reusable Kubernetes workflow, with kindnet replaced by pinned Calico for policy
41+ enforcement, and participate in ` Core E2E result ` . CI uploads the evidence even
42+ on failure. They still require the normal current-head ` /ok to test <SHA> `
43+ approval mirror.
44+
45+ ### Checking an already deployed release
46+
47+ Build the gateway, supervisor, sandbox, and CLI from the branch under test and
48+ deploy them through the local Helm development workflow. Use an isolated release
49+ namespace with gateway TLS, unauthenticated development API access, and the app
50+ listener enabled. Provide the application TLS Secret before installing the
51+ release. The workload and client fixture use ` python:3.12-slim ` .
52+
53+ Run from the repository root, supplying the public application certificate/CA:
54+
55+ ``` shell
56+ KUBECONFIG=" $PWD /kubeconfig" uv run --no-project python \
57+ e2e/kubernetes/app-listener/verify.py \
58+ --namespace listener-review-shared \
59+ --gateway-endpoint https://localhost:29203 \
60+ --forward-gateway service/listener-review \
61+ --app-ca /path/to/app-ca.crt \
62+ --network-policy \
63+ --takeover graceful
64+ ```
65+
66+ Use the actual namespace and gateway Service name of the test release. The
67+ runner maintains its API port-forward across gateway restarts; application
68+ traffic originates in client Pods and uses cluster networking. Application TLS
69+ verifies the supplied CA and hostname. The development API connection uses
70+ ` --gateway-insecure ` with an isolated temporary CLI configuration.
71+
72+ The runner creates and cleans up its sandboxes, client Pods, public-CA ConfigMap,
73+ and ingress policies. It checks named/unnamed HTTP routes, public Host/Origin and
74+ cookies, credential stripping and explicit bearer passthrough, unknown routes,
75+ Host/SNI mismatch, quiet WebSockets beyond 30 seconds, selective withdrawal, and
76+ re-exposure without restarting the application. When dedicated app Services are
77+ configured, it also verifies their DNS and EndpointSlices.
78+
79+ ` --network-policy ` requires an enforcing cluster network implementation, such as
80+ the local k3s default. A default kind cluster needs a policy-enforcing CNI before
81+ this assertion can establish isolation.
82+
83+ For a two-member shared pool, ` --takeover graceful ` deletes the owning Pod and
84+ checks that its sandbox keeps its Pod UID, runtime generation, process, and
85+ in-memory state, while another owner's WebSocket survives. ` --takeover abrupt `
86+ first SIGKILLs the supervisor container through the local k3d/kind node's Docker
87+ container, preventing a graceful leave; it requires access to that Docker engine.
88+ These options deliberately interrupt test resources in the supplied namespace.
89+
90+ For dedicated topology, omit ` --takeover ` . Add
91+ ` --expire-gateway statefulset/listener-review ` (using the actual workload name)
92+ to scale the isolated gateway to zero, verify route/stream expiry, restore its
93+ original replica count, and check application survival. Repeat with gateway
94+ ` config_delivery_mode ` set to ` push ` and ` poll ` .
95+
96+ The lower-level runner leaves the Helm release and TLS Secret in place. Use
97+ ` --disabled --gateway-service <service> ` instead of takeover/expiry flags to
98+ check an already disabled release. Configuration rejection and the additional
99+ deployment cleanup scenarios remain in the manual checklist below.
100+
101+ ## Manual deployment and additional scenarios
102+
8103Before deployment, provide an operator-owned ` openshell-app-tls ` Secret in the
9104supervisor namespace with ` tls.crt ` and ` tls.key ` for
10105` *.services.example.com ` . Keep private keys outside the checkout. Allow a labeled
@@ -63,7 +158,7 @@ that it accepts its own non-controller Sandbox owner reference and has Service
63158Services must be left untouched, and cleanup uses UID/resource-version
64159preconditions.
65160
66- For HA pool validation after integration with # 4864 , use at least two supervisor
161+ For HA pool validation, use at least two supervisor
67162members with distinct sandbox owners. Move one owner through graceful downscale
68163and abrupt loss. Existing streams may disconnect; after selecting the new owner,
69164new HTTP/WebSocket connections must work without restarting the workload.
0 commit comments