Skip to content

Commit af867d4

Browse files
authored
Merge pull request #296 from crazy-max/secret-file
Allow to use secret file mount
2 parents 3db4797 + 33eec15 commit af867d4

File tree

9 files changed

+122
-33
lines changed

9 files changed

+122
-33
lines changed

Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#syntax=docker/dockerfile:1.1-experimental
1+
#syntax=docker/dockerfile:1.2
22

33
FROM node:12 AS deps
44
WORKDIR /src

README.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -471,9 +471,6 @@ using [actions/cache](https://github.com/actions/cache) with this action:
471471
```
472472
</details>
473473

474-
> If you want to [export layers for all stages](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue),
475-
> you have to specify `mode=max` attribute in `cache-to`.
476-
477474
### Handle tags and labels
478475

479476
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
622619
| `outputs` | List | List of [output destinations](https://github.com/docker/buildx#-o---outputpath-typetypekeyvalue) (format: `type=local,dest=path`) |
623620
| `cache-from` | List | List of [external cache sources](https://github.com/docker/buildx#--cache-fromnametypetypekeyvalue) (eg. `type=local,src=path/to/dir`) |
624621
| `cache-to` | List | List of [cache export destinations](https://github.com/docker/buildx#--cache-tonametypetypekeyvalue) (eg. `type=local,dest=path/to/dir`) |
625-
| `secrets` | List | List of secrets to expose to the build (eg. `key=value`, `GIT_AUTH_TOKEN=mytoken`) |
622+
| `secrets` | List | List of secrets to expose to the build (eg. `key=string`, `GIT_AUTH_TOKEN=mytoken`) |
623+
| `secret-files` | List | List of secret files to expose to the build (eg. `key=filename`, `MY_SECRET=./secret.txt`) |
626624
| `ssh` | List | List of SSH agent socket or keys to expose to the build |
627625

628626
### outputs

__tests__/buildx.test.ts

+26-13
Original file line numberDiff line numberDiff line change
@@ -119,21 +119,34 @@ describe('parseVersion', () => {
119119

120120
describe('getSecret', () => {
121121
test.each([
122-
['A_SECRET=abcdef0123456789', 'A_SECRET', 'abcdef0123456789', false],
123-
['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', false],
124-
['MY_KEY=c3RyaW5nLXdpdGgtZXF1YWxzCg==', 'MY_KEY', 'c3RyaW5nLXdpdGgtZXF1YWxzCg==', false],
125-
['aaaaaaaa', '', '', true],
126-
['aaaaaaaa=', '', '', true],
127-
['=bbbbbbb', '', '', true]
128-
])('given %p key and %p secret', async (kvp, key, secret, invalid) => {
122+
['A_SECRET=abcdef0123456789', false, 'A_SECRET', 'abcdef0123456789', false],
123+
['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', false, 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', false],
124+
['MY_KEY=c3RyaW5nLXdpdGgtZXF1YWxzCg==', false, 'MY_KEY', 'c3RyaW5nLXdpdGgtZXF1YWxzCg==', false],
125+
['aaaaaaaa', false, '', '', true],
126+
['aaaaaaaa=', false, '', '', true],
127+
['=bbbbbbb', false, '', '', true],
128+
[
129+
`foo=${path.join(__dirname, 'fixtures', 'secret.txt').split(path.sep).join(path.posix.sep)}`,
130+
true,
131+
'foo',
132+
'bar',
133+
false
134+
],
135+
[`notfound=secret`, true, '', '', true]
136+
])('given %p key and %p secret', async (kvp, file, exKey, exValue, invalid) => {
129137
try {
130-
const secretArgs = await buildx.getSecret(kvp);
138+
let secret: string;
139+
if (file) {
140+
secret = await buildx.getSecretFile(kvp);
141+
} else {
142+
secret = await buildx.getSecretString(kvp);
143+
}
131144
expect(true).toBe(!invalid);
132-
console.log(`secretArgs: ${secretArgs}`);
133-
expect(secretArgs).toEqual(`id=${key},src=${tmpNameSync}`);
134-
const secretContent = await fs.readFileSync(tmpNameSync, 'utf-8');
135-
console.log(`secretValue: ${secretContent}`);
136-
expect(secretContent).toEqual(secret);
145+
console.log(`secret: ${secret}`);
146+
expect(secret).toEqual(`id=${exKey},src=${tmpNameSync}`);
147+
const secretValue = await fs.readFileSync(tmpNameSync, 'utf-8');
148+
console.log(`secretValue: ${secretValue}`);
149+
expect(secretValue).toEqual(exValue);
137150
} catch (err) {
138151
expect(true).toBe(invalid);
139152
}

__tests__/context.test.ts

+21
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,27 @@ ccc`],
337337
'--push',
338338
'https://github.com/docker/build-push-action.git#heads/master'
339339
]
340+
],
341+
[
342+
'0.5.1',
343+
new Map<string, string>([
344+
['context', 'https://github.com/docker/build-push-action.git#heads/master'],
345+
['tag', 'localhost:5000/name/app:latest'],
346+
['secret-files', `MY_SECRET=${path.join(__dirname, 'fixtures', 'secret.txt').split(path.sep).join(path.posix.sep)}`],
347+
['file', './test/Dockerfile'],
348+
['builder', 'builder-git-context-2'],
349+
['push', 'true']
350+
]),
351+
[
352+
'buildx',
353+
'build',
354+
'--iidfile', '/tmp/.docker-build-push-jest/iidfile',
355+
'--secret', 'id=MY_SECRET,src=/tmp/.docker-build-push-jest/.tmpname-jest',
356+
'--file', './test/Dockerfile',
357+
'--builder', 'builder-git-context-2',
358+
'--push',
359+
'https://github.com/docker/build-push-action.git#heads/master'
360+
]
340361
]
341362
])(
342363
'given %p with %p as inputs, returns %p',

__tests__/fixtures/secret.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bar

action.yml

+7-4
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,18 @@ inputs:
6060
description: "List of cache export destinations for buildx (eg. user/app:cache, type=local,dest=path/to/dir)"
6161
required: false
6262
secrets:
63-
description: "List of secrets to expose to the build (eg. key=value, GIT_AUTH_TOKEN=mytoken)"
63+
description: "List of secrets to expose to the build (eg. key=string, GIT_AUTH_TOKEN=mytoken)"
6464
required: false
65-
github-token:
66-
description: "GitHub Token used to authenticate against a repository for Git context"
67-
default: ${{ github.token }}
65+
secret-files:
66+
description: "List of secret files to expose to the build (eg. key=filename, MY_SECRET=./secret.txt)"
6867
required: false
6968
ssh:
7069
description: "List of SSH agent socket or keys to expose to the build"
7170
required: false
71+
github-token:
72+
description: "GitHub Token used to authenticate against a repository for Git context"
73+
default: ${{ github.token }}
74+
required: false
7275

7376
outputs:
7477
digest:

dist/index.js

+33-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/buildx.ts

+20-3
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,34 @@ export async function getImageID(): Promise<string | undefined> {
1818
return fs.readFileSync(iidFile, {encoding: 'utf-8'});
1919
}
2020

21-
export async function getSecret(kvp: string): Promise<string> {
21+
export async function getSecretString(kvp: string): Promise<string> {
22+
return getSecret(kvp, false);
23+
}
24+
25+
export async function getSecretFile(kvp: string): Promise<string> {
26+
return getSecret(kvp, true);
27+
}
28+
29+
export async function getSecret(kvp: string, file: boolean): Promise<string> {
2230
const delimiterIndex = kvp.indexOf('=');
2331
const key = kvp.substring(0, delimiterIndex);
24-
const value = kvp.substring(delimiterIndex + 1);
32+
let value = kvp.substring(delimiterIndex + 1);
2533
if (key.length == 0 || value.length == 0) {
2634
throw new Error(`${kvp} is not a valid secret`);
2735
}
36+
37+
if (file) {
38+
if (!fs.existsSync(value)) {
39+
throw new Error(`secret file ${value} not found`);
40+
}
41+
value = fs.readFileSync(value, {encoding: 'utf-8'});
42+
}
43+
2844
const secretFile = context.tmpNameSync({
2945
tmpdir: context.tmpDir()
3046
});
31-
await fs.writeFileSync(secretFile, value);
47+
fs.writeFileSync(secretFile, value);
48+
3249
return `id=${key},src=${secretFile}`;
3350
}
3451

src/context.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export interface Inputs {
3030
cacheFrom: string[];
3131
cacheTo: string[];
3232
secrets: string[];
33+
secretFiles: string[];
3334
githubToken: string;
3435
ssh: string[];
3536
}
@@ -73,6 +74,7 @@ export async function getInputs(defaultContext: string): Promise<Inputs> {
7374
cacheFrom: await getInputList('cache-from', true),
7475
cacheTo: await getInputList('cache-to', true),
7576
secrets: await getInputList('secrets', true),
77+
secretFiles: await getInputList('secret-files', true),
7678
githubToken: core.getInput('github-token'),
7779
ssh: await getInputList('ssh')
7880
};
@@ -123,13 +125,20 @@ async function getBuildArgs(inputs: Inputs, defaultContext: string, buildxVersio
123125
});
124126
await asyncForEach(inputs.secrets, async secret => {
125127
try {
126-
args.push('--secret', await buildx.getSecret(secret));
128+
args.push('--secret', await buildx.getSecretString(secret));
129+
} catch (err) {
130+
core.warning(err.message);
131+
}
132+
});
133+
await asyncForEach(inputs.secretFiles, async secretFile => {
134+
try {
135+
args.push('--secret', await buildx.getSecretFile(secretFile));
127136
} catch (err) {
128137
core.warning(err.message);
129138
}
130139
});
131140
if (inputs.githubToken && !buildx.hasGitAuthToken(inputs.secrets) && inputs.context == defaultContext) {
132-
args.push('--secret', await buildx.getSecret(`GIT_AUTH_TOKEN=${inputs.githubToken}`));
141+
args.push('--secret', await buildx.getSecretString(`GIT_AUTH_TOKEN=${inputs.githubToken}`));
133142
}
134143
await asyncForEach(inputs.ssh, async ssh => {
135144
args.push('--ssh', ssh);

0 commit comments

Comments
 (0)