Skip to content

Commit

Permalink
Merge pull request #126 from crazy-max/aws-sdk
Browse files Browse the repository at this point in the history
ecr: switch implementation to use the AWS SDK
  • Loading branch information
crazy-max authored Dec 20, 2021
2 parents 4d84a3c + cb21399 commit b20b9f5
Show file tree
Hide file tree
Showing 10 changed files with 39,290 additions and 3,059 deletions.
44 changes: 32 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ jobs:
matrix:
os:
- ubuntu-latest
- ubuntu-20.04
- ubuntu-18.04
- windows-latest
steps:
-
name: Checkout
Expand All @@ -103,8 +102,7 @@ jobs:
matrix:
os:
- ubuntu-latest
- ubuntu-20.04
- ubuntu-18.04
- windows-latest
steps:
-
name: Checkout
Expand All @@ -124,8 +122,7 @@ jobs:
matrix:
os:
- ubuntu-latest
- ubuntu-20.04
- ubuntu-18.04
- windows-latest
steps:
-
name: Checkout
Expand All @@ -150,8 +147,7 @@ jobs:
matrix:
os:
- ubuntu-latest
- ubuntu-20.04
- ubuntu-18.04
- windows-latest
steps:
-
name: Checkout
Expand All @@ -165,7 +161,13 @@ jobs:
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

github-container:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
Expand All @@ -179,7 +181,13 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}

gitlab:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
Expand All @@ -193,7 +201,13 @@ jobs:
password: ${{ secrets.GITLAB_TOKEN }}

google-artifact:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
Expand All @@ -207,7 +221,13 @@ jobs:
password: ${{ secrets.GAR_JSON_KEY }}

google-container:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
steps:
-
name: Checkout
Expand Down
148 changes: 110 additions & 38 deletions __tests__/aws.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as semver from 'semver';
import * as aws from '../src/aws';
import {AuthorizationData} from 'aws-sdk/clients/ecr';

describe('isECR', () => {
test.each([
Expand All @@ -10,7 +10,7 @@ describe('isECR', () => {
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', true],
['public.ecr.aws', true]
])('given registry %p', async (registry, expected) => {
expect(await aws.isECR(registry)).toEqual(expected);
expect(aws.isECR(registry)).toEqual(expected);
});
});

Expand All @@ -23,40 +23,7 @@ describe('isPubECR', () => {
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', false],
['public.ecr.aws', true]
])('given registry %p', async (registry, expected) => {
expect(await aws.isPubECR(registry)).toEqual(expected);
});
});

describe('getCLI', () => {
it('exists', async () => {
const awsPath = await aws.getCLI();
console.log(`awsPath: ${awsPath}`);
expect(awsPath).not.toEqual('');
});
});

describe('execCLI', () => {
it('--version not empty', async () => {
const cliCmdOutput = await aws.execCLI(['--version']);
console.log(`cliCmdOutput: ${cliCmdOutput}`);
expect(cliCmdOutput).not.toEqual('');
}, 100000);
});

describe('getCLIVersion', () => {
it('valid', async () => {
const cliVersion = await aws.getCLIVersion();
console.log(`cliVersion: ${cliVersion}`);
expect(semver.valid(cliVersion)).not.toBeNull();
}, 100000);
});

describe('parseCLIVersion', () => {
test.each([
['v1', 'aws-cli/1.18.120 Python/2.7.17 Linux/5.3.0-1034-azure botocore/1.17.43', '1.18.120'],
['v2', 'aws-cli/2.0.41 Python/3.7.3 Linux/4.19.104-microsoft-standard exe/x86_64.ubuntu.18', '2.0.41']
])('given aws %p', async (version, stdout, expected) => {
expect(await aws.parseCLIVersion(stdout)).toEqual(expected);
expect(aws.isPubECR(registry)).toEqual(expected);
});
});

