From 62936413261a54829131f3e6354d7ffc8a8db2d0 Mon Sep 17 00:00:00 2001
From: Oleg Krivtsov <olegkrivtsov@gmail.com>
Date: Thu, 25 Nov 2021 18:18:27 +0700
Subject: [PATCH] feat(config): add safeguard timeouts  (#12604)

* Add safeguard timeouts #2804

* Fix unit tests

* Fix unit tests

* Update lib/util/exec/index.ts

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>

* Changes after code review

* Fixes after merge

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
Co-authored-by: Rhys Arkins <rhys@arkins.net>
---
 docs/usage/self-hosted-configuration.md |  5 +++++
 lib/config/global.ts                    |  1 +
 lib/config/options/index.ts             |  8 ++++++++
 lib/config/types.ts                     |  1 +
 lib/util/exec/index.spec.ts             | 20 ++++++++++++++++++++
 lib/util/exec/index.ts                  | 12 ++++++++++--
 6 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md
index 362f3af83f..6283d86b00 100644
--- a/docs/usage/self-hosted-configuration.md
+++ b/docs/usage/self-hosted-configuration.md
@@ -250,6 +250,11 @@ e.g.
 
 ## endpoint
 
+## executionTimeout
+
+Default execution timeout in minutes for child processes Renovate creates.
+If this option is not set, Renovate will fallback to 15 minutes.
+
 ## exposeAllEnv
 
 By default, Renovate only passes a limited set of environment variables to package managers.
diff --git a/lib/config/global.ts b/lib/config/global.ts
index 313bc2ff4b..9a1b68f7fa 100644
--- a/lib/config/global.ts
+++ b/lib/config/global.ts
@@ -16,6 +16,7 @@ export class GlobalConfig {
     'dockerUser',
     'dryRun',
     'exposeAllEnv',
+    'executionTimeout',
     'localDir',
     'migratePresets',
     'privateKey',
diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts
index 2d0d0bebb3..da9e1d713b 100644
--- a/lib/config/options/index.ts
+++ b/lib/config/options/index.ts
@@ -747,6 +747,14 @@ const options: RenovateOptions[] = [
     subType: 'string',
     default: [],
   },
+  {
+    name: 'executionTimeout',
+    description:
+      'Default execution timeout in minutes for child processes Renovate creates.',
+    type: 'integer',
+    default: 15,
+    globalOnly: true,
+  },
   {
     name: 'aliases',
     description: 'Aliases for registries, package manager specific.',
diff --git a/lib/config/types.ts b/lib/config/types.ts
index c1ca573ce6..27634a140a 100644
--- a/lib/config/types.ts
+++ b/lib/config/types.ts
@@ -102,6 +102,7 @@ export interface RepoGlobalConfig {
   dockerImagePrefix?: string;
   dockerUser?: string;
   dryRun?: boolean;
+  executionTimeout?: number;
   exposeAllEnv?: boolean;
   migratePresets?: Record<string, string>;
   privateKey?: string;
diff --git a/lib/util/exec/index.spec.ts b/lib/util/exec/index.spec.ts
index eca56e89d9..cf0eddd085 100644
--- a/lib/util/exec/index.spec.ts
+++ b/lib/util/exec/index.spec.ts
@@ -542,6 +542,26 @@ describe('util/exec/index', () => {
       },
     ],
 
+    [
+      'Default timeout from executionTimeout config option',
+      {
+        processEnv,
+        inCmd,
+        inOpts: {},
+        outCmd,
+        outOpts: [
+          {
+            cwd,
+            encoding,
+            env: envMock.basic,
+            timeout: 30 * 60 * 1000,
+            maxBuffer: 10485760,
+          },
+        ],
+        adminConfig: { executionTimeout: 30 },
+      },
+    ],
+
     [
       'Explicit maxBuffer',
       {
diff --git a/lib/util/exec/index.ts b/lib/util/exec/index.ts
index 221790b16a..4e2310bf73 100644
--- a/lib/util/exec/index.ts
+++ b/lib/util/exec/index.ts
@@ -68,6 +68,7 @@ function getCwd({ cwd, cwdFile }: ExecOptions): string {
 }
 
 function getRawExecOptions(opts: ExecOptions): RawExecOptions {
+  const defaultExecutionTimeout = GlobalConfig.get('executionTimeout');
   const execOptions: ExecOptions = { ...opts };
   delete execOptions.extraEnv;
   delete execOptions.docker;
@@ -82,8 +83,15 @@ function getRawExecOptions(opts: ExecOptions): RawExecOptions {
     env: childEnv,
     cwd,
   };
-  // Set default timeout to 15 minutes
-  rawExecOptions.timeout = rawExecOptions.timeout || 15 * 60 * 1000;
+  // Set default timeout config.executionTimeout if specified; othrwise to 15 minutes
+  if (!rawExecOptions.timeout) {
+    if (defaultExecutionTimeout) {
+      rawExecOptions.timeout = defaultExecutionTimeout * 60 * 1000;
+    } else {
+      rawExecOptions.timeout = 15 * 60 * 1000;
+    }
+  }
+
   // Set default max buffer size to 10MB
   rawExecOptions.maxBuffer = rawExecOptions.maxBuffer || 10 * 1024 * 1024;
   return rawExecOptions;
-- 
GitLab