Class: AgentsControl::Secrets::Providers::Keychain

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

Overview

macOS Keychain.

Instance Method Summary collapse

Constructor Details

#initialize(executor: Executor.new) ⇒ Keychain

Returns a new instance of Keychain.



91
92
93
# File 'lib/agents_control/secrets.rb', line 91

def initialize(executor: Executor.new)
  @executor = executor
end

Instance Method Details

#available?Boolean

Returns:

  • (Boolean)


97
# File 'lib/agents_control/secrets.rb', line 97

def available? = !binary.nil?

#delete(key) ⇒ Object



127
128
129
# File 'lib/agents_control/secrets.rb', line 127

def delete(key)
  @executor.run(binary, "delete-generic-password", "-s", SERVICE, "-a", key).success?
end

#get(key) ⇒ Object



101
102
103
104
105
106
# File 'lib/agents_control/secrets.rb', line 101

def get(key)
  result = @executor.run(binary, "find-generic-password", "-s", SERVICE, "-a", key, "-w")
  return nil unless result.success?

  decode(result.stdout.strip)
end

#nameObject



95
# File 'lib/agents_control/secrets.rb', line 95

def name = "Keychain (macOS)"

#set(key, value) ⇒ Object

The command goes over stdin in interactive mode, not argv: security add-generic-password -w SECRET would expose the token in ps, and the man page calls passing a password as an argument insecure outright.

The cost of this is that interactive mode splits the line on whitespace, so a value containing a space or newline would be silently mangled. Better to refuse loudly than to save a truncated token and chase a confusing auth error later.



117
118
119
120
121
122
123
124
125
# File 'lib/agents_control/secrets.rb', line 117

def set(key, value)
  unless value.to_s.match?(/\A[\x21-\x7E]+\z/)
    raise Error, "Keychain only accepts printable ASCII with no whitespace"
  end

  command = "add-generic-password -s #{SERVICE} -a #{key} -w #{value} -U\n"

  @executor.run(binary, "-i", stdin: command).success?
end

#writable?Boolean

Returns:

  • (Boolean)


99
# File 'lib/agents_control/secrets.rb', line 99

def writable? = true