Skip to content

Commit 2306df3

Browse files
committed
chore: Bump oktokit/auth-app (github-aws-runners#904)
The newer version of the library requires different input data for yyy in the createAppAuth(xxx)(yyy) function, and also returns a different data structure for the 'app' and 'installation' scenarios. - Set dependency to version 3.6.0 - Fix some (misleading) test descriptions
1 parent 946b2ea commit 2306df3

File tree

10 files changed

+110
-71
lines changed

10 files changed

+110
-71
lines changed

modules/runners/lambdas/runners/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
},
3636
"dependencies": {
3737
"@aws-sdk/client-ssm": "^3.25.0",
38-
"@octokit/auth-app": "3.4.0",
38+
"@octokit/auth-app": "3.6.0",
3939
"@octokit/rest": "^18.3.5",
4040
"@octokit/types": "^6.25.0",
4141
"@types/aws-lambda": "^8.10.82",

modules/runners/lambdas/runners/src/scale-runners/gh-auth.test.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createOctoClient, createGithubAuth } from './gh-auth';
1+
import { createOctoClient, createGithubAppAuth, createGithubInstallationAuth } from './gh-auth';
22
import nock from 'nock';
33
import { createAppAuth } from '@octokit/auth-app';
44

@@ -36,7 +36,7 @@ beforeEach(() => {
3636
nock.disableNetConnect();
3737
});
3838

