mirror of
				https://github.com/docker/login-action.git
				synced 2025-10-31 10:10:09 +08:00 
			
		
		
		
	Merge pull request #126 from crazy-max/aws-sdk
ecr: switch implementation to use the AWS SDK
This commit is contained in:
		
						commit
						b20b9f5e31
					
				
							
								
								
									
										44
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @ -83,8 +83,7 @@ jobs: | ||||
|       matrix: | ||||
|         os: | ||||
|           - ubuntu-latest | ||||
|           - ubuntu-20.04 | ||||
|           - ubuntu-18.04 | ||||
|           - windows-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
| @ -103,8 +102,7 @@ jobs: | ||||
|       matrix: | ||||
|         os: | ||||
|           - ubuntu-latest | ||||
|           - ubuntu-20.04 | ||||
|           - ubuntu-18.04 | ||||
|           - windows-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
| @ -124,8 +122,7 @@ jobs: | ||||
|       matrix: | ||||
|         os: | ||||
|           - ubuntu-latest | ||||
|           - ubuntu-20.04 | ||||
|           - ubuntu-18.04 | ||||
|           - windows-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
| @ -150,8 +147,7 @@ jobs: | ||||
|       matrix: | ||||
|         os: | ||||
|           - ubuntu-latest | ||||
|           - ubuntu-20.04 | ||||
|           - ubuntu-18.04 | ||||
|           - windows-latest | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
| @ -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 | ||||
| @ -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 | ||||
| @ -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 | ||||
| @ -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 | ||||
|  | ||||
| @ -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([ | ||||
| @ -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); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| @ -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); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| @ -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); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| @ -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); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| @ -1,5 +1,3 @@ | ||||
| import osm = require('os'); | ||||
| 
 | ||||
| import {getInputs} from '../src/context'; | ||||
| 
 | ||||
| test('with password and username getInputs does not throw error', async () => { | ||||
|  | ||||
| @ -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'; | ||||
| 
 | ||||
| @ -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); | ||||
| }); | ||||
|  | ||||
							
								
								
									
										42344
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										42344
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -66,18 +66,6 @@ FROM docker:${DOCKER_VERSION} as docker | ||||
| FROM docker/buildx-bin:${BUILDX_VERSION} as buildx | ||||
| 
 | ||||
| FROM deps AS test | ||||
| RUN apk add --no-cache binutils curl unzip | ||||
| ENV GLIBC_VER=2.31-r0 | ||||
| RUN curl -sL "https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub" -o "/etc/apk/keys/sgerrand.rsa.pub" \ | ||||
|   && curl -sLO "https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-${GLIBC_VER}.apk" \ | ||||
|   && curl -sLO "https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk" \ | ||||
|   && apk add --no-cache \ | ||||
|     glibc-${GLIBC_VER}.apk \ | ||||
|     glibc-bin-${GLIBC_VER}.apk \ | ||||
|   && curl -sL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \ | ||||
|   && unzip -qq "awscliv2.zip" \ | ||||
|   && ./aws/install \ | ||||
|   && aws --version | ||||
| ENV RUNNER_TEMP=/tmp/github_runner | ||||
| ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache | ||||
| RUN --mount=type=bind,target=.,rw \ | ||||
|  | ||||
| @ -30,7 +30,7 @@ | ||||
|     "@actions/core": "^1.6.0", | ||||
|     "@actions/exec": "^1.1.0", | ||||
|     "@actions/io": "^1.1.1", | ||||
|     "semver": "^7.3.5" | ||||
|     "aws-sdk": "^2.1046.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/jest": "^26.0.23", | ||||
|  | ||||
							
								
								
									
										98
									
								
								src/aws.ts
									
									
									
									
									
								
							
							
						
						
									
										98
									
								
								src/aws.ts
									
									
									
									
									
								
							| @ -1,6 +1,5 @@ | ||||
| import * as semver from 'semver'; | ||||
| import * as exec from '@actions/exec'; | ||||
| import * as io from '@actions/io'; | ||||
| import * as core from '@actions/core'; | ||||
| import * as aws from 'aws-sdk'; | ||||
| 
 | ||||
