Skip to content

Commit c6393e7

Browse files
authored
Merge pull request #1030 from crazy-max/secret-file-rm-copy
buildx(build): preserve original paths for file secrets
2 parents ed92d5b + 8b5d8e5 commit c6393e7

2 files changed

Lines changed: 56 additions & 38 deletions

File tree

__tests__/buildx/build.test.ts

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -267,44 +267,63 @@ describe('resolveProvenanceAttrs', () => {
267267
});
268268

269269
describe('resolveSecret', () => {
270+
// prettier-ignore
270271
test.each([
271-
['A_SECRET=abcdef0123456789', false, 'A_SECRET', 'abcdef0123456789', null],
272-
['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', false, 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789', null],
273-
['MY_KEY=c3RyaW5nLXdpdGgtZXF1YWxzCg==', false, 'MY_KEY', 'c3RyaW5nLXdpdGgtZXF1YWxzCg==', null],
274-
['aaaaaaaa', false, '', '', new Error('aaaaaaaa is not a valid secret')],
275-
['aaaaaaaa=', false, '', '', new Error('aaaaaaaa= is not a valid secret')],
276-
['=bbbbbbb', false, '', '', new Error('=bbbbbbb is not a valid secret')],
277-
[`foo=${path.join(fixturesDir, 'secret.txt')}`, true, 'foo', 'bar', null],
278-
[`notfound=secret`, true, '', '', new Error('secret file secret not found')]
279-
])('given %o key and %o secret', async (kvp: string, file: boolean, exKey: string, exValue: string, error: Error | null) => {
280-
try {
281-
let secret: string;
282-
if (file) {
283-
secret = Build.resolveSecretFile(kvp);
284-
} else {
285-
secret = Build.resolveSecretString(kvp);
286-
}
287-
expect(secret).toEqual(`id=${exKey},src=${tmpName}`);
288-
expect(fs.readFileSync(tmpName, 'utf-8')).toEqual(exValue);
289-
} catch (e) {
290-
// eslint-disable-next-line vitest/no-conditional-expect
291-
expect(e.message).toEqual(error?.message);
292-
}
272+
['A_SECRET=abcdef0123456789', 'A_SECRET', 'abcdef0123456789'],
273+
['GIT_AUTH_TOKEN=abcdefghijklmno=0123456789', 'GIT_AUTH_TOKEN', 'abcdefghijklmno=0123456789'],
274+
['MY_KEY=c3RyaW5nLXdpdGgtZXF1YWxzCg==', 'MY_KEY', 'c3RyaW5nLXdpdGgtZXF1YWxzCg==']
275+
])('given %o key and string secret', (kvp: string, exKey: string, exValue: string) => {
276+
const secret = Build.resolveSecretString(kvp);
277+
expect(secret).toEqual(`id=${exKey},src=${tmpName}`);
278+
expect(fs.readFileSync(tmpName, 'utf-8')).toEqual(exValue);
279+
});
280+
281+
// prettier-ignore
282+
test.each([
283+
[`foo=${path.join(fixturesDir, 'secret.txt')}`, 'foo', path.join(fixturesDir, 'secret.txt')]
284+
])('given %o key and file secret', (kvp: string, exKey: string, exSrc: string) => {
285+
const secret = Build.resolveSecretFile(kvp);
286+
expect(secret).toEqual(`id=${exKey},src=${exSrc}`);
287+
});
288+
289+
// prettier-ignore
290+
test.each([
291+
['aaaaaaaa', false, 'aaaaaaaa is not a valid secret'],
292+
['aaaaaaaa=', false, 'aaaaaaaa= is not a valid secret'],
293+
['=bbbbbbb', false, '=bbbbbbb is not a valid secret'],
294+
['notfound=secret', true, 'secret file secret not found']
295+
])('given %o key and %o secret throws', (kvp: string, file: boolean, errorMessage: string) => {
296+
const resolve = (): string => (file ? Build.resolveSecretFile(kvp) : Build.resolveSecretString(kvp));
297+
expect(resolve).toThrow(errorMessage);
293298
});
294299

300+
// prettier-ignore
301+
test('preserves file-backed secret path and bytes', async () => {
302+
fs.mkdirSync(tmpDir, {recursive: true});
303+
const sourceFile = path.join(tmpDir, 'secret.bin');
304+
const sourceBytes = Buffer.from([0x50, 0x4b, 0x03, 0x04, 0x00, 0xff, 0x41, 0x42, 0x43, 0x0a, 0x80]);
305+
fs.writeFileSync(sourceFile, sourceBytes);
306+
const secret = Build.resolveSecretFile(`foo=${sourceFile}`);
307+
expect(secret).toEqual(`id=foo,src=${sourceFile}`);
308+
expect(fs.readFileSync(sourceFile)).toEqual(sourceBytes);
309+
expect(fs.existsSync(tmpName)).toBeFalsy();
310+
});
311+
312+
// prettier-ignore
313+
test.each([
314+
['FOO=bar', 'FOO', 'bar'],
315+
['FOO=bar=baz', 'FOO', 'bar=baz']
316+
])('given %o key and %o env', (kvp: string, exKey: string, exValue: string) => {
317+
const secret = Build.resolveSecretEnv(kvp);
318+
expect(secret).toEqual(`id=${exKey},env=${exValue}`);
319+
});
320+
321+
// prettier-ignore
295322
test.each([
296-
['FOO=bar', 'FOO', 'bar', null],
297-
['FOO=', 'FOO', '', new Error('FOO= is not a valid secret')],
298-
['=bar', '', '', new Error('=bar is not a valid secret')],
299-
['FOO=bar=baz', 'FOO', 'bar=baz', null]
300-
])('given %o key and %o env', async (kvp: string, exKey: string, exValue: string, error: Error | null) => {
301-
try {
302-
const secret = Build.resolveSecretEnv(kvp);
303-
expect(secret).toEqual(`id=${exKey},env=${exValue}`);
304-
} catch (e) {
305-
// eslint-disable-next-line vitest/no-conditional-expect
306-
expect(e.message).toEqual(error?.message);
307-
}
323+
['FOO=', 'FOO= is not a valid secret'],
324+
['=bar', '=bar is not a valid secret']
325+
])('given %o key and %o env throws', (kvp: string, errorMessage: string) => {
326+
expect(() => Build.resolveSecretEnv(kvp)).toThrow(errorMessage);
308327
});
309328
});
310329

src/buildx/build.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,15 +206,14 @@ export class Build {
206206

207207
public static resolveSecret(kvp: string, opts?: ResolveSecretsOpts): [string, string] {
208208
const [key, value] = Build.parseSecretKvp(kvp, opts?.redact);
209-
const secretFile = Context.tmpName({tmpdir: Context.tmpDir()});
210209
if (opts?.asFile) {
211210
if (!fs.existsSync(value)) {
212211
throw new Error(`secret file ${value} not found`);
213212
}
214-
fs.copyFileSync(value, secretFile);
215-
} else {
216-
fs.writeFileSync(secretFile, value);
213+
return [key, value];
217214
}
215+
const secretFile = Context.tmpName({tmpdir: Context.tmpDir()});
216+
fs.writeFileSync(secretFile, value);
218217
return [key, secretFile];
219218
}
220219

0 commit comments

Comments
 (0)