fix(desktop): normalize agent pubkeys through one helper, and guard it - #6235
Open
mfethe1 wants to merge 1 commit into
Open
fix(desktop): normalize agent pubkeys through one helper, and guard it#6235mfethe1 wants to merge 1 commit into
mfethe1 wants to merge 1 commit into
Conversation
`normalizePubkey` is `trim().toLowerCase()`. Across `features/agents`, 20 call sites reached for a bare `.toLowerCase()` instead. The two agree for every well-formed pubkey and disagree the moment one carries surrounding whitespace, so the divergence is invisible until a value arrives from somewhere untidy — a pasted allowlist entry, a relay tag, a config file — and then one surface stops matching another with nothing thrown and nothing logged. That is the same failure shape the agent-identity work keeps turning up: two places answer "is this the same agent?" differently, and a user reports that an agent "isn't there". One site was already asymmetric rather than merely inconsistent. `RespondToField.handleRemove` compared `p.toLowerCase()` against a pubkey that had been normalized, so removing an allowlist entry could fail to match the entry it was given. That is a live bug, not a style point. ## Guard `check-pubkey-normalization.mjs` matches any `.toLowerCase()` call and then filters on the receiver, rather than anchoring the pubkey inside the pattern. The first version did anchor it, and could not see `agent?.pubkey.toLowerCase()` — the optional link sits between the identifier and the segment being matched. Filtering on the receiver found three optional-chained sites the initial sweep had skipped, two of which the anchored pattern could never have reported. Scoped to `src/features/agents` deliberately. Hand-rolled lowercasing is repo-wide — 87 files under `desktop/src` against 113 using `normalizePubkey` — and failing on all of them would make the guard unshippable. A guard that must be disabled to land anything protects nothing. So it covers the surface whose divergence caused an outage, and covers it completely: no allowlist. Widening it is a follow-up that has to arrive with the call-site fixes, not a flag flip. ## Interaction with block#6077 Both this PR and block#6077 add a `check:*` script and extend the same `check` line in `desktop/package.json`, so whichever lands second needs a one-line rebase there. Nothing else overlaps: block#6077 guards how an identity KEY is minted, this guards how the pubkey inside it is normalized. Note that `main` recently removed `pnpm check:file-sizes` from that line (block#6187 made the ratchet a first-class root gate). Neither PR should put it back. ## Verification `npx tsc --noEmit` clean. `pnpm check` clean. Desktop unit suite: 4993 passed, 0 failed. Guard proven to fail, not just to pass: an injected `x.pubkey.toLowerCase()` under `features/agents` is reported and exits 1; removing it exits 0. Signed-off-by: Michael Feth <michael@jira-flow.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(desktop): normalize agent pubkeys through one helper, and guard it
normalizePubkeyistrim().toLowerCase(). Acrossfeatures/agents, 20 callsites reached for a bare
.toLowerCase()instead. The two agree for everywell-formed pubkey and disagree the moment one carries surrounding whitespace,
so the divergence is invisible until a value arrives from somewhere untidy — a
pasted allowlist entry, a relay tag, a config file — and then one surface stops
matching another with nothing thrown and nothing logged.
That is the same failure shape the agent-identity work keeps turning up: two
places answer "is this the same agent?" differently, and a user reports that an
agent "isn't there".
One site was already asymmetric rather than merely inconsistent.
RespondToField.handleRemovecomparedp.toLowerCase()against a pubkey thathad been normalized, so removing an allowlist entry could fail to match the
entry it was given. That is a live bug, not a style point.
Guard
check-pubkey-normalization.mjsmatches any.toLowerCase()call and thenfilters on the receiver, rather than anchoring the pubkey inside the pattern.
The first version did anchor it, and could not see
agent?.pubkey.toLowerCase()— the optional link sits between the identifierand the segment being matched. Filtering on the receiver found three
optional-chained sites the initial sweep had skipped, two of which the anchored
pattern could never have reported.
Scoped to
src/features/agentsdeliberately. Hand-rolled lowercasing isrepo-wide — 87 files under
desktop/srcagainst 113 usingnormalizePubkey—and failing on all of them would make the guard unshippable. A guard that must
be disabled to land anything protects nothing. So it covers the surface whose
divergence caused an outage, and covers it completely: no allowlist. Widening it
is a follow-up that has to arrive with the call-site fixes, not a flag flip.
Interaction with #6077
Both this PR and #6077 add a
check:*script and extend the samechecklinein
desktop/package.json, so whichever lands second needs a one-line rebasethere. Nothing else overlaps: #6077 guards how an identity KEY is minted, this
guards how the pubkey inside it is normalized.
Note that
mainrecently removedpnpm check:file-sizesfrom that line (#6187made the ratchet a first-class root gate). Neither PR should put it back.
Verification
npx tsc --noEmitclean.pnpm checkclean. Desktop unit suite: 4993 passed,0 failed.
Guard proven to fail, not just to pass: an injected
x.pubkey.toLowerCase()under
features/agentsis reported and exits 1; removing it exits 0.Signed-off-by: Michael Feth michael@jira-flow.com