fix(sync): auto-trigger auth flow on unauthenticated sync actions (#120) (#123)

Problem: running a sync action (e.g. `:Pending gtasks push`) without
being authenticated would silently abort with a warning, requiring
the user to manually run `:Pending auth` first.

Solution: `oauth.with_token()` now auto-triggers the browser auth flow
when no token exists (for non-bundled credentials) and resumes the
original action on success. `auth()` and `_exchange_code()` now call
`on_complete(ok)` on all exit paths. S3 backends run
`aws sts get-caller-identity` before every sync action, auto-triggering
SSO login on expired sessions.
This commit is contained in:
Barrett Ruth 2026-03-10 11:37:16 -04:00
parent dbf0ab1221
commit 625ee01074
5 changed files with 256 additions and 5 deletions

View file

@ -374,6 +374,64 @@ describe('s3', function()
end)
end)
describe('ensure_credentials', function()
it('returns true on valid credentials', function()
util.system = function(args)
if vim.tbl_contains(args, 'get-caller-identity') then
return { code = 0, stdout = '{"Account":"123"}', stderr = '' }
end
return { code = 0, stdout = '', stderr = '' }
end
assert.is_true(s3._ensure_credentials())
end)
it('returns false on missing credentials', function()
util.system = function()
return { code = 1, stdout = '', stderr = 'Unable to locate credentials' }
end
local msg
local orig_notify = vim.notify
vim.notify = function(m, level)
if level == vim.log.levels.ERROR then
msg = m
end
end
assert.is_false(s3._ensure_credentials())
vim.notify = orig_notify
assert.truthy(msg and msg:find('no AWS credentials'))
end)
it('retries SSO login on expired session', function()
local calls = {}
util.system = function(args)
if vim.tbl_contains(args, 'get-caller-identity') then
return { code = 1, stdout = '', stderr = 'Error: SSO session expired' }
end
if vim.tbl_contains(args, 'sso') then
table.insert(calls, 'sso-login')
return { code = 0, stdout = '', stderr = '' }
end
return { code = 0, stdout = '', stderr = '' }
end
assert.is_true(s3._ensure_credentials())
assert.equals(1, #calls)
assert.equals('sso-login', calls[1])
end)
it('returns false when SSO login fails', function()
util.system = function(args)
if vim.tbl_contains(args, 'get-caller-identity') then
return { code = 1, stdout = '', stderr = 'SSO token expired' }
end
if vim.tbl_contains(args, 'sso') then
return { code = 1, stdout = '', stderr = 'login failed' }
end
return { code = 0, stdout = '', stderr = '' }
end
assert.is_false(s3._ensure_credentials())
end)
end)
describe('push', function()
it('uploads store to S3', function()
local s = pending.store()
@ -383,6 +441,9 @@ describe('s3', function()
local captured_args
util.system = function(args)
if vim.tbl_contains(args, 'get-caller-identity') then
return { code = 0, stdout = '{"Account":"123"}', stderr = '' }
end
if vim.tbl_contains(args, 's3') then
captured_args = args
return { code = 0, stdout = '', stderr = '' }
@ -405,6 +466,13 @@ describe('s3', function()
pending = require('pending')
s3 = require('pending.sync.s3')
util.system = function(args)
if vim.tbl_contains(args, 'get-caller-identity') then
return { code = 0, stdout = '{"Account":"123"}', stderr = '' }
end
return { code = 0, stdout = '', stderr = '' }
end
local msg
local orig_notify = vim.notify
vim.notify = function(m, level)