vaultkit 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 693839ee170f79bd7012760053b2e0240f2730693741603029182066462b6c20
4
- data.tar.gz: 5e200af5f55787dc471f8299f63e33f5aeb2613646aa3f28dd0012142559ca38
3
+ metadata.gz: 992511b9fff48dc39ffa343776721e9c24077c00cfdbe97b9f98e0f1454f4093
4
+ data.tar.gz: bcc02c8d21f7d0e66d1b30fd16ef2080aedf8271ac7159d775f05bf1e6db15d1
5
5
  SHA512:
6
- metadata.gz: 89687754411a6d542d819443638129bfbb1650a0745e18e71e2cb6d677ab71d9d43bb57768af450d3a51a5d821c0297fe485bcaedee687b595220b3b47e69c38
7
- data.tar.gz: 2771cbb8bbcb6a1c6570ddeaa9854a232c07f2583195cf9eb0dc2ed8615b52438b6da150cb415b7f95b53f2955e31b5b4101b2157b0c3da1823431dce811e8eb
6
+ metadata.gz: dd8c2496c757661ade482f3ac01bf68ab1d073903db14dec88d9a4d4d40721beb9ea36e8942deb4f9296b3f6e6f49014d1724b8bbfb3d67d351ed886024629bf
7
+ data.tar.gz: 2881996c7f00bb58a92a62d00dea1408ab2ea42c0e0d3acc2fb0f6fc782ac27aa6eac943b458ddcd5dee416debb8714b0f285a7f6954db9d2c9e00290f2206a7
data/README.md CHANGED
@@ -200,6 +200,14 @@ Clear stored credentials and end session.
200
200
  vkit logout
