Skip to content

feat: add chunked keyring storage for Windows - #1

Merged
jlitola merged 3 commits into
mainfrom
jlitola/win-keyring-chunking
Feb 24, 2026
Merged

feat: add chunked keyring storage for Windows#1
jlitola merged 3 commits into
mainfrom
jlitola/win-keyring-chunking

Conversation

@jlitola

@jlitola jlitola commented Feb 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add ChunkingKeyringService decorator that transparently splits large keyring values across multiple entries, fixing Windows login failures caused by Credential Manager's 2560 UTF-16 char limit
  • Decorator uses versioned write-IDs for crash-safe atomicity: new chunks are written before the sentinel, old chunks cleaned up after
  • Applied only on Windows (process.platform === "win32") — macOS and Linux have no practical per-entry size limits

Details

Windows Credential Manager limits password fields to 2560 UTF-16 code units. JSON-serialized OAuth token data (JWT access token + refresh token + timestamps) can exceed this limit, causing KeychainUnavailableError during githits login.

The ChunkingKeyringService wraps KeyringService and:

  • Values ≤2400 chars: pass through unchanged (backward compatible)
  • Values >2400 chars: split into numbered chunks with a CHUNKED:<writeId>:<count> sentinel in the main key
  • Chunk size is configurable via constructor for future platform support
  • 33 tests covering pure helpers, decorator behavior, edge cases, and crash safety

Test plan

  • bun test src/services/chunking-keyring-service.test.ts — 33 tests pass
  • bun test — no regressions
  • bun run build — compiles cleanly
  • Pre-commit hooks pass (lint, format, typecheck)
  • Manual test on Windows with JWT token exceeding 2560 chars

🤖 Generated with Claude Code

Windows Credential Manager limits password fields to 2560 UTF-16 code
units. JSON-serialized OAuth token data (JWT access token + refresh
token + timestamps) can exceed this, causing login failure.

Add ChunkingKeyringService decorator that transparently splits large
values across multiple keyring entries. Values under 2400 chars pass
through unchanged (backward compatible). Each write uses a unique
writeId namespace for crash-safe atomicity.

The decorator is only applied on Windows (process.platform === "win32")
in container.ts. macOS and Linux have no practical per-entry size
limits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jlitola jlitola added the enhancement New feature or request label Feb 24, 2026
jlitola and others added 2 commits February 24, 2026 11:16
The Windows CRED_MAX_CREDENTIAL_BLOB_SIZE limit is 2560 bytes, not
2560 UTF-16 code units. Since @napi-rs/keyring encodes passwords as
UTF-16 (2 bytes per character), the effective character limit is 1280.

WINDOWS_MAX_ENTRY_SIZE was set to 2400 (assuming char limit of 2560),
but a value of 2400 chars becomes 4800 bytes in UTF-16, far exceeding
the 2560-byte limit. Reduced to 1200 (80-char margin from 1280).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Patch release for Windows chunked keyring storage fix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jlitola
jlitola merged commit 44244b4 into main Feb 24, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant