fix(e2e): cloud auth via cookie, local port, Playwright WebSocket gotcha
E2E harness fixes to get all three modes (demo/cloud/local) passing: - conftest.py: use ctx.add_cookies() for cloud auth instead of ctx.route() or set_extra_http_headers(). Playwright's route() only intercepts HTTP; set_extra_http_headers() explicitly excludes WebSocket handshakes. Streamlit reads st.context.headers from the WebSocket upgrade, so cookies are the only vehicle that reaches it without a reverse proxy. - cloud_session.py: fall back to Cookie header when X-CF-Session is absent — supports direct access (E2E tests, dev without Caddy). In production Caddy sets X-CF-Session; in tests the cf_session cookie is set on the browser context and arrives in the Cookie header. - modes/cloud.py: add /peregrine base URL path (STREAMLIT_SERVER_BASE_URL_PATH=peregrine) - modes/local.py: correct port from 8502 → 8501 and add /peregrine path All three modes now pass smoke + interaction tests clean.
This commit is contained in:
parent
5d14542142
commit
cb8afa6539
4 changed files with 19 additions and 8 deletions
|
|
@ -151,7 +151,12 @@ def resolve_session(app: str = "peregrine") -> None:
|
|||
if st.session_state.get("user_id"):
|
||||
return
|
||||
|
||||
cookie_header = st.context.headers.get("x-cf-session", "")
|
||||
# Primary: Caddy injects X-CF-Session header in production.
|
||||
# Fallback: direct access (E2E tests, dev without Caddy) reads the cookie header.
|
||||
cookie_header = (
|
||||
st.context.headers.get("x-cf-session", "")
|
||||
or st.context.headers.get("cookie", "")
|
||||
)
|
||||
session_jwt = _extract_session_token(cookie_header)
|
||||
if not session_jwt:
|
||||
_render_auth_wall("Please sign in to access Peregrine.")
|
||||
|
|
|
|||
|
|
@ -93,11 +93,17 @@ def mode_contexts(active_modes, playwright) -> dict[str, BrowserContext]:
|
|||
for mode in active_modes:
|
||||
ctx = browser.new_context(viewport={"width": 1280, "height": 900})
|
||||
if mode.name == "cloud":
|
||||
def _inject_jwt(route, request):
|
||||
# Cookies are sent on WebSocket upgrade requests; set_extra_http_headers
|
||||
# and ctx.route() are both HTTP-only and miss st.context.headers.
|
||||
# cloud_session.py falls back to the Cookie header when X-CF-Session
|
||||
# is absent (direct access without Caddy).
|
||||
jwt = _get_jwt()
|
||||
headers = {**request.headers, "x-cf-session": f"cf_session={jwt}"}
|
||||
route.continue_(headers=headers)
|
||||
ctx.route(f"{mode.base_url}/**", _inject_jwt)
|
||||
ctx.add_cookies([{
|
||||
"name": "cf_session",
|
||||
"value": jwt,
|
||||
"domain": "localhost",
|
||||
"path": "/",
|
||||
}])
|
||||
else:
|
||||
mode.auth_setup(ctx)
|
||||
contexts[mode.name] = ctx
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ def _cloud_auth_setup(context: Any) -> None:
|
|||
|
||||
CLOUD = ModeConfig(
|
||||
name="cloud",
|
||||
base_url="http://localhost:8505",
|
||||
base_url="http://localhost:8505/peregrine",
|
||||
auth_setup=_cloud_auth_setup,
|
||||
expected_failures=[],
|
||||
results_dir=Path("tests/e2e/results/cloud"),
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ _BASE_SETTINGS_TABS = [
|
|||
|
||||
LOCAL = ModeConfig(
|
||||
name="local",
|
||||
base_url="http://localhost:8502",
|
||||
base_url="http://localhost:8501/peregrine",
|
||||
auth_setup=lambda ctx: None,
|
||||
expected_failures=[],
|
||||
results_dir=Path("tests/e2e/results/local"),
|
||||
|
|
|
|||
Loading…
Reference in a new issue