Commit 7b05740
ak2k
fix(claude): stop macOS Keychain corrupting OAuth credentials on refresh
Claude credentials are persisted to the macOS login Keychain with
`security add-generic-password -w <json>`. credentialPayload wrote the JSON
with json.MarshalIndent (multi-line). macOS `security find-generic-password -w`
hex-encodes any generic-password value containing a newline on read, so the
stored credential came back as an ASCII hex string like "7b0a2020..." that
fails to JSON-parse ("invalid character 'b' after top-level value").
Because the daemon rewrites the credential after every OAuth token refresh,
each Claude account self-corrupted within its access-token lifetime: reads
then fail, the account is skipped, usage fetches 401, it scores headroom=0,
and routing returns "no non-exhausted claude accounts available".
Fix:
- credentialPayload writes compact json.Marshal (single line). json.Marshal
escapes any in-string newline to \n, so the value can never contain a raw
newline and `security` returns it as text.
- parseCredentialPayload heals already-hex-encoded blobs on read via
healHexEncodedCredential (gated on the "7b"/"5b" ASCII-hex prefix; the
hex decode + json.Unmarshal are the real gate, so it is a no-op on ordinary
JSON, which starts with the byte '{' not the ASCII "7b").
Adds unit tests for the compact-write invariant, hex heal round-trip, no-op on
plain JSON, and fail-closed handling of malformed input.1 parent 46607df commit 7b05740
2 files changed
Lines changed: 101 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
592 | 592 | | |
593 | 593 | | |
594 | 594 | | |
| 595 | + | |
595 | 596 | | |
596 | 597 | | |
597 | 598 | | |
| |||
601 | 602 | | |
602 | 603 | | |
603 | 604 | | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
604 | 636 | | |
605 | | - | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
606 | 642 | | |
607 | | - | |
| 643 | + | |
608 | 644 | | |
609 | 645 | | |
610 | 646 | | |
611 | | - | |
612 | 647 | | |
613 | 648 | | |
614 | 649 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
| 4 | + | |
4 | 5 | | |
| 6 | + | |
5 | 7 | | |
6 | 8 | | |
7 | 9 | | |
| |||
91 | 93 | | |
92 | 94 | | |
93 | 95 | | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
94 | 157 | | |
95 | 158 | | |
96 | 159 | | |
| |||
0 commit comments