From 0f1e13cd2dfeb25d3ffb89b440f325d0aaa3f133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Verlhac?= Date: Wed, 11 Mar 2026 09:32:19 +0100 Subject: [PATCH] fix: secrets handled without environment-variables --- index.js | 72 +++++++++++++++++++++++++-------------------------- index.test.js | 50 +++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 36 deletions(-) diff --git a/index.js b/index.js index 96be5256..9b1f15bd 100644 --- a/index.js +++ b/index.js @@ -171,45 +171,45 @@ async function run() { containerDef.environment.push(variable); } }) + } - if (secrets) { - // If secrets array is missing, create it - if (!Array.isArray(containerDef.secrets)) { - containerDef.secrets = []; - } + if (secrets) { + // If secrets array is missing, create it + if (!Array.isArray(containerDef.secrets)) { + containerDef.secrets = []; + } - // Get pairs by splitting on newlines - secrets.split('\n').forEach(function (line) { - // Trim whitespace - const trimmedLine = line.trim(); - // Skip if empty - if (trimmedLine.length === 0) { return; } - // Split on = - const separatorIdx = trimmedLine.indexOf("="); - // If there's nowhere to split - if (separatorIdx === -1) { - throw new Error( - `Cannot parse the secret '${trimmedLine}'. Secret pairs must be of the form NAME=valueFrom, - where valueFrom is an arn from parameter store or secrets manager. See AWS documentation for more information: - https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data.html.`); - } - // Build object - const secret = { - name: trimmedLine.substring(0, separatorIdx), - valueFrom: trimmedLine.substring(separatorIdx + 1), - }; + // Get pairs by splitting on newlines + secrets.split('\n').forEach(function (line) { + // Trim whitespace + const trimmedLine = line.trim(); + // Skip if empty + if (trimmedLine.length === 0) { return; } + // Split on = + const separatorIdx = trimmedLine.indexOf("="); + // If there's nowhere to split + if (separatorIdx === -1) { + throw new Error( + `Cannot parse the secret '${trimmedLine}'. Secret pairs must be of the form NAME=valueFrom, + where valueFrom is an arn from parameter store or secrets manager. See AWS documentation for more information: + https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data.html.`); + } + // Build object + const secret = { + name: trimmedLine.substring(0, separatorIdx), + valueFrom: trimmedLine.substring(separatorIdx + 1), + }; - // Search container definition environment for one matching name - const secretDef = containerDef.secrets.find((s) => s.name == secret.name); - if (secretDef) { - // If found, update - secretDef.valueFrom = secret.valueFrom; - } else { - // Else, create - containerDef.secrets.push(secret); - } - }) - } + // Search container definition environment for one matching name + const secretDef = containerDef.secrets.find((s) => s.name == secret.name); + if (secretDef) { + // If found, update + secretDef.valueFrom = secret.valueFrom; + } else { + // Else, create + containerDef.secrets.push(secret); + } + }) } if (logConfigurationLogDriver) { diff --git a/index.test.js b/index.test.js index 1958ad29..45866dd6 100644 --- a/index.test.js +++ b/index.test.js @@ -315,6 +315,56 @@ describe('Render task definition', () => { expect(mockEcsDescribeTaskDef).toHaveBeenCalledTimes(0); }); + test('renders secrets even if environment-variables is empty', async () => { + core.getInput = jest + .fn() + .mockReturnValueOnce('/secrets/task-definition.json') // task-definition + .mockReturnValueOnce('web') // container-name + .mockReturnValueOnce('nginx:latest') // image + .mockReturnValueOnce('') // environment-variables + .mockReturnValueOnce('') // env-files + .mockReturnValueOnce('') // log Configuration Log Driver + .mockReturnValueOnce('') // log Configuration Options + .mockReturnValueOnce('') // docker labels + .mockReturnValueOnce('') // command + .mockReturnValueOnce('') // task-definition arn + .mockReturnValueOnce('') // task-definition family + .mockReturnValueOnce('') // task-definition revision + .mockReturnValueOnce('NEW_SECRET=arn:aws:ssm:region:0123456789:parameter/secret'); // secrets + + jest.mock('/secrets/task-definition.json', () => ({ + family: 'task-def-family', + containerDefinitions: [ + { + name: "web", + image: "old-image" + } + ] + }), { virtual: true }); + + await run(); + + expect(fs.writeFileSync).toHaveBeenNthCalledWith(1, 'new-task-def-file-name', + JSON.stringify({ + family: 'task-def-family', + containerDefinitions: [ + { + name: "web", + image: "nginx:latest", + secrets: [ + { + name: "NEW_SECRET", + valueFrom: "arn:aws:ssm:region:0123456789:parameter/secret" + } + ] + } + ] + }, null, 2) + ); + + expect(core.setOutput).toHaveBeenNthCalledWith(1, 'task-definition', 'new-task-def-file-name'); + }); + test('renders logConfiguration on the task definition', async () => { core.getInput = jest .fn()