From 5aa2c024e0fd92ba04a9c95d4d38a35efb983af7 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sat, 7 Mar 2026 19:50:04 -0500 Subject: [PATCH] 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. --- lua/cp/credentials.lua | 16 ++++++++++++++++ lua/cp/git_credential.lua | 26 ++++++++++++++++++++++++++ lua/cp/health.lua | 7 +++++++ lua/cp/submit.lua | 8 ++++++++ 4 files changed, 57 insertions(+) diff --git a/lua/cp/credentials.lua b/lua/cp/credentials.lua index 1d5c759..1d1fa36 100644 --- a/lua/cp/credentials.lua +++ b/lua/cp/credentials.lua @@ -71,6 +71,14 @@ function M.login(platform) return end + if not git_credential.has_helper() then + logger.log( + 'No git credential helper configured. See :help cp-credentials', + { level = vim.log.levels.ERROR } + ) + return + end + local display = constants.PLATFORM_DISPLAY_NAMES[platform] or platform local existing = git_credential.get(platform) or {} @@ -111,6 +119,14 @@ function M.logout(platform) ) return end + if not git_credential.has_helper() then + logger.log( + 'No git credential helper configured. See :help cp-credentials', + { level = vim.log.levels.ERROR } + ) + return + end + local display = constants.PLATFORM_DISPLAY_NAMES[platform] or platform local existing = git_credential.get(platform) if existing then diff --git a/lua/cp/git_credential.lua b/lua/cp/git_credential.lua index c6fbf01..c6dfc39 100644 --- a/lua/cp/git_credential.lua +++ b/lua/cp/git_credential.lua @@ -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 +---@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 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 diff --git a/lua/cp/health.lua b/lua/cp/health.lua index b6d708f..2987205 100644 --- a/lua/cp/health.lua +++ b/lua/cp/health.lua @@ -84,6 +84,13 @@ local function check() vim.health.warn('git >= 1.7.9 required for credential storage, found ' .. ver_str) end end + + local helper = vim.system({ 'git', 'config', 'credential.helper' }, { text = true }):wait() + if helper.code == 0 and helper.stdout and vim.trim(helper.stdout) ~= '' then + vim.health.ok('git credential helper: ' .. vim.trim(helper.stdout)) + else + vim.health.warn('no git credential helper configured (required for login/submit)') + end else vim.health.warn('git not found (required for credential storage)') end diff --git a/lua/cp/submit.lua b/lua/cp/submit.lua index 4c5eb70..50d0bf2 100644 --- a/lua/cp/submit.lua +++ b/lua/cp/submit.lua @@ -42,6 +42,14 @@ end ---@param opts { language?: string }? function M.submit(opts) + if not git_credential.has_helper() then + logger.log( + 'No git credential helper configured. See :help cp-credentials', + { level = vim.log.levels.ERROR } + ) + return + end + local platform = state.get_platform() local contest_id = state.get_contest_id() local problem_id = state.get_problem_id()