Add flyte proxy app: authenticated localhost proxy into a Flyte App - #1435
Open
mhotan wants to merge 2 commits into
Open
Add flyte proxy app: authenticated localhost proxy into a Flyte App#1435mhotan wants to merge 2 commits into
flyte proxy app: authenticated localhost proxy into a Flyte App#1435mhotan wants to merge 2 commits into
Conversation
mhotan
force-pushed
the
mike/flyte-proxy-app
branch
from
August 14, 2026 04:28
af3a5ee to
7aa0069
Compare
mhotan
force-pushed
the
mike/flyte-proxy-app
branch
4 times, most recently
from
September 1, 2026 10:13
4be3f27 to
c425c88
Compare
mhotan
commented
Sep 1, 2026
| # resolved value — matching the container path (get_proto_container). Without | ||
| # this the pod path serializes the raw, unresolved parameter and the serve | ||
| # entrypoint can't download it. | ||
| container.command = app_env.container_cmd(serialization_context, parameter_overrides) |
Contributor
Author
There was a problem hiding this comment.
This is actually a bug fix I think I found.
mhotan
force-pushed
the
mike/flyte-proxy-app
branch
from
September 1, 2026 11:18
faa78b4 to
4e53058
Compare
kumare3
reviewed
Sep 1, 2026
|
|
||
| import rich_click as click | ||
|
|
||
| import flyte.remote as remote |
Contributor
Author
There was a problem hiding this comment.
Done in 39fd218 — moved import flyte.remote as remote into the app command's name-resolution branch, so the heavy remote client stack only loads when resolving an app by name (the --url path skips it entirely). Module top now imports only stdlib + rich_click (needed for the decorators).
Adds a `flyte proxy app NAME` command — an authenticated localhost reverse proxy into a no-auth-inside Flyte App. Reuses the CLI authenticator to inject a fresh bearer on every request so a local HTTP client (an MCP server, curl, a browser) reaches an app-edge-gated app with no token handling. - Resolve the target by app name (App.get) or an explicit --url. - Bind loopback on both 127.0.0.1 and ::1 so `localhost` (which resolves to ::1 first on macOS) is not silently shadowed by a wildcard listener from another process (e.g. a container runtime on *:PORT with SO_REUSEPORT); a genuine conflict now fails loudly with EADDRINUSE instead of half-binding. - Stream responses unbuffered and preserve Content-Encoding (SSE-safe for MCP streamable-HTTP). - Drop inbound Authorization/hop-by-hop headers; inject the fresh bearer on the standard `authorization` header (the SDK auth flow may emit it under a gRPC-style metadata key the HTTP app edge never reads); refresh + retry once when the edge bounces an expired token to /login. - --emit-mcp-config prints a generic HTTP-MCP client block. Also materialize delayed app parameters (e.g. RunOutput) on the pod_template serialization path: the container path already resolved them to a File/Dir URI, but the pod_template path serialized the raw getter, so an app that set a pod_template could not download its input. Thread parameter_overrides through _get_k8s_pod / _serialized_pod_spec. Unit tests cover header filtering, Content-Encoding preservation, JWT identity display, and the MCP-config block. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Michael Hotan <mike@union.ai>
mhotan
force-pushed
the
mike/flyte-proxy-app
branch
from
September 3, 2026 05:18
efedc30 to
fe7405c
Compare
Addresses review feedback: the flyte.remote client stack is heavy and was imported at module top, slowing every 'flyte' CLI invocation. Move it into the app command's name-resolution branch so it only loads when resolving an app by name (the --url path skips it entirely). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mhotan
force-pushed
the
mike/flyte-proxy-app
branch
from
September 4, 2026 11:17
39fd218 to
f1b26ca
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Adds a
flyte proxy app NAMEcommand — an authenticated localhost reverse proxy into a no-auth-inside Flyte App. It reuses the CLI's own authenticator to inject a fresh bearer on every request, so a local HTTP client (an MCP server,curl, a browser) can reach an app-edge-gated app with no token handling. Thinkkubectl port-forwardfor Flyte Apps.Details
App.get) or an explicit--url.127.0.0.1and::1solocalhost— which resolves to::1first on macOS — can't be silently shadowed by a wildcard listener from another process (e.g. a container runtime binding*:PORTwithSO_REUSEPORT). Previously an IPv4-only bind still "succeeded" while every request landed on the other listener and reset; now a genuine conflict fails loudly withEADDRINUSE. A non-loopback--addressbinds a single family and warns (the proxy is ambient authority for the caller's identity).Content-Encoding— SSE-safe for MCP streamable-HTTP.Authorization/hop-by-hop headers, injects the fresh bearer on the standardauthorizationheader (the SDK auth flow may emit it under a gRPC-style metadata key the HTTP app edge never reads), and refreshes + retries once when the edge bounces an expired token to/login.--emit-mcp-configprints a generic HTTP-MCP client block pointed at the local port.Also included
RunOutput), it is materialized to a resolvedFile/DirURI at deploy time. The container path already did this; thepod_templateserialization path did not — so an app that set apod_templateserialized the raw, unresolved getter and the serve entrypoint couldn't download it. Threadsparameter_overridesthrough_get_k8s_pod/_serialized_pod_specso the pod command carries the resolved value. Independent of the proxy — can be split into its own PR on request.Testing
tests/cli/test_proxy.py): inbound-auth/hop-by-hop stripping,Content-Encodingpreservation, JWT identity display, and the MCP-config block.mcp-grafanaserver driven by the official MCP Python client SDK (ClientSession):initialize-> 65 tools ->list_datasourcesandquery_prometheusreturned live data through the proxy with no real credential in the MCP config.curl localhost:PORTreaches the proxy (not the other listener); a conflicting specific bind fails withEADDRINUSE.🤖 Generated with Claude Code