Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ecr: switch implementation to use the AWS SDK #126

Merged
merged 2 commits into from Dec 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 32 additions & 12 deletions .github/workflows/ci.yml
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
@@ -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
@@ -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
@@ -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);
});