CB-606: refuse an unknown auth.mode/placement at config load #107

Closed
agent wants to merge 0 commits from worker/cb-606-b9343a-25 into main
Member

Fixes CB-606 (lms/claude-bridge#106).

Three config fields followed the same shape: lower-case in a compact constructor, then compared against exactly one string, so a typo was silently accepted.

  • auth.mode typo (e.g. toekn) used to silently behave as loopback-trust. On a loopback bind, validateAuthExposure() never runs, so the typo produced NO signal anywhere — the daemon started cleanly and authenticated nobody while the operator believed token mode was live. Now refused unconditionally at config load, naming the value and the accepted set.
  • Per-profile placement: typo used to silently fall back to legacy pane placement. Now refused at config load the same way.
  • Top-level placement: policy name WAS already validated by PlacementPolicies.fromName, but only lazily, at first spawn, through CompositePeerLauncher's per-spawn Supplier. Now validated eagerly in BridgedConfig.load(), calling fromName itself as the single source of truth (no duplicated accepted-set list).

Swept for a fourth instance of the same shape (toLowerCase() in a compact constructor followed by a single .equals comparison) across bridged/src/main/java — found none beyond the three fixed here plus the CB-604 kind: fix already on main.

Tests: 4 new tests (rejection + default) added to BridgedConfigTest; mvn clean install — 853 tests, BUILD SUCCESS.

Fixes CB-606 (https://git.ltms.dev/lms/claude-bridge/issues/106). Three config fields followed the same shape: lower-case in a compact constructor, then compared against exactly one string, so a typo was silently accepted. - `auth.mode` typo (e.g. `toekn`) used to silently behave as `loopback-trust`. On a loopback bind, `validateAuthExposure()` never runs, so the typo produced NO signal anywhere — the daemon started cleanly and authenticated nobody while the operator believed `token` mode was live. Now refused unconditionally at config load, naming the value and the accepted set. - Per-profile `placement:` typo used to silently fall back to legacy pane placement. Now refused at config load the same way. - Top-level `placement:` policy name WAS already validated by `PlacementPolicies.fromName`, but only lazily, at first spawn, through `CompositePeerLauncher`'s per-spawn `Supplier`. Now validated eagerly in `BridgedConfig.load()`, calling `fromName` itself as the single source of truth (no duplicated accepted-set list). Swept for a fourth instance of the same shape (`toLowerCase()` in a compact constructor followed by a single `.equals` comparison) across bridged/src/main/java — found none beyond the three fixed here plus the CB-604 `kind:` fix already on main. Tests: 4 new tests (rejection + default) added to BridgedConfigTest; mvn clean install — 853 tests, BUILD SUCCESS.
agent added 1 commit 2026-08-16 18:54:54 +02:00
CB-606: refuse an unrecognized auth.mode, per-profile placement, or top-level placement policy at config load
CI / build (pull_request) Successful in 1m7s
CI / contract (pull_request) Successful in 1m25s
bb750cdba3
An auth.mode typo (e.g. "toekn") used to silently fall back to loopback-trust with no signal
anywhere — validateAuthExposure() only checks the pairing on a non-loopback bind, so on the
common loopback bind the daemon started cleanly and authenticated nobody. Per-profile placement
had the same shape, falling back to legacy pane placement. The top-level placement policy name
was already validated by PlacementPolicies.fromName, but only lazily at first spawn through
CompositePeerLauncher's Supplier; it is now checked eagerly at load, calling fromName itself as
the single source of truth.
Owner

Merged locally into main as aa4ee64 and pushed. Gitea cannot mark a locally merged PR as merged, so I am closing it by hand — merged, not rejected.

Good work. Two things in particular: calling PlacementPolicies.fromName instead of copying its accepted set is the right call and keeps one source of truth, and noticing that it also covers ConfigRef.reload() is a real bonus nobody asked for.

Verification is on #106, including the one check you had no way to run: the live gitignored bridged.yaml still loads.

Merged locally into `main` as `aa4ee64` and pushed. Gitea cannot mark a locally merged PR as merged, so I am closing it by hand — **merged, not rejected**. Good work. Two things in particular: calling `PlacementPolicies.fromName` instead of copying its accepted set is the right call and keeps one source of truth, and noticing that it also covers `ConfigRef.reload()` is a real bonus nobody asked for. Verification is on #106, including the one check you had no way to run: the live gitignored `bridged.yaml` still loads.
ltms closed this pull request 2026-08-16 18:59:16 +02:00
Some checks are pending
CI / build (pull_request) Successful in 1m7s
CI / contract (pull_request) Successful in 1m25s

Pull request closed

Sign in to join this conversation.