secure actions execution context

This commit is contained in:
Conor Sloan
2024-08-28 12:10:13 +01:00
parent 8a96626c28
commit 86a49c7f6a
6 changed files with 115 additions and 68 deletions
+29 -20
View File
@@ -48,7 +48,7 @@ describe('config.resolvePublishActionOptions', () => {
it('throws an error when the ref is not provided', async () => { it('throws an error when the ref is not provided', async () => {
getInputMock.mockReturnValueOnce('token') getInputMock.mockReturnValueOnce('token')
process.env.GITHUB_REF = '' github.context.ref = ''
await expect(cfg.resolvePublishActionOptions()).rejects.toThrow( await expect(cfg.resolvePublishActionOptions()).rejects.toThrow(
'Could not find GITHUB_REF.' 'Could not find GITHUB_REF.'
@@ -66,7 +66,7 @@ describe('config.resolvePublishActionOptions', () => {
it('throws an error when the repository is not provided', async () => { it('throws an error when the repository is not provided', async () => {
getInputMock.mockReturnValueOnce('token') getInputMock.mockReturnValueOnce('token')
process.env.GITHUB_REPOSITORY = '' github.context.payload.repository = undefined
await expect(cfg.resolvePublishActionOptions()).rejects.toThrow( await expect(cfg.resolvePublishActionOptions()).rejects.toThrow(
'Could not find Repository.' 'Could not find Repository.'
@@ -75,7 +75,7 @@ describe('config.resolvePublishActionOptions', () => {
it('throws an error when the apiBaseUrl is not provided', async () => { it('throws an error when the apiBaseUrl is not provided', async () => {
getInputMock.mockReturnValueOnce('token') getInputMock.mockReturnValueOnce('token')
process.env.GITHUB_API_URL = '' github.context.apiUrl = ''
await expect(cfg.resolvePublishActionOptions()).rejects.toThrow( await expect(cfg.resolvePublishActionOptions()).rejects.toThrow(
'Could not find GITHUB_API_URL.' 'Could not find GITHUB_API_URL.'
@@ -93,7 +93,7 @@ describe('config.resolvePublishActionOptions', () => {
it('throws an error when the sha is not provided', async () => { it('throws an error when the sha is not provided', async () => {
getInputMock.mockReturnValueOnce('token') getInputMock.mockReturnValueOnce('token')
process.env.GITHUB_SHA = '' github.context.sha = ''
await expect(cfg.resolvePublishActionOptions()).rejects.toThrow( await expect(cfg.resolvePublishActionOptions()).rejects.toThrow(
'Could not find GITHUB_SHA.' 'Could not find GITHUB_SHA.'
@@ -102,7 +102,7 @@ describe('config.resolvePublishActionOptions', () => {
it('throws an error when the githubServerUrl is not provided', async () => { it('throws an error when the githubServerUrl is not provided', async () => {
getInputMock.mockReturnValueOnce('token') getInputMock.mockReturnValueOnce('token')
process.env.GITHUB_SERVER_URL = '' github.context.serverUrl = ''
await expect(cfg.resolvePublishActionOptions()).rejects.toThrow( await expect(cfg.resolvePublishActionOptions()).rejects.toThrow(
'Could not find GITHUB_SERVER_URL.' 'Could not find GITHUB_SERVER_URL.'
@@ -235,7 +235,7 @@ describe('config.resolvePublishActionOptions', () => {
ownerId: 'repositoryOwnerId' ownerId: 'repositoryOwnerId'
}) })
process.env.GITHUB_SERVER_URL = 'https://github-enterprise.com' github.context.serverUrl = 'https://github-enterprise.com'
const options = await cfg.resolvePublishActionOptions() const options = await cfg.resolvePublishActionOptions()
@@ -296,27 +296,36 @@ describe('config.serializeOptions', () => {
}) })
function configureEventContext(): void { function configureEventContext(): void {
process.env.GITHUB_REF = 'ref' github.context.ref = 'ref'
process.env.GITHUB_WORKSPACE = 'workspaceDir' github.context.eventName = 'release'
process.env.GITHUB_REPOSITORY = 'nameWithOwner' github.context.apiUrl = 'apiBaseUrl'
process.env.GITHUB_API_URL = 'apiBaseUrl' github.context.sha = 'sha'
github.context.serverUrl = 'https://github.com/'
github.context.payload = {
repository: {
full_name: 'nameWithOwner',
name: 'name',
owner: {
login: 'owner'
}
}
}
process.env.RUNNER_TEMP = 'runnerTempDir' process.env.RUNNER_TEMP = 'runnerTempDir'
process.env.GITHUB_SHA = 'sha' process.env.GITHUB_WORKSPACE = 'workspaceDir'
process.env.GITHUB_SERVER_URL = 'https://github.com/'
process.env.GITHUB_REPOSITORY_ID = 'repositoryId' process.env.GITHUB_REPOSITORY_ID = 'repositoryId'
process.env.GITHUB_REPOSITORY_OWNER_ID = 'repositoryOwnerId' process.env.GITHUB_REPOSITORY_OWNER_ID = 'repositoryOwnerId'
github.context.eventName = 'release'
} }
function clearEventContext(): void { function clearEventContext(): void {
process.env.GITHUB_REF = '' github.context.ref = ''
process.env.GITHUB_WORKSPACE = '' github.context.eventName = ''
process.env.GITHUB_REPOSITORY = '' github.context.apiUrl = ''
process.env.GITHUB_API_URL = '' github.context.sha = ''
github.context.serverUrl = ''
github.context.payload = {}
process.env.RUNNER_TEMP = '' process.env.RUNNER_TEMP = ''
process.env.GITHUB_SHA = '' process.env.GITHUB_WORKSPACE = ''
process.env.GITHUB_SERVER_URL = ''
process.env.GITHUB_REPOSITORY_ID = '' process.env.GITHUB_REPOSITORY_ID = ''
process.env.GITHUB_REPOSITORY_OWNER_ID = '' process.env.GITHUB_REPOSITORY_OWNER_ID = ''
github.context.eventName = ''
} }
+17 -3
View File
@@ -256,18 +256,32 @@ describe('ensureCorrectShaCheckedOut', () => {
it('throws an error if the correct SHA is not checked out', async () => { it('throws an error if the correct SHA is not checked out', async () => {
await expect( await expect(
fsHelper.ensureTagAndRefCheckedOut(`refs/tags/${tag1}`, commit1, dir) fsHelper.ensureTagAndRefCheckedOut(`refs/tags/${tag1}`, commit1, dir)
).rejects.toThrow() ).rejects.toThrow(
'The expected commit associated with the tag refs/tags/tag1 is not checked out.'
)
})
it('throws if there is an issue getting sha for tag', async () => {
await expect(async () =>
fsHelper.ensureTagAndRefCheckedOut(
`refs/tags/some-unknown-tag`,
commit2,
dir
)
).rejects.toThrow('Error retrieving commit associated with tag')
}) })
it('throws an error if the sha of the tag does not match expected sha', async () => { it('throws an error if the sha of the tag does not match expected sha', async () => {
await expect(async () => await expect(async () =>
fsHelper.ensureTagAndRefCheckedOut(`refs/tags/${tag1}`, commit2, dir) fsHelper.ensureTagAndRefCheckedOut(`refs/tags/${tag1}`, commit2, dir)
).rejects.toThrow() ).rejects.toThrow(
'The commit associated with the tag refs/tags/tag1 does not match the SHA of the commit provided by the actions context.'
)
}) })
it('throws if the provided ref is not a tag ref', async () => { it('throws if the provided ref is not a tag ref', async () => {
await expect(async () => await expect(async () =>
fsHelper.ensureTagAndRefCheckedOut(`refs/heads/main`, commit2, dir) fsHelper.ensureTagAndRefCheckedOut(`refs/heads/main`, commit2, dir)
).rejects.toThrow() ).rejects.toThrow('Tag ref provided is not in expected format.')
}) })
}) })
+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="116" height="20" role="img" aria-label="Coverage: 97.56%"><title>Coverage: 97.56%</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="116" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="63" height="20" fill="#555"/><rect x="63" width="53" height="20" fill="#4c1"/><rect width="116" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">Coverage</text><text x="325" y="140" transform="scale(.1)" fill="#fff" textLength="530">Coverage</text><text aria-hidden="true" x="885" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">97.56%</text><text x="885" y="140" transform="scale(.1)" fill="#fff" textLength="430">97.56%</text></g></svg> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="116" height="20" role="img" aria-label="Coverage: 97.31%"><title>Coverage: 97.31%</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="116" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="63" height="20" fill="#555"/><rect x="63" width="53" height="20" fill="#4c1"/><rect width="116" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">Coverage</text><text x="325" y="140" transform="scale(.1)" fill="#fff" textLength="530">Coverage</text><text aria-hidden="true" x="885" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">97.31%</text><text x="885" y="140" transform="scale(.1)" fill="#fff" textLength="430">97.31%</text></g></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Generated Vendored
+32 -20
View File
@@ -106410,35 +106410,35 @@ async function resolvePublishActionOptions() {
if (event === '') { if (event === '') {
throw new Error(`Could not find event name.`); throw new Error(`Could not find event name.`);
} }
// Environment Variables const ref = github.context.ref || '';
const ref = process.env.GITHUB_REF || '';
if (ref === '') { if (ref === '') {
throw new Error(`Could not find GITHUB_REF.`); throw new Error(`Could not find GITHUB_REF.`);
} }
const nameWithOwner = github.context.payload.repository?.full_name || '';
if (nameWithOwner === '') {
throw new Error(`Could not find Repository.`);
}
const sha = github.context.sha || '';
if (sha === '') {
throw new Error(`Could not find GITHUB_SHA.`);
}
const apiBaseUrl = github.context.apiUrl || '';
if (apiBaseUrl === '') {
throw new Error(`Could not find GITHUB_API_URL.`);
}
const githubServerUrl = github.context.serverUrl || '';
if (githubServerUrl === '') {
throw new Error(`Could not find GITHUB_SERVER_URL.`);
}
// Environment Variables
const workspaceDir = process.env.GITHUB_WORKSPACE || ''; const workspaceDir = process.env.GITHUB_WORKSPACE || '';
if (workspaceDir === '') { if (workspaceDir === '') {
throw new Error(`Could not find GITHUB_WORKSPACE.`); throw new Error(`Could not find GITHUB_WORKSPACE.`);
} }
const nameWithOwner = process.env.GITHUB_REPOSITORY || '';
if (nameWithOwner === '') {
throw new Error(`Could not find Repository.`);
}
const apiBaseUrl = process.env.GITHUB_API_URL || '';
if (apiBaseUrl === '') {
throw new Error(`Could not find GITHUB_API_URL.`);
}
const runnerTempDir = process.env.RUNNER_TEMP || ''; const runnerTempDir = process.env.RUNNER_TEMP || '';
if (runnerTempDir === '') { if (runnerTempDir === '') {
throw new Error(`Could not find RUNNER_TEMP.`); throw new Error(`Could not find RUNNER_TEMP.`);
} }
const sha = process.env.GITHUB_SHA || '';
if (sha === '') {
throw new Error(`Could not find GITHUB_SHA.`);
}
const githubServerUrl = process.env.GITHUB_SERVER_URL || '';
if (githubServerUrl === '') {
throw new Error(`Could not find GITHUB_SERVER_URL.`);
}
const repositoryId = process.env.GITHUB_REPOSITORY_ID || ''; const repositoryId = process.env.GITHUB_REPOSITORY_ID || '';
if (repositoryId === '') { if (repositoryId === '') {
throw new Error(`Could not find GITHUB_REPOSITORY_ID.`); throw new Error(`Could not find GITHUB_REPOSITORY_ID.`);
@@ -106622,11 +106622,23 @@ async function ensureTagAndRefCheckedOut(tagRef, expectedSha, gitDir) {
throw new Error(`Tag ref provided is not in expected format.`); throw new Error(`Tag ref provided is not in expected format.`);
} }
const git = simpleGit.simpleGit(gitDir); const git = simpleGit.simpleGit(gitDir);
const tagCommitSha = await git.raw(['rev-parse', '--verify', tagRef]); let tagCommitSha;
try {
tagCommitSha = await git.raw(['rev-parse', '--verify', tagRef]);
}
catch (err) {
throw new Error(`Error retrieving commit associated with tag: ${err}`);
}
if (tagCommitSha.trim() !== expectedSha) { if (tagCommitSha.trim() !== expectedSha) {
throw new Error(`The commit associated with the tag ${tagRef} does not match the SHA of the commit provided by the actions context.`); throw new Error(`The commit associated with the tag ${tagRef} does not match the SHA of the commit provided by the actions context.`);
} }
const currentlyCheckedOutSha = await git.revparse(['HEAD']); let currentlyCheckedOutSha;
try {
currentlyCheckedOutSha = await git.revparse(['HEAD']);
}
catch (err) {
throw new Error(`Error validating checked out tag and ref: ${err}`);
}
if (currentlyCheckedOutSha.trim() !== expectedSha) { if (currentlyCheckedOutSha.trim() !== expectedSha) {
throw new Error(`The expected commit associated with the tag ${tagRef} is not checked out.`); throw new Error(`The expected commit associated with the tag ${tagRef} is not checked out.`);
} }
+23 -22
View File
@@ -45,42 +45,43 @@ export async function resolvePublishActionOptions(): Promise<PublishActionOption
throw new Error(`Could not find event name.`) throw new Error(`Could not find event name.`)
} }
// Environment Variables const ref: string = github.context.ref || ''
const ref: string = process.env.GITHUB_REF || ''
if (ref === '') { if (ref === '') {
throw new Error(`Could not find GITHUB_REF.`) throw new Error(`Could not find GITHUB_REF.`)
} }
const nameWithOwner: string =
github.context.payload.repository?.full_name || ''
if (nameWithOwner === '') {
throw new Error(`Could not find Repository.`)
}
const sha: string = github.context.sha || ''
if (sha === '') {
throw new Error(`Could not find GITHUB_SHA.`)
}
const apiBaseUrl: string = github.context.apiUrl || ''
if (apiBaseUrl === '') {
throw new Error(`Could not find GITHUB_API_URL.`)
}
const githubServerUrl = github.context.serverUrl || ''
if (githubServerUrl === '') {
throw new Error(`Could not find GITHUB_SERVER_URL.`)
}
// Environment Variables
const workspaceDir: string = process.env.GITHUB_WORKSPACE || '' const workspaceDir: string = process.env.GITHUB_WORKSPACE || ''
if (workspaceDir === '') { if (workspaceDir === '') {
throw new Error(`Could not find GITHUB_WORKSPACE.`) throw new Error(`Could not find GITHUB_WORKSPACE.`)
} }
const nameWithOwner: string = process.env.GITHUB_REPOSITORY || ''
if (nameWithOwner === '') {
throw new Error(`Could not find Repository.`)
}
const apiBaseUrl: string = process.env.GITHUB_API_URL || ''
if (apiBaseUrl === '') {
throw new Error(`Could not find GITHUB_API_URL.`)
}
const runnerTempDir: string = process.env.RUNNER_TEMP || '' const runnerTempDir: string = process.env.RUNNER_TEMP || ''
if (runnerTempDir === '') { if (runnerTempDir === '') {
throw new Error(`Could not find RUNNER_TEMP.`) throw new Error(`Could not find RUNNER_TEMP.`)
} }
const sha: string = process.env.GITHUB_SHA || ''
if (sha === '') {
throw new Error(`Could not find GITHUB_SHA.`)
}
const githubServerUrl = process.env.GITHUB_SERVER_URL || ''
if (githubServerUrl === '') {
throw new Error(`Could not find GITHUB_SERVER_URL.`)
}
const repositoryId = process.env.GITHUB_REPOSITORY_ID || '' const repositoryId = process.env.GITHUB_REPOSITORY_ID || ''
if (repositoryId === '') { if (repositoryId === '') {
throw new Error(`Could not find GITHUB_REPOSITORY_ID.`) throw new Error(`Could not find GITHUB_REPOSITORY_ID.`)
+13 -2
View File
@@ -129,14 +129,25 @@ export async function ensureTagAndRefCheckedOut(
const git: simpleGit.SimpleGit = simpleGit.simpleGit(gitDir) const git: simpleGit.SimpleGit = simpleGit.simpleGit(gitDir)
const tagCommitSha = await git.raw(['rev-parse', '--verify', tagRef]) let tagCommitSha: string
try {
tagCommitSha = await git.raw(['rev-parse', '--verify', tagRef])
} catch (err) {
throw new Error(`Error retrieving commit associated with tag: ${err}`)
}
if (tagCommitSha.trim() !== expectedSha) { if (tagCommitSha.trim() !== expectedSha) {
throw new Error( throw new Error(
`The commit associated with the tag ${tagRef} does not match the SHA of the commit provided by the actions context.` `The commit associated with the tag ${tagRef} does not match the SHA of the commit provided by the actions context.`
) )
} }
const currentlyCheckedOutSha = await git.revparse(['HEAD']) let currentlyCheckedOutSha: string
try {
currentlyCheckedOutSha = await git.revparse(['HEAD'])
} catch (err) {
throw new Error(`Error validating checked out tag and ref: ${err}`)
}
if (currentlyCheckedOutSha.trim() !== expectedSha) { if (currentlyCheckedOutSha.trim() !== expectedSha) {
throw new Error( throw new Error(
`The expected commit associated with the tag ${tagRef} is not checked out.` `The expected commit associated with the tag ${tagRef} is not checked out.`