Skip to content

Commit bf55480

Browse files
committed
feat: lazy load secrets (issue: #152)
1 parent 29bdf86 commit bf55480

File tree

5 files changed

+93
-29
lines changed

5 files changed

+93
-29
lines changed

lua/gp/dispatcher.lua

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,8 @@ D.setup = function(opts)
4444
end
4545
end
4646

47-
local callbacks = { copilot = vault.refresh_copilot_bearer }
4847
for name, provider in pairs(D.providers) do
49-
vault.resolve_secret(name, provider.secret, callbacks[name])
48+
vault.add_secret(name, provider.secret)
5049
provider.secret = nil
5150
end
5251

@@ -168,7 +167,7 @@ end
168167
---@param handler function # response handler
169168
---@param on_exit function | nil # optional on_exit handler
170169
---@param callback function | nil # optional callback handler
171-
D.query = function(buf, provider, payload, handler, on_exit, callback)
170+
local query = function(buf, provider, payload, handler, on_exit, callback)
172171
-- make sure handler is a function
173172
if type(handler) ~= "function" then
174173
logger.error(
@@ -296,19 +295,18 @@ D.query = function(buf, provider, payload, handler, on_exit, callback)
296295
---TODO: this could be moved to a separate function returning endpoint and headers
297296
local endpoint = D.providers[provider].endpoint
298297
local headers = {}
299-
local bearer = vault.get_secret(provider)
298+
299+
local secret = provider
300+
if provider == "copilot" then
301+
secret = "copilot_bearer"
302+
end
303+
local bearer = vault.get_secret(secret)
300304
if not bearer then
305+
logger.warning(provider .. " bearer token is missing")
301306
return
302307
end
303308

304309
if provider == "copilot" then
305-
vault.refresh_copilot_bearer()
306-
bearer = vault.get_secret("copilot_bearer")
307-
local expires_at = vault.get_secret("copilot_bearer_expires_at")
308-
if not bearer or not expires_at or expires_at < os.time() then
309-
logger.warning("copilot bearer token is missing or expired, trying to refresh..")
310-
return
311-
end
312310
headers = {
313311
"-H",
314312
"editor-version: vscode/1.85.1",
@@ -373,6 +371,26 @@ D.query = function(buf, provider, payload, handler, on_exit, callback)
373371
tasker.run(buf, "curl", curl_params, nil, out_reader(), nil)
374372
end
375373

374+
-- gpt query
375+
---@param buf number | nil # buffer number
376+
---@param provider string # provider name
377+
---@param payload table # payload for api
378+
---@param handler function # response handler
379+
---@param on_exit function | nil # optional on_exit handler
380+
---@param callback function | nil # optional callback handler
381+
D.query = function(buf, provider, payload, handler, on_exit, callback)
382+
if provider == "copilot" then
383+
return vault.run_with_secret(provider, function()
384+
vault.refresh_copilot_bearer(function()
385+
query(buf, provider, payload, handler, on_exit, callback)
386+
end)
387+
end)
388+
end
389+
vault.run_with_secret(provider, function()
390+
query(buf, provider, payload, handler, on_exit, callback)
391+
end)
392+
end
393+
376394
-- response handler
377395
---@param buf number | nil # buffer to insert response into
378396
---@param win number | nil # window to insert response into

lua/gp/imager.lua

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ I.setup = function(opts)
7575
I.refresh()
7676

7777
for cmd, _ in pairs(I.cmd) do
78-
helpers.create_user_command(I.config.cmd_prefix .. cmd, I.cmd[cmd], function()
78+
helpers.create_user_command(I.config.cmd_prefix .. cmd, I.cmd[cmd], function()
7979
if cmd == "ImageAgent" then
8080
return I._agents
8181
end
@@ -84,7 +84,7 @@ I.setup = function(opts)
8484
end)
8585
end
8686

87-
vault.resolve_secret("imager_secret", I.config.secret)
87+
vault.add_secret("imager_secret", I.config.secret)
8888
I.config.secret = nil
8989

9090
logger.debug("imager setup finished")
@@ -156,7 +156,7 @@ I.cmd.Image = function(params)
156156
end
157157
end
158158

159-
I.generate_image = function(prompt, model, quality, style, size)
159+
local generate_image = function(prompt, model, quality, style, size)
160160
local bearer = vault.get_secret("imager_secret")
161161
if not bearer then
162162
return
@@ -262,4 +262,10 @@ I.generate_image = function(prompt, model, quality, style, size)
262262
end)
263263
end
264264

265+
I.generate_image = function(prompt, model, quality, style, size)
266+
vault.run_with_secret("imager_secret", function()
267+
generate_image(prompt, model, quality, style, size)
268+
end)
269+
end
270+
265271
return I

lua/gp/init.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ M.setup = function(opts)
6666

6767
M.vault.setup({ state_dir = state_dir, curl_params = curl_params })
6868

69-
M.vault.resolve_secret("openai_api_key", openai_api_key)
69+
M.vault.add_secret("openai_api_key", openai_api_key)
7070
M.config.openai_api_key = nil
7171
opts.openai_api_key = nil
7272

lua/gp/vault.lua

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,23 @@ V.setup = function(opts)
3232
logger.debug("vault setup finished\n" .. vim.inspect(V), true)
3333
end
3434

35+
---@param name string # provider name
36+
---@param secret string | table | nil # secret or command to retrieve it
37+
V.add_secret = function(name, secret)
38+
local s = { secret = secret }
39+
s = vim.deepcopy(s)
40+
name = alias[name] or name
41+
secrets[name] = s.secret
42+
logger.debug("vault adding secret " .. name .. ": " .. vim.inspect(s.secret), true)
43+
end
44+
3545
---@param name string # secret name
3646
---@return string | nil # secret or nil if not found
3747
V.get_secret = function(name)
3848
name = alias[name] or name
3949

4050
local secret = secrets[name]
41-
logger.debug("vault get_secret " .. name .. ": " .. vim.inspect(secret), true)
51+
logger.debug("vault get_secret:" .. name .. ": " .. vim.inspect(secret), true)
4252

4353
if not secret then
4454
logger.warning("vault secret " .. name .. " not found", true)
@@ -58,8 +68,10 @@ end
5868
V.resolve_secret = function(name, secret, callback)
5969
logger.debug("vault resolver started for " .. name .. ": " .. vim.inspect(secret), true)
6070
name = alias[name] or name
61-
if secrets[name] then
62-
logger.debug("vault resolver secret " .. name .. " already exists", true)
71+
callback = callback or function() end
72+
if secrets[name] and type(secrets[name]) ~= "table" then
73+
logger.debug("vault resolver secret " .. name .. " already resolved", true)
74+
callback()
6375
return
6476
end
6577

@@ -72,13 +84,11 @@ V.resolve_secret = function(name, secret, callback)
7284

7385
V._obfuscated_secrets[name] = s:sub(1, 3) .. string.rep("*", #s - 6) .. s:sub(-3)
7486

75-
if callback then
76-
callback()
77-
end
87+
callback()
7888
end
7989

8090
if not secret then
81-
logger.debug("vault resolver for " .. name .. " got empty secret", true)
91+
logger.warning("vault resolver for " .. name .. " got empty secret", true)
8292
return
8393
end
8494

@@ -118,12 +128,14 @@ V.resolve_secret = function(name, secret, callback)
118128
end
119129
end
120130

121-
V.refresh_copilot_bearer = function()
131+
V.refresh_copilot_bearer = function(callback)
122132
local secret = secrets.copilot
123133
if not secret or type(secret) == "table" then
124134
return
125135
end
126-
logger.debug("vault refresh_copilot_bearer started", true)
136+
logger.debug("vault refresh_copilot_bearer: started", true)
137+
138+
callback = callback or function() end
127139

128140
local state_file = V.config.state_dir .. "/vault_state.json"
129141

@@ -134,9 +146,9 @@ V.refresh_copilot_bearer = function()
134146

135147
local bearer = V._state.copilot_bearer or state.copilot_bearer or {}
136148
if bearer.token and bearer.expires_at and bearer.expires_at > os.time() then
137-
logger.debug("vault refresh_copilot_bearer token still valid", true)
138149
secrets.copilot_bearer = bearer.token
139-
secrets.copilot_bearer_expires_at = bearer.expires_at
150+
logger.debug("vault refresh_copilot_bearer: token still valid, running callback", true)
151+
callback()
140152
return
141153
end
142154

@@ -171,10 +183,30 @@ V.refresh_copilot_bearer = function()
171183

172184
V._state.copilot_bearer = vim.json.decode(stdout)
173185
secrets.copilot_bearer = V._state.copilot_bearer.token
174-
175-
logger.debug("vault refresh_copilot_bearer finished", true)
176186
helpers.table_to_file(V._state, state_file)
187+
188+
logger.debug("vault refresh_copilot_bearer: token resolved, running callback", true)
189+
callback()
177190
end, nil, nil)
178191
end
179192

193+
---@param name string # secret name
194+
---@param callback function # function to run after secret is resolved
195+
V.run_with_secret = function(name, callback)
196+
name = alias[name] or name
197+
if not secrets[name] then
198+
logger.warning("vault secret " .. name .. " not found", true)
199+
return
200+
end
201+
if type(secrets[name]) == "table" then
202+
V.resolve_secret(name, secrets[name], function()
203+
logger.debug("vault run_with_secret: " .. name .. " resolved, running callback", true)
204+
callback()
205+
end)
206+
else
207+
logger.debug("vault run_with_secret: " .. name .. " already resolved, running callback", true)
208+
callback()
209+
end
210+
end
211+
180212
return V

lua/gp/whisper.lua

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ end
4444

4545
---@param callback function # callback function(text)
4646
---@param language string | nil # language code
47-
W.Whisper = function(callback, language)
47+
local whisper = function(callback, language)
4848
language = language or W.config.language
4949
-- make sure sox is installed
5050
if vim.fn.executable("sox") == 0 then
@@ -297,6 +297,14 @@ W.Whisper = function(callback, language)
297297
end)
298298
end
299299

300+
---@param callback function # callback function(text)
301+
---@param language string | nil # language code
302+
W.Whisper = function(callback, language)
303+
vault.run_with_secret("openai_api_key", function()
304+
whisper(callback, language)
305+
end)
306+
end
307+
300308
W.cmd.Whisper = function(params)
301309
local buf = vim.api.nvim_get_current_buf()
302310
local start_line = vim.api.nvim_win_get_cursor(0)[1]

0 commit comments

Comments
 (0)