Skip to content

Commit 3526e1b

Browse files
authored
Mask each line of multi-line secrets (#208)
* Mask each line of multi-line secrets * Don't include carriage return characters in masking * Update CHANGELOG.md
1 parent f60544f commit 3526e1b

File tree

3 files changed

+46
-2
lines changed

3 files changed

+46
-2
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
## Unreleased
22

3+
Security:
4+
* multi-line secrets are now properly masked in logs [GH-208](https://github.com/hashicorp/vault-action/pull/208)
5+
36
Features:
47
* JWT auth method is now supported [GH-188](https://github.com/hashicorp/vault-action/pull/188)
58

src/action.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,12 @@ async function exportSecrets() {
7777
const { value, request, cachedResponse } = result;
7878
if (cachedResponse) {
7979
core.debug('ℹ using cached response');
80-
}
81-
command.issue('add-mask', value);
80+
}
81+
for (const line of value.replace(/\r/g, '').split('\n')) {
82+
if (line.length > 0) {
83+
command.issue('add-mask', line);
84+
}
85+
}
8286
if (exportEnv) {
8387
core.exportVariable(request.envVarName, `${value}`);
8488
}

src/action.test.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ jest.mock('got');
22
jest.mock('@actions/core');
33
jest.mock('@actions/core/lib/command');
44

5+
const command = require('@actions/core/lib/command');
56
const core = require('@actions/core');
67
const got = require('got');
78
const {
@@ -294,4 +295,40 @@ describe('exportSecrets', () => {
294295
expect(core.exportVariable).toBeCalledWith('KEY', '1');
295296
expect(core.setOutput).toBeCalledWith('key', '1');
296297
});
298+
299+
it('single-line secret gets masked', async () => {
300+
mockInput('test key');
301+
mockVaultData({
302+
key: 'secret'
303+
});
304+
mockExportToken("false")
305+
306+
await exportSecrets();
307+
308+
expect(command.issue).toBeCalledTimes(1);
309+
310+
expect(command.issue).toBeCalledWith('add-mask', 'secret');
311+
expect(core.setOutput).toBeCalledWith('key', 'secret');
312+
})
313+
314+
it('multi-line secret gets masked for each line', async () => {
315+
const multiLineString = `a multi-line string
316+
317+
with blank lines
318+
319+
`
320+
mockInput('test key');
321+
mockVaultData({
322+
key: multiLineString
323+
});
324+
mockExportToken("false")
325+
326+
await exportSecrets();
327+
328+
expect(command.issue).toBeCalledTimes(2); // 1 for each non-empty line.
329+
330+
expect(command.issue).toBeCalledWith('add-mask', 'a multi-line string');
331+
expect(command.issue).toBeCalledWith('add-mask', 'with blank lines');
332+
expect(core.setOutput).toBeCalledWith('key', multiLineString);
333+
})
297334
});

0 commit comments

Comments
 (0)