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

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:36:31 -04:00
parent 422f8f9b05
commit 149f2dac2e
5 changed files with 256 additions and 5 deletions

View file

@ -232,4 +232,98 @@ describe('oauth', function()
assert.equals('test', c.config_key)
end)
end)
describe('with_token', function()
it('auto-triggers auth when not authenticated', function()
local c = oauth.new({ name = 'test_auth', scope = 'x', port = 0, config_key = 'gtasks' })
local call_count = 0
c.get_access_token = function()
call_count = call_count + 1
if call_count == 1 then
return nil
end
return 'new-token'
end
c.resolve_credentials = function()
return { client_id = 'real-id', client_secret = 'real-secret' }
end
local auth_called = false
c.auth = function(_, on_complete)
auth_called = true
vim.schedule(function()
on_complete(true)
end)
end
local received_token
oauth.with_token(c, 'test_auth', function(token)
received_token = token
end)
vim.wait(1000, function()
return received_token ~= nil
end)
assert.is_true(auth_called)
assert.equals('new-token', received_token)
end)
it('bails on bundled credentials without calling auth', function()
local c = oauth.new({ name = 'test_bail', scope = 'x', port = 0, config_key = 'gtasks' })
c.get_access_token = function()
return nil
end
c.resolve_credentials = function()
return { client_id = oauth.BUNDLED_CLIENT_ID, client_secret = 'x' }
end
local auth_called = false
c.auth = function()
auth_called = true
end
local callback_called = false
oauth.with_token(c, 'test_bail', function()
callback_called = true
end)
vim.wait(500, function()
return false
end)
assert.is_false(auth_called)
assert.is_false(callback_called)
end)
it('stops when auth fails', function()
local c = oauth.new({ name = 'test_fail', scope = 'x', port = 0, config_key = 'gtasks' })
c.get_access_token = function()
return nil
end
c.resolve_credentials = function()
return { client_id = 'real-id', client_secret = 'real-secret' }
end
c.auth = function(_, on_complete)
vim.schedule(function()
on_complete(false)
end)
end
local callback_called = false
oauth.with_token(c, 'test_fail', function()
callback_called = true
end)
vim.wait(500, function()
return false
end)
assert.is_false(callback_called)
end)
it('proceeds directly when already authenticated', function()
local c = oauth.new({ name = 'test_ok', scope = 'x', port = 0, config_key = 'gtasks' })
c.get_access_token = function()
return 'existing-token'
end
local received_token
oauth.with_token(c, 'test_ok', function(token)
received_token = token
end)
vim.wait(1000, function()
return received_token ~= nil
end)
assert.equals('existing-token', received_token)
end)
end)
end)