Class: CredentialStore

Inherits:
Object
  • Object
show all
Defined in:
lib/credential_store.rb

Overview

Low-level read/write operations on Rails encrypted credentials. Wraps the merge-and-write pattern used by SessionChannel#write_anthropic_token in a reusable helper. All namespacing (e.g. mcp, anthropic) is the caller’s responsibility — this class operates on raw top-level keys.

Examples:

Writing a nested credential

CredentialStore.write("mcp", "linear_api_key" => "sk-xxx")

Reading a nested credential

CredentialStore.read("mcp", "linear_api_key") #=> "sk-xxx"

Class Method Summary collapse

Class Method Details

.list(namespace) ⇒ Array<String>

Lists all keys under a namespace.

Parameters:

  • namespace (String)

    top-level YAML key

Returns:

  • (Array<String>)

    credential keys (not values)



45
46
47
48
49
50
# File 'lib/credential_store.rb', line 45

def list(namespace)
  section = Rails.application.credentials.dig(namespace.to_sym)
  return [] unless section.is_a?(Hash)

  section.keys.map(&:to_s)
end

.read(namespace, key) ⇒ String?

Reads a single credential value from a namespace. Busts the Rails credentials cache first so cross-process writes (e.g. token saved in the web process, read in the SolidQueue worker) are always visible.

Parameters:

  • namespace (String)

    top-level YAML key

  • key (String)

    credential key within the namespace

Returns:

  • (String, nil)

    credential value or nil if not found



36
37
38
39
# File 'lib/credential_store.rb', line 36

def read(namespace, key)
  bust_credentials_cache!
  Rails.application.credentials.dig(namespace.to_sym, key.to_sym)
end

.remove(namespace, key) ⇒ void

This method returns an undefined value.

Removes a single key from a namespace. No-op if the key does not exist.

Parameters:

  • namespace (String)

    top-level YAML key

  • key (String)

    credential key to remove



58
59
60
61
62
63
64
65
66
67
# File 'lib/credential_store.rb', line 58

def remove(namespace, key)
  existing = load_credentials
  section = existing[namespace]
  return unless section.is_a?(Hash)
  return unless section.key?(key)

  section.delete(key)
  existing.delete(namespace) if section.empty?
  save_credentials(existing)
end

.write(namespace, pairs) ⇒ void

This method returns an undefined value.

Writes one or more key-value pairs under a top-level namespace. Merges into existing credentials, preserving sibling keys.

Parameters:

  • namespace (String)

    top-level YAML key (e.g. “mcp”, “anthropic”)

  • pairs (Hash<String, String>)

    key-value pairs to store



21
22
23
24
25
26
# File 'lib/credential_store.rb', line 21

def write(namespace, pairs)
  existing = load_credentials
  section = existing[namespace] ||= {}
  section.merge!(pairs)
  save_credentials(existing)
end