diff --git a/lib/util/exec/buildpack.ts b/lib/util/exec/buildpack.ts
index 14c9bec7f15acbc5d87ec4b567f290f666aa1f78..ba8c92c01cc9ee7ac9cc08b5952b77b5d9dd6f01 100644
--- a/lib/util/exec/buildpack.ts
+++ b/lib/util/exec/buildpack.ts
@@ -7,7 +7,7 @@ import { id as composerVersioningId } from '../../modules/versioning/composer';
 import { id as npmVersioningId } from '../../modules/versioning/npm';
 import { id as pep440VersioningId } from '../../modules/versioning/pep440';
 import { id as semverVersioningId } from '../../modules/versioning/semver';
-import type { ToolConfig, ToolConstraint } from './types';
+import type { Opt, ToolConfig, ToolConstraint } from './types';
 
 const allToolConfig: Record<string, ToolConfig> = {
   bundler: {
@@ -61,7 +61,9 @@ export function isBuildpack(): boolean {
   return !!process.env.BUILDPACK;
 }
 
-export function isDynamicInstall(toolConstraints?: ToolConstraint[]): boolean {
+export function isDynamicInstall(
+  toolConstraints?: Opt<ToolConstraint[]>
+): boolean {
   const { binarySource } = GlobalConfig.get();
   if (binarySource !== 'install') {
     return false;
@@ -125,9 +127,9 @@ export async function resolveConstraint(
 }
 
 export async function generateInstallCommands(
-  toolConstraints: ToolConstraint[]
+  toolConstraints: Opt<ToolConstraint[]>
 ): Promise<string[]> {
-  const installCommands = [];
+  const installCommands: string[] = [];
   if (toolConstraints?.length) {
     for (const toolConstraint of toolConstraints) {
       const toolVersion = await resolveConstraint(toolConstraint);
diff --git a/lib/util/exec/index.ts b/lib/util/exec/index.ts
index 85424870b29ff069e33375ece8d09f95a002cf86..0bbd94e620290df8b411e971343621fe334efa93 100644
--- a/lib/util/exec/index.ts
+++ b/lib/util/exec/index.ts
@@ -52,7 +52,7 @@ function dockerEnvVars(extraEnv: ExtraEnv, childEnv: ExtraEnv): string[] {
   return extraEnvKeys.filter((key) => is.nonEmptyString(childEnv[key]));
 }
 
-function getCwd({ cwd, cwdFile }: ExecOptions): string {
+function getCwd({ cwd, cwdFile }: ExecOptions): string | undefined {
   const defaultCwd = GlobalConfig.get('localDir');
   const paramCwd = cwdFile
     ? upath.join(defaultCwd, upath.dirname(cwdFile))
@@ -139,7 +139,8 @@ export async function exec(
   opts: ExecOptions = {}
 ): Promise<ExecResult> {
   const { docker } = opts;
-  const dockerChildPrefix = GlobalConfig.get('dockerChildPrefix');
+  const dockerChildPrefix =
+    GlobalConfig.get('dockerChildPrefix') ?? 'renovate_';
 
   const { rawCommands, rawOptions } = await prepareRawExec(cmd, opts);
   const useDocker = isDocker(docker);
diff --git a/lib/util/exec/types.ts b/lib/util/exec/types.ts
index 1abfb3af20c039ea17c9d8334469f8e683efe0c9..b97279b2af8675e21c6f91ccf75b0d25cc180ebe 100644
--- a/lib/util/exec/types.ts
+++ b/lib/util/exec/types.ts
@@ -17,9 +17,6 @@ export type Opt<T> = T | null | undefined;
 export type VolumesPair = [string, string];
 export type VolumeOption = Opt<string | VolumesPair>;
 
-export type DockerExtraCommand = Opt<string>;
-export type DockerExtraCommands = Opt<DockerExtraCommand[]>;
-
 export interface DockerOptions {
   image: string;
   tag?: Opt<string>;
@@ -48,7 +45,7 @@ export interface ExecOptions {
   extraEnv?: Opt<ExtraEnv>;
   docker?: Opt<DockerOptions>;
   toolConstraints?: Opt<ToolConstraint[]>;
-  preCommands?: DockerExtraCommands;
+  preCommands?: Opt<string[]>;
   // Following are pass-through to child process
   maxBuffer?: number | undefined;
   timeout?: number | undefined;
diff --git a/lib/util/git/index.spec.ts b/lib/util/git/index.spec.ts
index d22551eb39f4ada4fbc406a4ad6a041e2ca58e6d..4f0d99779b4801c1bdc16a50bbb0279c95d91ef8 100644
--- a/lib/util/git/index.spec.ts
+++ b/lib/util/git/index.spec.ts
@@ -293,7 +293,7 @@ describe('util/git/index', () => {
       };
       await git.commitFiles({
         branchName: 'renovate/branch_with_changes',
-        files: [file],
+        files: [file, { type: 'addition', path: 'dummy', contents: null }],
         message: 'Create something',
       });
       const branchFiles = await git.getBranchFiles(
diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts
index 32b53c13e05ac570c4bb49329776490e0f8c3949..014c0efb17b7127ba9b6ea04a241a19f059ef5a1 100644
--- a/lib/util/git/index.ts
+++ b/lib/util/git/index.ts
@@ -117,7 +117,7 @@ async function getDefaultBranch(git: SimpleGit): Promise<string> {
       res = (await git.raw(['remote', 'show', 'origin']))
         .split('\n')
         .map((line) => line.trim())
-        .find((line) => line.startsWith(headPrefix))
+        .find((line) => line.startsWith(headPrefix))!
         .replace(headPrefix, '');
     }
     return res.replace('origin/', '').trim();
@@ -144,7 +144,8 @@ async function getDefaultBranch(git: SimpleGit): Promise<string> {
 
 let config: LocalConfig = {} as any;
 
-let git: SimpleGit | undefined;
+// TODO: can be undefined
+let git: SimpleGit;
 let gitInitialized: boolean;
 
 let privateKeySet = false;
@@ -152,7 +153,7 @@ let privateKeySet = false;
 export const GIT_MINIMUM_VERSION = '2.33.0'; // git show-current
 
 export async function validateGitVersion(): Promise<boolean> {
-  let version: string;
+  let version: string | undefined;
   const globalGit = simpleGit();
   try {
     const raw = await globalGit.raw(['--version']);
@@ -248,7 +249,7 @@ async function cleanLocalBranches(): Promise<void> {
   }
 }
 
-export function setGitAuthor(gitAuthor: string): void {
+export function setGitAuthor(gitAuthor: string | undefined): void {
   const gitAuthorParsed = parseGitAuthor(
     gitAuthor || 'Renovate Bot <renovate@whitesourcesoftware.com>'
   );
@@ -325,8 +326,8 @@ export async function syncGit(): Promise<void> {
     return;
   }
   gitInitialized = true;
-  const { localDir } = GlobalConfig.get();
-  logger.debug('Initializing git repository into ' + localDir);
+  const localDir = GlobalConfig.get('localDir')!;
+  logger.debug(`Initializing git repository into ${localDir}`);
   const gitHead = upath.join(localDir, '.git/HEAD');
   let clone = true;
 
@@ -355,7 +356,7 @@ export async function syncGit(): Promise<void> {
   if (clone) {
     const cloneStart = Date.now();
     try {
-      const opts = [];
+      const opts: string[] = [];
       if (config.fullClone) {
         logger.debug('Performing full clone');
       } else {
@@ -506,10 +507,10 @@ export async function getFileList(): Promise<string[]> {
   }
   return files
     .split(newlineRegex)
-    .filter(Boolean)
+    .filter(is.string)
     .filter((line) => line.startsWith('100'))
-    .map((line) => line.split(regEx(/\t/)).pop())
-    .filter((file: string) =>
+    .map((line) => line.split(regEx(/\t/)).pop()!)
+    .filter((file) =>
       submodules.every((submodule: string) => !file.startsWith(submodule))
     );
 }
@@ -557,7 +558,7 @@ export async function isBranchModified(branchName: string): Promise<boolean> {
     return false;
   }
   // Retrieve the author of the most recent commit
-  let lastAuthor: string;
+  let lastAuthor: string | undefined;
   try {
     lastAuthor = (
       await git.raw([
@@ -691,7 +692,7 @@ export async function deleteBranch(branchName: string): Promise<void> {
 }
 
 export async function mergeBranch(branchName: string): Promise<void> {
-  let status: StatusResult;
+  let status: StatusResult | undefined;
   try {
     await syncGit();
     await git.reset(ResetMode.HARD);
@@ -742,7 +743,9 @@ export async function getBranchLastCommitTime(
   }
 }
 
-export async function getBranchFiles(branchName: string): Promise<string[]> {
+export async function getBranchFiles(
+  branchName: string
+): Promise<string[] | null> {
   await syncGit();
   try {
     const diff = await gitRetry(() =>
@@ -815,7 +818,7 @@ export async function prepareCommit({
   message,
   force = false,
 }: CommitFilesConfig): Promise<CommitResult | null> {
-  const { localDir } = GlobalConfig.get();
+  const localDir = GlobalConfig.get('localDir')!;
   await syncGit();
   logger.debug(`Preparing files for committing to branch ${branchName}`);
   await handleCommitAuth(localDir);
@@ -848,7 +851,6 @@ export async function prepareCommit({
           // This is usually a git submodule update
           logger.trace({ fileName }, 'Adding directory commit');
         } else if (file.contents === null) {
-          // istanbul ignore next
           continue;
         } else {
           let contents: Buffer;
@@ -1135,7 +1137,9 @@ const treeShaRegex = regEx(/tree\s+(?<treeSha>[0-9a-f]{40})\s*/);
  */
 export async function listCommitTree(commitSha: string): Promise<TreeItem[]> {
   const commitOutput = await git.catFile(['-p', commitSha]);
-  const { treeSha } = treeShaRegex.exec(commitOutput)?.groups ?? {};
+  const { treeSha } =
+    treeShaRegex.exec(commitOutput)?.groups ??
+    /* istanbul ignore next: will never happen */ {};
   const contents = await git.catFile(['-p', treeSha]);
   const lines = contents.split(newlineRegex);
   const result: TreeItem[] = [];
diff --git a/lib/util/git/private-key.spec.ts b/lib/util/git/private-key.spec.ts
index 21faa327a4460d09f78cb947f903521716c9bec3..d3921992b2df424c3edfd27bbd3852252e8e1321 100644
--- a/lib/util/git/private-key.spec.ts
+++ b/lib/util/git/private-key.spec.ts
@@ -1,10 +1,7 @@
 import { mocked } from '../../../test/util';
 import * as exec_ from '../exec';
-import {
-  configSigningKey,
-  setPrivateKey,
-  writePrivateKey,
-} from './private-key';
+import { configSigningKey, writePrivateKey } from './private-key';
+import { setPrivateKey } from '.';
 
 jest.mock('fs-extra');
 jest.mock('../exec');
@@ -20,7 +17,7 @@ describe('util/git/private-key', () => {
 
     it('throws error if failing', async () => {
       setPrivateKey('some-key');
-      exec.exec.mockResolvedValueOnce({
+      exec.exec.mockRejectedValueOnce({
         stderr: `something wrong`,
         stdout: '',
       });
diff --git a/lib/util/git/private-key.ts b/lib/util/git/private-key.ts
index 834c0930a1c874f6e96520445246f27082e13016..254c280258a447c8b599a66ca9ff0fc0bf4786fd 100644
--- a/lib/util/git/private-key.ts
+++ b/lib/util/git/private-key.ts
@@ -6,8 +6,8 @@ import { logger } from '../../logger';
 import { exec } from '../exec';
 import { newlineRegex } from '../regex';
 
-let gitPrivateKey: string;
-let keyId: string;
+let gitPrivateKey: string | undefined;
+let keyId: string | undefined;
 
 export function setPrivateKey(key: string): void {
   gitPrivateKey = key?.trim();
@@ -21,10 +21,10 @@ async function importKey(): Promise<void> {
   await fs.outputFile(keyFileName, gitPrivateKey);
   const { stdout, stderr } = await exec(`gpg --import ${keyFileName}`);
   logger.debug({ stdout, stderr }, 'Private key import result');
-  keyId = (stdout + stderr)
+  keyId = `${stdout}${stderr}`
     .split(newlineRegex)
     .find((line) => line.includes('secret key imported'))
-    .replace('gpg: key ', '')
+    ?.replace('gpg: key ', '')
     .split(':')
     .shift();
   await fs.remove(keyFileName);
diff --git a/lib/util/git/types.ts b/lib/util/git/types.ts
index 9879eee87a7c41ee4f99e4fe99e84da1eda0cebc..587cd5205d55bd81285b5285eb7d51963dd477c3 100644
--- a/lib/util/git/types.ts
+++ b/lib/util/git/types.ts
@@ -26,7 +26,7 @@ export interface LocalConfig extends StorageConfig {
   branchCommits: Record<string, CommitSha>;
   branchIsModified: Record<string, boolean>;
   ignoredAuthors: string[];
-  gitAuthorName?: string;
+  gitAuthorName?: string | null;
   gitAuthorEmail?: string;
 
   writeGitDone?: boolean;
diff --git a/lib/util/package-rules.spec.ts b/lib/util/package-rules.spec.ts
index 427c9754c0125bb34d9ef1d285da3770916a987f..98c018f383c0c8ab9cc76b0203d1f0580f5fdff3 100644
--- a/lib/util/package-rules.spec.ts
+++ b/lib/util/package-rules.spec.ts
@@ -52,7 +52,6 @@ describe('util/package-rules', () => {
         },
         {
           excludePackagePatterns: ['*'],
-          matchPackageNames: ['b'],
         },
         {
           matchUpdateTypes: ['bump'],
@@ -340,6 +339,10 @@ describe('util/package-rules', () => {
           matchDatasources: [OrbDatasource.id, DockerDatasource.id],
           x: 1,
         },
+        {
+          matchDatasources: [DockerDatasource.id],
+          y: 1,
+        },
       ],
     };
     const dep = {
@@ -349,6 +352,7 @@ describe('util/package-rules', () => {
     };
     const res = applyPackageRules({ ...config, ...dep });
     expect(res.x).toBe(1);
+    expect(res.y).toBeUndefined();
   });
 
   it('filters branches with matching branch', () => {
@@ -446,6 +450,10 @@ describe('util/package-rules', () => {
           matchUpdateTypes: ['minor', 'patch'],
           x: 1,
         },
+        {
+          matchUpdateTypes: ['minor'],
+          y: 1,
+        },
       ],
     };
     const dep = {
@@ -455,6 +463,7 @@ describe('util/package-rules', () => {
     };
     const res = applyPackageRules({ ...config, ...dep });
     expect(res.x).toBe(1);
+    expect(res.y).toBeUndefined();
   });
 
   it('matches matchSourceUrlPrefixes', () => {
@@ -649,6 +658,14 @@ describe('util/package-rules', () => {
       },
     });
     expect(res2.x).toBeUndefined();
+    const res3 = applyPackageRules({
+      ...config,
+      ...{
+        depName: 'test',
+        lockedVersion: '^1.0.0',
+      },
+    });
+    expect(res3.x).toBe(1);
   });
 
   it('checks if matchCurrentVersion selector is valid and satisfies the condition on pinned to range overlap', () => {
diff --git a/lib/util/package-rules.ts b/lib/util/package-rules.ts
index ec18e0f909ddcd078f670097f42470d1e48a6a1d..abe8428496a9ae8fbf0001d61f892122779efb03 100644
--- a/lib/util/package-rules.ts
+++ b/lib/util/package-rules.ts
@@ -73,7 +73,7 @@ function matchesRule(
     }
     positiveMatch = true;
   }
-  if (matchPaths.length) {
+  if (matchPaths.length && packageFile) {
     const isMatch = matchPaths.some(
       (rulePath) =>
         packageFile.includes(rulePath) ||
@@ -86,21 +86,21 @@ function matchesRule(
   }
   if (matchDepTypes.length) {
     const isMatch =
-      matchDepTypes.includes(depType) ||
+      (depType && matchDepTypes.includes(depType)) ||
       depTypes?.some((dt) => matchDepTypes.includes(dt));
     if (!isMatch) {
       return false;
     }
     positiveMatch = true;
   }
-  if (matchLanguages.length) {
+  if (matchLanguages.length && language) {
     const isMatch = matchLanguages.includes(language);
     if (!isMatch) {
       return false;
     }
     positiveMatch = true;
   }
-  if (matchBaseBranches.length) {
+  if (matchBaseBranches.length && baseBranch) {
     const isMatch = matchBaseBranches.some((matchBaseBranch): boolean => {
       const isAllowedPred = configRegexPredicate(matchBaseBranch);
       if (isAllowedPred) {
@@ -114,14 +114,14 @@ function matchesRule(
     }
     positiveMatch = true;
   }
-  if (matchManagers.length) {
+  if (matchManagers.length && manager) {
     const isMatch = matchManagers.includes(manager);
     if (!isMatch) {
       return false;
     }
     positiveMatch = true;
   }
-  if (matchDatasources.length) {
+  if (matchDatasources.length && datasource) {
     const isMatch = matchDatasources.includes(datasource);
     if (!isMatch) {
       return false;
@@ -130,7 +130,7 @@ function matchesRule(
   }
   if (matchUpdateTypes.length) {
     const isMatch =
-      matchUpdateTypes.includes(updateType) ||
+      (updateType && matchUpdateTypes.includes(updateType)) ||
       (isBump && matchUpdateTypes.includes('bump'));
     if (!isMatch) {
       return false;
@@ -169,7 +169,7 @@ function matchesRule(
     }
     positiveMatch = true;
   }
-  if (excludePackageNames.length) {
+  if (excludePackageNames.length && depName) {
     const isMatch = excludePackageNames.includes(depName);
     if (isMatch) {
       return false;
@@ -221,7 +221,7 @@ function matchesRule(
     }
     positiveMatch = true;
   }
-  if (matchCurrentVersion) {
+  if (matchCurrentVersion && currentValue) {
     const version = allVersioning.get(versioning);
     const matchCurrentVersionStr = matchCurrentVersion.toString();
     const matchCurrentVersionPred = configRegexPredicate(
diff --git a/tsconfig.strict.json b/tsconfig.strict.json
index 3ae8abea46c1fea93fb7a19c89828386d4833de0..b21b703173a3d42dab11ff82cdd5bd31bcc66f7d 100644
--- a/tsconfig.strict.json
+++ b/tsconfig.strict.json
@@ -266,13 +266,7 @@
     "lib/modules/platform/gitlab/index.ts",
     "lib/modules/platform/index.ts",
     "lib/renovate.ts",
-    "lib/util/exec/buildpack.ts",
-    "lib/util/exec/docker/index.ts",
-    "lib/util/exec/index.ts",
-    "lib/util/git/index.ts",
-    "lib/util/git/private-key.ts",
-    "lib/util/git/url.ts",
-    "lib/util/package-rules.ts",
+    "lib/util/package-rules.ts", // depends on config -> manager
     "lib/workers/repository/update/branch/artifacts.ts",
     "lib/workers/repository/update/branch/auto-replace.ts",
     "lib/workers/repository/update/branch/automerge.ts",
@@ -359,14 +353,11 @@
     "lib/workers/repository/updates/generate.ts",
     "test/util.ts",
     "tools/docs/config.ts",
-    "tools/docs/datasources.ts",
     "tools/docs/manager.ts",
     "tools/docs/modules.ts",
     "tools/docs/platforms.ts",
     "tools/docs/presets.ts",
     "tools/docs/schema.ts",
-    "tools/docs/templates.ts",
-    "tools/docs/utils.ts",
     "tools/docs/versioning.ts",
     "tools/generate-docs.ts",
     "tools/generate-schema.ts"