diff --git a/.changeset/chatty-parrots-trade.md b/.changeset/chatty-parrots-trade.md new file mode 100644 index 0000000000..149fc3b2e1 --- /dev/null +++ b/.changeset/chatty-parrots-trade.md @@ -0,0 +1,13 @@ +--- +'@backstage/config-loader': minor +--- + +The default environment variable substitution function will now trim whitespace characters from the substituted value. This alleviates bugs where whitespace characters are mistakenly included in environment variables. + +If you depend on the old behavior, you can override the default substitution function with your own, for example: + +```ts +ConfigSources.default({ + substitutionFunc: async name => process.env[name], +}); +``` diff --git a/packages/config-loader/api-report.md b/packages/config-loader/api-report.md index 66572dd960..bc8f217bbb 100644 --- a/packages/config-loader/api-report.md +++ b/packages/config-loader/api-report.md @@ -25,7 +25,6 @@ export interface BaseConfigSourcesOptions { remote?: Pick; // (undocumented) rootDir?: string; - // (undocumented) substitutionFunc?: EnvFunc; // (undocumented) watch?: boolean; diff --git a/packages/config-loader/src/sources/ConfigSources.ts b/packages/config-loader/src/sources/ConfigSources.ts index 03fc6d83d6..ecff39da2d 100644 --- a/packages/config-loader/src/sources/ConfigSources.ts +++ b/packages/config-loader/src/sources/ConfigSources.ts @@ -74,6 +74,14 @@ export interface BaseConfigSourcesOptions { watch?: boolean; rootDir?: string; remote?: Pick; + + /** + * A custom substitution function that overrides the default one. + * + * @remarks + * The substitution function handles syntax like `${MY_ENV_VAR}` in configuration values. + * The default substitution will read the value from the environment and trim whitespace. + */ substitutionFunc?: SubstitutionFunc; } diff --git a/packages/config-loader/src/sources/transform/apply.test.ts b/packages/config-loader/src/sources/transform/apply.test.ts index 9f1dfbc672..3e5a4bd5e6 100644 --- a/packages/config-loader/src/sources/transform/apply.test.ts +++ b/packages/config-loader/src/sources/transform/apply.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { applyConfigTransforms } from './apply'; +import { applyConfigTransforms, createConfigTransformer } from './apply'; describe('applyConfigTransforms', () => { it('should apply no transforms to input', async () => { @@ -84,3 +84,32 @@ describe('applyConfigTransforms', () => { }); }); }); + +describe('createConfigTransformer', () => { + const origEnv = process.env; + process.env = { + ...process.env, + SECRET: 'my-secret', + PADDED_SECRET: ' \nmy-space \t', + }; + + afterAll(() => { + process.env = origEnv; + }); + + it('should substitute environment variables', async () => { + const transformer = createConfigTransformer({}); + + await expect( + transformer({ + testAlone: '${SECRET}', + testMiddle: 'hello ${SECRET}!', + testSpace: 'hello ${PADDED_SECRET}!', + }), + ).resolves.toEqual({ + testAlone: 'my-secret', + testMiddle: 'hello my-secret!', + testSpace: 'hello my-space!', + }); + }); +}); diff --git a/packages/config-loader/src/sources/transform/apply.ts b/packages/config-loader/src/sources/transform/apply.ts index 48d9c5a1e8..89ca647a1a 100644 --- a/packages/config-loader/src/sources/transform/apply.ts +++ b/packages/config-loader/src/sources/transform/apply.ts @@ -105,8 +105,10 @@ export function createConfigTransformer(options: { substitutionFunc?: SubstitutionFunc; readFile?(path: string): Promise; }): ConfigTransformer { - const { substitutionFunc = async name => process.env[name], readFile } = - options; + const { + substitutionFunc = async name => process.env[name]?.trim(), + readFile, + } = options; const substitutionTransform = createSubstitutionTransform(substitutionFunc); const transforms = [substitutionTransform]; if (readFile) {