devantler-tech / devantler-tech/ksail

fix(webui): unmanaged clusters with URL-unsafe context names (EKS ARNs) 404 from every web request

Open Beginner friendly
#6,908 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Go
Stars
165
Forks
12
Avg merge
5h 41m
Merged PRs (30d)
337

Description

> 🤖 Generated by the Agentic Engineer

## Evidence

The web UI interpolates a cluster's name straight into single-segment API routes without escaping it. Every cluster-scoped call in `web/ui/src/api.ts` does this — logs (line 250), get/delete (458, 466), resources (531), kubeconfig (552), apply (596), the resource-detail routes (618) and the exec WebSocket (709):

```ts
return request(`/api/v1/clusters/${namespace}/${name}/resources?${params.toString()}`);
```

For a KSail-managed cluster the name is a DNS-1123 label, so this is safe. It stops being safe now that **unmanaged kubeconfig contexts are surfaced under their raw context name**: a context name is arbitrary text, and the common EKS form is an ARN containing a slash — `arn:aws:eks:us-east-1:123456789012:cluster/prod`.

Probed directly against Go's `ServeMux` with the same route pattern the server uses:

| request path | result |
|---|---|
| `.../clusters/default/plain/resources` | `200`, `PathValue("name") == "plain"` |
| `.../clusters/default/arn:...:cluster%2Fprod/resources` | `200`, `PathValue("name") == "arn:...:cluster/prod"` |
| `.../clusters/default/arn:...:cluster/prod/resources` | **`404`** |

So the slash becomes an extra path segment and the route does not match. `?` and `#` in a context name would truncate or fragment the URL the same way.

## Affected audience and impact

Anyone whose kubeconfig holds an unmanaged context with a name that is not URL-safe — most obviously anyone using EKS, where the ARN form is what `aws eks update-kubeconfig` writes by default.

The effect is that the row is visible but inert: the cluster list shows it, and every action on it fails with a 404 that gives no hint why. That is exactly the "advertised but not operable" state that #6116 set out to remove, reappearing one layer up. The backend resolver added there is correct and does resolve these names; the request never reaches it.

## Expected behaviour

An unmanaged cluster whose context name contains URL-significant characters is operable from the web UI exactly like any other — its resources list, logs stream, kubeconfig downloads, and exec connects.

## Proposed direction

Encode the namespace and name at every cluster-scoped call site in `web/ui/src/api.ts` before interpolation. The probe above establishes that this is sufficient on the server side: Go's `ServeMux` matches the percent-encoded form and hands the handler the decoded value, so no backend change is needed and `PathValue` keeps returning the raw context name the resolver expects.

Two details to get right:

- **The WebSocket URL (line 709) needs the same treatment**, and it is easy to miss because it is built as a full `ws(s)://` string rather than through `request()`.
- **Encode once, centrally if possible.** Eight call sites repeating `encodeURIComponent` is a pattern that drifts — a small helper that builds the cluster-scoped path prefix would keep the ninth call site correct by construction.

## Acceptance criteria

- [ ] Every cluster-scoped request in `web/ui/src/api.ts`, including the exec WebSocket, escapes the namespace and cluster name.
- [ ] A test covers a context name containing `/` and asserts the constructed URL, so a new unescaped call site fails the suite.
- [ ] End-to-end: an unmanaged context named with an EKS ARN can be selected in the UI and its resources listed.
- [ ] Names without special characters produce byte-identical URLs to today (no behaviour change for managed clusters).

## Rough size

S. A mechanical frontend change plus the guard test; the server side needs nothing.

Found while reviewing #6893 (the backend half of #6116). Reported by Codex on that PR and verified independently here.

Contributor guide

Open the contributing guide

Research direction

Start in web/ui/src/api.ts, reviewing every cluster-scoped request and the exec WebSocket URL identified in the issue. Trace how namespace and context names are assembled, then add coverage for a name containing `/`; done means all listed requests escape both path segments, EKS ARN contexts work end to end, and ordinary names produce unchanged URLs.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
84/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.