Skip to content

feat(gateway): expose workspace service route snapshots and watches - #4941

Draft
TaylorMutch wants to merge 1 commit into
feat/4939-service-advertisements/TaylorMutchfrom
feat/4667-service-discovery/TaylorMutch
Draft

TaylorMutch wants to merge 1 commit into
feat/4939-service-advertisements/TaylorMutchfrom
feat/4667-service-discovery/TaylorMutch

Conversation

@TaylorMutch

@TaylorMutch TaylorMutch commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Expose accepted supervisor installations through GetServiceRouteSnapshot and WatchServiceRoutes for one explicit authorized workspace. Independent proxies and infrastructure controllers consume exact hostnames and trusted supervisor endpoints through the same API.

Rebased onto main at 9f1cdb4ef. Stacked on feat/4939-service-advertisements/TaylorMutch.

Related Issue

Closes #4667. Part of RFC 0017.

Changes

  • Publish accepted installation records from feat(supervisor): advertise accepted application route installations #4940, which resolves trusted supervisor endpoints through the private ResolveSupervisorAppEndpoint compute RPC. External consumers use the public discovery RPCs; ordinary GetSandbox observations do not resolve routes.
  • Return complete replacements with installation versions, declaration revisions, expiry, and current owner endpoints.
  • Recheck session, runtime, credential epoch, and shared pool authority before publishing routes.
  • Bound collection, watches, buffering, send time, and lifetime; periodically reauthorize watches and fail closed on storage errors.
  • Document client cache expiry and stable installation versions across lease-only renewal.

Release Notes

Discovery and Kubernetes request flow

Discovery returns an application hostname and a trusted supervisor endpoint
(host and port), together with installation identity and expiry. name is the
sandbox route's service name; an empty value identifies the unnamed/default
service. It is not a Kubernetes Service resource name.

The endpoint is the owning supervisor Pod IP and app-listener port. Consumers
preserve the application hostname as TLS SNI and HTTP Host/authority. Multiple
routes can share one supervisor endpoint; the hostname selects the sandbox
instance and service. The authoritative public application URL is separate and
can use a different public port.

flowchart TB
    subgraph Control["Control plane: build and publish discovery"]
        SUP["Supervisor<br/>Reports installed routes against a lease"]
        GW["OpenShell gateway<br/>Validates installation and ownership"]
        KD["Kubernetes compute driver<br/>ResolveSupervisorAppEndpoint"]
        KUBE["Kubernetes objects + supervisor ownership<br/>Find and validate owning supervisor Pod"]
        API["Discovery API<br/>hostname + Pod IP:8443 + expiry"]
        CONSUMER["Sandbox proxy or<br/>example Kubernetes HTTPRoute controller"]

        SUP -->|"Installed-route advertisement"| GW
        GW -->|"Resolve trusted endpoint"| KD
        KD --> KUBE
        KUBE -->|"Validated Pod IP and listener port"| KD
        KD --> GW
        GW --> API
        API -->|"Snapshot / watch"| CONSUMER
    end

    subgraph Data["Application data plane"]
        CLIENT["Client<br/>https://team--demo--web.apps.example.com"]
        EDGE["Configured proxy or Kubernetes Gateway<br/>Public listener, e.g. port 443"]
        LISTENER["Owning supervisor Pod<br/>10.42.1.27:8443<br/>TLS app listener"]
        DISPATCH["Select sandbox instance + named service<br/>using SNI / Host"]
        CONNECTOR["Selected instance's sandbox connector"]
        APP["Application inside sandbox<br/>127.0.0.1:8080"]

        CLIENT --> EDGE
        EDGE -->|"Connect to discovered endpoint<br/>preserve application SNI / Host"| LISTENER
        LISTENER --> DISPATCH
        DISPATCH --> CONNECTOR
        CONNECTOR --> APP
    end

    CONSUMER -.->|"Configure forwarding"| EDGE
Loading

Addresses, domain names, and ports above are illustrative. Discovery describes
accepted installations, not application health or external ingress readiness.
The Kubernetes driver resolves trusted endpoints; a separate consumer configures
HTTPRoutes or proxy forwarding. Application traffic bypasses the OpenShell
gateway. The proxy and example controller are separate consumers, not part of
this PR's implementation.

