From 678f0083241d52863febd27cb1d46701be93f0a9 Mon Sep 17 00:00:00 2001 From: Scott Motte Date: Sat, 17 Feb 2024 16:35:53 -0800 Subject: [PATCH] fix recursive expansion --- lib/main.js | 8 ++++-- package-lock.json | 16 +++++------ package.json | 2 +- tests/.env.test | 10 ++++--- tests/main.js | 69 +++++++++++++++++++---------------------------- 5 files changed, 49 insertions(+), 56 deletions(-) diff --git a/lib/main.js b/lib/main.js index 40bf18b..33e38db 100644 --- a/lib/main.js +++ b/lib/main.js @@ -22,7 +22,12 @@ function interpolate (value, processEnv, parsed) { return match.slice(1) } else { if (processEnv[key]) { - return processEnv[key] + if (processEnv[key] === parsed[key]) { + return processEnv[key] + } else { + // scenario: PASSWORD_EXPAND_NESTED=${PASSWORD_EXPAND} + return interpolate(processEnv[key], processEnv, parsed) + } } if (parsed[key]) { @@ -57,7 +62,6 @@ function expand (options) { let value = options.parsed[key] const inProcessEnv = Object.prototype.hasOwnProperty.call(processEnv, key) - if (inProcessEnv) { if (processEnv[key] === options.parsed[key]) { // assume was set to processEnv from the .env file if the values match and therefore interpolate diff --git a/package-lock.json b/package-lock.json index da68650..45272b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "11.0.4", "license": "BSD-2-Clause", "dependencies": { - "dotenv": "^16.4.1" + "dotenv": "^16.4.4" }, "devDependencies": { "@types/node": "^18.11.3", @@ -1615,14 +1615,14 @@ } }, "node_modules/dotenv": { - "version": "16.4.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", - "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==", + "version": "16.4.4", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.4.tgz", + "integrity": "sha512-XvPXc8XAQThSjAbY6cQ/9PcBXmFoWuw1sQ3b8HqUCR6ziGXjkTi//kB9SWa2UwqlgdAIuRqAa/9hVljzPehbYg==", "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" + "url": "https://dotenvx.com" } }, "node_modules/dotgitignore": { @@ -9841,9 +9841,9 @@ } }, "dotenv": { - "version": "16.4.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", - "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==" + "version": "16.4.4", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.4.tgz", + "integrity": "sha512-XvPXc8XAQThSjAbY6cQ/9PcBXmFoWuw1sQ3b8HqUCR6ziGXjkTi//kB9SWa2UwqlgdAIuRqAa/9hVljzPehbYg==" }, "dotgitignore": { "version": "2.1.0", diff --git a/package.json b/package.json index 6ea8fe4..76cd467 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,6 @@ "node": ">=12" }, "dependencies": { - "dotenv": "^16.4.1" + "dotenv": "^16.4.4" } } diff --git a/tests/.env.test b/tests/.env.test index 389dc57..b5a602f 100644 --- a/tests/.env.test +++ b/tests/.env.test @@ -73,7 +73,9 @@ EXPAND_SELF=$EXPAND_SELF HOST="something" DOMAIN="https://${HOST}" -https://github.com/motdotla/dotenv-expand/issues/120 -BASE_URL=https://${APP_DOMAIN}/api/ -PUBLIC_DOMAIN="${DEVCONTAINER_CADDY_PUBLIC_DOMAIN}" -PUBLIC_BASE_URL="https://${PUBLIC_DOMAIN}" +# https://github.com/motdotla/dotenv-expand/issues/120 +PASSWORD=password +PASSWORD_EXPAND=${PASSWORD} +PASSWORD_EXPAND_SIMPLE=$PASSWORD +PASSWORD_EXPAND_NESTED=${PASSWORD_EXPAND} +PASSWORD_EXPAND_NESTED_NESTED=${PASSWORD_EXPAND_NESTED} diff --git a/tests/main.js b/tests/main.js index 2864199..3db8947 100644 --- a/tests/main.js +++ b/tests/main.js @@ -63,24 +63,6 @@ t.test('uses environment variables existing already on the machine for expansion ct.end() }) -t.test('does not expand environment variables existing already on the machine that look like they could expand', ct => { - process.env.PASSWORD = 'pas$word' - const dotenv = { - parsed: { - PASSWORD: 'dude', - PASSWORD_EXPAND: '${PASSWORD}', - PASSWORD_EXPAND_SIMPLE: '$PASSWORD' - } - } - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.PASSWORD_EXPAND, 'pas$word') - ct.equal(parsed.PASSWORD_EXPAND_SIMPLE, 'pas$word') - ct.equal(parsed.PASSWORD, 'pas$word') - - ct.end() -}) - t.test('expands missing environment variables to an empty string', ct => { const dotenv = { parsed: { @@ -510,29 +492,6 @@ t.test('does not attempt to expand password if already existed in processEnv', c ct.end() }) -t.test('expands using processEnv already set on docker machine', ct => { - process.env.APP_DOMAIN = 'example.com' // simulate env set on docker already - - const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) - dotenvExpand.expand(dotenv) - - ct.equal(process.env.BASE_URL, 'https://example.com/api/') - - ct.end() -}) - -t.test('recursively expands using processEnv already set on docker machine', ct => { - process.env.DEVCONTAINER_CADDY_PUBLIC_DOMAIN = 'mydom.test' // simulate env set on docker already - - const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) - dotenvExpand.expand(dotenv) - - ct.equal(process.env.PUBLIC_DOMAIN, 'mydom.test') - ct.equal(process.env.PUBLIC_BASE_URL, 'https://mydom.test') - - ct.end() -}) - t.test('does not expand dollar sign that are not variables', ct => { const dotenv = { parsed: { @@ -579,3 +538,31 @@ t.test('expands recursively reverse order', ct => { ct.end() }) + +t.test('expands recursively', ct => { + const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) + dotenvExpand.expand(dotenv) + + ct.equal(process.env.PASSWORD_EXPAND, 'password') + ct.equal(process.env.PASSWORD_EXPAND_SIMPLE, 'password') + ct.equal(process.env.PASSWORD, 'password') + ct.equal(process.env.PASSWORD_EXPAND_NESTED, 'password') + ct.equal(process.env.PASSWORD_EXPAND_NESTED, 'password') + + ct.end() +}) + +t.test('expands recursively but is smart enough to not attempt expansion of a pre-set env in process.env', ct => { + process.env.PASSWORD = 'pas$word' + + const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) + dotenvExpand.expand(dotenv) + + ct.equal(process.env.PASSWORD_EXPAND, 'pas$word') + ct.equal(process.env.PASSWORD_EXPAND_SIMPLE, 'pas$word') + ct.equal(process.env.PASSWORD, 'pas$word') + ct.equal(process.env.PASSWORD_EXPAND_NESTED, 'pas$word') + ct.equal(process.env.PASSWORD_EXPAND_NESTED, 'pas$word') + + ct.end() +})