Repository navigation
Description
id(server_config): a blank or whitespace-padded key passes parse — a blank user key only fails mid-provisioning, after earlier users are already created
Summary
ServerConfig::parse (pkgs/id/src/server_config/parse.rs) blank-checks every
human-facing string it accepts except the key itself:
- group
name:trim().is_empty()→ConfigError::Empty { field: "name" }(parse.rs, group pass) alias: trimmed, blank →ConfigError::Empty { field: "alias" }(record_alias)- role: trimmed and lower-cased before matching (
parse_role)
But claim() (the one place every user/group key passes through) records the
key verbatim — no trim, no empty check:
fn claim(names: &mut BTreeMap<String, Object>, key: &str, object: Object) -> Result<(), ConfigError> {
if names.contains_key(key) {
return Err(ConfigError::DuplicateKey(key.to_owned()));
}
names.insert(key.to_owned(), object);
Ok(())
}So key = "", key = " ", and key = " ann " are all accepted for users
and for groups, and every reference (creator, members[].user,
[create].users/groups) resolves against the verbatim string.
Why it matters
The user key is not just a local label: provisioning passes it as the
account's name — Provisioned::apply calls
directory.sign_up_keyed(&id, &user.key) (provision.rs), and
Directory::insert_account runs that name through clean_name
(directory.rs), which trims it and refuses an empty one
("name must not be empty"). Consequences, all verified this run (see below):
- A blank user key passes parse and fails only at provisioning, as a
ProvisionError::Userwrapping the directory's "name must not be empty" —
not as aConfigErrornaming the key.applycreates users in file
order and returns on the first failure, so every user listed before the
blank-key user has already been created when it fails. The module doc's
promise — "ServerConfig::parsechecks the whole file … so a bad file
fails at startup" — is exactly what the blank check on names/aliases
delivers and the key check misses. - A whitespace-padded key silently diverges from the account it creates.
Keys"ann"and" ann "are distinct keys toclaim(no
DuplicateKey), both provision successfully, and both accounts end up
namedann(the directory trims; the config does not). Afterwards
config.user_id(" ann ")resolves, while the directory knows the account
only under the trimmed name.
Evidence (verified this run, main 528886e)
Laptop probe in the real crate (worktree of origin/main at
~/git/fleet/probe-2026-10-28-laneA-configkey, integration test
pkgs/id/tests/probe_configkey.rs calling the public
ServerConfig::parse / Provisioned::apply; parse.rs sha256 on the
laptop worktree identical to the sandbox clone,
14673ade04923b574ea2adaedeebda03cf967e0d403bed28e4caa6cec450210d):
key = ""user → parse Ok;key = " "user → parse Ok;
blank group key → parse Ok- controls: blank group name →
Err(Empty { field: "name" });
blank alias →Err(Empty { field: "alias" }) - config
[ann (good), "" (blank)]→applyfails at the blank user with
the directory's empty-name refusal, and the good user's account already
exists in the directory afterwards - config with keys
"ann"and" ann "(different ids) → parse Ok, apply
Ok, and the directory holds two accounts both namedann
(Full probe output is attached in the filing run's bookkeeping:
hidden_files/probe-2026-10-28-laneA-configkey/ in the fleet goal workspace.)
Acceptance criteria
ServerConfig::parserefuses a user or group key that is empty or
whitespace-only, with aConfigErrorthat names the offending entry the
wayEmptynames a blank name/alias (a dedicated variant is fine).- The rule for surrounding whitespace is pinned one way or the other by
tests: either keys are trimmed before claiming (so" ann "isann,
and a repeat isDuplicateKey), or padded keys are refused at parse.
Silent divergence between the config key and the provisioned account
name must be impossible. - References (
creator, members,[create]) follow the same rule as the
declarations they name. - Existing config parse/provision tests keep passing, including the
blank name/alias refusals and the duplicate-key refusals. - New tests cover: blank user key, blank group key, whitespace-only key,
and the pinned padded-key behaviour.
Activity
developing-today commentedon Oct 28, 2026
CODE-754
dezren39 commentedon Oct 28, 2026
🤖 Agent note · state: filed
9 remaining items
dezren39 commentedon Nov 1, 2026
🤖 Agent note · picked up
dezren39 commentedon Nov 1, 2026
🤖 Agent note · handed off
Merge pull request #4045 from developing-today/queue/5050-1824-blank-…
dezren39 commentedon Nov 1, 2026
🤖 Agent note · done