Skip to content

Expose what the configuration page cannot currently reach - #13

Merged
fylorn merged 1 commit into
mainfrom
dev
Sep 14, 2026
Merged

fylorn merged 1 commit into
mainfrom
dev

Conversation

@fylorn

@fylorn fylorn commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Why

The overview carried enough to render a read-only page and not enough to build an editor. Four gaps, each of which made a whole section of the configuration unreachable from the UI.

Proxies were a list of names

proxies: Vec<String>. The dropdown on an upstream could reference a proxy, but nothing could create one — so anyone who had not hand-edited config.yaml saw a menu holding only direct and system.

ProxyView now carries name, kind, address, and how many upstreams use it, which is what you need to know before deleting one.

The password does not travel. ProxyAuth.pass is the same class of thing as an upstream key, and this view reaches logs, diagnostic bundles, and screenshots people paste into issues. has_auth says whether there is one. The test asserts that neither the password nor the username appears in the serialised view — the username is half a credential.

client_probes had no representation at all

And its absence was compounding: a routing rule's when.intent condition can only match when the corresponding probe class is set to route, so any rule written with intent was silently dead and nothing said why.

The five classes now come through with their mode and a sentence each describing what that class of request is. That list lives on ClientProbes rather than in the frontend — adding a sixth class is this struct's business, and a list hard-coded in the UI silently loses a row on the day that happens.

Also newly visible

limits, and per key: its bound route, its allow list, its concurrency ceiling.

One real bug

listen.bind was rendered with format!("{:?}").to_lowercase(). That happens to produce the right word for Loopback and All — and produces addr(192.168.1.5) for a concrete interface, which the UI then compares against its three choices and never matches. It uses Display now, which exists for exactly this.

Verification

cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings, 1089 tests, and scripts/smoke.sh — 46 checks, 0 failures.

🤖 Generated with Claude Code

The overview carried enough to render a read-only page and not enough to
build an editor. Four gaps, each of which made a whole section of the
config unreachable from the UI.

**Proxies were a list of names.** `proxies: Vec<String>` — so the
dropdown on an upstream could reference a proxy but nothing could create
one, and anyone who had not hand-edited `config.yaml` saw a menu holding
only `direct` and `system`. `ProxyView` carries name, kind, address, and
how many upstreams use it, which is what you need before deleting one.

**The password does not travel.** `ProxyAuth.pass` is the same class of
thing as an upstream key, and this view reaches logs, diagnostic bundles
and screenshots people paste into issues. `has_auth` says whether there
is one; the test asserts neither the password nor the username appears in
the serialised view.

**`client_probes` had no representation at all**, and its absence was
compounding: a routing rule's `when.intent` condition can only match when
the corresponding probe class is set to `route`, so any rule written with
`intent` was silently dead and nothing said why. The five classes now
come through with their mode, along with a sentence each describing what
that class of request is. That list lives on `ClientProbes` rather than
in the frontend — adding a sixth class is this struct's business, and a
list hard-coded in the UI silently loses a row that day.

**`limits` was likewise invisible**, as were a key's `route`, its
`allow`, and its concurrency ceiling.

## One real bug

`listen.bind` was rendered with `format!("{:?}").to_lowercase()`. That
happens to produce the right word for `Loopback` and `All`, and produces
`addr(192.168.1.5)` for a concrete interface — which the UI then compares
against its three choices and never matches. It uses `Display` now, which
exists precisely for this.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@fylorn
fylorn merged commit 5cb451e into main Sep 14, 2026
3 checks passed
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.

1 participant