Skip to content

Commit 900f221

Browse files
yaananthCopilot
andauthored
fix: expand merge commit SHA regex and add SHA-256 test cases (#2414)
* fix: expand merge commit SHA regex and add SHA-256 test cases Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test: add checkCommitInfo SHA coverage Add checkCommitInfo tests for SHA-1 and SHA-256 merge messages and reject invalid 50-character hex merge heads.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * style: fix Prettier formatting in test and source files Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 0c366fd commit 900f221

5 files changed

Lines changed: 164 additions & 4 deletions

File tree

__test__/input-helper.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,16 @@ describe('input-helper tests', () => {
133133
expect(settings.commit).toBe('1111111111222222222233333333334444444444')
134134
})
135135

136+
it('sets ref to empty when explicit sha-256', async () => {
137+
inputs.ref =
138+
'1111111111222222222233333333334444444444555555555566666666667777'
139+
const settings: IGitSourceSettings = await inputHelper.getInputs()
140+
expect(settings.ref).toBeFalsy()
141+
expect(settings.commit).toBe(
142+
'1111111111222222222233333333334444444444555555555566666666667777'
143+
)
144+
})
145+
136146
it('sets sha to empty when explicit ref', async () => {
137147
inputs.ref = 'refs/heads/some-other-ref'
138148
const settings: IGitSourceSettings = await inputHelper.getInputs()

__test__/ref-helper.test.ts

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import * as assert from 'assert'
2+
import * as core from '@actions/core'
3+
import * as github from '@actions/github'
24
import * as refHelper from '../lib/ref-helper'
35
import {IGitCommandManager} from '../lib/git-command-manager'
46

57
const commit = '1234567890123456789012345678901234567890'
8+
const sha256Commit =
9+
'1234567890123456789012345678901234567890123456789012345678901234'
610
let git: IGitCommandManager
711

812
describe('ref-helper tests', () => {
@@ -37,6 +41,12 @@ describe('ref-helper tests', () => {
3741
expect(checkoutInfo.startPoint).toBeFalsy()
3842
})
3943

44+
it('getCheckoutInfo sha-256 only', async () => {
45+
const checkoutInfo = await refHelper.getCheckoutInfo(git, '', sha256Commit)
46+
expect(checkoutInfo.ref).toBe(sha256Commit)
47+
expect(checkoutInfo.startPoint).toBeFalsy()
48+
})
49+
4050
it('getCheckoutInfo refs/heads/', async () => {
4151
const checkoutInfo = await refHelper.getCheckoutInfo(
4252
git,
@@ -227,4 +237,142 @@ describe('ref-helper tests', () => {
227237
'+refs/heads/my/branch:refs/remotes/origin/my/branch'
228238
)
229239
})
240+
241+
describe('checkCommitInfo', () => {
242+
const repositoryOwner = 'some-owner'
243+
const repositoryName = 'some-repo'
244+
const ref = 'refs/pull/123/merge'
245+
const sha1Head = '1111111111222222222233333333334444444444'
246+
const sha1Base = 'aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd'
247+
const sha256Head =
248+
'1111111111222222222233333333334444444444555555555566666666667777'
249+
const sha256Base =
250+
'aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffff0000'
251+
let debugSpy: jest.SpyInstance
252+
let getOctokitSpy: jest.SpyInstance
253+
let repoGetSpy: jest.Mock
254+
let originalEventName: string
255+
let originalPayload: unknown
256+
let originalRef: string
257+
let originalSha: string
258+
259+
function setPullRequestContext(
260+
expectedHeadSha: string,
261+
expectedBaseSha: string,
262+
mergeCommit: string
263+
): void {
264+
;(github.context as any).eventName = 'pull_request'
265+
github.context.ref = ref
266+
github.context.sha = mergeCommit
267+
;(github.context as any).payload = {
268+
action: 'synchronize',
269+
after: expectedHeadSha,
270+
number: 123,
271+
pull_request: {
272+
base: {
273+
sha: expectedBaseSha
274+
}
275+
},
276+
repository: {
277+
private: false
278+
}
279+
}
280+
}
281+
282+
beforeEach(() => {
283+
originalEventName = github.context.eventName
284+
originalPayload = github.context.payload
285+
originalRef = github.context.ref
286+
originalSha = github.context.sha
287+
288+
jest.spyOn(github.context, 'repo', 'get').mockReturnValue({
289+
owner: repositoryOwner,
290+
repo: repositoryName
291+
})
292+
debugSpy = jest.spyOn(core, 'debug').mockImplementation(jest.fn())
293+
repoGetSpy = jest.fn(async () => ({}))
294+
getOctokitSpy = jest.spyOn(github, 'getOctokit').mockReturnValue({
295+
rest: {
296+
repos: {
297+
get: repoGetSpy
298+
}
299+
}
300+
} as any)
301+
})
302+
303+
afterEach(() => {
304+
;(github.context as any).eventName = originalEventName
305+
;(github.context as any).payload = originalPayload
306+
github.context.ref = originalRef
307+
github.context.sha = originalSha
308+
jest.restoreAllMocks()
309+
})
310+
311+
it('returns early for SHA-1 merge commit', async () => {
312+
setPullRequestContext(sha1Head, sha1Base, commit)
313+
314+
await refHelper.checkCommitInfo(
315+
'token',
316+
`Merge ${sha1Head} into ${sha1Base}`,
317+
repositoryOwner,
318+
repositoryName,
319+
ref,
320+
commit
321+
)
322+
323+
expect(getOctokitSpy).not.toHaveBeenCalled()
324+
expect(repoGetSpy).not.toHaveBeenCalled()
325+
})
326+
327+
it('matches SHA-256 merge commit info', async () => {
328+
const actualHeadSha =
329+
'9999999999888888888877777777776666666666555555555544444444443333'
330+
setPullRequestContext(sha256Head, sha256Base, sha256Commit)
331+
332+
await refHelper.checkCommitInfo(
333+
'token',
334+
`Merge ${actualHeadSha} into ${sha256Base}`,
335+
repositoryOwner,
336+
repositoryName,
337+
ref,
338+
sha256Commit
339+
)
340+
341+
expect(getOctokitSpy).toHaveBeenCalledWith(
342+
'token',
343+
expect.objectContaining({
344+
userAgent: expect.stringContaining(
345+
`expected_head_sha=${sha256Head};actual_head_sha=${actualHeadSha}`
346+
)
347+
})
348+
)
349+
expect(repoGetSpy).toHaveBeenCalledWith({
350+
owner: repositoryOwner,
351+
repo: repositoryName
352+
})
353+
expect(debugSpy).toHaveBeenCalledWith(
354+
`Expected head sha ${sha256Head}; actual head sha ${actualHeadSha}`
355+
)
356+
expect(debugSpy).not.toHaveBeenCalledWith('Unexpected message format')
357+
})
358+
359+
it('does not match 50-char hex as a valid merge', async () => {
360+
const invalidHeadSha =
361+
'99999999998888888888777777777766666666665555555555'
362+
setPullRequestContext(sha1Head, sha1Base, commit)
363+
364+
await refHelper.checkCommitInfo(
365+
'token',
366+
`Merge ${invalidHeadSha} into ${sha1Base}`,
367+
repositoryOwner,
368+
repositoryName,
369+
ref,
370+
commit
371+
)
372+
373+
expect(getOctokitSpy).not.toHaveBeenCalled()
374+
expect(repoGetSpy).not.toHaveBeenCalled()
375+
expect(debugSpy).toHaveBeenCalledWith('Unexpected message format')
376+
})
377+
})
230378
})

dist/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,7 +2021,7 @@ function getInputs() {
20212021
}
20222022
}
20232023
// SHA?
2024-
else if (result.ref.match(/^[0-9a-fA-F]{40}$/)) {
2024+
else if (result.ref.match(/^(?:[0-9a-fA-F]{40}|[0-9a-fA-F]{64})$/)) {
20252025
result.commit = result.ref;
20262026
result.ref = '';
20272027
}
@@ -2444,7 +2444,7 @@ function checkCommitInfo(token, commitInfo, repositoryOwner, repositoryName, ref
24442444
return;
24452445
}
24462446
// Extract details from message
2447-
const match = commitInfo.match(/Merge ([0-9a-f]{40}) into ([0-9a-f]{40})/);
2447+
const match = commitInfo.match(/Merge ([0-9a-f]{40}|[0-9a-f]{64}) into ([0-9a-f]{40}|[0-9a-f]{64})/);
24482448
if (!match) {
24492449
core.debug('Unexpected message format');
24502450
return;

src/input-helper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export async function getInputs(): Promise<IGitSourceSettings> {
7171
}
7272
}
7373
// SHA?
74-
else if (result.ref.match(/^[0-9a-fA-F]{40}$/)) {
74+
else if (result.ref.match(/^(?:[0-9a-fA-F]{40}|[0-9a-fA-F]{64})$/)) {
7575
result.commit = result.ref
7676
result.ref = ''
7777
}

src/ref-helper.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,9 @@ export async function checkCommitInfo(
258258
}
259259

260260
// Extract details from message
261-
const match = commitInfo.match(/Merge ([0-9a-f]{40}) into ([0-9a-f]{40})/)
261+
const match = commitInfo.match(
262+
/Merge ([0-9a-f]{40}|[0-9a-f]{64}) into ([0-9a-f]{40}|[0-9a-f]{64})/
263+
)
262264
if (!match) {
263265
core.debug('Unexpected message format')
264266
return

0 commit comments

Comments
 (0)