From dad3863e8aa5f6ec7369f76d7e29970cc63d4263 Mon Sep 17 00:00:00 2001
From: Oleg Krivtsov <olegkrivtsov@gmail.com>
Date: Wed, 22 Dec 2021 14:38:49 +0700
Subject: [PATCH] fix(config): detect missing RENOVATE_CONFIG_FILE (#13196)

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
---
 .../__fixtures__/config-ref-error.js-invalid  |  4 ++++
 lib/workers/global/config/parse/file.spec.ts  | 24 +++++++++++++++++++
 lib/workers/global/config/parse/file.ts       | 15 ++++++++++++
 3 files changed, 43 insertions(+)
 create mode 100644 lib/workers/global/config/parse/__fixtures__/config-ref-error.js-invalid

diff --git a/lib/workers/global/config/parse/__fixtures__/config-ref-error.js-invalid b/lib/workers/global/config/parse/__fixtures__/config-ref-error.js-invalid
new file mode 100644
index 0000000000..156a4ee747
--- /dev/null
+++ b/lib/workers/global/config/parse/__fixtures__/config-ref-error.js-invalid
@@ -0,0 +1,4 @@
+// @ts-ignore
+module.exports = {
+  endpoint: CI_API_V4_URL
+};
diff --git a/lib/workers/global/config/parse/file.spec.ts b/lib/workers/global/config/parse/file.spec.ts
index a082675216..f69792d891 100644
--- a/lib/workers/global/config/parse/file.spec.ts
+++ b/lib/workers/global/config/parse/file.spec.ts
@@ -1,4 +1,5 @@
 import fs from 'fs';
+import fsExtra from 'fs-extra';
 import { DirectoryResult, dir } from 'tmp-promise';
 import upath from 'upath';
 import { logger } from '../../../../logger';
@@ -92,6 +93,29 @@ describe('workers/global/config/parse/file', () => {
       expect(mockProcessExit).toHaveBeenCalledWith(1);
     });
 
+    it('fatal error and exit if config.js contains unresolved env var', async () => {
+      const mockProcessExit = jest
+        .spyOn(process, 'exit')
+        .mockImplementation(() => undefined as never);
+
+      const configFile = upath.resolve(
+        __dirname,
+        './__fixtures__/config-ref-error.js-invalid'
+      );
+      const tmpDir = tmp.path;
+      await fsExtra.ensureDir(tmpDir);
+
+      const tmpConfigFile = upath.resolve(tmpDir, 'config-ref-error.js');
+      await fsExtra.copy(configFile, tmpConfigFile);
+
+      await file.getConfig({ RENOVATE_CONFIG_FILE: tmpConfigFile });
+
+      expect(logger.fatal).toHaveBeenCalledWith(
+        `Error parsing config file due to unresolved variable(s): CI_API_V4_URL is not defined`
+      );
+      expect(mockProcessExit).toHaveBeenCalledWith(1);
+    });
+
     it.each([
       ['invalid config file type', './file.txt'],
       ['missing config file type', './file'],
diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts
index 90bd2aa809..fa2076c3c1 100644
--- a/lib/workers/global/config/parse/file.ts
+++ b/lib/workers/global/config/parse/file.ts
@@ -1,4 +1,5 @@
 import is from '@sindresorhus/is';
+import * as fs from 'fs-extra';
 import { load } from 'js-yaml';
 import JSON5 from 'json5';
 import upath from 'upath';
@@ -36,6 +37,15 @@ export async function getConfig(env: NodeJS.ProcessEnv): Promise<AllConfig> {
   if (!upath.isAbsolute(configFile)) {
     configFile = `${process.cwd()}/${configFile}`;
   }
+
+  if (env.RENOVATE_CONFIG_FILE && !(await fs.pathExists(configFile))) {
+    logger.fatal(
+      { configFile },
+      `Custom config file specified in RENOVATE_CONFIG_FILE must exist`
+    );
+    process.exit(1);
+  }
+
   logger.debug('Checking for config file in ' + configFile);
   let config: AllConfig = {};
   try {
@@ -45,6 +55,11 @@ export async function getConfig(env: NodeJS.ProcessEnv): Promise<AllConfig> {
     if (err instanceof SyntaxError || err instanceof TypeError) {
       logger.fatal(`Could not parse config file \n ${err.stack}`);
       process.exit(1);
+    } else if (err instanceof ReferenceError) {
+      logger.fatal(
+        `Error parsing config file due to unresolved variable(s): ${err.message}`
+      );
+      process.exit(1);
     } else if (err.message === 'Unsupported file type') {
       logger.fatal(err.message);
       process.exit(1);
-- 
GitLab