Last 12 weeks · 6 commits
1 of 6 standards met
Upgrade the dependency from to and updates all concurrent map usages across the codebase to the updated generic APIs. In , the library has removed the older non-generic structures and consolidated the generic map under . [!NOTE] Low Risk Mechanical dependency and type renames on concurrent maps; behavior should match v3 for the same Load/Store/Range usage, with low change surface beyond the library bump. Overview Bumps * from v3.5.1 to v4.5.0 and aligns call sites with the v4 generic map API: / become / . That rename is applied everywhere concurrent maps back proxy networking state: connection tracking (), IP allocation (), Kubernetes port-forward dialer caching (), and tunnel multiplexed connections (). is updated accordingly. The only non-mechanical change is minor * formatting in conntrack cleanup. Reviewed by Cursor Bugbot for commit 0358bc8add3a21967db7e2fd51d3a696dd8e7809. Bugbot is set up for automated code reviews on this repo. Configure here.
The bug dispatches five typed kinds and sends everything else through the dynamic client. only knew those five typed kinds and took no dynamic client at all — so any other kind in a source manifest is created on every bridge and never removed. Staging today, namespace: against 16 live bridge deployments. The typed kinds are the control: they clean up correctly. The untyped ones leak ~95%. This is not just clutter — orphaned HPAs still pointing at put an on the live service. The fix Sweep the remaining kinds through the dynamic client, discovering them from the server rather than hardcoding a list, so cleanup stays symmetric with as new kinds appear in manifests instead of needing another patch here each time. The sweep is pinned to the same + selector (both bridge-set, so nothing else can match), skips the typed kinds handled above, and skips kinds the API server garbage-collects with their owner — pods inherit the bridge labels from the deployment's pod template and would otherwise be deleted redundantly. Failures are logged and never fatal: cleanup runs on error paths where a partial delete beats none, and callers may legitimately lack access to some kinds. was already available at all four call sites, passed to on the adjacent line. Verification Simulated against staging for one real orphaned bridge: the sweep lists 39 kinds and deletes exactly 2 — the leaked HPA and PDB — with no collateral. Two traps in the test doubles, both of which would have produced tests that pass while asserting nothing: is hardcoded to , so a test using the fake clientset skips the sweep entirely. Discovery is therefore behind a one-method interface. client-go's has a but no case for delete-collection, so is recorded and silently does nothing. The test installs a reactor implementing those semantics against the tracker (it can't call back into the client — holds a non-reentrant lock). Mutation-tested: disabling the sweep fails the two behavioural tests; restoring it passes them. clean, full suite green including the 218s e2e. Not covered here This stops new leaks; it does not retroactively remove the 226 already-orphaned resources in staging. Those are deletable by label in one pass — happy to do it as a follow-up, but they span other developers' device IDs so it wants a deliberate call rather than riding along with a code change. 🤖 Generated with Claude Code
Summary Adds that launches the from devcontainer.json (e.g. ), streams its output, and waits until the source deployment's probes report the local app healthy. PID is persisted across invocations so re-running cleanly kills the previous server. What's in this PR command — positional bridge name, (default 2m, ). Reads from devcontainer.json (string or array) Starts the command via with so it survives the CLI exit Streams the log file into the same uses Re-running kills the previously tracked PID first (SIGTERM with 3s grace → SIGKILL) Exit precedence: dev process exits → all probes pass → RPC on InterceptorService — synchronous, stateless "is the app responding right now?" check. Bypasses the threshold-tracked view so a stale HEALTHY from a previous session can't fool the new run. Bridge dev polls ; keeps using for the smoothed steady-state view. APPLICATION column — new field on . Queried in parallel per bridge with a 1.5s timeout. Values: / / / / . Defaults to when the source has no probes. / on — starts the devcontainer after creating the bridge but doesn't attach. now implies . Useful for agent flows that want a container running without holding the terminal. Install path moved to — no sudo, no xattr, no Gatekeeper workaround needed (curl doesn't quarantine its downloads). Override with . Hint about is printed only when the directory isn't already on it. no longer dev-only-relative — prefers when present so works from any CWD; falls back to only for the in-repo development workflow. Misc**: Session proto extended with / / so callers can Load → mutate → Write without losing fields; still resets dev state on fresh creates PID is persisted regardless of dev-command outcome — agents/next runs can use it for diagnostics or cleanup even on a failed start Tests — Probe interface contract, HTTP/TCP/Exec handlers — string / array / missing / invalid devCommand — fresh save, full round-trip with dev fields, Save resets, idempotent Delete — orchestrator state machine via fakeInterceptor ( shape now): immediate healthy, exit-wins-over-health, timeout, half-passing, no-probes-defaults-to-healthy, mid-wait healthy transition, context cancel, mid-wait exit Full unit suite + clean 🤖 Generated with Claude Code
Summary Add an with that surfaces the live result of running the source deployment's liveness / readiness / startup probes against the developer's local app inside the devcontainer. Carry the source probes through from the proxy and run them on a per-probe Monitor goroutine. Remap probe ports: if the source probe targets the deployment's primary app port, the interceptor checks locally; other ports (e.g. dedicated ports) pass through. Stacked on — the discover work touches the same flag-parsing block. Once that PR merges, this one will rebase cleanly onto . Architecture What's in this PR proto/bridge/v1/proxy.proto — + / / / / ; new fields on : , , , . proto/bridge/v1/interceptor.proto (new) — , , enum. pkg/k8s/resources/probes.go (new) — , named-port resolution, JSON-encoded flag emission. pkg/k8s/resources/resources.go — captures the source's probes before clobbering them and threads / / / into the proxy command. pkg/commands/server.go — parses the new flags, passes them through . pkg/proxy/grpcserver.go — stores probes + source app port; surfaces them via . pkg/probe/ (new) — Monitor with HTTP, TCP, gRPC, and Exec runners; tracks consecutive successes/failures; thread-safe snapshot via . pkg/commands/intercept.go — builds one Monitor per configured probe with port remap (). pkg/commands/intercept_health.go — implements ; returns + per-probe . Design notes All four handler types implemented in-tree (): HTTP (2xx/3xx success, follows headers, TLS skip for local self-signed dev), TCP (dial-and-close), gRPC (uses with optional service name), Exec (, exit code 0 = healthy). Port remap is hint-based. The proxy advertises (the source's first non-grpc port). The interceptor only remaps when a probe targets exactly that port — management ports (e.g. on 9090) keep their original target so health checks against dedicated endpoints still work. Defaults match the kubelet. Period 10s, timeout 1s, success threshold 1, failure threshold 3 — matching defaults so behaviour is identical to in-cluster. State is read-only over gRPC. is safe to poll; it returns a of the cached status (no fresh probe runs triggered). Pending → Healthy → Unhealthy. A probe starts until enough consecutive successes/failures meet the thresholds. Test plan [x] — all pass [x] pkg/probe tests: HTTP healthy, HTTP failing (≥failure_threshold transitions to UNHEALTHY), TCP open/closed, Exec success/failure, nil-handler rejection, context-cancel stops the goroutine. [x] pkg/k8s/resources/probes_test.go: HTTP numeric port, HTTP named-port resolution, unresolvable named port → nil, TCP/gRPC/Exec conversions, corner cases, emits the new flags. [x] pkg/commands/intercept_health_test.go**: before ready, after ready + one monitor, all three monitors attached. [ ] Manual: , run the local app, against the interceptor's (or curl the intercept gRPC) and confirm probe statuses match. 🤖 Generated with Claude Code
Repository: vercel/bridge. Description: Develop services locally in the context of a K8s cluster Stars: 11, Forks: 3. Primary language: Go. Languages: Go (93.2%), JavaScript (5.3%), Shell (1.2%), Dockerfile (0.2%), Makefile (0.1%). Open PRs: 1, open issues: 0. Last activity: 4d ago. Community health: 37%. Top contributors: vercel-eddie.