fix(identity): reject control characters in identity fingerprints - #452
Conversation
An identity fingerprint containing a control character passed configuration validation and passed verification, and was then silently rewritten into a verification failure by the binding store. Three layers disagreed about what a storable identity field is. The configuration schema and the probe parser both accepted control characters, while the durable binding store rejected any code point below 0x20 or equal to 0x7f. A fingerprint that genuinely matched its probe therefore returned "verified" and was immediately downgraded to failed / IDENTITY_BINDING_ UNAVAILABLE, because the store raises its record rejection outside save()'s own error handling, the manager catches it as a bare failure, and the resulting unavailable flag is process-sticky and so downgraded identity verification for every profile in that process. Extract the single shared predicate and use it in all three layers so they cannot drift again. An unstorable fingerprint is now refused at configuration time with its exact path, and unstorable probe evidence can never reach the store. Doctor appends the IDENTITY_* code to its explanation so the cause is recoverable from its output rather than requiring a patched build. Fail-closed behavior on a genuine binding-storage outage is deliberate and is unchanged. Probe tools whose response spans multiple lines remain unusable for identity verification; that limitation is now reported by validate instead of surfacing as an unexplained runtime failure. Refs #451 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Team Run ID: 📒 Files selected for processing (9)
Included review availability: 3 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 4 reviews per hour. 📝 WalkthroughWalkthroughIdentity fingerprints now reject control characters during configuration and probe parsing. A shared predicate supports all relevant validation paths. Doctor reports identity error codes, and tests cover failed verification without binding-store unavailability. ChangesIdentity fingerprint validation
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix · Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to No concrete merge-blocking risk remains in the current change. Caution Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional.
❌ Failed checks (1 error)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 8 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
A rabbit checks each fingerprint line Comment |
Pull request
Summary
Fixes #451. An identity fingerprint containing a control character passed configuration validation and passed verification, and was then silently rewritten into a verification failure by the binding store. The operator saw only
Configured upstream identity verification did not complete.with no recoverable cause.Three layers disagreed about what a storable identity field is:
identityFieldSchema(src/config/schema.ts)boundedIdentityField(src/identity/identity-manager.ts)verifiedboundedIdentifier(src/identity/identity-binding-store.ts)< 0x20or0x7f)The rejection was masked three times:
normalizeRecords()raises outsidesave()'s owntry, the manager catches it bare and sets the process-stickybindingStoreUnavailable, andapplyBindingResult()then rewrote the already-verified status tofailed/IDENTITY_BINDING_UNAVAILABLE. Because the flag is per-process, one bad fingerprint downgraded identity verification for every profile in that process.This extracts the single shared predicate (
src/utils/control-characters.ts) and uses it in all three layers so they cannot drift again, and hasdoctorappend theIDENTITY_*code to its explanation.Observed before the fix, from one instrumented run:
MATCHED= true→RETURNING verified→ doctor receivedstatus= failed errorCode= IDENTITY_BINDING_UNAVAILABLE.Security impact
Fail-closed behavior on a genuine binding-storage outage is deliberate and is unchanged —
tests/identity-manager.test.tsstill assertsstatus: "failed",bindingState: "unavailable",errorCode: "IDENTITY_BINDING_UNAVAILABLE"whensave()throws. No credential handling, routing, redaction, audit, subprocess, or dependency change.Two boundaries move deliberately, both tightening:
The
IDENTITY_*codes added to doctor output are fixed enumeration members, not identity values;tests/doctor.test.tscontinues to assert the report contains no config path, account name, probe tool name, or management-tool name.Probe tools whose response spans multiple lines remain unusable for identity verification. That limitation is now reported by
miftah validaterather than surfacing as an unexplained runtime failure. Making them usable needs field extraction in the probe rather than whole-response matching, which is a feature and out of scope.Validation
npm run lint— 728 problems, all pre-existing.worktreestsconfigRootDirparser errors. Baseline on a clean tree is 727; the +1 is the new file hitting the same error. The five changed files lint clean when invoked directly.npm run typecheck— clean.npm test— 162 files, 2003 passed, 34 skipped, 0 failed.npm run build— success.node dist/cli/main.js schema— success.npm run check:pack—Package contract verified (58 files).tests/fixtures/fake-upstream-runtime.mjsis not modified, so the named-host evidence hash is intact.CHANGELOG.mdare updated when applicable —CHANGELOG.mdunder[Unreleased].🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
miftah validatenow reports multi-line probe responses.doctorprovides more specific identity verification failure codes when available.Validation