From 3cdfd7a20a2a8c483a58d9cff78f52b52e16989d Mon Sep 17 00:00:00 2001 From: Matt Palmer <9059517+56KBs@users.noreply.github.com> Date: Tue, 21 Dec 2021 13:09:49 +0000 Subject: [PATCH] fix(manager/gomod): GitLab Private Authentication (#13216) --- lib/manager/gomod/artifacts.spec.ts | 20 +++++-- lib/manager/gomod/artifacts.ts | 10 ++-- lib/util/git/auth.spec.ts | 87 ++++++++++++++++++++++------- lib/util/git/auth.ts | 28 ++++++++-- 4 files changed, 112 insertions(+), 33 deletions(-) diff --git a/lib/manager/gomod/artifacts.spec.ts b/lib/manager/gomod/artifacts.spec.ts index e29babff35..d84c82d52b 100644 --- a/lib/manager/gomod/artifacts.spec.ts +++ b/lib/manager/gomod/artifacts.spec.ts @@ -3,6 +3,7 @@ import { envMock, exec, mockExecAll } from '../../../test/exec-util'; import { env, fs, git, mocked } from '../../../test/util'; import { GlobalConfig } from '../../config/global'; import type { RepoGlobalConfig } from '../../config/types'; +import { PlatformId } from '../../constants/platforms'; import * as docker from '../../util/exec/docker'; import type { StatusResult } from '../../util/git/types'; import * as _hostRules from '../../util/host-rules'; @@ -222,6 +223,7 @@ describe('manager/gomod/artifacts', () => { { token: 'some-enterprise-token', matchHost: 'github.enterprise.com', + hostType: PlatformId.Github, }, ]); fs.readLocalFile.mockResolvedValueOnce('Current go.sum'); @@ -263,6 +265,7 @@ describe('manager/gomod/artifacts', () => { { token: 'some-enterprise-token', matchHost: 'gitlab.enterprise.com', + hostType: PlatformId.Gitlab, }, ]); fs.readLocalFile.mockResolvedValueOnce('Current go.sum'); @@ -287,7 +290,7 @@ describe('manager/gomod/artifacts', () => { env: expect.objectContaining({ GIT_CONFIG_COUNT: '1', GIT_CONFIG_KEY_0: - 'url.https://some-enterprise-token@gitlab.enterprise.com/.insteadOf', + 'url.https://gitlab-ci-token:some-enterprise-token@gitlab.enterprise.com/.insteadOf', GIT_CONFIG_VALUE_0: 'https://gitlab.enterprise.com/', }), }), @@ -302,10 +305,12 @@ describe('manager/gomod/artifacts', () => { { token: 'some-enterprise-token-repo1', matchHost: 'https://gitlab.enterprise.com/repo1', + hostType: PlatformId.Gitlab, }, { token: 'some-enterprise-token-repo2', matchHost: 'https://gitlab.enterprise.com/repo2', + hostType: PlatformId.Gitlab, }, ]); fs.readLocalFile.mockResolvedValueOnce('Current go.sum'); @@ -330,9 +335,9 @@ describe('manager/gomod/artifacts', () => { env: expect.objectContaining({ GIT_CONFIG_COUNT: '2', GIT_CONFIG_KEY_0: - 'url.https://some-enterprise-token-repo1@gitlab.enterprise.com/repo1.insteadOf', + 'url.https://gitlab-ci-token:some-enterprise-token-repo1@gitlab.enterprise.com/repo1.insteadOf', GIT_CONFIG_KEY_1: - 'url.https://some-enterprise-token-repo2@gitlab.enterprise.com/repo2.insteadOf', + 'url.https://gitlab-ci-token:some-enterprise-token-repo2@gitlab.enterprise.com/repo2.insteadOf', GIT_CONFIG_VALUE_0: 'https://gitlab.enterprise.com/repo1', GIT_CONFIG_VALUE_1: 'https://gitlab.enterprise.com/repo2', }), @@ -348,10 +353,12 @@ describe('manager/gomod/artifacts', () => { { token: 'some-token', matchHost: 'ssh://github.enterprise.com', + hostType: PlatformId.Github, }, { token: 'some-gitlab-token', matchHost: 'gitlab.enterprise.com', + hostType: PlatformId.Gitlab, }, ]); fs.readLocalFile.mockResolvedValueOnce('Current go.sum'); @@ -376,7 +383,7 @@ describe('manager/gomod/artifacts', () => { env: expect.objectContaining({ GIT_CONFIG_COUNT: '1', GIT_CONFIG_KEY_0: - 'url.https://some-gitlab-token@gitlab.enterprise.com/.insteadOf', + 'url.https://gitlab-ci-token:some-gitlab-token@gitlab.enterprise.com/.insteadOf', GIT_CONFIG_VALUE_0: 'https://gitlab.enterprise.com/', }), }), @@ -394,14 +401,17 @@ describe('manager/gomod/artifacts', () => { { token: 'some-token', matchHost: 'api.github.com', + hostType: PlatformId.Github, }, { token: 'some-enterprise-token', matchHost: 'github.enterprise.com', + hostType: PlatformId.Github, }, { token: 'some-gitlab-token', matchHost: 'gitlab.enterprise.com', + hostType: PlatformId.Gitlab, }, ]); fs.readLocalFile.mockResolvedValueOnce('Current go.sum'); @@ -431,7 +441,7 @@ describe('manager/gomod/artifacts', () => { GIT_CONFIG_KEY_2: 'url.https://some-enterprise-token@github.enterprise.com/.insteadOf', GIT_CONFIG_KEY_3: - 'url.https://some-gitlab-token@gitlab.enterprise.com/.insteadOf', + 'url.https://gitlab-ci-token:some-gitlab-token@gitlab.enterprise.com/.insteadOf', GIT_CONFIG_VALUE_0: 'https://github.com/', GIT_CONFIG_VALUE_1: 'https://api.github.com/', GIT_CONFIG_VALUE_2: 'https://github.enterprise.com/', diff --git a/lib/manager/gomod/artifacts.ts b/lib/manager/gomod/artifacts.ts index dbb2083ef9..d53839f2dc 100644 --- a/lib/manager/gomod/artifacts.ts +++ b/lib/manager/gomod/artifacts.ts @@ -23,16 +23,16 @@ import type { function getGitEnvironmentVariables(): NodeJS.ProcessEnv { let environmentVariables: NodeJS.ProcessEnv = {}; - // hard-coded logic to use authentication for github.com based on the credentials for api.github.com - const credentials = find({ + // hard-coded logic to use authentication for github.com based on the githubToken for api.github.com + const githubToken = find({ hostType: PlatformId.Github, url: 'https://api.github.com/', }); - if (credentials?.token) { + if (githubToken?.token) { environmentVariables = getGitAuthenticatedEnvironmentVariables( 'https://github.com/', - credentials.token + githubToken ); } @@ -65,7 +65,7 @@ function getGitEnvironmentVariables(): NodeJS.ProcessEnv { ); environmentVariables = getGitAuthenticatedEnvironmentVariables( httpUrl, - hostRule.token, + hostRule, environmentVariables ); } else { diff --git a/lib/util/git/auth.spec.ts b/lib/util/git/auth.spec.ts index 6e3d5690a8..86d0c3fcf4 100644 --- a/lib/util/git/auth.spec.ts +++ b/lib/util/git/auth.spec.ts @@ -1,3 +1,4 @@ +import { PlatformId } from '../../constants'; import { getGitAuthenticatedEnvironmentVariables } from './auth'; describe('util/git/auth', () => { @@ -7,10 +8,11 @@ describe('util/git/auth', () => { describe('getGitAuthenticatedEnvironmentVariables()', () => { it('returns url with token', () => { expect( - getGitAuthenticatedEnvironmentVariables( - 'https://github.com/', - 'token1234' - ) + getGitAuthenticatedEnvironmentVariables('https://github.com/', { + token: 'token1234', + hostType: PlatformId.Github, + matchHost: 'github.com', + }) ).toStrictEqual({ GIT_CONFIG_KEY_0: 'url.https://token1234@github.com/.insteadOf', GIT_CONFIG_VALUE_0: 'https://github.com/', @@ -20,10 +22,11 @@ describe('util/git/auth', () => { it('returns correct url if token already contains GitHub App username', () => { expect( - getGitAuthenticatedEnvironmentVariables( - 'https://github.com/', - 'x-access-token:token1234' - ) + getGitAuthenticatedEnvironmentVariables('https://github.com/', { + token: 'x-access-token:token1234', + hostType: PlatformId.Github, + matchHost: 'github.com', + }) ).toStrictEqual({ GIT_CONFIG_KEY_0: 'url.https://x-access-token:token1234@github.com/.insteadOf', @@ -36,7 +39,11 @@ describe('util/git/auth', () => { expect( getGitAuthenticatedEnvironmentVariables( 'https://github.com/', - 'token1234', + { + token: 'token1234', + hostType: PlatformId.Github, + matchHost: 'github.com', + }, { GIT_CONFIG_COUNT: '1' } ) ).toStrictEqual({ @@ -51,7 +58,11 @@ describe('util/git/auth', () => { expect( getGitAuthenticatedEnvironmentVariables( 'https://github.com/', - 'token1234', + { + token: 'token1234', + hostType: PlatformId.Github, + matchHost: 'github.com', + }, { GIT_CONFIG_COUNT: '1' } ) ).toStrictEqual({ @@ -64,10 +75,11 @@ describe('util/git/auth', () => { it('returns url with token and already existing GIT_CONFIG_COUNT from environment', () => { process.env.GIT_CONFIG_COUNT = '1'; expect( - getGitAuthenticatedEnvironmentVariables( - 'https://github.com/', - 'token1234' - ) + getGitAuthenticatedEnvironmentVariables('https://github.com/', { + token: 'token1234', + hostType: PlatformId.Github, + matchHost: 'github.com', + }) ).toStrictEqual({ GIT_CONFIG_KEY_1: 'url.https://token1234@github.com/.insteadOf', GIT_CONFIG_VALUE_1: 'https://github.com/', @@ -79,7 +91,11 @@ describe('util/git/auth', () => { expect( getGitAuthenticatedEnvironmentVariables( 'https://github.com/', - 'token1234', + { + token: 'token1234', + hostType: PlatformId.Github, + matchHost: 'github.com', + }, { RANDOM_VARIABLE: 'random' } ) ).toStrictEqual({ @@ -93,15 +109,48 @@ describe('util/git/auth', () => { it('return url with token with invalid GIT_CONFIG_COUNT from environment', () => { process.env.GIT_CONFIG_COUNT = 'notvalid'; expect( - getGitAuthenticatedEnvironmentVariables( - 'https://github.com/', - 'token1234' - ) + getGitAuthenticatedEnvironmentVariables('https://github.com/', { + token: 'token1234', + hostType: PlatformId.Github, + matchHost: 'github.com', + }) ).toStrictEqual({ GIT_CONFIG_KEY_0: 'url.https://token1234@github.com/.insteadOf', GIT_CONFIG_VALUE_0: 'https://github.com/', GIT_CONFIG_COUNT: '1', }); }); + + it('returns url with token containing username for GitLab token', () => { + expect( + getGitAuthenticatedEnvironmentVariables('https://gitlab.com/', { + token: 'token1234', + hostType: PlatformId.Gitlab, + matchHost: 'github.com', + }) + ).toStrictEqual({ + GIT_CONFIG_KEY_0: + 'url.https://gitlab-ci-token:token1234@gitlab.com/.insteadOf', + GIT_CONFIG_VALUE_0: 'https://gitlab.com/', + GIT_CONFIG_COUNT: '1', + }); + }); + + it('returns original environment variables when no token is set', () => { + expect( + getGitAuthenticatedEnvironmentVariables( + 'https://gitlab.com/', + { + username: 'testing', + password: '1234', + hostType: PlatformId.Gitlab, + matchHost: 'github.com', + }, + { env: 'value' } + ) + ).toStrictEqual({ + env: 'value', + }); + }); }); }); diff --git a/lib/util/git/auth.ts b/lib/util/git/auth.ts index 0d04ef526c..49d77dfb61 100644 --- a/lib/util/git/auth.ts +++ b/lib/util/git/auth.ts @@ -1,4 +1,6 @@ +import { PlatformId } from '../../constants'; import { logger } from '../../logger'; +import type { HostRule } from '../../types'; import { getHttpUrl } from './url'; /** @@ -7,9 +9,16 @@ import { getHttpUrl } from './url'; */ export function getGitAuthenticatedEnvironmentVariables( gitUrl: string, - token: string, + { token, hostType, matchHost }: HostRule, environmentVariables?: NodeJS.ProcessEnv ): NodeJS.ProcessEnv { + if (!token) { + logger.warn( + `Could not create environment variable for ${matchHost} as token was empty` + ); + return { ...environmentVariables }; + } + // check if the environmentVariables already contain a GIT_CONFIG_COUNT or if the process has one const gitConfigCountEnvVariable = environmentVariables?.GIT_CONFIG_COUNT || process.env.GIT_CONFIG_COUNT; @@ -25,17 +34,28 @@ export function getGitAuthenticatedEnvironmentVariables( } } - const gitUrlWithToken = getHttpUrl(gitUrl, token); + const gitUrlWithToken = getUrlWithToken(gitUrl, hostType, token); // create a shallow copy of the environmentVariables as base so we don't modify the input parameter object // add the two new config key and value to the returnEnvironmentVariables object // increase the CONFIG_COUNT by one and add it to the object - const returnEnvironmentVariables = { + return { ...environmentVariables, [`GIT_CONFIG_KEY_${gitConfigCount}`]: `url.${gitUrlWithToken}.insteadOf`, [`GIT_CONFIG_VALUE_${gitConfigCount}`]: gitUrl, GIT_CONFIG_COUNT: (gitConfigCount + 1).toString(), }; +} + +function getUrlWithToken( + gitUrl: string, + hostType: string, + authToken: string +): string { + let token = authToken; + if (hostType === PlatformId.Gitlab) { + token = `gitlab-ci-token:${token}`; + } - return returnEnvironmentVariables; + return getHttpUrl(gitUrl, token); } -- GitLab