Skip to content

Commit

Permalink
refactor(docker): use aws-sdk v3 (#8298)
Browse files Browse the repository at this point in the history
  • Loading branch information
viceice committed Feb 5, 2021
1 parent d00d1e8 commit c90c506
Show file tree
Hide file tree
Showing 4 changed files with 521 additions and 245 deletions.
68 changes: 36 additions & 32 deletions lib/datasource/docker/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,46 @@
import AWS from 'aws-sdk';
import AWSMock from 'aws-sdk-mock';
import * as _AWS from '@aws-sdk/client-ecr';
import { getDigest, getPkgReleases } from '..';
import * as httpMock from '../../../test/http-mock';
import { getName, mocked } from '../../../test/util';
import { getName, mocked, partial } from '../../../test/util';
import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
import * as _hostRules from '../../util/host-rules';
import { MediaType } from './types';
import * as docker from '.';

const hostRules = mocked(_hostRules);

jest.mock('@aws-sdk/client-ecr');
jest.mock('../../util/host-rules');

type ECR = _AWS.ECR;
type GetAuthorizationTokenCommandOutput = _AWS.GetAuthorizationTokenCommandOutput;
const AWS = mocked(_AWS);

const baseUrl = 'https://index.docker.io/v2';
const authUrl = 'https://auth.docker.io';
const amazonUrl = 'https://123456789.dkr.ecr.us-east-1.amazonaws.com/v2';

function mockEcrAuthResolve(
res: Partial<GetAuthorizationTokenCommandOutput> = {}
) {
AWS.ECR.mockImplementationOnce(() =>
partial<ECR>({
getAuthorizationToken: () =>
Promise.resolve<GetAuthorizationTokenCommandOutput>(
partial<GetAuthorizationTokenCommandOutput>(res)
),
})
);
}

function mockEcrAuthReject(msg: string) {
AWS.ECR.mockImplementationOnce(() =>
partial<ECR>({
getAuthorizationToken: jest.fn().mockRejectedValue(new Error(msg)),
})
);
}

describe(getName(__filename), () => {
beforeEach(() => {
httpMock.setup();
Expand Down Expand Up @@ -227,16 +252,11 @@ describe(getName(__filename), () => {
.reply(200)
.get('/node/manifests/some-tag')
.reply(200, '', { 'docker-content-digest': 'some-digest' });
AWSMock.setSDKInstance(AWS);
AWSMock.mock(
'ECR',
'getAuthorizationToken',
(params: unknown, callback: (...unknown) => void) => {
callback(null, {
authorizationData: [{ authorizationToken: 'abcdef' }],
});
}
);

mockEcrAuthResolve({
authorizationData: [{ authorizationToken: 'abcdef' }],
});

const res = await getDigest(
{
datasource: 'docker',
Expand All @@ -248,7 +268,6 @@ describe(getName(__filename), () => {
expect(res).toBe('some-digest');
expect(trace[1].headers.authorization).toBe('Basic abcdef');
expect(trace).toMatchSnapshot();
AWSMock.restore('ECR');
});
it('continues without token if ECR authentication could not be extracted', async () => {
httpMock
Expand All @@ -259,14 +278,8 @@ describe(getName(__filename), () => {
})
.get('/')
.reply(403);
AWSMock.setSDKInstance(AWS);
AWSMock.mock(
'ECR',
'getAuthorizationToken',
(params: unknown, callback: (...unknown) => void) => {
callback(null, {});
}
);
mockEcrAuthResolve();

const res = await getDigest(
{
datasource: 'docker',
Expand All @@ -276,7 +289,6 @@ describe(getName(__filename), () => {
);
expect(res).toBeNull();
expect(httpMock.getTrace()).toMatchSnapshot();
AWSMock.restore('ECR');
});
it('continues without token if ECR authentication fails', async () => {
hostRules.find.mockReturnValue({});
Expand All @@ -288,14 +300,7 @@ describe(getName(__filename), () => {
})
.get('/')
.reply(403);
AWSMock.setSDKInstance(AWS);
AWSMock.mock(
'ECR',
'getAuthorizationToken',
(params: unknown, callback: (...unknown) => void) => {
callback(Error('some error'), null);
}
);
mockEcrAuthReject('some error');
const res = await getDigest(
{
datasource: 'docker',
Expand All @@ -305,7 +310,6 @@ describe(getName(__filename), () => {
);
expect(res).toBeNull();
expect(httpMock.getTrace()).toMatchSnapshot();
AWSMock.restore('ECR');
});
it('continues without token, when no header is present', async () => {
httpMock
Expand Down
40 changes: 17 additions & 23 deletions lib/datasource/docker/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { OutgoingHttpHeaders } from 'http';
import URL from 'url';
import AWS from 'aws-sdk';
import { ECR } from '@aws-sdk/client-ecr';
import hasha from 'hasha';
import parseLinkHeader from 'parse-link-header';
import wwwAuthenticate from 'www-authenticate';
Expand Down Expand Up @@ -105,7 +105,7 @@ export function getRegistryRepository(
};
}

function getECRAuthToken(
async function getECRAuthToken(
region: string,
opts: HostRule
): Promise<string | null> {
Expand All @@ -114,27 +114,21 @@ function getECRAuthToken(
config.accessKeyId = opts.username;
config.secretAccessKey = opts.password;
}
const ecr = new AWS.ECR(config);
return new Promise<string>((resolve) => {
ecr.getAuthorizationToken({}, (err, data) => {
if (err) {
logger.trace({ err }, 'err');
logger.debug('ECR getAuthorizationToken error');
resolve(null);
} else {
const authorizationToken =
data?.authorizationData?.[0]?.authorizationToken;
if (authorizationToken) {
resolve(authorizationToken);
} else {
logger.warn(
'Could not extract authorizationToken from ECR getAuthorizationToken response'
);
resolve(null);
}
}
});
});
const ecr = new ECR(config);
try {
const data = await ecr.getAuthorizationToken({});
const authorizationToken = data?.authorizationData?.[0]?.authorizationToken;
if (authorizationToken) {
return authorizationToken;
}
logger.warn(
'Could not extract authorizationToken from ECR getAuthorizationToken response'
);
} catch (err) {
logger.trace({ err }, 'err');
logger.debug('ECR getAuthorizationToken error');
}
return null;
}

async function getAuthHeaders(
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,14 @@
"yarn": "^1.17.0"
},
"dependencies": {
"@aws-sdk/client-ecr": "3.2.0",
"@breejs/later": "4.0.2",
"@iarna/toml": "2.2.5",
"@renovate/pep440": "0.4.1",
"@renovatebot/ruby-semver": "0.2.1",
"@sindresorhus/is": "4.0.0",
"@yarnpkg/core": "2.4.0",
"@yarnpkg/parsers": "2.3.0",
"aws-sdk": "2.827.0",
"azure-devops-node-api": "10.2.1",
"bunyan": "1.8.15",
"cacache": "15.0.5",
Expand Down Expand Up @@ -231,7 +231,6 @@
"@types/xmldoc": "1.1.5",
"@typescript-eslint/eslint-plugin": "4.6.0",
"@typescript-eslint/parser": "4.6.0",
"aws-sdk-mock": "5.1.0",
"babel-jest": "26.6.3",
"babel-plugin-dynamic-import-node": "2.3.3",
"conventional-changelog-conventionalcommits": "4.5.0",
Expand Down

0 comments on commit c90c506

Please sign in to comment.