diff --git a/src/utils/cve-to-ghsa.mts b/src/utils/cve-to-ghsa.mts index 37470d9ef..74be27e83 100644 --- a/src/utils/cve-to-ghsa.mts +++ b/src/utils/cve-to-ghsa.mts @@ -5,6 +5,7 @@ import type { CResult } from '../types.mts' /** * Converts CVE IDs to GHSA IDs using GitHub API. + * CVE to GHSA mappings are permanent, so we cache for 30 days. */ export async function convertCveToGhsa( cveId: string, @@ -13,11 +14,16 @@ export async function convertCveToGhsa( const cacheKey = `cve-to-ghsa-${cveId}` const octokit = getOctokit() - const response = await cacheFetch(cacheKey, () => - octokit.rest.securityAdvisories.listGlobalAdvisories({ - cve_id: cveId, - per_page: 1, - }), + const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000 + + const response = await cacheFetch( + cacheKey, + () => + octokit.rest.securityAdvisories.listGlobalAdvisories({ + cve_id: cveId, + per_page: 1, + }), + THIRTY_DAYS_MS, ) if (!response.data.length) { @@ -32,9 +38,21 @@ export async function convertCveToGhsa( data: response.data[0]!.ghsa_id, } } catch (e) { + const errorCause = getErrorCause(e) + const errorLower = errorCause.toLowerCase() + // Detect GitHub API rate limit and network errors. + const isRateLimitOrNetworkError = + errorLower.includes('rate limit') || + errorLower.includes('epipe') || + errorLower.includes('econnreset') || + errorLower.includes('status: 403') || + errorLower.includes('status code 403') + return { ok: false, - message: `Failed to convert CVE to GHSA: ${getErrorCause(e)}`, + message: isRateLimitOrNetworkError + ? 'GitHub API rate limit exceeded while converting CVE to GHSA. Wait an hour or set SOCKET_CLI_GITHUB_TOKEN environment variable with a personal access token for higher limits.' + : `Failed to convert CVE to GHSA: ${errorCause}`, } } }