Skip to content

fleet-config: [[proxy.services]] is never validated — duplicate ports silently collapse last-wins in the broker's routing map, and port 0 / empty names load #6397

Open

Description

@dezren39

fleet-config: [[proxy.services]] is never validated — duplicate ports silently collapse last-wins in the broker's routing map, and port 0 / empty names load

Summary

The [proxy] services table is, by the crate's own docs, the proxy's routing table ("the services map IS the routing table"). fleet-config loads it with no validation at all: two rows with the same port both load, a row with port 0 loads, and a row with an empty name loads. Downstream, both consumers build the advertised services map by collecting the rows into a BTreeMap keyed by port string, so a duplicate port silently collapses — the last row wins and the earlier service vanishes from the hello/routing map with no error anywhere.

That breaks the crate's stated config policy (crate docs, lib.rs:14-16): "a malformed file is a loud error, never a silent fallback" — unknown sections and keys are already loud errors for exactly this reason (#5460). A duplicated port is a misspelling-class error with a worse failure mode: instead of a wrong key being ignored, one live service is silently substituted for another in the routing table.

Evidence (file:line, origin/main @ 967fb22)

  • pkgs/fleet/crates/fleet-config/src/lib.rs:146-155 — ServiceConfig { port: u16, name: String, version: Option<String> } with deny_unknown_fields only; no value validation anywhere.
  • pkgs/fleet/crates/fleet-config/src/lib.rs:362-… — Config::services() returns self.proxy.services.clone() verbatim when non-empty; no duplicate/zero/empty checks.
  • pkgs/fleet/crates/fleet-proxy/src/serve.rs:370 — Broker::services_map() collects config.services() into BTreeMap<String, ServiceInfo> keyed by port.to_string(): duplicate ports collapse, last row wins.
  • pkgs/fleet/crates/fleet-proxy/src/client.rs:114 — built_in_services() builds the legacy/shim services map the same way, so the collapse happens on both the broker and client paths.

Verification (this run, laptop, real fleet-config crate)

Probe ~/git/fleet/probe-fleet-config-xdg-rel (services bin; path-depends on the real fleet-config crate; the map step mirrors serve.rs:370's collect verbatim):

dup-port:            load_ok rows=2 [4801:queue-broker,4801:impostor] map_len=1 map4801=Some("impostor")
port-zero-empty-name: load_ok rows=1 [0:]                             map_len=1
dup-name:            load_ok rows=2 [4801:queue-broker,4999:queue-broker] map_len=2
valid-control:       load_ok rows=1 [4801:queue-broker]               map_len=1 map4801=Some("queue-broker")

So a config that names port 4801 twice advertises exactly one service on 4801 — whichever row came last — and a port = 0, name = "" row is advertised as "0": "".

Why it matters

Acceptance criteria

  • Config::load_from (or services()) rejects a [[proxy.services]] table with a duplicate port, a duplicate name, port 0, or an empty/blank name, with a loud ConfigError naming the offending row — consistent with the crate's malformed-is-loud policy.
  • The duplicate-port case can never reach the BTreeMap collect in fleet-proxy: the collapse is impossible by construction, not just unlikely.
  • Pinning tests cover duplicate port, duplicate name, port 0, and empty name alongside the existing services_* tests in fleet-config; the valid single-row and built-in-default cases stay green.
  • No change to the built-in default table or to valid configs.

Activity

  1. developing-today commented on Nov 5, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/triageQueue packet kind: verify, reproduce, and route this item
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/fleetpkgs/fleet multicall binary + platform crates
    on Nov 5, 2026
  3. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (new-issue-creator-code-a)
    • Session / ID: cron new-issue-creator-code-a run 2026-11-05 17:05 CST
    • Found via: filed this run
    • Task: Filed after verifying on the laptop with probe ~/git/fleet/probe-fleet-config-xdg-rel (services bin, real fleet-config crate): [[proxy.services]] loads with duplicate ports / port 0 / empty names, and the duplicate port collapses last-wins in the BTreeMap routing map (fleet-proxy serve.rs:370, client.rs:114) — against the crate's loud-error config policy (fleet-config: misspelled fleet.toml section/key is silently ignored — a typo'd [domains] disable loads Ok and the domain stays enabled #5460).
    • Expectation: effort s — triage via the enqueued repo-task/v1 packet; done = services table validated at load with pinning tests, per the issue's acceptance criteria.
    • Links: queue packet packet-6397-triage.json (repo-health-code-pilot)
  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  5. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · triaged — CONFIRMED

  6. 68 remaining items

  7. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    queue/claimedQueue worker lifecycle state
    and removed
    queue/claimedQueue worker lifecycle state
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 6, 2026
  8. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  9. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Nov 6, 2026
  10. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  11. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    app/fleetpkgs/fleet multicall binary + platform crateskind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)queue/parkedQueue task is parked (waiting on CI, time, or an event)source/creatorFiled by the new-issue-creator jobstatus/parkedDeliberately paused with a recorded resume conditiontask/triageQueue packet kind: verify, reproduce, and route this itemwork/assignedQueue worker lifecycle state

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions