module

Secrets::KeychainMacOS

macOS Keychain backend, via shell-out to /usr/bin/security.

The key material is fed/read through stdin/stdout — never through argv (which would leak via ps). Each entry uses a fixed service (= the shard's bundle id) and a caller-chosen account to disambiguate (e.g. "master-key").

Constants

LEGACY_SERVICE = "dev.aloli.crystal-secrets"
SERVICE = "dev.aloli.secrets"

Instance methods

binary

Override at runtime (tests use a fake script).

Source
delete(account : String) : Nil

Remove the entry for (SERVICE, account). No-op if absent.

Source
exists?(account : String) : Bool

True if (SERVICE, account) currently has an entry.

Source
fetch(account : String) : String

Retrieve the value as a raw string. Raises KeychainError if absent.

Source
migrate_legacy_if_needed!(account : String) : Bool

Transparent rename migration — Keychain entries created before the v0.2.6 rename live under LEGACY_SERVICE ("dev.aloli.crystal-secrets"). If a caller looks up account under SERVICE and finds nothing, but the entry exists under LEGACY_SERVICE, this method copies it to SERVICE then deletes the legacy one. Idempotent and safe to call on every read path. Returns true if a migration happened.

Source
store(account : String, value : String) : Nil

Store (or update) a generic password under (SERVICE, account). The value is passed via stdin (-w -), never via argv.

Source