feat(credentials): guard login/submit/logout on credential helper

Problem: if no git credential helper is configured, login and
submit silently fail to persist credentials.

Solution: add `has_helper()` to `git_credential.lua` that checks
`git config credential.helper`. Guard the top of `login()`,
`logout()`, and `submit()` with an early-return error. Add a
healthcheck warning when no helper is configured. Add LuaCATS
annotations to all `git_credential` functions.
This commit is contained in:
Barrett Ruth 2026-03-07 19:50:04 -05:00
parent 8348b6195e
commit 5aa2c024e0
Signed by: barrett
GPG key ID: A6C96C9349D2FC81
4 changed files with 57 additions and 0 deletions

View file

@ -9,6 +9,24 @@ local HOSTS = {
usaco = 'usaco.org',
}
local _helper_checked = false
local _helper_ok = false
---@return boolean
function M.has_helper()
if not _helper_checked then
local r = vim
.system({ 'git', 'config', 'credential.helper' }, { text = true, timeout = 5000 })
:wait()
_helper_ok = r.code == 0 and r.stdout ~= nil and vim.trim(r.stdout) ~= ''
_helper_checked = true
end
return _helper_ok
end
---@param host string
---@param extra? table<string, string>
---@return string
local function _build_input(host, extra)
local lines = { 'protocol=https', 'host=' .. host }
if extra then
@ -21,6 +39,8 @@ local function _build_input(host, extra)
return table.concat(lines, '\n')
end
---@param stdout string
---@return table<string, string>
local function _parse_output(stdout)
local result = {}
for line in stdout:gmatch('[^\n]+') do
@ -32,6 +52,8 @@ local function _parse_output(stdout)
return result
end
---@param platform string
---@return { username: string, password: string, token?: string }?
function M.get(platform)
local host = HOSTS[platform]
if not host then
@ -69,6 +91,8 @@ function M.get(platform)
return creds
end
---@param platform string
---@param creds { username: string, password: string, token?: string }
function M.store(platform, creds)
local host = HOSTS[platform]
if not host then
@ -85,6 +109,8 @@ function M.store(platform, creds)
end
end
---@param platform string
---@param creds { username: string, password: string, token?: string }
function M.reject(platform, creds)
local host = HOSTS[platform]
if not host or not creds then