Skip to content

refactor(daemon): make the token permission check assertable, and cover it - #86

Merged
acamarata merged 1 commit into
mainfrom
refactor/token-permissions
Sep 16, 2026
Merged

acamarata merged 1 commit into
mainfrom
refactor/token-permissions

Conversation

@acamarata

Copy link
Copy Markdown
Contributor

Every mutant the gate generated for check_token_permissions survived, and the reason was structural rather than an oversight in the tests: the function's only output was a tracing::warn!. There was no value to assert, so !path.exists(), the & 0o777 mask and the != 0o600 comparison could all be flipped without a single test noticing.

The split

token_permissions() returns the decision:

pub enum TokenPermissions {
    Absent,                    // no token file yet
    Secure,                    // exactly owner read/write
    Insecure { mode: u32 },    // carries the offending mode
    Unknown,                   // metadata unreadable, or not a Unix platform
}

check_token_permissions() keeps its signature and simply warns on Insecure, so the single caller in commands/server.rs is untouched and the same condition produces the same warning.

Unknown is a deliberate fourth variant rather than folding a failed metadata read into Secure. The original silently skipped the check when metadata could not be read — that is the right call, since an unreadable file is not evidence of a bad mode — but calling it "secure" would be a lie in the type.

Mutants

All 7 hand-applied and confirmed to fail the suite: 7 killed, 0 survived.

The mask mutations are the ones worth naming. A file created 0644 has a raw mode of 0o100644 including the file-type bits:

expression result verdict
mode & 0o777 0o644 insecure
mode ^ 0o777 0o100133 insecure
mode | 0o777 0o100777 insecure

All three are "insecure", so a test asserting only the variant would miss both mutations. The tests assert the mode value that comes back, which is what separates them.

validate_bearer gains coverage in the same pass, including the cases that distinguish a prefix check from an equality: a token that is a prefix of the expected one, a token that extends it, and a header whose prefix is "Bearer" without the trailing space.

cargo fmt --check, cargo clippy --all-targets -- -D warnings and the full 872-test lib suite are clean.

…er it

Every mutant the gate generated for check_token_permissions survived, and
the reason was structural rather than an oversight in the tests: the
function's only output was a tracing::warn!. There was no value to assert,
so `!path.exists()`, the `& 0o777` mask and the `!= 0o600` comparison could
all be flipped without any test noticing.

This splits the decision from the reporting. token_permissions() returns
Absent / Secure / Insecure{mode} / Unknown, and check_token_permissions()
keeps its signature and simply warns on Insecure, so the single caller in
commands/server.rs is untouched. Behaviour is unchanged: the same condition
produces the same warning.

Unknown is a deliberate fourth variant rather than folding a failed
metadata read into Secure. The original silently skipped the check when
metadata could not be read, which is the right call - an unreadable file is
not evidence of a bad mode - but calling that "secure" would be a lie in
the type.

All 7 mutants were hand-applied and the suite confirmed to fail: 7 killed,
0 survived.

The mask mutations are the ones worth noting. A file created 0644 has a raw
mode of 0o100644 including the file-type bits: masking gives 0o644, `^`
gives 0o100133 and `|` gives 0o100777. All three are "insecure", so a test
asserting only the variant would miss both mutations. The tests assert the
mode value that comes back, which is what separates them.

validate_bearer gains coverage in the same pass, including the cases that
distinguish a prefix check from an equality: a token that is a prefix of
the expected one, a token that extends it, and a header whose prefix is
"Bearer" without the trailing space.
@acamarata
acamarata merged commit 3b8e5ae into main Sep 16, 2026
12 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