diff --git a/CHANGELOG.md b/CHANGELOG.md index bae4e99..757215b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## Unreleased +Security: +* multi-line secrets are now properly masked in logs [GH-208](https://github.com/hashicorp/vault-action/pull/208) + Features: * JWT auth method is now supported [GH-188](https://github.com/hashicorp/vault-action/pull/188) diff --git a/src/action.js b/src/action.js index 8b982e4..dd2c904 100644 --- a/src/action.js +++ b/src/action.js @@ -77,8 +77,12 @@ async function exportSecrets() { const { value, request, cachedResponse } = result; if (cachedResponse) { core.debug('ℹ using cached response'); - } - command.issue('add-mask', value); + } + for (const line of value.replace(/\r/g, '').split('\n')) { + if (line.length > 0) { + command.issue('add-mask', line); + } + } if (exportEnv) { core.exportVariable(request.envVarName, `${value}`); } diff --git a/src/action.test.js b/src/action.test.js index cd7828e..1837eaf 100644 --- a/src/action.test.js +++ b/src/action.test.js @@ -2,6 +2,7 @@ jest.mock('got'); jest.mock('@actions/core'); jest.mock('@actions/core/lib/command'); +const command = require('@actions/core/lib/command'); const core = require('@actions/core'); const got = require('got'); const { @@ -294,4 +295,40 @@ describe('exportSecrets', () => { expect(core.exportVariable).toBeCalledWith('KEY', '1'); expect(core.setOutput).toBeCalledWith('key', '1'); }); + + it('single-line secret gets masked', async () => { + mockInput('test key'); + mockVaultData({ + key: 'secret' + }); + mockExportToken("false") + + await exportSecrets(); + + expect(command.issue).toBeCalledTimes(1); + + expect(command.issue).toBeCalledWith('add-mask', 'secret'); + expect(core.setOutput).toBeCalledWith('key', 'secret'); + }) + + it('multi-line secret gets masked for each line', async () => { + const multiLineString = `a multi-line string + +with blank lines + +` + mockInput('test key'); + mockVaultData({ + key: multiLineString + }); + mockExportToken("false") + + await exportSecrets(); + + expect(command.issue).toBeCalledTimes(2); // 1 for each non-empty line. + + expect(command.issue).toBeCalledWith('add-mask', 'a multi-line string'); + expect(command.issue).toBeCalledWith('add-mask', 'with blank lines'); + expect(core.setOutput).toBeCalledWith('key', multiLineString); + }) });