Testing

  • Validated against main fdce6ef26: 2,557 server tests passed (34 ignored), 279 supervisor tests, 310 Kubernetes driver tests, 8 proxy tests, full Go SDK CI, and 431 gateway + 6 workspace + 6 proxy Helm tests. All eight PR layers independently passed locked Rust compilation with test targets. Repository pre-commit passed with SETUPTOOLS_SCM_PRETEND_VERSION_FOR_OPENSHELL=0.0.0; plain invocation hits an existing main-branch setuptools-scm failure parsing tag sdk/go/v0.1.6. The final advance to main 9f1cdb4ef changes only tests/suites/features/Cargo.lock in each validated layer. Live HA qualification was not rerun for this rebase.
  • After the internal RPC separation in feat(supervisor): advertise accepted application route installations #4940, this rebased layer independently passed locked Rust compilation with test targets.
  • Updated stack tip: 2,494 server library tests passed (34 ignored), 306 Kubernetes driver tests, RPC tracing coverage, SDK binding regeneration, and full repository pre-commit checks passed. The public discovery schema and generated SDK bindings are unchanged by the internal RPC refactor.
  • Earlier HA validation, before the internal RPC separation: 3,136 runtime library tests passed (34 ignored), 48 Rust SDK mock tests, 8 proxy tests, full Go SDK CI, and 412 gateway + 6 workspace + 6 proxy Helm tests passed.
  • Combined stack: full repository pre-commit (including strict Clippy), strict docs, and navigation checks passed.
  • Earlier live Kubernetes validation, before the internal RPC separation: two gateways, shared supervisors, and proxy replicas; direct/proxy TLS and HTTP/WebSockets, abrupt owner-process loss/recovery, populated 2→1→2→1 scaling, route renewal/withdrawal, and discovery grant narrowing/regrant passed. Workload Pod identity, PID, and in-memory state survived owner handoff.

Qualification limits

Live HA validation exercised supervisor process/Pod loss on a local k3d cluster. Whole-node failure, real network partitions, metric-driven HPA, sustained production load, and published release artifacts remain unqualified. Grant-file projection contributes to revocation propagation time. Main now includes #4842 for gateway-mediated hashed hostnames. Direct application-listener/discovery hostnames remain readable; extending hashed naming to that path and installation-status presentation (#4670) remain separate work.

The example Kubernetes HTTPRoute controller is a deferred compatibility POC outside this stack.

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Relevant implementation, configuration, and API documentation updated

PR dependency order: #4936 → #4940 → #4941 → #4956 → #4963 → #4964 → #4957 → #4958.

@copy-pr-bot

copy-pr-bot Bot commented Oct 26, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@github-actions

Copy link
Copy Markdown

@TaylorMutch
TaylorMutch added this pull request to stack #4942 October 26, 2026 22:35
@TaylorMutch
TaylorMutch force-pushed the feat/4667-service-discovery/TaylorMutch branch from c724036 to 932643d Compare October 27, 2026 03:15
@TaylorMutch
TaylorMutch force-pushed the feat/4667-service-discovery/TaylorMutch branch from 932643d to 6c83b66 Compare October 27, 2026 05:42
@TaylorMutch
TaylorMutch removed this pull request from stack #4942 October 27, 2026 05:45
@TaylorMutch
TaylorMutch added this pull request to stack #4965 October 27, 2026 05:46
@TaylorMutch
TaylorMutch removed this pull request from stack #4965 October 27, 2026 05:47
@TaylorMutch
TaylorMutch added this pull request to stack #4966 October 27, 2026 06:24
@TaylorMutch
TaylorMutch force-pushed the feat/4667-service-discovery/TaylorMutch branch from 6c83b66 to 755e4d1 Compare October 27, 2026 06:24
@TaylorMutch
TaylorMutch force-pushed the feat/4667-service-discovery/TaylorMutch branch from 755e4d1 to 0944ea2 Compare October 27, 2026 06:25
@TaylorMutch
TaylorMutch force-pushed the feat/4667-service-discovery/TaylorMutch branch from 0944ea2 to 8504067 Compare October 27, 2026 06:46
@TaylorMutch
TaylorMutch force-pushed the feat/4667-service-discovery/TaylorMutch branch from 8504067 to feac6b4 Compare October 27, 2026 21:06
@TaylorMutch
TaylorMutch force-pushed the feat/4667-service-discovery/TaylorMutch branch from feac6b4 to 0939a70 Compare October 28, 2026 17:05
@TaylorMutch
TaylorMutch force-pushed the feat/4667-service-discovery/TaylorMutch branch from 0939a70 to cf5448a Compare October 28, 2026 22:52
Signed-off-by: Taylor Mutch <taylormutch@gmail.com>
@TaylorMutch
TaylorMutch force-pushed the feat/4667-service-discovery/TaylorMutch branch from cf5448a to d43f1ae Compare October 29, 2026 01:16

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(gateway): expose workspace service route snapshots and watches

1 participant