Repository navigation
Re-verify issue #209 (bare-404 Host-header routing) against current staging gateway ingress #249
Description
Summary
Issue #209 (already tracked in code -- see OpenShellSpawner._wait_ready_with_host()'s _INGRESS_MISMATCH_STREAK_LIMIT mechanism and its docstring) describes a gateway ingress that doesn't support Host-header-based HTTP routing to sandbox ports on its main TLS port, causing 5 consecutive bare 404s (no body, no content-type) and an early, diagnostic RuntimeError instead of the full readiness timeout.
This was observed live twice against the staging gateway (<staging-gateway-host>:443) via lightspeed-stack's workflow-ephemeral and workflow-ephemeral-approval demo scenarios, both with the current (post-#238/#244/#246) fixed cloud_agents code:
RuntimeError: Gateway returned a bare 404 (no body, no content-type) 5 times in a row for
Host 'default--intimate-bowfin.openshell.localhost' at
https://<staging-gateway-host>:443/health.
In both observed runs, the sandbox successfully reached CreateSandbox -> exec'd the server -> ExposeService, and only then failed the Host-header health check -- i.e. this is a later-stage failure than plain provisioning flakiness (see #248 for that separate issue), and matches the exact fingerprint _wait_ready_with_host()'s bare-404 detection was built for.
What's NOT yet confirmed
A follow-up attempt to independently re-reproduce this (spawn a fresh bare sandbox, manually curl /health with the correct vs. an incorrect Host header to directly compare the ingress's behavior) did not get far enough to test it: the fresh sandbox got stuck in SANDBOX_PHASE_PROVISIONING for 60s+ before ever reaching a state where the HTTP health check could be attempted (see #248). So the current live behavior of staging's ingress for Host-header routing has not been independently re-confirmed in this pass -- only the original two occurrences (with full tracebacks matching #209's known fingerprint) are the evidence so far.
Suggested next steps
- Once Staging gateway: sandboxes intermittently stuck in Provisioning phase for 60s+ (not an image-arch issue) #248's provisioning flakiness allows a sandbox to reliably reach
READY, manually compareGET /healthwith the correctHost: default--<sandbox>.openshell.localhostheader vs. an obviously wrong Host header vs. no Host header, on the current staging gateway, to directly confirm whether the ingress is still ignoring the Host header (vs. some other transient cause). - If confirmed, determine whether staging exposes a separate HTTP ingress route for sandbox traffic (distinct from the main gRPC/TLS port) that
OpenShellSpawner'shttp_endpointparameter could be pointed at instead -- the error message itself suggests this workaround, but it hasn't been verified whether such a route actually exists for this specific staging deployment. - If no such route exists, this may require staging's ingress config to be updated to support Host-header-based virtual routing on its main port, matching the working configurations already confirmed on local Kind and (per the original OpenShellSpawner: unnecessary direct LLM egress when using a custom provider URL (fixed in #220) #209 investigation) a real OCP cluster.
Activity
jameswnl commentedon Sep 1, 2026
Update: re-confirmed live against the current staging gateway, "not yet confirmed" section resolved
Just reproduced this end-to-end against
<staging-gateway-host>:443(the live gateway named above), with a new diagnostic script that isolates exactly this question: #250 addsscripts/gateway-verification/diagnose_host_header_routing.py.What it does
lightspeed_agentic.appserver inside it.curl 127.0.0.1:8080/health(ruling out an app-level failure).ExposeService, then issues three gateway-proxiedGET /healthrequests: correct virtualHostheader, an obviously-wrongHostheader, and noHostheader at all.Result (this run)
curl 127.0.0.1:8080/health→200— app confirmed healthy.Host→ bare404(no body, nocontent-type).Host→ identical bare404.Host→ identical bare404.All three are indistinguishable. This resolves the "What's NOT yet confirmed" section above: it's not that the ingress might be routing to some other sandbox or behaving inconsistently — Host-header-based HTTP routing to sandbox ports isn't functioning at all on this gateway's main TLS port right now, for any Host value. The original #209 fingerprint (bare 404, no body/content-type) is confirmed as the current, live behavior of this specific staging deployment, not a stale/transient observation from the earlier #238/#244 investigation.
This also directly answers the next step this issue proposed: since Host-header multiplexing on the main port is confirmed non-functional (not just flaky), the path forward is checking whether this gateway exposes a separate HTTP ingress route for sandbox traffic that
OpenShellSpawner'shttp_endpointparam could point at instead, or getting the ingress config fixed to support Host-header virtual routing on the main port (matching local Kind and real OCP, which both already work per the original #209 investigation).Bonus, relevant to #248
While reproducing this, none of my spawns actually got stuck in Provisioning (9–18s to Ready each time) — but I found that
SandboxStatus.conditions(a repeated, Kubernetes-condition-shaped{type, status, reason, message, last_transition_time}) is already populated by the gateway with real diagnostic detail during Provisioning (observed:reason=DependenciesNotReady, message="Pod exists with phase: Pending"). The Python SDK'sSandboxStatusRef(openshell.sandbox._sandbox_ref()) silently drops this field, exposing onlyphase/current_policy_version/exit_code— confirmed still true in both the pinned SDK (0.0.111) and the unreleased~/ws/Openshellsource. That's likely why #248's repro saw "no message field populated at any point" — it's a client-visibility gap, not proof the gateway is silent. The new script bypasses this by readingconditionsoff the rawGetSandboxstub response directly, so a future stuck-in-Provisioning repro should show the actual reason without needing cluster-admin access.Script: #250
Add live-gateway diagnostic script for issue #249 (bare-404 Host-head…
Add live-gateway diagnostic script for issue #249 (bare-404 Host-head…
jameswnl commentedon Sep 2, 2026
Re-verified against the prod gateway (
openshell-prod) — routing WORKS here, opposite of stagingThe prior evidence in this issue (and #250) was gathered against the staging gateway. I re-ran the same #250 diagnostic (
scripts/gateway-verification/diagnose_host_header_routing.py, unchanged) against the prod gatewayopenshell-prod-openshell-prod.apps.rosa.df92w-mrmzx-si5.jryo.p3.openshiftapps.com:443. Result: Host-header routing is functioning — the #209/#249 bare-404 fingerprint does NOT reproduce on this deployment.Result
Contrast with staging, where correct/wrong/no Host all returned an identical bare 404 (no body, no content-type). On prod:
200 {"status":"ok"}).text/plain,Service endpoint not found) — proving the ingress is genuinely doing Host-based virtual routing, not blindly 404ing.This confirms #209/#249 is a per-deployment ingress-config issue, not universal: it reproduces on staging but not on prod (which matches the working local-Kind and real-OCP configs from the original #209 investigation).
Two setup gaps hit while connecting (may bite others / the spawner)
openshell-cliis a public OIDC client. The client-credentials grant is rejected ("Public client not allowed to retrieve service account"), soOidcClientCredentialsTokenProvider/ the diagnostic's client-credentials path can't authenticate to this realm. I used the CLI's cached~/.config/openshell/gateways/ocp-prod/oidc_token.jsonand minted fresh access tokens via the refresh_token grant (300s access-token TTL, so re-minted per run).CN=openshell-prod-external, issuerCN=openshell-selfsigned-ca). certifi can't verify it (CERTIFICATE_VERIFY_FAILED), and theopenshellCLI hits the same wall (invalid peer certificate: UnknownIssuer) — i.e. the CLI currently can't talk to this gateway over TLS. I extracted the CA from the cluster secretopenshell-prod/openshell-prod-server-external-tls(.data.ca\.crt), which verifies the gateway cert (return code 0), and passed it as the TLS CA.Side notes
SandboxStatus.conditionsfrom the rawGetSandboxstub showed real diagnostic detail during provisioning (DependenciesNotReady/Pod exists with phase: Pending→DependenciesReady/Supervisor session connected), matching the Add live-gateway diagnostic script for issue #249 (bare-404 Host-header routing) #250 bonus finding aboutSandboxStatusRefdroppingconditions.noble-ibis) deleted afterward.jameswnl commentedon Sep 2, 2026
Conclusion: this is a per-deployment (ingress) issue, not a gateway/code defect
Reconfirmed on a second, independent prod cluster (
openshell-prod-openshell-prod.apps.rosa.xpit3-4ibom-49z.pddx.p3.openshiftapps.com), same #250 diagnostic, unchanged:200 {"status":"ok"}404 text/plain "Service endpoint not found"(genuine Host-based virtual routing)Also validated the full path end-to-end on this cluster —
workflow-ephemeral-approvalspawned sandboxes to Ready and the gateway proxied/healthcorrectly.Summary across deployments:
df92w…)xpit3…)So the bare-404 is a property of the staging ingress, not the OpenShell gateway or
lightspeed-cloud-agents. Thehttp_endpoint=fallback the error message suggests remains the right escape hatch for any ingress that can't do Host-header routing on its TLS port. Recommend tracking the staging ingress fix separately and closing this verification issue.jameswnl commentedon Sep 2, 2026
Root cause traced and filed upstream: openshift-online/hypershell#234.
Neither of HyperShell's ingress modes (
routeorgateway-api) provisions any routing for OpenShell's per-sandboxExposeServiceHTTP virtual-hosting — only a single fixed hostname per gateway ever gets created, pointed at the gRPC port. OpenShell's HTTP-exposure feature depends on the raw TLS connection reaching the gateway pod so it can demux internally byHostheader, but a client hitting the per-sandbox hostname presents that hostname as the TLS SNI, which doesn't match the platform router's one registered Route/GRPCRoute hostname — so the platform router itself returns the bare 404 (no body/content-type) before the request ever reaches the OpenShell gateway.This confirms the ingress is not "flaky" or transiently misconfigured on staging — it's a structural gap in how the staging gateway is provisioned (by HyperShell), not something fixable on the
cloud_agents/OpenShellSpawnerside, and not an OpenShell core bug either. See hypershell#234 for the full trace (file/line citations into bothreconcilePassthroughRouteandreconcileGatewayAPIResources).Relevant to #221's scoping decision: since the platform-side fix has unclear timeline/ownership (hypershell#234 is newly filed, and the adjacent #220 there is closed without adding wildcard-hostname support), #221's "full replacement" option (gRPC
ForwardTcptunnel as the sole transport, bypassing Host-header routing entirely) looks like the more durable path forward rather than waiting on upstream ingress changes.