fix: classification banner working for SPAs#2710
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the Istio classification-banner EnvoyFilter to avoid hanging on streamed HTML responses (notably Grafana 13’s streamed shell), standardizes banner font styling, reserves viewport space to prevent overlap in SPAs, and enables/validates the banner in the k3d-standard demo bundle via a new Playwright test.
Changes:
- Update the classification-banner Lua filter to inject safely for both bounded (Content-Length) and streamed (chunked/no Content-Length) HTML responses, and skip non-200 responses.
- Adjust injected banner styling and add client-side logic to reserve space so fixed-position SPA chrome doesn’t overlap the banner.
- Enable the banner on demo bundle hosts (sso/portal/grafana) and add a Playwright test to verify banner injection.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| test/playwright/classification-banner.test.ts | Adds an end-to-end Playwright check that the banner is injected on sso/grafana (and portal when present). |
| src/istio/common/chart/templates/classification-banner.yaml | Updates Envoy Lua injection logic to avoid blocking on streamed responses and improves banner layout/styling behavior. |
| bundles/k3d-standard/uds-bundle.yaml | Enables the banner on selected demo hosts and sets demo text to UNKNOWN. |
Greptile SummaryThis PR fixes the classification-banner EnvoyFilter which previously hung the gateway on Grafana 13 because
Confidence Score: 4/5The change is safe to merge — it fixes a real gateway hang and the new code paths degrade gracefully when tag boundaries straddle chunk edges. The buffered and streaming injection logic is correct: inject_banner uses gsub-with-limit-1 so it cannot double-inject, the injected flag correctly tracks completion, and the early-return on non-200 status closes the original redirect hang. The only open items are cosmetic: a redundant response_handle:body() call and a tostring() wrapper that the Envoy Lua runtime makes a no-op. No files require special attention; the Lua logic in classification-banner.yaml is the most complex part and reads correctly after careful review. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[envoy_on_response] --> B{status == 200\nAND text/html\nAND enabled host?}
B -- No --> Z[return — pass through untouched]
B -- Yes --> C{content-length\nheader present?}
C -- Yes --> D[response_handle:body\nbuffer full response]
D --> E[inject_banner on full body]
E --> F[body:setBytes patched body]
C -- No --> G[response_handle:bodyChunks\nstreaming iterator]
G --> H{chunk non-empty\nAND not yet injected?}
H -- No --> I[pass chunk through]
I --> H
H -- Yes --> J[inject_banner on chunk]
J --> K[chunk:setBytes patched chunk]
K --> L{classification-banner-top\nfound in patched data?}
L -- Yes --> M[injected = true\npass remaining chunks through]
L -- No --> H
subgraph inject_banner
N[gsub body tag → insert header div]
N --> O[gsub head tag → insert padding script]
end
Reviews (1): Last reviewed commit: "fix: classification banner working for S..." | Re-trigger Greptile |
Description
The classification banner was noticed to block traffic to Grafana in uds-identity-config. See: defenseunicorns/uds-identity-config#870. In our envoy filter
response_handle:body()buffers the entire body and blocks until end-of-stream and on Grafana 13's streamed shell (no Content-Length) this hung.This PR:
NOTE: People will see the UNKNOWN classification banner for demo bundle deploys. If we feel this is weird I would be open to changing this. I also set this to UNKNOWN instead of UNCLASSIFIED as I didn't want to assume classification for where people are deploying the demo bundle locally.
Related Issue
Fixes CORE-590
Type of change
Steps to Validate
uds runand check the banners on portal, sso, and grafanaChecklist before merging