diff --git a/lib/entry-points.js b/lib/entry-points.js index 78a5f058af..bb8e472579 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -158049,15 +158049,11 @@ var GITHUB_TOKEN_PATTERNS = [ }, { type: "Server-to-Server Token" /* ServerToServer */, - pattern: /\bghs_[a-zA-Z0-9]{36}\b/g + pattern: /ghs_[A-Za-z0-9._-]{36,}/g }, { type: "Refresh Token" /* Refresh */, pattern: /\bghr_[a-zA-Z0-9]{36}\b/g - }, - { - type: "App Installation Access Token" /* AppInstallationAccess */, - pattern: /\bghs_[a-zA-Z0-9]{255}\b/g } ]; function isAuthToken(value, patterns = GITHUB_TOKEN_PATTERNS) { @@ -158070,15 +158066,23 @@ function isAuthToken(value, patterns = GITHUB_TOKEN_PATTERNS) { } function scanFileForTokens(filePath, relativePath, logger) { const findings = []; + const seenMatches = /* @__PURE__ */ new Set(); try { const content = fs23.readFileSync(filePath, "utf8"); for (const { type: type2, pattern } of GITHUB_TOKEN_PATTERNS) { - const matches = content.match(pattern); - if (matches) { - for (let i = 0; i < matches.length; i++) { - findings.push({ tokenType: type2, filePath: relativePath }); + const regex = new RegExp(pattern.source, pattern.flags); + let matchCount = 0; + for (const match of content.matchAll(regex)) { + const index = match.index; + if (index === void 0 || seenMatches.has(index)) { + continue; } - logger.debug(`Found ${matches.length} ${type2}(s) in ${relativePath}`); + seenMatches.add(index); + findings.push({ tokenType: type2, filePath: relativePath }); + matchCount++; + } + if (matchCount > 0) { + logger.debug(`Found ${matchCount} ${type2}(s) in ${relativePath}`); } } return findings; diff --git a/src/artifact-scanner.test.ts b/src/artifact-scanner.test.ts index 56f99e1138..31840ab7cc 100644 --- a/src/artifact-scanner.test.ts +++ b/src/artifact-scanner.test.ts @@ -23,6 +23,8 @@ test("makeTestToken", (t) => { t.is(makeTestToken(255).length, 255); }); +const NEW_FORMAT_GHS_TOKEN = "ghs_abc123.def456.ghi789_abc123.def456.ghi789"; + test("isAuthToken", (t) => { // Undefined for strings that aren't tokens t.is(isAuthToken("some string"), undefined); @@ -32,10 +34,8 @@ test("isAuthToken", (t) => { // Token types for strings that are tokens. t.is(isAuthToken(`ghp_${makeTestToken()}`), TokenType.PersonalAccessClassic); t.is(isAuthToken(`ghp_${makeTestToken()}`), TokenType.PersonalAccessClassic); - t.is( - isAuthToken(`ghs_${makeTestToken(255)}`), - TokenType.AppInstallationAccess, - ); + t.is(isAuthToken(NEW_FORMAT_GHS_TOKEN), TokenType.ServerToServer); + t.is(isAuthToken(`ghs_${makeTestToken(255)}`), TokenType.ServerToServer); t.is( isAuthToken(`github_pat_${makeTestToken(22)}_${makeTestToken(59)}`), TokenType.PersonalAccessFineGrained, @@ -52,6 +52,15 @@ test("isAuthToken", (t) => { ]), undefined, ); + t.is( + isAuthToken(NEW_FORMAT_GHS_TOKEN, [ + { + type: TokenType.ServerToServer, + pattern: /ghs_[A-Za-z0-9._-]{36,}/g, + }, + ]), + TokenType.ServerToServer, + ); }); const testTokens = [ @@ -76,16 +85,12 @@ const testTokens = [ }, { type: TokenType.ServerToServer, - value: `ghs_${makeTestToken()}`, + value: NEW_FORMAT_GHS_TOKEN, }, { type: TokenType.Refresh, value: `ghr_${makeTestToken()}`, }, - { - type: TokenType.AppInstallationAccess, - value: `ghs_${makeTestToken(255)}`, - }, ]; for (const { type, value, checkPattern } of testTokens) { diff --git a/src/artifact-scanner.ts b/src/artifact-scanner.ts index 5f238811a1..dc4eba8895 100644 --- a/src/artifact-scanner.ts +++ b/src/artifact-scanner.ts @@ -17,7 +17,6 @@ export enum TokenType { UserToServer = "User-to-Server Token", ServerToServer = "Server-to-Server Token", Refresh = "Refresh Token", - AppInstallationAccess = "App Installation Access Token", } /** A value of this type associates a token type with its pattern. */ @@ -55,16 +54,12 @@ const GITHUB_TOKEN_PATTERNS: TokenPattern[] = [ }, { type: TokenType.ServerToServer, - pattern: /\bghs_[a-zA-Z0-9]{36}\b/g, + pattern: /ghs_[A-Za-z0-9._-]{36,}/g, }, { type: TokenType.Refresh, pattern: /\bghr_[a-zA-Z0-9]{36}\b/g, }, - { - type: TokenType.AppInstallationAccess, - pattern: /\bghs_[a-zA-Z0-9]{255}\b/g, - }, ]; interface TokenFinding { @@ -109,16 +104,27 @@ function scanFileForTokens( logger: Logger, ): TokenFinding[] { const findings: TokenFinding[] = []; + const seenMatches = new Set(); try { const content = fs.readFileSync(filePath, "utf8"); for (const { type, pattern } of GITHUB_TOKEN_PATTERNS) { - const matches = content.match(pattern); - if (matches) { - for (let i = 0; i < matches.length; i++) { - findings.push({ tokenType: type, filePath: relativePath }); + const regex = new RegExp(pattern.source, pattern.flags); + let matchCount = 0; + + for (const match of content.matchAll(regex)) { + const index = match.index; + if (index === undefined || seenMatches.has(index)) { + continue; } - logger.debug(`Found ${matches.length} ${type}(s) in ${relativePath}`); + + seenMatches.add(index); + findings.push({ tokenType: type, filePath: relativePath }); + matchCount++; + } + + if (matchCount > 0) { + logger.debug(`Found ${matchCount} ${type}(s) in ${relativePath}`); } }