Skip to content

Add generic_password_read op: signed-helper keychain reads - #24

Merged
0thernet merged 2 commits into
mainfrom
claude/safe-storage-read-20260927
Sep 27, 2026
Merged

0thernet merged 2 commits into
mainfrom
claude/safe-storage-read-20260927

Conversation

@0thernet

Copy link
Copy Markdown
Member

What

Adds a product-neutral generic_password_read op to the local-custody sidecar, backed by SecItemCopyMatching on macOS.

Why

Cookie readers that spawn /usr/bin/security get prompts naming security, and "Always Allow" widens access to every security caller. When the read happens inside a caller-chosen signed binary — a helper assembled into the product's Contents/Helpers/ — the prompt names the product and the keychain ACL binds to that helper's signature, surviving upgrades under the shared local signing identity.

This is the foundation half of the ux-audit GG-8 item ("signed cookie reader"): consumers ship the same binary signed as their own helper (e.g. ghostget-cookie-reader) and call this op for the Safe Storage read.

Contract

  • {"op":"generic_password_read","service":"...","account":"..."} → {"contentBase64":"…"}
  • Selectors are required, 1–256 UTF-8 bytes, no control characters; no enumeration form.
  • Value bound 4096 bytes (limit).
  • Typed failures: missing, denied, interaction-not-allowed (locked/no-UI), keychain-error (numeric status only), unsupported off macOS.
  • No TypeScript fallback by design — the op exists so the read happens inside the caller-chosen signed binary.

Changes

  • rust/src/lib.rs: read_generic_password (security-framework 3 on macOS; unsupported elsewhere, after selector validation).
  • rust/src/main.rs: sidecar dispatch + doc line.
  • src/custody-rust.ts: readGenericPassword(binaryPath, service, account) over the existing bounded spawn protocol.
  • spec/custody.md, spec/vectors.json: contract section + five shared vectors.
  • src/custody-rust.test.ts, rust/tests/sidecar.rs: validation, typed-error, and missing-binary coverage (macOS missing verified against the real keychain on this host).

bun run check is green end-to-end on darwin-arm64.

…ller's signed binary

The sidecar gains a product-neutral generic-password op backed by
SecItemCopyMatching so a product can ship a signed helper copy inside its
own app bundle and get a Keychain prompt and access-list entry in its own
name instead of the 'security' tool's. Selectors are exact and bounded,
values return as bounded base64, and denials, missing items, locked
keychains and other OS failures map to typed codes. There is no TypeScript
fallback by design: a native read is the whole point of the op.
@0thernet
0thernet merged commit 6ece65b into main Sep 27, 2026
7 checks passed
@0thernet
0thernet deleted the claude/safe-storage-read-20260927 branch September 27, 2026 10:07
0thernet added a commit that referenced this pull request Sep 27, 2026
Version bump for the merged signed-helper keychain read (#24):
package.json, rust/Cargo.toml, Cargo.lock, portfolio-inventory.json, and
a README change note.

Co-authored-by: 0thernet <894119+0thernet@users.noreply.github.com>
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