| const ecrRegistryRegex = /^(([0-9]{12})\.dkr\.ecr\.(.+)\.amazonaws\.com(.cn)?)(\/([^:]+)(:.+)?)?$/; | ||||
| 
 | ||||
| @ -38,48 +37,65 @@ export const getAccountIDs = (registry: string): string[] => { | ||||
|   return accountIDs.filter((item, index) => accountIDs.indexOf(item) === index); | ||||
| }; | ||||
| 
 | ||||
| export const getCLI = async (): Promise<string> => { | ||||
|   return io.which('aws', true); | ||||
| }; | ||||
| export interface RegistryData { | ||||
|   registry: string; | ||||
|   username: string; | ||||
|   password: string; | ||||
| } | ||||
| 
 | ||||
| export const execCLI = async (args: string[]): Promise<string> => { | ||||
|   return exec | ||||
|     .getExecOutput(await getCLI(), args, { | ||||
|       ignoreReturnCode: true, | ||||
|       silent: true | ||||
|     }) | ||||
|     .then(res => { | ||||
|       if (res.stderr.length > 0 && res.exitCode != 0) { | ||||
|         throw new Error(res.stderr.trim()); | ||||
|       } else if (res.stderr.length > 0) { | ||||
|         return res.stderr.trim(); | ||||
| export const getRegistriesData = async (registry: string, username?: string, password?: string): Promise<RegistryData[]> => { | ||||
|   const region = getRegion(registry); | ||||
|   const accountIDs = getAccountIDs(registry); | ||||
| 
 | ||||
|   const authTokenRequest = {}; | ||||
|   if (accountIDs.length > 0) { | ||||
|     core.debug(`Requesting AWS ECR auth token for ${accountIDs.join(', ')}`); | ||||
|     authTokenRequest['registryIds'] = accountIDs; | ||||
|   } | ||||
| 
 | ||||
|   if (isPubECR(registry)) { | ||||
|     core.info(`AWS Public ECR detected with ${region} region`); | ||||
|     const ecrPublic = new aws.ECRPUBLIC({ | ||||
|       customUserAgent: 'docker-login-action', | ||||
|       accessKeyId: username || process.env.AWS_ACCESS_KEY_ID || '', | ||||
|       secretAccessKey: password || process.env.AWS_SECRET_ACCESS_KEY || '', | ||||
|       region: region | ||||
|     }); | ||||
|     const authTokenResponse = await ecrPublic.getAuthorizationToken(authTokenRequest).promise(); | ||||
|     if (!authTokenResponse.authorizationData || !authTokenResponse.authorizationData.authorizationToken) { | ||||
|       throw new Error('Could not retrieve an authorization token from AWS Public ECR'); | ||||
|     } | ||||
|     const authToken = Buffer.from(authTokenResponse.authorizationData.authorizationToken, 'base64').toString('utf-8'); | ||||
|     const creds = authToken.split(':', 2); | ||||
|     return [ | ||||
|       { | ||||
|         registry: 'public.ecr.aws', | ||||
|         username: creds[0], | ||||
|         password: creds[1] | ||||
|       } | ||||
|     ]; | ||||
|   } else { | ||||
|         return res.stdout.trim(); | ||||
|       } | ||||
|     core.info(`AWS ECR detected with ${region} region`); | ||||
|     const ecr = new aws.ECR({ | ||||
|       customUserAgent: 'docker-login-action', | ||||
|       accessKeyId: username || process.env.AWS_ACCESS_KEY_ID || '', | ||||
|       secretAccessKey: password || process.env.AWS_SECRET_ACCESS_KEY || '', | ||||
|       region: region | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| export const getCLIVersion = async (): Promise<string> => { | ||||
|   return parseCLIVersion(await execCLI(['--version'])); | ||||
| }; | ||||
| 
 | ||||
| export const parseCLIVersion = async (stdout: string): Promise<string> => { | ||||
|   const matches = /aws-cli\/([0-9.]+)/.exec(stdout); | ||||
|   if (!matches) { | ||||
|     throw new Error(`Cannot parse AWS CLI version`); | ||||
|     const authTokenResponse = await ecr.getAuthorizationToken(authTokenRequest).promise(); | ||||
|     if (!Array.isArray(authTokenResponse.authorizationData) || !authTokenResponse.authorizationData.length) { | ||||
|       throw new Error('Could not retrieve an authorization token from AWS ECR'); | ||||
|     } | ||||
|   return semver.clean(matches[1]); | ||||
| }; | ||||
| 
 | ||||
| export const getDockerLoginCmds = async (cliVersion: string, registry: string, region: string, accountIDs: string[]): Promise<string[]> => { | ||||
|   let ecrCmd = (await isPubECR(registry)) ? 'ecr-public' : 'ecr'; | ||||
|   if (semver.satisfies(cliVersion, '>=2.0.0') || (await isPubECR(registry))) { | ||||
|     return execCLI([ecrCmd, 'get-login-password', '--region', region]).then(pwd => { | ||||
|       return [`docker login --username AWS --password ${pwd} ${registry}`]; | ||||
|     }); | ||||
|   } else { | ||||
|     return execCLI([ecrCmd, 'get-login', '--region', region, '--registry-ids', accountIDs.join(' '), '--no-include-email']).then(dockerLoginCmds => { | ||||
|       return dockerLoginCmds.trim().split(`\n`); | ||||
|     const regDatas: RegistryData[] = []; | ||||
|     for (const authData of authTokenResponse.authorizationData) { | ||||
|       const authToken = Buffer.from(authData.authorizationToken || '', 'base64').toString('utf-8'); | ||||
|       const creds = authToken.split(':', 2); | ||||
|       regDatas.push({ | ||||
|         registry: authData.proxyEndpoint || '', | ||||
|         username: creds[0], | ||||
|         password: creds[1] | ||||
|       }); | ||||
|     } | ||||
|     return regDatas; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| @ -3,7 +3,7 @@ import * as core from '@actions/core'; | ||||
| import * as exec from '@actions/exec'; | ||||
| 
 | ||||
| export async function login(registry: string, username: string, password: string): Promise<void> { | ||||
|   if (await aws.isECR(registry)) { | ||||
|   if (aws.isECR(registry)) { | ||||
|     await loginECR(registry, username, password); | ||||
|   } else { | ||||
|     await loginStandard(registry, username, password); | ||||
| @ -51,43 +51,21 @@ export async function loginStandard(registry: string, username: string, password | ||||
| } | ||||
| 
 | ||||
| export async function loginECR(registry: string, username: string, password: string): Promise<void> { | ||||
|   const cliPath = await aws.getCLI(); | ||||
|   const cliVersion = await aws.getCLIVersion(); | ||||
|   const region = await aws.getRegion(registry); | ||||
|   const accountIDs = await aws.getAccountIDs(registry); | ||||
| 
 | ||||
|   if (await aws.isPubECR(registry)) { | ||||
|     core.info(`AWS Public ECR detected with ${region} region`); | ||||
|   } else { | ||||
|     core.info(`AWS ECR detected with ${region} region`); | ||||
|   } | ||||
| 
 | ||||
|   if (username) { | ||||
|     process.env.AWS_ACCESS_KEY_ID = username; | ||||
|   } | ||||
|   if (password) { | ||||
|     process.env.AWS_SECRET_ACCESS_KEY = password; | ||||
|   } | ||||
| 
 | ||||
|   core.info(`Retrieving docker login command through AWS CLI ${cliVersion} (${cliPath})...`); | ||||
|   const loginCmds = await aws.getDockerLoginCmds(cliVersion, registry, region, accountIDs); | ||||
| 
 | ||||
|   core.info(`Logging into ${registry}...`); | ||||
|   loginCmds.forEach((loginCmd, index) => { | ||||
|     exec | ||||
|       .getExecOutput(loginCmd, [], { | ||||
|   core.info(`Retrieving registries data through AWS SDK...`); | ||||
|   const regDatas = await aws.getRegistriesData(registry, username, password); | ||||
|   for (const regData of regDatas) { | ||||
|     core.info(`Logging into ${regData.registry}...`); | ||||
|     await exec | ||||
|       .getExecOutput('docker', ['login', '--password-stdin', '--username', regData.username, regData.registry], { | ||||
|         ignoreReturnCode: true, | ||||
|         silent: true | ||||
|         silent: true, | ||||
|         input: Buffer.from(regData.password) | ||||
|       }) | ||||
|       .then(res => { | ||||
|         if (res.stderr.length > 0 && res.exitCode != 0) { | ||||
|           throw new Error(res.stderr.trim()); | ||||
|         } | ||||
|         if (loginCmds.length > 1) { | ||||
|           core.info(`Login Succeeded! (${index}/${loginCmds.length})`); | ||||
|         } else { | ||||
|         core.info('Login Succeeded!'); | ||||
|         } | ||||
|       }); | ||||
|       }); | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										99
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								yarn.lock
									
									
									
									
									
								
							| @ -763,6 +763,21 @@ atob@^2.1.2: | ||||
|   resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" | ||||
|   integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== | ||||
| 
 | ||||
| aws-sdk@^2.1046.0: | ||||
|   version "2.1046.0" | ||||
|   resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1046.0.tgz#9147b0fa1c86acbebd1a061e951ab5012f4499d7" | ||||
|   integrity sha512-ocwHclMXdIA+NWocUyvp9Ild3/zy2vr5mHp3mTyodf0WU5lzBE8PocCVLSWhMAXLxyia83xv2y5f5AzAcetbqA== | ||||
|   dependencies: | ||||
|     buffer "4.9.2" | ||||
|     events "1.1.1" | ||||
|     ieee754 "1.1.13" | ||||
|     jmespath "0.15.0" | ||||
|     querystring "0.2.0" | ||||
|     sax "1.2.1" | ||||
|     url "0.10.3" | ||||
|     uuid "3.3.2" | ||||
|     xml2js "0.4.19" | ||||
| 
 | ||||
| babel-jest@^26.6.3: | ||||
|   version "26.6.3" | ||||
|   resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" | ||||
| @ -829,6 +844,11 @@ balanced-match@^1.0.0: | ||||
|   resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" | ||||
|   integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== | ||||
| 
 | ||||
| base64-js@^1.0.2: | ||||
|   version "1.5.1" | ||||
|   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" | ||||
|   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== | ||||
| 
 | ||||
| base@^0.11.1: | ||||
|   version "0.11.2" | ||||
|   resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" | ||||
| @ -908,6 +928,15 @@ buffer-from@1.x, buffer-from@^1.0.0: | ||||
|   resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" | ||||
|   integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== | ||||
| 
 | ||||
| buffer@4.9.2: | ||||
|   version "4.9.2" | ||||
|   resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" | ||||
|   integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== | ||||
|   dependencies: | ||||
|     base64-js "^1.0.2" | ||||
|     ieee754 "^1.1.4" | ||||
|     isarray "^1.0.0" | ||||
| 
 | ||||
| cache-base@^1.0.1: | ||||
|   version "1.0.1" | ||||
|   resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" | ||||
| @ -1307,6 +1336,11 @@ esutils@^2.0.2: | ||||
|   resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" | ||||
|   integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== | ||||
| 
 | ||||
| events@1.1.1: | ||||
|   version "1.1.1" | ||||
|   resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" | ||||
|   integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= | ||||
| 
 | ||||
| exec-sh@^0.3.2: | ||||
|   version "0.3.6" | ||||
|   resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" | ||||
| @ -1632,6 +1666,16 @@ iconv-lite@0.4.24: | ||||
|   dependencies: | ||||
|     safer-buffer ">= 2.1.2 < 3" | ||||
| 
 | ||||
| ieee754@1.1.13: | ||||
|   version "1.1.13" | ||||
|   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" | ||||
|   integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== | ||||
| 
 | ||||
| ieee754@^1.1.4: | ||||
|   version "1.2.1" | ||||
|   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" | ||||
|   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== | ||||
| 
 | ||||
| import-local@^3.0.2: | ||||
|   version "3.0.2" | ||||
|   resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" | ||||
| @ -1806,7 +1850,7 @@ is-wsl@^2.2.0: | ||||
|   dependencies: | ||||
|     is-docker "^2.0.0" | ||||
| 
 | ||||
| isarray@1.0.0: | ||||
| isarray@1.0.0, isarray@^1.0.0: | ||||
|   version "1.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" | ||||
|   integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= | ||||
| @ -2269,6 +2313,11 @@ jest@^26.6.3: | ||||
|     import-local "^3.0.2" | ||||
|     jest-cli "^26.6.3" | ||||
| 
 | ||||
| jmespath@0.15.0: | ||||
|   version "0.15.0" | ||||
|   resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" | ||||
|   integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= | ||||
| 
 | ||||
| js-tokens@^4.0.0: | ||||
|   version "4.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" | ||||
| @ -2809,11 +2858,21 @@ pump@^3.0.0: | ||||
|     end-of-stream "^1.1.0" | ||||
|     once "^1.3.1" | ||||
| 
 | ||||
| punycode@1.3.2: | ||||
|   version "1.3.2" | ||||
|   resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" | ||||
|   integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= | ||||
| 
 | ||||
| punycode@^2.1.1: | ||||
|   version "2.1.1" | ||||
|   resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" | ||||
|   integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== | ||||
| 
 | ||||
| querystring@0.2.0: | ||||
|   version "0.2.0" | ||||
|   resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" | ||||
|   integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= | ||||
| 
 | ||||
| react-is@^17.0.1: | ||||
|   version "17.0.2" | ||||
|   resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" | ||||
| @ -2945,6 +3004,16 @@ sane@^4.0.3: | ||||
|     minimist "^1.1.1" | ||||
|     walker "~1.0.5" | ||||
| 
 | ||||
| sax@1.2.1: | ||||
|   version "1.2.1" | ||||
|   resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" | ||||
|   integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= | ||||
| 
 | ||||
| sax@>=0.6.0: | ||||
|   version "1.2.4" | ||||
|   resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" | ||||
|   integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== | ||||
| 
 | ||||
| saxes@^5.0.1: | ||||
|   version "5.0.1" | ||||
|   resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" | ||||
| @ -2957,7 +3026,7 @@ saxes@^5.0.1: | ||||
|   resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" | ||||
|   integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== | ||||
| 
 | ||||
| semver@7.x, semver@^7.3.2, semver@^7.3.5: | ||||
| semver@7.x, semver@^7.3.2: | ||||
|   version "7.3.5" | ||||
|   resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" | ||||
|   integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== | ||||
| @ -3397,11 +3466,24 @@ urix@^0.1.0: | ||||
|   resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" | ||||
|   integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= | ||||
| 
 | ||||
| url@0.10.3: | ||||
|   version "0.10.3" | ||||
|   resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" | ||||
|   integrity sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ= | ||||
|   dependencies: | ||||
|     punycode "1.3.2" | ||||
|     querystring "0.2.0" | ||||
| 
 | ||||
| use@^3.1.0: | ||||
|   version "3.1.1" | ||||
|   resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" | ||||
|   integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== | ||||
| 
 | ||||
| uuid@3.3.2: | ||||
|   version "3.3.2" | ||||
|   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" | ||||
|   integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== | ||||
| 
 | ||||
| uuid@^8.3.0: | ||||
|   version "8.3.2" | ||||
|   resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" | ||||
| @ -3534,6 +3616,19 @@ xml-name-validator@^3.0.0: | ||||
|   resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" | ||||
|   integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== | ||||
| 
 | ||||
| xml2js@0.4.19: | ||||
|   version "0.4.19" | ||||
|   resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" | ||||
|   integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== | ||||
|   dependencies: | ||||
|     sax ">=0.6.0" | ||||
|     xmlbuilder "~9.0.1" | ||||
| 
 | ||||
| xmlbuilder@~9.0.1: | ||||
|   version "9.0.7" | ||||
|   resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" | ||||
|   integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= | ||||
| 
 | ||||
| xmlchars@^2.2.0: | ||||
|   version "2.2.0" | ||||
|   resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 CrazyMax
						CrazyMax