From 22709f43f07becbb65e6d3d92c0466c6b282e612 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Mon, 9 Oct 2023 21:41:19 +0100
Subject: [PATCH] feat(github): automatic ghcr.io auth when using github.com
 (#25017)

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
---
 .../github/__snapshots__/index.spec.ts.snap   | 32 +++++++++++++++++++
 lib/modules/platform/github/index.spec.ts     | 16 ++++++++++
 lib/modules/platform/github/index.ts          | 12 ++++++-
 lib/modules/platform/index.spec.ts            | 31 ++++++++++++++++++
 lib/modules/platform/types.ts                 |  6 +++-
 5 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/lib/modules/platform/github/__snapshots__/index.spec.ts.snap b/lib/modules/platform/github/__snapshots__/index.spec.ts.snap
index 9bbc6ed9a5..d6f64d0555 100644
--- a/lib/modules/platform/github/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/platform/github/__snapshots__/index.spec.ts.snap
@@ -31,6 +31,14 @@ exports[`modules/platform/github/index initPlatform() should support default end
 {
   "endpoint": "https://api.github.com/",
   "gitAuthor": undefined,
+  "hostRules": [
+    {
+      "hostType": "docker",
+      "matchHost": "ghcr.io",
+      "password": "123test",
+      "username": "USERNAME",
+    },
+  ],
   "renovateUsername": "renovate-bot",
   "token": "123test",
 }
@@ -40,6 +48,14 @@ exports[`modules/platform/github/index initPlatform() should support default end
 {
   "endpoint": "https://api.github.com/",
   "gitAuthor": undefined,
+  "hostRules": [
+    {
+      "hostType": "docker",
+      "matchHost": "ghcr.io",
+      "password": "123test",
+      "username": "USERNAME",
+    },
+  ],
   "renovateUsername": "renovate-bot",
   "token": "123test",
 }
@@ -49,6 +65,14 @@ exports[`modules/platform/github/index initPlatform() should support default end
 {
   "endpoint": "https://api.github.com/",
   "gitAuthor": "undefined <user@domain.com>",
+  "hostRules": [
+    {
+      "hostType": "docker",
+      "matchHost": "ghcr.io",
+      "password": "123test",
+      "username": "USERNAME",
+    },
+  ],
   "renovateUsername": "renovate-bot",
   "token": "123test",
 }
@@ -58,6 +82,14 @@ exports[`modules/platform/github/index initPlatform() should support gitAuthor a
 {
   "endpoint": "https://api.github.com/",
   "gitAuthor": "renovate@whitesourcesoftware.com",
+  "hostRules": [
+    {
+      "hostType": "docker",
+      "matchHost": "ghcr.io",
+      "password": "123test",
+      "username": "USERNAME",
+    },
+  ],
   "renovateUsername": "renovate-bot",
   "token": "123test",
 }
diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts
index 7f456f21ad..2fb51a67dc 100644
--- a/lib/modules/platform/github/index.spec.ts
+++ b/lib/modules/platform/github/index.spec.ts
@@ -177,12 +177,28 @@ describe('modules/platform/github/index', () => {
       ).toEqual({
         endpoint: 'https://api.github.com/',
         gitAuthor: 'my-app[bot] <12345+my-app[bot]@users.noreply.github.com>',
+        hostRules: [
+          {
+            hostType: 'docker',
+            matchHost: 'ghcr.io',
+            password: 'ghs_123test',
+            username: 'USERNAME',
+          },
+        ],
         renovateUsername: 'my-app[bot]',
         token: 'x-access-token:ghs_123test',
       });
       expect(await github.initPlatform({ token: 'ghs_123test' })).toEqual({
         endpoint: 'https://api.github.com/',
         gitAuthor: 'my-app[bot] <12345+my-app[bot]@users.noreply.github.com>',
+        hostRules: [
+          {
+            hostType: 'docker',
+            matchHost: 'ghcr.io',
+            password: 'ghs_123test',
+            username: 'USERNAME',
+          },
+        ],
         renovateUsername: 'my-app[bot]',
         token: 'x-access-token:ghs_123test',
       });
diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts
index 7cfb7f2359..3daeb83791 100644
--- a/lib/modules/platform/github/index.ts
+++ b/lib/modules/platform/github/index.ts
@@ -204,7 +204,17 @@ export async function initPlatform({
     renovateUsername,
     token,
   };
-
+  if (platformResult.endpoint === 'https://api.github.com/') {
+    logger.debug('Adding GitHub token as GHCR password');
+    platformResult.hostRules = [
+      {
+        matchHost: 'ghcr.io',
+        hostType: 'docker',
+        username: 'USERNAME',
+        password: token.replace(/^x-access-token:/, ''),
+      },
+    ];
+  }
   return platformResult;
 }
 
diff --git a/lib/modules/platform/index.spec.ts b/lib/modules/platform/index.spec.ts
index 8ae91610c3..660e33344d 100644
--- a/lib/modules/platform/index.spec.ts
+++ b/lib/modules/platform/index.spec.ts
@@ -118,4 +118,35 @@ describe('modules/platform/index', () => {
       renovateUsername: 'abc',
     });
   });
+
+  it('merges platform hostRules with additionalHostRules', async () => {
+    const config = {
+      platform: 'github' as PlatformId,
+      endpoint: 'https://api.github.com',
+      gitAuthor: 'user@domain.com',
+      username: 'abc',
+      token: '123',
+    };
+
+    expect(await platform.initPlatform(config)).toEqual({
+      endpoint: 'https://api.github.com/',
+      gitAuthor: 'user@domain.com',
+      hostRules: [
+        {
+          hostType: 'docker',
+          matchHost: 'ghcr.io',
+          password: '123',
+          username: 'USERNAME',
+        },
+        {
+          hostType: 'github',
+          matchHost: 'api.github.com',
+          token: '123',
+          username: 'abc',
+        },
+      ],
+      platform: 'github',
+      renovateUsername: 'abc',
+    });
+  });
 });
diff --git a/lib/modules/platform/types.ts b/lib/modules/platform/types.ts
index 1e87dec950..ca98ae3337 100644
--- a/lib/modules/platform/types.ts
+++ b/lib/modules/platform/types.ts
@@ -1,5 +1,5 @@
 import type { MergeStrategy } from '../../config/types';
-import type { BranchStatus, VulnerabilityAlert } from '../../types';
+import type { BranchStatus, HostRule, VulnerabilityAlert } from '../../types';
 import type { CommitFilesConfig, CommitSha } from '../../util/git/types';
 
 type VulnerabilityKey = string;
@@ -23,6 +23,10 @@ export interface PlatformResult {
   renovateUsername?: string;
   token?: string;
   gitAuthor?: string;
+  /*
+   * return these only if _additional_ rules/hosts are required
+   */
+  hostRules?: HostRule[];
 }
 
 export interface RepoResult {
-- 
GitLab