39-
describe('Test createGithubAuth', () => {
39+
describe('Test createOctoClient', () => {
4040
test('Creates app client to GitHub public', async () => {
4141
// Arrange
4242
const token = '123456';
@@ -62,7 +62,7 @@ describe('Test createGithubAuth', () => {
6262
});
6363
});
6464

65-
describe('Test createGithubAuth', () => {
65+
describe('Test createGithubAppAuth', () => {
6666
const mockedCreatAppAuth = createAppAuth as unknown as jest.Mock;
6767
const mockedDefaults = jest.spyOn(request, 'defaults');
6868
let mockedRequestInterface: MockProxy<RequestInterface>;
@@ -99,7 +99,7 @@ describe('Test createGithubAuth', () => {
9999
});
100100

101101
// Act
102-
const result = await createGithubAuth(installationId, authType);
102+
const result = await createGithubAppAuth(installationId);
103103

104104
// Assert
105105
expect(getParameterValue).toBeCalledWith(PARAMETER_GITHUB_APP_ID_NAME);
@@ -144,7 +144,7 @@ describe('Test createGithubAuth', () => {
144144
});
145145

146146
// Act
147-
const result = await createGithubAuth(installationId, authType, githubServerUrl);
147+
const result = await createGithubAppAuth(installationId, githubServerUrl);
148148

149149
// Assert
150150
expect(getParameterValue).toBeCalledWith(PARAMETER_GITHUB_APP_ID_NAME);
@@ -189,7 +189,7 @@ describe('Test createGithubAuth', () => {
189189
});
190190

191191
// Act
192-
const result = await createGithubAuth(installationId, authType, githubServerUrl);
192+
const result = await createGithubAppAuth(installationId, githubServerUrl);
193193

194194
// Assert
195195
expect(getParameterValue).toBeCalledWith(PARAMETER_GITHUB_APP_ID_NAME);

modules/runners/lambdas/runners/src/scale-runners/gh-auth.ts

+27-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { Octokit } from '@octokit/rest';
22
import { request } from '@octokit/request';
33
import { createAppAuth } from '@octokit/auth-app';
4-
import { StrategyOptions, AppAuthentication } from '@octokit/auth-app/dist-types/types';
4+
import {
5+
StrategyOptions,
6+
AppAuthentication,
7+
AppAuthOptions,
8+
InstallationAuthOptions,
9+
InstallationAccessTokenAuthentication,
10+
AuthInterface,
11+
} from '@octokit/auth-app/dist-types/types';
512
import { OctokitOptions } from '@octokit/core/dist-types/types';
613
import { getParameterValue } from './ssm';
714

@@ -16,13 +23,28 @@ export async function createOctoClient(token: string, ghesApiUrl = ''): Promise<
1623
return new Octokit(ocktokitOptions);
1724
}
1825

19-
export async function createGithubAuth(
26+
export async function createGithubAppAuth(
2027
installationId: number | undefined,
21-
authType: 'app' | 'installation',
2228
ghesApiUrl = '',
2329
): Promise<AppAuthentication> {
30+
const auth = await createAuth(installationId, ghesApiUrl);
31+
const appAuthOptions: AppAuthOptions = { type: 'app' };
32+
return await auth(appAuthOptions);
33+
}
34+
35+
export async function createGithubInstallationAuth(
36+
installationId: number | undefined,
37+
ghesApiUrl = '',
38+
): Promise<InstallationAccessTokenAuthentication> {
39+
const auth = await createAuth(installationId, ghesApiUrl);
40+
const installationAuthOptions: InstallationAuthOptions = { type: 'installation', installationId };
41+
return await auth(installationAuthOptions);
42+
}
43+
44+
async function createAuth(installationId: number | undefined, ghesApiUrl: string): Promise<AuthInterface> {
45+
const appId = parseInt(await getParameterValue(process.env.PARAMETER_GITHUB_APP_ID_NAME));
2446
let authOptions: StrategyOptions = {
25-
appId: parseInt(await getParameterValue(process.env.PARAMETER_GITHUB_APP_ID_NAME)),
47+
appId,
2648
privateKey: Buffer.from(
2749
await getParameterValue(process.env.PARAMETER_GITHUB_APP_KEY_BASE64_NAME),
2850
'base64',
@@ -38,6 +60,5 @@ export async function createGithubAuth(
3860
baseUrl: ghesApiUrl,
3961
});
4062
}
41-
const result = (await createAppAuth(authOptions)({ type: authType })) as AppAuthentication;
42-
return result;
63+
return createAppAuth(authOptions);
4364
}

modules/runners/lambdas/runners/src/scale-runners/scale-down.test.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ jest.mock('./runners');
2727
jest.mock('./gh-auth');
2828

2929
const mocktokit = Octokit as jest.MockedClass<typeof Octokit>;
30-
const mockedAuth = mocked(ghAuth.createGithubAuth, true);
30+
const mockedAppAuth = mocked(ghAuth.createGithubAppAuth, true);
31+
const mockedInstallationAuth = mocked(ghAuth.createGithubInstallationAuth, true);
3132
const mockCreateClient = mocked(ghAuth.createOctoClient, true);
3233

3334
export interface TestData {
@@ -153,12 +154,21 @@ describe('scaleDown', () => {
153154

154155
describe('no runners running', () => {
155156
beforeAll(() => {
156-
mockedAuth.mockResolvedValue({
157+
mockedAppAuth.mockResolvedValue({
157158
type: 'app',
158159
token: 'token',
159160
appId: 1,
160161
expiresAt: 'some-date',
161162
});
163+
mockedInstallationAuth.mockResolvedValue({
164+
type: 'token',
165+
tokenType: 'installation',
166+
token: 'token',
167+
createdAt: 'some-date',
168+
expiresAt: 'some-date',
169+
permissions: {},
170+
repositorySelection: 'all',
171+
});
162172
mockCreateClient.mockResolvedValue(new mocktokit());
163173
const mockListRunners = mocked(listRunners);
164174
mockListRunners.mockImplementation(async () => []);

modules/runners/lambdas/runners/src/scale-runners/scale-down.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import moment from 'moment';
33
import yn from 'yn';
44
import { listRunners, RunnerInfo, terminateRunner } from './runners';
55
import { getIdleRunnerCount, ScalingDownConfig } from './scale-down-config';
6-
import { createOctoClient, createGithubAuth } from './gh-auth';
6+
import { createOctoClient, createGithubAppAuth, createGithubInstallationAuth } from './gh-auth';
77

88
interface Repo {
99
repoName: string;
@@ -35,7 +35,7 @@ function createGitHubClientForRunnerFactory(): (runner: RunnerInfo, orgLevel: bo
3535
if (ghesBaseUrl) {
3636
ghesApiUrl = `${ghesBaseUrl}/api/v3`;
3737
}
38-
const ghAuth = await createGithubAuth(undefined, 'app', ghesApiUrl);
38+
const ghAuth = await createGithubAppAuth(undefined, ghesApiUrl);
3939
const githubClient = await createOctoClient(ghAuth.token, ghesApiUrl);
4040
const installationId = orgLevel
4141
? (
@@ -49,7 +49,7 @@ function createGitHubClientForRunnerFactory(): (runner: RunnerInfo, orgLevel: bo
4949
repo: repo.repoName,
5050
})
5151
).data.id;
52-
const ghAuth2 = await createGithubAuth(installationId, 'installation', ghesApiUrl);
52+
const ghAuth2 = await createGithubInstallationAuth(installationId, ghesApiUrl);
5353
const octokit = await createOctoClient(ghAuth2.token, ghesApiUrl);
5454
cache.set(key, octokit);
5555

modules/runners/lambdas/runners/src/scale-runners/scale-up.test.ts

+46-36
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ jest.mock('./runners');
2626
jest.mock('./gh-auth');
2727

2828
const mocktokit = Octokit as jest.MockedClass<typeof Octokit>;
29-
const mockedAuth = mocked(ghAuth.createGithubAuth, true);
29+
const mockedAppAuth = mocked(ghAuth.createGithubAppAuth, true);
30+
const mockedInstallationAuth = mocked(ghAuth.createGithubInstallationAuth, true);
3031
const mockCreateClient = mocked(ghAuth.createOctoClient, true);
3132

3233
const TEST_DATA: scaleUpModule.ActionRequestMessage = {
@@ -115,12 +116,21 @@ beforeEach(() => {
115116

116117
describe('scaleUp with GHES', () => {
117118
beforeEach(() => {
118-
mockedAuth.mockResolvedValue({
119+
mockedAppAuth.mockResolvedValue({
119120
type: 'app',
120121
token: 'token',
121122
appId: TEST_DATA.installationId,
122123
expiresAt: 'some-date',
123124
});
125+
mockedInstallationAuth.mockResolvedValue({
126+
type: 'token',
127+
tokenType: 'installation',
128+
token: 'token',
129+
createdAt: 'some-date',
130+
expiresAt: 'some-date',
131+
permissions: {},
132+
repositorySelection: 'all',
133+
});
124134

125135
mockCreateClient.mockResolvedValue(new mocktokit());
126136

@@ -180,26 +190,23 @@ describe('scaleUp with GHES', () => {
180190
});
181191

182192
it('does not retrieve installation id if already set', async () => {
183-
const spy = jest.spyOn(ghAuth, 'createGithubAuth');
193+
const appSpy = jest.spyOn(ghAuth, 'createGithubAppAuth');
194+
const installationSpy = jest.spyOn(ghAuth, 'createGithubInstallationAuth');
184195
await scaleUpModule.scaleUp('aws:sqs', TEST_DATA);
185196
expect(mockOctokit.apps.getOrgInstallation).not.toBeCalled();
186197
expect(mockOctokit.apps.getRepoInstallation).not.toBeCalled();
187-
expect(spy).toBeCalledWith(
188-
TEST_DATA.installationId,
189-
'installation',
190-
'https://github.enterprise.something/api/v3',
191-
);
198+
expect(appSpy).not.toBeCalled();
199+
expect(installationSpy).toBeCalledWith(TEST_DATA.installationId, 'https://github.enterprise.something/api/v3');
192200
});
193201

194202
it('retrieves installation id if not set', async () => {
195-
const spy = jest.spyOn(ghAuth, 'createGithubAuth');
203+
const appSpy = jest.spyOn(ghAuth, 'createGithubAppAuth');
204+
const installationSpy = jest.spyOn(ghAuth, 'createGithubInstallationAuth');
196205
await scaleUpModule.scaleUp('aws:sqs', TEST_DATA_WITH_ZERO_INSTALL_ID);
197206
expect(mockOctokit.apps.getRepoInstallation).not.toBeCalled();
198-
expect(spy).toHaveBeenNthCalledWith(1, undefined, 'app', 'https://github.enterprise.something/api/v3');
199-
expect(spy).toHaveBeenNthCalledWith(
200-
2,
207+
expect(appSpy).toHaveBeenCalledWith(undefined, 'https://github.enterprise.something/api/v3');
208+
expect(installationSpy).toHaveBeenCalledWith(
201209
TEST_DATA.installationId,
202-
'installation',
203210
'https://github.enterprise.something/api/v3',
204211
);
205212
});
@@ -271,7 +278,7 @@ describe('scaleUp with GHES', () => {
271278
expect(mockOctokit.actions.createRegistrationTokenForOrg).not.toBeCalled();
272279
expect(mockOctokit.actions.createRegistrationTokenForRepo).not.toBeCalled();
273280
});
274-
281+
275282
it('creates a token when maximum runners has not been reached', async () => {
276283
await scaleUpModule.scaleUp('aws:sqs', TEST_DATA);
277284
expect(mockOctokit.actions.createRegistrationTokenForOrg).not.toBeCalled();
@@ -291,30 +298,27 @@ describe('scaleUp with GHES', () => {
291298
});
292299

293300
it('does not retrieve installation id if already set', async () => {
294-
const spy = jest.spyOn(ghAuth, 'createGithubAuth');
301+
const appSpy = jest.spyOn(ghAuth, 'createGithubAppAuth');
302+
const installationSpy = jest.spyOn(ghAuth, 'createGithubInstallationAuth');
295303
await scaleUpModule.scaleUp('aws:sqs', TEST_DATA);
296304
expect(mockOctokit.apps.getOrgInstallation).not.toBeCalled();
297305
expect(mockOctokit.apps.getRepoInstallation).not.toBeCalled();
298-
expect(spy).toBeCalledWith(
299-
TEST_DATA.installationId,
300-
'installation',
301-
'https://github.enterprise.something/api/v3',
302-
);
306+
expect(appSpy).not.toBeCalled();
307+
expect(installationSpy).toBeCalledWith(TEST_DATA.installationId, 'https://github.enterprise.something/api/v3');
303308
});
304309

305310
it('retrieves installation id if not set', async () => {
306-
const spy = jest.spyOn(ghAuth, 'createGithubAuth');
311+
const appSpy = jest.spyOn(ghAuth, 'createGithubAppAuth');
312+
const installationSpy = jest.spyOn(ghAuth, 'createGithubInstallationAuth');
307313
await scaleUpModule.scaleUp('aws:sqs', TEST_DATA_WITH_ZERO_INSTALL_ID);
308314
expect(mockOctokit.apps.getOrgInstallation).not.toBeCalled();
309315
expect(mockOctokit.apps.getRepoInstallation).toBeCalledWith({
310316
owner: TEST_DATA.repositoryOwner,
311317
repo: TEST_DATA.repositoryName,
312318
});
313-
expect(spy).toHaveBeenNthCalledWith(1, undefined, 'app', 'https://github.enterprise.something/api/v3');
314-
expect(spy).toHaveBeenNthCalledWith(
315-
2,
319+
expect(appSpy).toHaveBeenCalledWith(undefined, 'https://github.enterprise.something/api/v3');
320+
expect(installationSpy).toHaveBeenCalledWith(
316321
TEST_DATA.installationId,
317-
'installation',
318322
'https://github.enterprise.something/api/v3',
319323
);
320324
});
@@ -371,20 +375,23 @@ describe('scaleUp with public GH', () => {
371375
});
372376

373377
it('does not retrieve installation id if already set', async () => {
374-
const spy = jest.spyOn(ghAuth, 'createGithubAuth');
378+
const appSpy = jest.spyOn(ghAuth, 'createGithubAppAuth');
379+
const installationSpy = jest.spyOn(ghAuth, 'createGithubInstallationAuth');
375380
await scaleUpModule.scaleUp('aws:sqs', TEST_DATA);
376381
expect(mockOctokit.apps.getOrgInstallation).not.toBeCalled();
377382
expect(mockOctokit.apps.getRepoInstallation).not.toBeCalled();
378-
expect(spy).toBeCalledWith(TEST_DATA.installationId, 'installation', '');
383+
expect(appSpy).not.toBeCalled();
384+
expect(installationSpy).toBeCalledWith(TEST_DATA.installationId, '');
379385
});
380386

381387
it('retrieves installation id if not set', async () => {
382-
const spy = jest.spyOn(ghAuth, 'createGithubAuth');
388+
const appSpy = jest.spyOn(ghAuth, 'createGithubAppAuth');
389+
const installationSpy = jest.spyOn(ghAuth, 'createGithubInstallationAuth');
383390
await scaleUpModule.scaleUp('aws:sqs', TEST_DATA_WITH_ZERO_INSTALL_ID);
384391
expect(mockOctokit.apps.getOrgInstallation).toBeCalled();
385392
expect(mockOctokit.apps.getRepoInstallation).not.toBeCalled();
386-
expect(spy).toHaveBeenNthCalledWith(1, undefined, 'app', '');
387-
expect(spy).toHaveBeenNthCalledWith(2, TEST_DATA.installationId, 'installation', '');
393+
expect(appSpy).toHaveBeenCalledWith(undefined, '');
394+
expect(installationSpy).toHaveBeenCalledWith(TEST_DATA.installationId, '');
388395
});
389396

390397
it('does not list runners when no workflows are queued', async () => {
@@ -481,7 +488,7 @@ describe('scaleUp with public GH', () => {
481488
expect(mockOctokit.actions.createRegistrationTokenForOrg).not.toBeCalled();
482489
expect(mockOctokit.actions.createRegistrationTokenForRepo).not.toBeCalled();
483490
});
484-
491+
485492
it('creates a token when maximum runners has not been reached', async () => {
486493
await scaleUpModule.scaleUp('aws:sqs', TEST_DATA);
487494
expect(mockOctokit.actions.createRegistrationTokenForOrg).not.toBeCalled();
@@ -492,20 +499,23 @@ describe('scaleUp with public GH', () => {
492499
});
493500

494501
it('does not retrieve installation id if already set', async () => {
495-
const spy = jest.spyOn(ghAuth, 'createGithubAuth');
502+
const appSpy = jest.spyOn(ghAuth, 'createGithubAppAuth');
503+
const installationSpy = jest.spyOn(ghAuth, 'createGithubInstallationAuth');
496504
await scaleUpModule.scaleUp('aws:sqs', TEST_DATA);
497505
expect(mockOctokit.apps.getOrgInstallation).not.toBeCalled();
498506
expect(mockOctokit.apps.getRepoInstallation).not.toBeCalled();
499-
expect(spy).toBeCalledWith(TEST_DATA.installationId, 'installation', '');
507+
expect(appSpy).not.toBeCalled();
508+
expect(installationSpy).toBeCalledWith(TEST_DATA.installationId, '');
500509
});
501510

502511
it('retrieves installation id if not set', async () => {
503-
const spy = jest.spyOn(ghAuth, 'createGithubAuth');
512+
const appSpy = jest.spyOn(ghAuth, 'createGithubAppAuth');
513+
const installationSpy = jest.spyOn(ghAuth, 'createGithubInstallationAuth');
504514
await scaleUpModule.scaleUp('aws:sqs', TEST_DATA_WITH_ZERO_INSTALL_ID);
505515
expect(mockOctokit.apps.getOrgInstallation).not.toBeCalled();
506516
expect(mockOctokit.apps.getRepoInstallation).toBeCalled();
507-
expect(spy).toHaveBeenNthCalledWith(1, undefined, 'app', '');
508-
expect(spy).toHaveBeenNthCalledWith(2, TEST_DATA.installationId, 'installation', '');
517+
expect(appSpy).toHaveBeenCalledWith(undefined, '');
518+
expect(installationSpy).toHaveBeenCalledWith(TEST_DATA.installationId, '');
509519
});
510520

511521
it('creates a runner with correct config and labels', async () => {

modules/runners/lambdas/runners/src/scale-runners/scale-up.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { listRunners, createRunner, RunnerInputParameters } from './runners';
2-
import { createOctoClient, createGithubAuth } from './gh-auth';
2+
import { createOctoClient, createGithubAppAuth, createGithubInstallationAuth } from './gh-auth';
33
import yn from 'yn';
44
import { Octokit } from '@octokit/rest';
55

@@ -27,7 +27,7 @@ export const scaleUp = async (eventSource: string, payload: ActionRequestMessage
2727

2828
let installationId = payload.installationId;
2929
if (installationId == 0) {
30-
const ghAuth = await createGithubAuth(undefined, 'app', ghesApiUrl);
30+
const ghAuth = await createGithubAppAuth(undefined, ghesApiUrl);
3131
const githubClient = await createOctoClient(ghAuth.token, ghesApiUrl);
3232
installationId = enableOrgLevel
3333
? (
@@ -43,10 +43,8 @@ export const scaleUp = async (eventSource: string, payload: ActionRequestMessage
4343
).data.id;
4444
}
4545

46-
const ghAuth = await createGithubAuth(installationId, 'installation', ghesApiUrl);
47-
46+
const ghAuth = await createGithubInstallationAuth(installationId, ghesApiUrl);
4847
const githubInstallationClient = await createOctoClient(ghAuth.token, ghesApiUrl);
49-
5048
const runnerType = enableOrgLevel ? 'Org' : 'Repo';
5149
const runnerOwner = enableOrgLevel ? payload.repositoryOwner : `${payload.repositoryOwner}/${payload.repositoryName}`;
5250

modules/runners/lambdas/runners/src/scale-runners/ssm.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ beforeEach(() => {
1313
nock.disableNetConnect();
1414
});
1515

16-
describe('Test createGithubAuth', () => {
16+
describe('Test getParameterValue', () => {
1717
test('Gets parameters and returns string', async () => {
1818
// Arrange
1919
const parameterValue = 'test';

0 commit comments

Comments
 (0)