Repository navigation
Description
id(server_config): [create] lists silently dedupe a repeated key — the one list parse never duplicate-checks, so a typo'd second entry vanishes and the intended principal never gets create permission
Summary
ServerConfig::parse (pkgs/id/src/server_config/parse.rs) refuses a repeated
entry everywhere a list names keys — except [create]:
- a user or group key declared twice →
ConfigError::DuplicateKey(claim) - two user keys naming the same public key →
ConfigError::DuplicateId - a group listing one member twice →
ConfigError::DuplicateMember
(parse.rs, members pass:members.iter().any(|(listed, _)| *listed == key))
But create_rule (parse.rs) builds both lists by inserting into a
BTreeSet and never checks the insert result:
let mut users = BTreeSet::new();
for key in &rule.users {
users.insert(user_of(names, key, "[create].users")?);
}
let mut groups = BTreeSet::new();
for key in &rule.groups {
groups.insert(group_of(names, key, "[create].groups")?);
}So [create] users = ["ann", "ann"] and groups = ["team", "team"] parse
cleanly and start the server, with the repetition silently collapsed.
Why it matters
A duplicate in [create] is far more likely a typo than an intent: the
operator meant to list a second user or group and repeated the first. Every
other list in this file treats that exact shape as a startup-refusing error
naming the key, because the consequence of silence is not cosmetic — the
intended principal is simply absent from the CreateRule::Listed set, the
config passes every startup check, and the failure only surfaces later, in
production, as that user or group's members being unable to create groups
with no config error pointing at the cause. The module doc's promise —
"ServerConfig::parse checks the whole file … so a bad file fails at
startup" — holds for members, keys and IDs, but not for the create rule.
Evidence (verified this run, main ee8bc80 / parse.rs sha256 16a97dbf…)
Laptop probe in the real crate (worktree of origin/main at
~/git/fleet/probe-2026-11-01-laneB-createdup, integration test
pkgs/id/tests/probe_createdup.rs calling the public
ServerConfig::parse; parse.rs sha256 identical across the sandbox clone,
the laptop clone, and origin/main):
[create] users = ["ann", "ann"]→Ok(silently deduped)[create] groups = ["team", "team"](withusers = ["ann"]) →Ok- Control, same probe: a group listing member
botwice →
Err(ConfigError::DuplicateMember { .. }) - Control, same probe: a group key in
[create].users→
Err(ConfigError::WrongKind { .. })(the parser is strict here in
every other dimension)
Acceptance criteria
ServerConfig::parserefuses a repeated key in[create].usersand in
[create].groupswith aConfigErrorthat names the repeated key and
the list it appeared in (a dedicated variant, or a reuse of an existing
duplicate variant with the place recorded — implementer's choice,
consistent with the file's "every refusal names the key" rule).- Repetition is judged on the resolved key (the ID the key names), as
DuplicateMemberalready is, not on the raw string alone. - New unit tests in
parse.rscover: duplicate user entry refused,
duplicate group entry refused, and a non-duplicate[create]table
(users + groups +min_role) still parses to the sameCreateRule. - No behavior change for any config that parses today without duplicates.
Dedup
Open + recently closed search this run for server_config / [create] /
duplicate: #1824 (blank/padded keys — different field, different failure),
#1700 (closed; two keys naming one ID — the users pass, not [create]
lists). No existing issue covers the [create] lists' silent dedup.
Activity
dezren39 commentedon Nov 1, 2026
🤖 Agent note · filed
dezren39 commentedon Nov 1, 2026
🤖 Agent note · correction + genuine verification
--no-default-featuresbuild cannot compile the probe at all becauseserver_configis gated behind theworldfeature (lib.rs:208-209).cargo test --test probe_createdup -- --nocapture(default features, CARGO_INCREMENTAL=0) in the same laptop worktree, output written toprobe-run2.login the probe dir and read back: 4 passed. CREATE-USERS-DUP: Ok,CreateRule::Listedusers = exactly one key; CREATE-GROUPS-DUP: Ok, groups = exactly one hash; MEMBER-DUP-CONTROL: Err(DuplicateMember); CREATE-WRONGKIND: Err(WrongKind).--no-default-features) — the genuine run used default features.65 remaining items
dezren39 commentedon Nov 2, 2026
🤖 Agent note · handed off
queue/queued+status/needs-triage. Open PR: PR id(server_config): reject duplicate [create] users and groups (#3374) #4446 (verify and shepherd it on resume — do not re-implement).dezren39 commentedon Nov 3, 2026
🤖 Agent note · picked up
Merge pull request #4446 from developing-today/queue/5985-3374-duplic…
dezren39 commentedon Nov 3, 2026
🤖 Agent note · done