fix(crossview): tell the app the request arrived over https - #3177
Conversation
Crossview builds its OIDC redirect_uri from the incoming request rather than from OIDC_CALLBACK_URL. Proven in prod: after a restart the pod resolved the env to the https public callback and still sent http://, so Dex rejected a redirect_uri it does not register. Every hop in front of the app is plaintext - the Gateway terminates TLS, then oauth2-proxy, then auth-proxy's :8080 entryPoint - and Traefik derives X-Forwarded-Proto from its own entryPoint scheme, so the app is told every request arrived over http. Add a Traefik middleware asserting X-Forwarded-Proto: https and attach it to the crossview router only. That router is reachable solely through the public HTTPS Gateway, so the assertion states a fact about the traffic. Apps given an explicit public hostname are deliberately left alone.
✅
|
Live login fix. Crossview builds its OIDC This asserts the real client scheme on the crossview router only. That router is reachable solely via Validated: ConfigMap and embedded Traefik config both parse, the middleware reference resolves (with @coderabbitai review |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '=== Changed files ==='
git diff --name-status HEAD^ HEAD
echo '=== PR diff ==='
git diff --find-renames --find-copies HEAD^ HEAD
echo '=== Candidate configuration files ==='
fd -HI -t f . | rg -i '(crossview|traefik|gateway|middleware|oauth|proxy)'
echo '=== References to Crossview and forwarded-proto handling ==='
rg -n -i -C 4 '(crossview|x-forwarded-proto|forwardedheaders|headers:|customrequestheaders|middleware)' \
-g '*.ya?ml' -g '*.toml' -g '*.json' .Length of output: 5930 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '=== auth-proxy ConfigMap ==='
nl -ba k8s/bases/infrastructure/controllers/auth-proxy/config-map.yaml | sed -n '1,180p'
echo '=== auth-proxy deployment ==='
nl -ba k8s/bases/infrastructure/controllers/auth-proxy/deployment.yaml | sed -n '1,260p'
echo '=== Crossview HTTPRoute ==='
nl -ba k8s/bases/apps/crossview/http-route.yaml | sed -n '1,220p'
echo '=== infrastructure Gateway route ==='
nl -ba k8s/bases/infrastructure/gateway/http-route.yaml | sed -n '1,280p'
echo '=== Gateway listeners ==='
nl -ba k8s/bases/infrastructure/gateway/gateway.yaml | sed -n '1,260p'
echo '=== References to auth-proxy service or crossview hostname ==='
rg -n -i -C 3 '(auth-proxy|crossview\.\$\{domain\}|crossview\.)' k8sLength of output: 1123 🏁 Script executed: #!/bin/bash
set -euo pipefail
show_file() {
local title="$1"
local file="$2"
local start="$3"
local end="$4"
echo "=== ${title} ==="
cat -n "$file" | sed -n "${start},${end}p"
}
show_file 'auth-proxy ConfigMap' \
k8s/bases/infrastructure/controllers/auth-proxy/config-map.yaml 1 180
show_file 'auth-proxy deployment' \
k8s/bases/infrastructure/controllers/auth-proxy/deployment.yaml 1 260
show_file 'Crossview HTTPRoute' \
k8s/bases/apps/crossview/http-route.yaml 1 220
show_file 'infrastructure Gateway route' \
k8s/bases/infrastructure/gateway/http-route.yaml 1 280
show_file 'Gateway listeners' \
k8s/bases/infrastructure/gateway/gateway.yaml 1 260
echo '=== References to auth-proxy service or Crossview hostname ==='
rg -n -i -C 3 '(auth-proxy|crossview\.\$\{domain\}|crossview\.)' k8s || trueLength of output: 56254
The
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository YAML (base), Organization UI (inherited) Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan includes up to 1 review per rolling hour; 0 remain after this review. 📜 Recent review details🧰 Additional context used📓 Path-based instructions (1)**/*.{yaml,yml}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (6)📚 Learning: 2026-07-01T21:13:36.950ZApplied to files:
📚 Learning: 2026-07-07T18:01:26.730ZApplied to files:
📚 Learning: 2026-08-08T15:10:00.349ZApplied to files:
📚 Learning: 2026-08-08T15:10:00.350ZApplied to files:
📚 Learning: 2026-08-08T21:23:32.529ZApplied to files:
📚 Learning: 2026-08-11T12:41:28.242ZApplied to files:
🔇 Additional comments (1)
📝 WalkthroughWalkthroughThe Crossview Traefik router now applies the Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
CodeRabbit returned Context: this is a live login fix. Crossview builds its OIDC The change asserts the real client scheme on the crossview router only; that router is reachable @codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Re-requesting after the stated rate-limit window elapsed. Recorded at this head: Live login fix: crossview builds its OIDC @coderabbitai review |
|
✅ Action performedReview finished.
|
Readiness at
|
| Condition | State |
|---|---|
| Programmatically tested | ✅ ConfigMap parses; embedded Traefik dynamic.yaml extracted and parsed; the router's middleware reference proven to resolve, with a negative control confirming a dangling reference is caught; ksail --config ksail.prod.yaml workload validate 575 files; CI green including 🔐 Validate EKS Authorization |
| Reviewed | ✅ cr@2cc9443c — head status Review completed, substantive summary comment updated 19:46:54Z (after the 19:45:01Z request) naming this head, 0 unresolved threads, no actionable finding section (only 🔇 Additional comments, whose single note is LGTM! on the changed lines) |
| Tried and evaluated as a user |
On the third condition, stated honestly rather than waved through. What is proven is the
failure and its mechanism: after a restart the pod had resolved the https callback from config and
still sent http://, so the app builds the redirect from the request; and Traefik derives
X-Forwarded-Proto from its own plaintext entryPoint, so the app is told every request arrived over
http. What is not proven is that crossview reads that header rather than only r.TLS. The chart
exposes no base-URL or trust-proxy setting, so there is no configuration path to test instead, and
the effect is only observable once Flux reconciles.
Merging on that basis because the alternative is leaving a live login broken while the one remaining
unknown is unobservable pre-deploy — which is exactly what the board's 📊 Verifying state is for.
Post-merge obligation. After reconciliation, retry the login. If it succeeds, #3172 closes. If it
still shows http://, this change is correct but insufficient — crossview trusts only the connection
scheme, and the fix moves upstream. Either outcome is decisive; revert is a single-route change.

Why
Crossview login fails at Dex with
Unregistered redirect_uri, and the app is the one getting itwrong: it builds the redirect from the incoming request rather than from the callback URL it is
configured with.
That is now proven rather than inferred. After the pod was restarted it had definitely resolved the
correct HTTPS callback from its config — and it still sent
http://. So the configured value is notwhat it uses.
The reason it sees
httpis that every hop in front of it is plaintext: TLS is terminated at theGateway, then the request passes through oauth2-proxy and auth-proxy. Traefik reports the scheme of
the entry point it received on, so the app is told every request arrived over plain HTTP — and Dex
correctly refuses a callback it does not register.
What
Assert the real client scheme on the way in, attached to the crossview route only. That route is
reachable solely through the public HTTPS gateway, so this states a fact about the traffic rather
than a preference. Apps that are given an explicit public hostname instead are deliberately left
untouched.
Fixes #3172. Independent of #3171, which fixes a different problem (config changes never rolling the
app) and is blocked by #3175.