Expand All @@ -67,7 +34,7 @@ describe('getRegion', () => {
['390948362332.dkr.ecr.cn-northwest-1.amazonaws.com.cn', 'cn-northwest-1'],
['public.ecr.aws', 'us-east-1']
])('given registry %p', async (registry, expected) => {
expect(await aws.getRegion(registry)).toEqual(expected);
expect(aws.getRegion(registry)).toEqual(expected);
});
});

Expand All @@ -82,6 +49,111 @@ describe('getAccountIDs', () => {
if (accountIDsEnv) {
process.env.AWS_ACCOUNT_IDS = accountIDsEnv;
}
expect(await aws.getAccountIDs(registry)).toEqual(expected);
expect(aws.getAccountIDs(registry)).toEqual(expected);
});
});

const mockEcrGetAuthToken = jest.fn();
const mockEcrPublicGetAuthToken = jest.fn();
jest.mock('aws-sdk', () => {
return {
ECR: jest.fn(() => ({
getAuthorizationToken: mockEcrGetAuthToken
})),
ECRPUBLIC: jest.fn(() => ({
getAuthorizationToken: mockEcrPublicGetAuthToken
}))
};
});

describe('getRegistriesData', () => {
beforeEach(() => {
jest.clearAllMocks();
delete process.env.AWS_ACCOUNT_IDS;
});
// prettier-ignore
test.each([
[
'012345678901.dkr.ecr.aws-region-1.amazonaws.com',
'dkr.ecr.aws-region-1.amazonaws.com', undefined,
[
{
registry: '012345678901.dkr.ecr.aws-region-1.amazonaws.com',
username: '012345678901',
password: 'world'
}
]
],
[
'012345678901.dkr.ecr.eu-west-3.amazonaws.com',
'dkr.ecr.eu-west-3.amazonaws.com',
'012345678910,023456789012',
[
{
registry: '012345678901.dkr.ecr.eu-west-3.amazonaws.com',
username: '012345678901',
password: 'world'
},
{
registry: '012345678910.dkr.ecr.eu-west-3.amazonaws.com',
username: '012345678910',
password: 'world'
},
{
registry: '023456789012.dkr.ecr.eu-west-3.amazonaws.com',
username: '023456789012',
password: 'world'
}
]
],
[
'public.ecr.aws',
undefined,
undefined,
[
{
registry: 'public.ecr.aws',
username: 'AWS',
password: 'world'
}
]
]
])('given registry %p', async (registry, fqdn, accountIDsEnv, expected: aws.RegistryData[]) => {
if (accountIDsEnv) {
process.env.AWS_ACCOUNT_IDS = accountIDsEnv;
}
const accountIDs = aws.getAccountIDs(registry);
const authData: AuthorizationData[] = [];
if (accountIDs.length == 0) {
mockEcrPublicGetAuthToken.mockImplementation(() => {
return {
promise() {
return Promise.resolve({
authorizationData: {
authorizationToken: Buffer.from(`AWS:world`).toString('base64'),
}
});
}
};
});
} else {
aws.getAccountIDs(registry).forEach(accountID => {
authData.push({
authorizationToken: Buffer.from(`${accountID}:world`).toString('base64'),
proxyEndpoint: `${accountID}.${fqdn}`
});
});
mockEcrGetAuthToken.mockImplementation(() => {
return {
promise() {
return Promise.resolve({
authorizationData: authData
});
}
};
});
}
const regData = await aws.getRegistriesData(registry);
expect(regData).toEqual(expected);
});
});
2 changes: 0 additions & 2 deletions __tests__/context.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import osm = require('os');

import {getInputs} from '../src/context';

test('with password and username getInputs does not throw error', async () => {
Expand Down
78 changes: 1 addition & 77 deletions __tests__/docker.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {loginECR, loginStandard, logout} from '../src/docker';
import * as aws from '../src/aws';
import {loginStandard, logout} from '../src/docker';

import * as path from 'path';

Expand Down Expand Up @@ -48,78 +47,3 @@ test('logout calls exec', async () => {
ignoreReturnCode: true
});
});