201
201
  ```
202
202
 
203
+ ### Where the login is saved
204
+
205
+ `vkit login` saves the endpoint and token in the macOS Keychain, or in the Secret
206
+ Service keyring (GNOME Keyring, KWallet) on Linux when `secret-tool` is installed.
207
+ Elsewhere, including Windows, or when saving to the keychain fails (for example, over
208
+ SSH with no unlocked keyring), it saves them to `~/.vkit/credentials.json`, readable
209
+ only by you, and says so. Login tokens expire after an hour.
210
+
203
211
  ### Credentials from the environment
204
212
 
205
213
  `vkit` normally uses the login saved by `vkit login`, in your OS keychain or
@@ -15,6 +15,8 @@ module Vkit
15
15
  class CredentialStore
16
16
  SERVICE = "vkit"
17
17
  ACCOUNT = "credentials"
18
+ # security -i reads lines of about 4 KB; a login is well under that.
19
+ MAC_KEYCHAIN_MAX_HEX = 3_900
18
20
 
19
21
  @override_noticed = false
20
22
 
@@ -34,15 +36,7 @@ module Vkit
34
36
  "user" => user
35
37
  }
36
38
 
37
- case
38
- when mac?
39
- mac_keychain_store(payload)
40
- when linux? && secret_tool_available?
41
- linux_secret_service_store(payload)
42
- else
43
- file_store(payload)
44
- end
45
-
39
+ store(payload)
46
40
  true
47
41
  end
48
42
 
@@ -56,16 +50,8 @@ module Vkit
56
50
  return unless payload
57
51
 
58
52
  payload["user"] = user
59
-
60
- case
61
- when mac?
62
- mac_keychain_store(payload)
63
- when linux? && secret_tool_available?
64
- linux_secret_service_store(payload)
65
- else
66
- file_store(payload)
67
- end
68
- end
53
+ store(payload)
54
+ end
69
55
 
70
56
  def endpoint
71
57
  load_payload&.dig("endpoint")
@@ -110,9 +96,8 @@ module Vkit
110
96
  mac_keychain_delete
111
97
  when linux? && secret_tool_available?
112
98
  linux_secret_service_delete
113
- else
114
- file_delete
115
99
  end
100
+ file_delete
116
101
  end
117
102
 
118
103
  def clear_token!
@@ -120,15 +105,7 @@ module Vkit
120
105
  return unless payload
121
106
 
122
107
  payload.delete("token")
123
-
124
- case
125
- when mac?
126
- mac_keychain_store(payload)
127
- when linux? && secret_tool_available?
128
- linux_secret_service_store(payload)
129
- else
130
- file_store(payload)
131
- end
108
+ store(payload)
132
109
  end
133
110
 
134
111
  # endpoint and token only; the user is looked up separately (#user),
@@ -137,15 +114,40 @@ module Vkit
137
114
  env_override || stored_payload
138
115
  end
139
116
 
117
+ # The keychain first, then the file, which also holds the login when
118
+ # saving to the keychain failed.
140
119
  def stored_payload
141
- case
142
- when mac?
143
- mac_keychain_load
144
- when linux? && secret_tool_available?
145
- linux_secret_service_load
146
- else
147
- file_load
120
+ keychain =
121
+ case
122
+ when mac?
123
+ mac_keychain_load
124
+ when linux? && secret_tool_available?
125
+ linux_secret_service_load
126
+ end
127
+
128
+ keychain || file_load
129
+ end
130
+
131
+ # Saves to the OS keychain when there is one. If that fails (no
132
+ # unlocked keyring over SSH, a locked login keychain), saves to
133
+ # ~/.vkit instead and says so, rather than reporting a login that
134
+ # wasn't kept.
135
+ def store(payload)
136
+ saved =
137
+ case
138
+ when mac?
139
+ mac_keychain_store(payload)
140
+ when linux? && secret_tool_available?
141
+ linux_secret_service_store(payload)
142
+ end
143
+
144
+ if saved
145
+ file_delete
146
+ return
148
147
  end
148
+
149
+ warn "vkit: couldn't save to the system keychain; saved to #{@fallback_path} instead." unless saved.nil?
150
+ file_store(payload)
149
151
  end
150
152
 
151
153
  def override_user(override)
@@ -171,15 +173,19 @@ module Vkit
171
173
  system("which secret-tool > /dev/null 2>&1")
172
174
  end
173
175
 
176
+ # `security -i` reads the command from stdin, so the token never
177
+ # appears in the process list, as it would with `-w` on the command
178
+ # line. The data goes in hex (-X) to avoid quoting.
174
179
  def mac_keychain_store(payload)
180
+ hex = payload.to_json.unpack1("H*")
181
+ return false if hex.bytesize > MAC_KEYCHAIN_MAX_HEX
182
+
175
183
  mac_keychain_delete
176
- system(
177
- "security", "add-generic-password",
178
- "-a", ACCOUNT,
179
- "-s", SERVICE,
180
- "-w", payload.to_json,
181
- "-U"
184
+ _stdout, _stderr, status = Open3.capture3(
185
+ "security", "-i",
186
+ stdin_data: "add-generic-password -a #{ACCOUNT} -s #{SERVICE} -U -X #{hex}\n"
182
187
  )
188
+ status.success?
183
189
  end
184
190
 
185
191
  def mac_keychain_load
@@ -208,7 +214,7 @@ module Vkit
208
214
  end
209
215
 
210
216
  def linux_secret_service_store(payload)
211
- Open3.capture3(
217
+ _stdout, _stderr, status = Open3.capture3(
212
218
  "secret-tool",
213
219
  "store",
214
220
  "--label=VaultKit Credentials",
@@ -216,6 +222,7 @@ module Vkit
216
222
  "account", ACCOUNT,
217
223
  stdin_data: payload.to_json
218
224
  )
225
+ status.success?
219
226
  end
220
227
 
221
228
  def linux_secret_service_load
@@ -234,7 +241,7 @@ module Vkit
234
241
  end
235
242
 
236
243
  def linux_secret_service_delete
237
- linux_secret_service_store({})
244
+ system("secret-tool", "clear", "service", SERVICE, "account", ACCOUNT, out: File::NULL, err: File::NULL)
238
245
  end
239
246
 
240
247
  def file_store(payload)
data/lib/vkit/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vkit
4
- VERSION = "1.2.1"
4
+ VERSION = "1.2.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vaultkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nnamdi Ogundu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-29 00:00:00.000000000 Z
11
+ date: 2026-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor