mirror of
				https://gitea.com/docker/build-push-action.git
				synced 2025-10-31 09:08:18 +07:00 
			
		
		
		
	Merge pull request #296 from crazy-max/secret-file
Allow to use secret file mount
This commit is contained in:
		
						commit
						af867d4937
					
				| @ -1,4 +1,4 @@ | |||||||
| #syntax=docker/dockerfile:1.1-experimental | #syntax=docker/dockerfile:1.2 | ||||||
| 
 | 
 | ||||||
| FROM node:12 AS deps | FROM node:12 AS deps | ||||||
| WORKDIR /src | WORKDIR /src | ||||||
|  | |||||||
| @ -471,9 +471,6 @@ using [actions/cache](https://github.com/actions/cache) with this action: | |||||||
|   ``` |   ``` | ||||||
| </details> | </details> | ||||||
| 
 | 
 | ||||||
| > If you want to [export layers for all stages](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue), |  | ||||||
| > you have to specify `mode=max` attribute in `cache-to`. |  | ||||||
| 
 |  | ||||||
| ### Handle tags and labels | ### Handle tags and labels | ||||||
| 
 | 
 | ||||||
| If you come from [`v1`](https://github.com/docker/build-push-action/tree/releases/v1#readme) and want an | If you come from [`v1`](https://github.com/docker/build-push-action/tree/releases/v1#readme) and want an | ||||||
| @ -622,7 +619,8 @@ Following inputs can be used as `step.with` keys | |||||||
| | `outputs`           | List     | List of [output destinations](https://github.com/docker/buildx#-o---outputpath-typetypekeyvalue) (format: `type=local,dest=path`) | | | `outputs`           | List     | List of [output destinations](https://github.com/docker/buildx#-o---outputpath-typetypekeyvalue) (format: `type=local,dest=path`) | | ||||||
| | `cache-from`        | List     | List of [external cache sources](https://github.com/docker/buildx#--cache-fromnametypetypekeyvalue) (eg. `type=local,src=path/to/dir`) | | | `cache-from`        | List     | List of [external cache sources](https://github.com/docker/buildx#--cache-fromnametypetypekeyvalue) (eg. `type=local,src=path/to/dir`) | | ||||||
| | `cache-to`          | List     | List of [cache export destinations](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue) (eg. `type=local,dest=path/to/dir`) | | | `cache-to`          | List     | List of [cache export destinations](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue) (eg. `type=local,dest=path/to/dir`) | | ||||||
| | `secrets`           | List     | List of secrets to expose to the build (eg. `key=value`, `GIT_AUTH_TOKEN=mytoken`) | | | `secrets`           | List     | List of secrets to expose to the build (eg. `key=string`, `GIT_AUTH_TOKEN=mytoken`) | | ||||||
|  | | `secret-files`      | List     | List of secret files to expose to the build (eg. `key=filename`, `MY_SECRET=./secret.txt`) | | ||||||
| | `ssh`               | List     | List of SSH agent socket or keys to expose to the build | | | `ssh`               | List     | List of SSH agent socket or keys to expose to the build | | ||||||
| 
 | 
 | ||||||
| ### outputs | ### outputs | ||||||
|  | |||||||
| @ -119,21 +119,34 @@ describe('parseVersion', () => { | |||||||
| 
 | 
 | ||||||
| describe('getSecret', () => { | describe('getSecret', () => { | ||||||
|   test.each([ |   test.each([ | ||||||
|     ['A_SECRET=abcdef0123456789', 'A_SECRET', 'abcdef0123456789', false], |     ['A_SECRET=abcdef0123456789', false, 'A_SECRET', 'abcdef0123456789', false], | ||||||
|     ['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', false], |     ['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', false, 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', false], | ||||||
|     ['MY_KEY=c3RyaW5nLXdpdGgtZXF1YWxzCg==', 'MY_KEY', 'c3RyaW5nLXdpdGgtZXF1YWxzCg==', false], |     ['MY_KEY=c3RyaW5nLXdpdGgtZXF1YWxzCg==', false, 'MY_KEY', 'c3RyaW5nLXdpdGgtZXF1YWxzCg==', false], | ||||||
|     ['aaaaaaaa', '', '', true], |     ['aaaaaaaa', false, '', '', true], | ||||||
|     ['aaaaaaaa=', '', '', true], |     ['aaaaaaaa=', false, '', '', true], | ||||||
|     ['=bbbbbbb', '', '', true] |     ['=bbbbbbb', false, '', '', true], | ||||||
|   ])('given %p key and %p secret', async (kvp, key, secret, invalid) => { |     [ | ||||||
|  |       `foo=${path.join(__dirname, 'fixtures', 'secret.txt').split(path.sep).join(path.posix.sep)}`, | ||||||
|  |       true, | ||||||
|  |       'foo', | ||||||
|  |       'bar', | ||||||
|  |       false | ||||||
|  |     ], | ||||||
|  |     [`notfound=secret`, true, '', '', true] | ||||||
|  |   ])('given %p key and %p secret', async (kvp, file, exKey, exValue, invalid) => { | ||||||
|     try { |     try { | ||||||
|       const secretArgs = await buildx.getSecret(kvp); |       let secret: string; | ||||||
|  |       if (file) { | ||||||
|  |         secret = await buildx.getSecretFile(kvp); | ||||||
|  |       } else { | ||||||
|  |         secret = await buildx.getSecretString(kvp); | ||||||
|  |       } | ||||||
|       expect(true).toBe(!invalid); |       expect(true).toBe(!invalid); | ||||||
|       console.log(`secretArgs: ${secretArgs}`); |       console.log(`secret: ${secret}`); | ||||||
|       expect(secretArgs).toEqual(`id=${key},src=${tmpNameSync}`); |       expect(secret).toEqual(`id=${exKey},src=${tmpNameSync}`); | ||||||
|       const secretContent = await fs.readFileSync(tmpNameSync, 'utf-8'); |       const secretValue = await fs.readFileSync(tmpNameSync, 'utf-8'); | ||||||
|       console.log(`secretValue: ${secretContent}`); |       console.log(`secretValue: ${secretValue}`); | ||||||
|       expect(secretContent).toEqual(secret); |       expect(secretValue).toEqual(exValue); | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       expect(true).toBe(invalid); |       expect(true).toBe(invalid); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -337,6 +337,27 @@ ccc`], | |||||||
|         '--push', |         '--push', | ||||||
|         'https://github.com/docker/build-push-action.git#heads/master' |         'https://github.com/docker/build-push-action.git#heads/master' | ||||||
|       ] |       ] | ||||||
|  |     ], | ||||||
|  |     [ | ||||||
|  |       '0.5.1', | ||||||
|  |       new Map<string, string>([ | ||||||
|  |         ['context', 'https://github.com/docker/build-push-action.git#heads/master'], | ||||||
|  |         ['tag', 'localhost:5000/name/app:latest'], | ||||||
|  |         ['secret-files', `MY_SECRET=${path.join(__dirname, 'fixtures', 'secret.txt').split(path.sep).join(path.posix.sep)}`], | ||||||
|  |         ['file', './test/Dockerfile'], | ||||||
|  |         ['builder', 'builder-git-context-2'], | ||||||
|  |         ['push', 'true'] | ||||||
|  |       ]), | ||||||
|  |       [ | ||||||
|  |         'buildx', | ||||||
|  |         'build', | ||||||
|  |         '--iidfile', '/tmp/.docker-build-push-jest/iidfile', | ||||||
|  |         '--secret', 'id=MY_SECRET,src=/tmp/.docker-build-push-jest/.tmpname-jest', | ||||||
|  |         '--file', './test/Dockerfile', | ||||||
|  |         '--builder', 'builder-git-context-2', | ||||||
|  |         '--push', | ||||||
|  |         'https://github.com/docker/build-push-action.git#heads/master' | ||||||
|  |       ] | ||||||
|     ] |     ] | ||||||
|   ])( |   ])( | ||||||
|     'given %p with %p as inputs, returns %p', |     'given %p with %p as inputs, returns %p', | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								__tests__/fixtures/secret.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								__tests__/fixtures/secret.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | bar | ||||||
							
								
								
									
										11
									
								
								action.yml
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								action.yml
									
									
									
									
									
								
							| @ -60,15 +60,18 @@ inputs: | |||||||
|     description: "List of cache export destinations for buildx (eg. user/app:cache, type=local,dest=path/to/dir)" |     description: "List of cache export destinations for buildx (eg. user/app:cache, type=local,dest=path/to/dir)" | ||||||
|     required: false |     required: false | ||||||
|   secrets: |   secrets: | ||||||
|     description: "List of secrets to expose to the build (eg. key=value, GIT_AUTH_TOKEN=mytoken)" |     description: "List of secrets to expose to the build (eg. key=string, GIT_AUTH_TOKEN=mytoken)" | ||||||
|  |     required: false | ||||||
|  |   secret-files: | ||||||
|  |     description: "List of secret files to expose to the build (eg. key=filename, MY_SECRET=./secret.txt)" | ||||||
|  |     required: false | ||||||
|  |   ssh: | ||||||
|  |     description: "List of SSH agent socket or keys to expose to the build" | ||||||
|     required: false |     required: false | ||||||
|   github-token: |   github-token: | ||||||
|     description: "GitHub Token used to authenticate against a repository for Git context" |     description: "GitHub Token used to authenticate against a repository for Git context" | ||||||
|     default: ${{ github.token }} |     default: ${{ github.token }} | ||||||
|     required: false |     required: false | ||||||
|   ssh: |  | ||||||
|     description: "List of SSH agent socket or keys to expose to the build" |  | ||||||
|     required: false |  | ||||||
| 
 | 
 | ||||||
| outputs: | outputs: | ||||||
|   digest: |   digest: | ||||||
|  | |||||||
							
								
								
									
										39
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -4581,7 +4581,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { | |||||||
|     return (mod && mod.__esModule) ? mod : { "default": mod }; |     return (mod && mod.__esModule) ? mod : { "default": mod }; | ||||||
| }; | }; | ||||||
| Object.defineProperty(exports, "__esModule", { value: true }); | Object.defineProperty(exports, "__esModule", { value: true }); | ||||||
| exports.parseVersion = exports.getVersion = exports.isAvailable = exports.hasGitAuthToken = exports.isLocalOrTarExporter = exports.getSecret = exports.getImageID = exports.getImageIDFile = void 0; | exports.parseVersion = exports.getVersion = exports.isAvailable = exports.hasGitAuthToken = exports.isLocalOrTarExporter = exports.getSecret = exports.getSecretFile = exports.getSecretString = exports.getImageID = exports.getImageIDFile = void 0; | ||||||
| const sync_1 = __importDefault(__webpack_require__(750)); | const sync_1 = __importDefault(__webpack_require__(750)); | ||||||
| const fs_1 = __importDefault(__webpack_require__(747)); | const fs_1 = __importDefault(__webpack_require__(747)); | ||||||
| const path_1 = __importDefault(__webpack_require__(622)); | const path_1 = __importDefault(__webpack_require__(622)); | ||||||
| @ -4604,18 +4604,36 @@ function getImageID() { | |||||||
|     }); |     }); | ||||||
| } | } | ||||||
| exports.getImageID = getImageID; | exports.getImageID = getImageID; | ||||||
| function getSecret(kvp) { | function getSecretString(kvp) { | ||||||
|  |     return __awaiter(this, void 0, void 0, function* () { | ||||||
|  |         return getSecret(kvp, false); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | exports.getSecretString = getSecretString; | ||||||
|  | function getSecretFile(kvp) { | ||||||
|  |     return __awaiter(this, void 0, void 0, function* () { | ||||||
|  |         return getSecret(kvp, true); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | exports.getSecretFile = getSecretFile; | ||||||
|  | function getSecret(kvp, file) { | ||||||
|     return __awaiter(this, void 0, void 0, function* () { |     return __awaiter(this, void 0, void 0, function* () { | ||||||
|         const delimiterIndex = kvp.indexOf('='); |         const delimiterIndex = kvp.indexOf('='); | ||||||
|         const key = kvp.substring(0, delimiterIndex); |         const key = kvp.substring(0, delimiterIndex); | ||||||
|         const value = kvp.substring(delimiterIndex + 1); |         let value = kvp.substring(delimiterIndex + 1); | ||||||
|         if (key.length == 0 || value.length == 0) { |         if (key.length == 0 || value.length == 0) { | ||||||
|             throw new Error(`${kvp} is not a valid secret`); |             throw new Error(`${kvp} is not a valid secret`); | ||||||
|         } |         } | ||||||
|  |         if (file) { | ||||||
|  |             if (!fs_1.default.existsSync(value)) { | ||||||
|  |                 throw new Error(`secret file ${value} not found`); | ||||||
|  |             } | ||||||
|  |             value = fs_1.default.readFileSync(value, { encoding: 'utf-8' }); | ||||||
|  |         } | ||||||
|         const secretFile = context.tmpNameSync({ |         const secretFile = context.tmpNameSync({ | ||||||
|             tmpdir: context.tmpDir() |             tmpdir: context.tmpDir() | ||||||
|         }); |         }); | ||||||
|         yield fs_1.default.writeFileSync(secretFile, value); |         fs_1.default.writeFileSync(secretFile, value); | ||||||
|         return `id=${key},src=${secretFile}`; |         return `id=${key},src=${secretFile}`; | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| @ -13032,6 +13050,7 @@ function getInputs(defaultContext) { | |||||||
|             cacheFrom: yield getInputList('cache-from', true), |             cacheFrom: yield getInputList('cache-from', true), | ||||||
|             cacheTo: yield getInputList('cache-to', true), |             cacheTo: yield getInputList('cache-to', true), | ||||||
|             secrets: yield getInputList('secrets', true), |             secrets: yield getInputList('secrets', true), | ||||||
|  |             secretFiles: yield getInputList('secret-files', true), | ||||||
|             githubToken: core.getInput('github-token'), |             githubToken: core.getInput('github-token'), | ||||||
|             ssh: yield getInputList('ssh') |             ssh: yield getInputList('ssh') | ||||||
|         }; |         }; | ||||||
| @ -13084,14 +13103,22 @@ function getBuildArgs(inputs, defaultContext, buildxVersion) { | |||||||
|         })); |         })); | ||||||
|         yield exports.asyncForEach(inputs.secrets, (secret) => __awaiter(this, void 0, void 0, function* () { |         yield exports.asyncForEach(inputs.secrets, (secret) => __awaiter(this, void 0, void 0, function* () { | ||||||
|             try { |             try { | ||||||
|                 args.push('--secret', yield buildx.getSecret(secret)); |                 args.push('--secret', yield buildx.getSecretString(secret)); | ||||||
|  |             } | ||||||
|  |             catch (err) { | ||||||
|  |                 core.warning(err.message); | ||||||
|  |             } | ||||||
|  |         })); | ||||||
|  |         yield exports.asyncForEach(inputs.secretFiles, (secretFile) => __awaiter(this, void 0, void 0, function* () { | ||||||
|  |             try { | ||||||
|  |                 args.push('--secret', yield buildx.getSecretFile(secretFile)); | ||||||
|             } |             } | ||||||
|             catch (err) { |             catch (err) { | ||||||
|                 core.warning(err.message); |                 core.warning(err.message); | ||||||
|             } |             } | ||||||
|         })); |         })); | ||||||
|         if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && inputs.context == defaultContext) { |         if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && inputs.context == defaultContext) { | ||||||
|             args.push('--secret', yield buildx.getSecret(`GIT_AUTH_TOKEN=${inputs.githubToken}`)); |             args.push('--secret', yield buildx.getSecretString(`GIT_AUTH_TOKEN=${inputs.githubToken}`)); | ||||||
|         } |         } | ||||||
|         yield exports.asyncForEach(inputs.ssh, (ssh) => __awaiter(this, void 0, void 0, function* () { |         yield exports.asyncForEach(inputs.ssh, (ssh) => __awaiter(this, void 0, void 0, function* () { | ||||||
|             args.push('--ssh', ssh); |             args.push('--ssh', ssh); | ||||||
|  | |||||||
| @ -18,17 +18,34 @@ export async function getImageID(): Promise<string | undefined> { | |||||||
|   return fs.readFileSync(iidFile, {encoding: 'utf-8'}); |   return fs.readFileSync(iidFile, {encoding: 'utf-8'}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getSecret(kvp: string): Promise<string> { | export async function getSecretString(kvp: string): Promise<string> { | ||||||
|  |   return getSecret(kvp, false); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export async function getSecretFile(kvp: string): Promise<string> { | ||||||
|  |   return getSecret(kvp, true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export async function getSecret(kvp: string, file: boolean): Promise<string> { | ||||||
|   const delimiterIndex = kvp.indexOf('='); |   const delimiterIndex = kvp.indexOf('='); | ||||||
|   const key = kvp.substring(0, delimiterIndex); |   const key = kvp.substring(0, delimiterIndex); | ||||||
|   const value = kvp.substring(delimiterIndex + 1); |   let value = kvp.substring(delimiterIndex + 1); | ||||||
|   if (key.length == 0 || value.length == 0) { |   if (key.length == 0 || value.length == 0) { | ||||||
|     throw new Error(`${kvp} is not a valid secret`); |     throw new Error(`${kvp} is not a valid secret`); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   if (file) { | ||||||
|  |     if (!fs.existsSync(value)) { | ||||||
|  |       throw new Error(`secret file ${value} not found`); | ||||||
|  |     } | ||||||
|  |     value = fs.readFileSync(value, {encoding: 'utf-8'}); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   const secretFile = context.tmpNameSync({ |   const secretFile = context.tmpNameSync({ | ||||||
|     tmpdir: context.tmpDir() |     tmpdir: context.tmpDir() | ||||||
|   }); |   }); | ||||||
|   await fs.writeFileSync(secretFile, value); |   fs.writeFileSync(secretFile, value); | ||||||
|  | 
 | ||||||
|   return `id=${key},src=${secretFile}`; |   return `id=${key},src=${secretFile}`; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -30,6 +30,7 @@ export interface Inputs { | |||||||
|   cacheFrom: string[]; |   cacheFrom: string[]; | ||||||
|   cacheTo: string[]; |   cacheTo: string[]; | ||||||
|   secrets: string[]; |   secrets: string[]; | ||||||
|  |   secretFiles: string[]; | ||||||
|   githubToken: string; |   githubToken: string; | ||||||
|   ssh: string[]; |   ssh: string[]; | ||||||
| } | } | ||||||
| @ -73,6 +74,7 @@ export async function getInputs(defaultContext: string): Promise<Inputs> { | |||||||
|     cacheFrom: await getInputList('cache-from', true), |     cacheFrom: await getInputList('cache-from', true), | ||||||
|     cacheTo: await getInputList('cache-to', true), |     cacheTo: await getInputList('cache-to', true), | ||||||
|     secrets: await getInputList('secrets', true), |     secrets: await getInputList('secrets', true), | ||||||
|  |     secretFiles: await getInputList('secret-files', true), | ||||||
|     githubToken: core.getInput('github-token'), |     githubToken: core.getInput('github-token'), | ||||||
|     ssh: await getInputList('ssh') |     ssh: await getInputList('ssh') | ||||||
|   }; |   }; | ||||||
| @ -123,13 +125,20 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersio | |||||||
|   }); |   }); | ||||||
|   await asyncForEach(inputs.secrets, async secret => { |   await asyncForEach(inputs.secrets, async secret => { | ||||||
|     try { |     try { | ||||||
|       args.push('--secret', await buildx.getSecret(secret)); |       args.push('--secret', await buildx.getSecretString(secret)); | ||||||
|  |     } catch (err) { | ||||||
|  |       core.warning(err.message); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  |   await asyncForEach(inputs.secretFiles, async secretFile => { | ||||||
|  |     try { | ||||||
|  |       args.push('--secret', await buildx.getSecretFile(secretFile)); | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       core.warning(err.message); |       core.warning(err.message); | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
|   if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && inputs.context == defaultContext) { |   if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && inputs.context == defaultContext) { | ||||||
|     args.push('--secret', await buildx.getSecret(`GIT_AUTH_TOKEN=${inputs.githubToken}`)); |     args.push('--secret', await buildx.getSecretString(`GIT_AUTH_TOKEN=${inputs.githubToken}`)); | ||||||
|   } |   } | ||||||
|   await asyncForEach(inputs.ssh, async ssh => { |   await asyncForEach(inputs.ssh, async ssh => { | ||||||
|     args.push('--ssh', ssh); |     args.push('--ssh', ssh); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user