test('loginECR sets AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY if username and password is set', async () => {
const execSpy: jest.SpyInstance = jest.spyOn(aws, 'getDockerLoginCmds');
execSpy.mockImplementation(() => Promise.resolve([]));
jest.spyOn(aws, 'getCLI').mockImplementation(() => Promise.resolve(''));
jest.spyOn(aws, 'getCLIVersion').mockImplementation(() => Promise.resolve(''));
jest.spyOn(aws, 'getRegion').mockImplementation(() => '');
jest.spyOn(aws, 'getAccountIDs').mockImplementation(() => []);
jest.spyOn(aws, 'isPubECR').mockImplementation(() => false);

const username: string = 'dbowie';
const password: string = 'groundcontrol';
const registry: string = 'https://ghcr.io';

await loginECR(registry, username, password);

expect(process.env.AWS_ACCESS_KEY_ID).toEqual(username);
expect(process.env.AWS_SECRET_ACCESS_KEY).toEqual(password);
});

test('loginECR keeps AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY if set', async () => {
const execSpy: jest.SpyInstance = jest.spyOn(aws, 'getDockerLoginCmds');
execSpy.mockImplementation(() => Promise.resolve([]));
jest.spyOn(aws, 'getCLI').mockImplementation(() => Promise.resolve(''));
jest.spyOn(aws, 'getCLIVersion').mockImplementation(() => Promise.resolve(''));
jest.spyOn(aws, 'getRegion').mockImplementation(() => '');
jest.spyOn(aws, 'getAccountIDs').mockImplementation(() => []);
jest.spyOn(aws, 'isPubECR').mockImplementation(() => false);

process.env.AWS_ACCESS_KEY_ID = 'banana';
process.env.AWS_SECRET_ACCESS_KEY = 'supersecret';

await loginECR('ecr.aws', '', '');

expect(process.env.AWS_ACCESS_KEY_ID).toEqual('banana');
expect(process.env.AWS_SECRET_ACCESS_KEY).toEqual('supersecret');
});

test('loginECR overrides AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY if username and password set', async () => {
const execSpy: jest.SpyInstance = jest.spyOn(aws, 'getDockerLoginCmds');
execSpy.mockImplementation(() => Promise.resolve([]));
jest.spyOn(aws, 'getCLI').mockImplementation(() => Promise.resolve(''));
jest.spyOn(aws, 'getCLIVersion').mockImplementation(() => Promise.resolve(''));
jest.spyOn(aws, 'getRegion').mockImplementation(() => '');
jest.spyOn(aws, 'getAccountIDs').mockImplementation(() => []);
jest.spyOn(aws, 'isPubECR').mockImplementation(() => false);

process.env.AWS_ACCESS_KEY_ID = 'banana';
process.env.AWS_SECRET_ACCESS_KEY = 'supersecret';
const username = 'myotheruser';
const password = 'providedpassword';

await loginECR('ecr.aws', username, password);

expect(process.env.AWS_ACCESS_KEY_ID).toEqual(username);
expect(process.env.AWS_SECRET_ACCESS_KEY).toEqual(password);
});

test('loginECR does not set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY if not set', async () => {
const execSpy: jest.SpyInstance = jest.spyOn(aws, 'getDockerLoginCmds');
execSpy.mockImplementation(() => Promise.resolve([]));
jest.spyOn(aws, 'getCLI').mockImplementation(() => Promise.resolve(''));
jest.spyOn(aws, 'getCLIVersion').mockImplementation(() => Promise.resolve(''));
jest.spyOn(aws, 'getRegion').mockImplementation(() => '');
jest.spyOn(aws, 'getAccountIDs').mockImplementation(() => []);
jest.spyOn(aws, 'isPubECR').mockImplementation(() => false);

delete process.env.AWS_ACCESS_KEY_ID;
delete process.env.AWS_SECRET_ACCESS_KEY;

await loginECR('ecr.aws', '', '');

expect('AWS_ACCESS_KEY_ID' in process.env).toEqual(false);
expect('AWS_SECRET_ACCESS_KEY' in process.env).toEqual(false);
});
Loading

0 comments on commit b20b9f5

Please sign in to comment.