From 12c6bf2bd324b4f521c61d30c9d661f9217b983a Mon Sep 17 00:00:00 2001 From: "Luis (LT) Carbonell" Date: Fri, 13 Jan 2023 12:48:54 -0600 Subject: [PATCH 1/3] Add decoding to secrets --- action.yml | 3 +++ dist/index.js | 18 ++++++++++++++++-- src/action.js | 18 ++++++++++++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/action.yml b/action.yml index 13b14ae3..7b4ed8af 100644 --- a/action.yml +++ b/action.yml @@ -76,6 +76,9 @@ inputs: description: 'Time in seconds, after which token expires' required: false default: 3600 + secretEncoding: + description: 'Encoding of the secret value. Can be "base64", "hex", "utf8".' + required: false runs: using: 'node16' main: 'dist/index.js' diff --git a/dist/index.js b/dist/index.js index fd4b100b..787fdba0 100644 --- a/dist/index.js +++ b/dist/index.js @@ -17129,6 +17129,8 @@ async function exportSecrets() { const secretsInput = core.getInput('secrets', { required: false }); const secretRequests = parseSecretsInput(secretsInput); + const secretEncoding = core.getInput('secretEncoding', { required: false }); + const vaultMethod = (core.getInput('method', { required: false }) || 'token').toLowerCase(); const authPayload = core.getInput('authPayload', { required: false }); if (!AUTH_METHODS.includes(vaultMethod) && !authPayload) { @@ -17193,11 +17195,23 @@ async function exportSecrets() { const results = await getSecrets(requests, client); + for (const result of results) { - const { value, request, cachedResponse } = result; + // Output the result + + var value = result.value; + const request = result.request; + const cachedResponse = result.cachedResponse; + if (cachedResponse) { core.debug('ℹ using cached response'); } + + // if a secret is encoded, decode it + if (secretEncoding) { + value = Buffer.from(value, secretEncoding).toString(); + } + for (const line of value.replace(/\r/g, '').split('\n')) { if (line.length > 0) { command.issue('add-mask', line); @@ -17211,7 +17225,7 @@ async function exportSecrets() { } }; -/** @typedef {Object} SecretRequest +/** @typedef {Object} SecretRequest * @property {string} path * @property {string} envVarName * @property {string} outputVarName diff --git a/src/action.js b/src/action.js index b52bba37..9bb229dc 100644 --- a/src/action.js +++ b/src/action.js @@ -17,6 +17,8 @@ async function exportSecrets() { const secretsInput = core.getInput('secrets', { required: false }); const secretRequests = parseSecretsInput(secretsInput); + const secretEncoding = core.getInput('secretEncoding', { required: false }); + const vaultMethod = (core.getInput('method', { required: false }) || 'token').toLowerCase(); const authPayload = core.getInput('authPayload', { required: false }); if (!AUTH_METHODS.includes(vaultMethod) && !authPayload) { @@ -81,11 +83,23 @@ async function exportSecrets() { const results = await getSecrets(requests, client); + for (const result of results) { - const { value, request, cachedResponse } = result; + // Output the result + + var value = result.value; + const request = result.request; + const cachedResponse = result.cachedResponse; + if (cachedResponse) { core.debug('ℹ using cached response'); } + + // if a secret is encoded, decode it + if (secretEncoding) { + value = Buffer.from(value, secretEncoding).toString(); + } + for (const line of value.replace(/\r/g, '').split('\n')) { if (line.length > 0) { command.issue('add-mask', line); @@ -99,7 +113,7 @@ async function exportSecrets() { } }; -/** @typedef {Object} SecretRequest +/** @typedef {Object} SecretRequest * @property {string} path * @property {string} envVarName * @property {string} outputVarName From 3e767302eb878d5e15970c9cc76b2181bf508b1a Mon Sep 17 00:00:00 2001 From: "Luis (LT) Carbonell" Date: Fri, 13 Jan 2023 14:32:37 -0600 Subject: [PATCH 2/3] remove index.js --- dist/index.js | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/dist/index.js b/dist/index.js index 787fdba0..fd4b100b 100644 --- a/dist/index.js +++ b/dist/index.js @@ -17129,8 +17129,6 @@ async function exportSecrets() { const secretsInput = core.getInput('secrets', { required: false }); const secretRequests = parseSecretsInput(secretsInput); - const secretEncoding = core.getInput('secretEncoding', { required: false }); - const vaultMethod = (core.getInput('method', { required: false }) || 'token').toLowerCase(); const authPayload = core.getInput('authPayload', { required: false }); if (!AUTH_METHODS.includes(vaultMethod) && !authPayload) { @@ -17195,23 +17193,11 @@ async function exportSecrets() { const results = await getSecrets(requests, client); - for (const result of results) { - // Output the result - - var value = result.value; - const request = result.request; - const cachedResponse = result.cachedResponse; - + const { value, request, cachedResponse } = result; if (cachedResponse) { core.debug('ℹ using cached response'); } - - // if a secret is encoded, decode it - if (secretEncoding) { - value = Buffer.from(value, secretEncoding).toString(); - } - for (const line of value.replace(/\r/g, '').split('\n')) { if (line.length > 0) { command.issue('add-mask', line); @@ -17225,7 +17211,7 @@ async function exportSecrets() { } }; -/** @typedef {Object} SecretRequest +/** @typedef {Object} SecretRequest * @property {string} path * @property {string} envVarName * @property {string} outputVarName From 90b1fb477d0b0a558ecd619a4d5b6a2b53390dae Mon Sep 17 00:00:00 2001 From: "Luis (LT) Carbonell" Date: Tue, 17 Jan 2023 10:10:05 -0600 Subject: [PATCH 3/3] Add test case, and other updates --- action.yml | 4 ++-- src/action.js | 7 ++++--- src/action.test.js | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/action.yml b/action.yml index 7b4ed8af..073f5794 100644 --- a/action.yml +++ b/action.yml @@ -76,8 +76,8 @@ inputs: description: 'Time in seconds, after which token expires' required: false default: 3600 - secretEncoding: - description: 'Encoding of the secret value. Can be "base64", "hex", "utf8".' + secretEncodingType: + description: 'The encoding type of the secret to decode. If not specified, the secret will not be decoded. Supported values: base64, hex, utf8' required: false runs: using: 'node16' diff --git a/src/action.js b/src/action.js index 9bb229dc..b898005d 100644 --- a/src/action.js +++ b/src/action.js @@ -6,6 +6,7 @@ const jsonata = require('jsonata'); const { auth: { retrieveToken }, secrets: { getSecrets } } = require('./index'); const AUTH_METHODS = ['approle', 'token', 'github', 'jwt', 'kubernetes']; +const ENCODING_TYPES = ['base64', 'hex', 'utf8']; async function exportSecrets() { const vaultUrl = core.getInput('url', { required: true }); @@ -17,7 +18,7 @@ async function exportSecrets() { const secretsInput = core.getInput('secrets', { required: false }); const secretRequests = parseSecretsInput(secretsInput); - const secretEncoding = core.getInput('secretEncoding', { required: false }); + const secretEncodingType = core.getInput('secretEncodingType', { required: false }); const vaultMethod = (core.getInput('method', { required: false }) || 'token').toLowerCase(); const authPayload = core.getInput('authPayload', { required: false }); @@ -96,8 +97,8 @@ async function exportSecrets() { } // if a secret is encoded, decode it - if (secretEncoding) { - value = Buffer.from(value, secretEncoding).toString(); + if (ENCODING_TYPES.includes(secretEncodingType)) { + value = Buffer.from(value, secretEncodingType).toString(); } for (const line of value.replace(/\r/g, '').split('\n')) { diff --git a/src/action.test.js b/src/action.test.js index 79cb655a..45899bd7 100644 --- a/src/action.test.js +++ b/src/action.test.js @@ -184,6 +184,12 @@ describe('exportSecrets', () => { .mockReturnValueOnce(doExport); } + function mockEncodeType(doEncode) { + when(core.getInput) + .calledWith('secretEncodingType', expect.anything()) + .mockReturnValueOnce(doEncode); + } + it('simple secret retrieval', async () => { mockInput('test key'); mockVaultData({ @@ -196,6 +202,19 @@ describe('exportSecrets', () => { expect(core.setOutput).toBeCalledWith('key', '1'); }); + it('encoded secret retrieval', async () => { + mockInput('test key'); + mockVaultData({ + key: 'MQ==' + }); + mockEncodeType('base64'); + + await exportSecrets(); + + expect(core.exportVariable).toBeCalledWith('KEY', '1'); + expect(core.setOutput).toBeCalledWith('key', '1'); + }); + it('intl secret retrieval', async () => { mockInput('测试 测试'); mockVaultData({