diff --git a/lib/modules/manager/gomod/__snapshots__/artifacts.spec.ts.snap b/lib/modules/manager/gomod/__snapshots__/artifacts.spec.ts.snap index f6c9eba1f5ceed2c64b7c8052ceca32358a0e095..1b233354a065aca2b9ec73b8820d4f5ab601547e 100644 --- a/lib/modules/manager/gomod/__snapshots__/artifacts.spec.ts.snap +++ b/lib/modules/manager/gomod/__snapshots__/artifacts.spec.ts.snap @@ -287,20 +287,26 @@ Array [ }, }, Object { - "cmd": "docker run --rm --name=renovate_go --label=renovate_child -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache\\":\\"/tmp/renovate/cache\\" -e GOPROXY -e GOPRIVATE -e GONOPROXY -e GONOSUMDB -e GOINSECURE -e GOFLAGS -e CGO_ENABLED -e GIT_CONFIG_KEY_0 -e GIT_CONFIG_VALUE_0 -e GIT_CONFIG_KEY_1 -e GIT_CONFIG_VALUE_1 -e GIT_CONFIG_KEY_2 -e GIT_CONFIG_VALUE_2 -e GIT_CONFIG_COUNT -e BUILDPACK_CACHE_DIR -w \\"/tmp/github/some/repo\\" renovate/go:latest bash -l -c \\"go get -d -t ./...\\"", + "cmd": "docker run --rm --name=renovate_go --label=renovate_child -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache\\":\\"/tmp/renovate/cache\\" -e GOPROXY -e GOPRIVATE -e GONOPROXY -e GONOSUMDB -e GOINSECURE -e GOFLAGS -e CGO_ENABLED -e GIT_CONFIG_KEY_0 -e GIT_CONFIG_VALUE_0 -e GIT_CONFIG_KEY_1 -e GIT_CONFIG_VALUE_1 -e GIT_CONFIG_KEY_2 -e GIT_CONFIG_VALUE_2 -e GIT_CONFIG_COUNT -e GIT_CONFIG_KEY_3 -e GIT_CONFIG_VALUE_3 -e GIT_CONFIG_KEY_4 -e GIT_CONFIG_VALUE_4 -e GIT_CONFIG_KEY_5 -e GIT_CONFIG_VALUE_5 -e BUILDPACK_CACHE_DIR -w \\"/tmp/github/some/repo\\" renovate/go:latest bash -l -c \\"go get -d -t ./...\\"", "options": Object { "cwd": "/tmp/github/some/repo", "encoding": "utf-8", "env": Object { "BUILDPACK_CACHE_DIR": "/tmp/renovate/cache/buildpack", "CGO_ENABLED": "1", - "GIT_CONFIG_COUNT": "3", + "GIT_CONFIG_COUNT": "6", "GIT_CONFIG_KEY_0": "url.https://ssh:some-token@github.com/.insteadOf", "GIT_CONFIG_KEY_1": "url.https://git:some-token@github.com/.insteadOf", "GIT_CONFIG_KEY_2": "url.https://some-token@github.com/.insteadOf", + "GIT_CONFIG_KEY_3": "url.https://ssh:some-other-token@gitea.com/.insteadOf", + "GIT_CONFIG_KEY_4": "url.https://git:some-other-token@gitea.com/.insteadOf", + "GIT_CONFIG_KEY_5": "url.https://some-other-token@gitea.com/.insteadOf", "GIT_CONFIG_VALUE_0": "ssh://git@github.com/", "GIT_CONFIG_VALUE_1": "git@github.com:", "GIT_CONFIG_VALUE_2": "https://github.com/", + "GIT_CONFIG_VALUE_3": "ssh://git@gitea.com/", + "GIT_CONFIG_VALUE_4": "git@gitea.com:", + "GIT_CONFIG_VALUE_5": "https://gitea.com/", "GOFLAGS": "-modcacherw", "GOINSECURE": "insecure.example.com/*", "GONOPROXY": "noproxy.example.com/*", diff --git a/lib/modules/manager/gomod/artifacts.spec.ts b/lib/modules/manager/gomod/artifacts.spec.ts index e82a24a31b2b2499cecf8961bfe731456ab58c23..db9317fa75164384d1f099896c1237198165262b 100644 --- a/lib/modules/manager/gomod/artifacts.spec.ts +++ b/lib/modules/manager/gomod/artifacts.spec.ts @@ -68,6 +68,7 @@ describe('modules/manager/gomod/artifacts', () => { env.getChildProcessEnv.mockReturnValue({ ...envMock.basic, ...goEnv }); GlobalConfig.set(adminConfig); docker.resetPrefetchedImages(); + hostRules.getAll.mockReturnValue([]); }); afterEach(() => { @@ -211,6 +212,14 @@ describe('modules/manager/gomod/artifacts', () => { hostRules.find.mockReturnValueOnce({ token: 'some-token', }); + hostRules.getAll.mockReturnValueOnce([ + { + token: 'some-token', + hostType: PlatformId.Github, + matchHost: 'api.github.com', + }, + { token: 'some-other-token', matchHost: 'https://gitea.com' }, + ]); fs.readLocalFile.mockResolvedValueOnce('Current go.sum'); // TODO: #7154 can be null fs.readLocalFile.mockResolvedValueOnce(null as never); // vendor modules filename @@ -236,6 +245,11 @@ describe('modules/manager/gomod/artifacts', () => { token: 'some-token', }); hostRules.getAll.mockReturnValueOnce([ + { + token: 'some-token', + hostType: PlatformId.Github, + matchHost: 'api.github.com', + }, { token: 'some-enterprise-token', matchHost: 'github.enterprise.com', @@ -258,34 +272,34 @@ describe('modules/manager/gomod/artifacts', () => { config, }) ).not.toBeNull(); - expect(execSnapshots).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - options: expect.objectContaining({ - env: expect.objectContaining({ - GIT_CONFIG_COUNT: '6', - GIT_CONFIG_KEY_0: - 'url.https://ssh:some-token@github.com/.insteadOf', - GIT_CONFIG_KEY_1: - 'url.https://git:some-token@github.com/.insteadOf', - GIT_CONFIG_KEY_2: 'url.https://some-token@github.com/.insteadOf', - GIT_CONFIG_KEY_3: - 'url.https://ssh:some-enterprise-token@github.enterprise.com/.insteadOf', - GIT_CONFIG_KEY_4: - 'url.https://git:some-enterprise-token@github.enterprise.com/.insteadOf', - GIT_CONFIG_KEY_5: - 'url.https://some-enterprise-token@github.enterprise.com/.insteadOf', - GIT_CONFIG_VALUE_0: 'ssh://git@github.com/', - GIT_CONFIG_VALUE_1: 'git@github.com:', - GIT_CONFIG_VALUE_2: 'https://github.com/', - GIT_CONFIG_VALUE_3: 'ssh://git@github.enterprise.com/', - GIT_CONFIG_VALUE_4: 'git@github.enterprise.com:', - GIT_CONFIG_VALUE_5: 'https://github.enterprise.com/', - }), - }), - }), - ]) - ); + expect(execSnapshots).toMatchObject([ + { cmd: 'docker pull renovate/go:latest' }, + { cmd: 'docker ps --filter name=renovate_go -aq' }, + { + options: { + env: { + GIT_CONFIG_COUNT: '6', + GIT_CONFIG_KEY_0: + 'url.https://ssh:some-token@github.com/.insteadOf', + GIT_CONFIG_KEY_1: + 'url.https://git:some-token@github.com/.insteadOf', + GIT_CONFIG_KEY_2: 'url.https://some-token@github.com/.insteadOf', + GIT_CONFIG_KEY_3: + 'url.https://ssh:some-enterprise-token@github.enterprise.com/.insteadOf', + GIT_CONFIG_KEY_4: + 'url.https://git:some-enterprise-token@github.enterprise.com/.insteadOf', + GIT_CONFIG_KEY_5: + 'url.https://some-enterprise-token@github.enterprise.com/.insteadOf', + GIT_CONFIG_VALUE_0: 'ssh://git@github.com/', + GIT_CONFIG_VALUE_1: 'git@github.com:', + GIT_CONFIG_VALUE_2: 'https://github.com/', + GIT_CONFIG_VALUE_3: 'ssh://git@github.enterprise.com/', + GIT_CONFIG_VALUE_4: 'git@github.enterprise.com:', + GIT_CONFIG_VALUE_5: 'https://github.enterprise.com/', + }, + }, + }, + ]); }); it('supports docker mode with single credential', async () => { @@ -491,42 +505,33 @@ describe('modules/manager/gomod/artifacts', () => { expect.objectContaining({ options: expect.objectContaining({ env: expect.objectContaining({ - GIT_CONFIG_COUNT: '12', + GIT_CONFIG_COUNT: '9', GIT_CONFIG_KEY_0: 'url.https://ssh:some-token@github.com/.insteadOf', GIT_CONFIG_KEY_1: 'url.https://git:some-token@github.com/.insteadOf', GIT_CONFIG_KEY_2: 'url.https://some-token@github.com/.insteadOf', GIT_CONFIG_KEY_3: - 'url.https://ssh:some-token@api.github.com/.insteadOf', - GIT_CONFIG_KEY_4: - 'url.https://git:some-token@api.github.com/.insteadOf', - GIT_CONFIG_KEY_5: - 'url.https://some-token@api.github.com/.insteadOf', - GIT_CONFIG_KEY_6: 'url.https://ssh:some-enterprise-token@github.enterprise.com/.insteadOf', - GIT_CONFIG_KEY_7: + GIT_CONFIG_KEY_4: 'url.https://git:some-enterprise-token@github.enterprise.com/.insteadOf', - GIT_CONFIG_KEY_8: + GIT_CONFIG_KEY_5: 'url.https://some-enterprise-token@github.enterprise.com/.insteadOf', - GIT_CONFIG_KEY_9: + GIT_CONFIG_KEY_6: 'url.https://gitlab-ci-token:some-gitlab-token@gitlab.enterprise.com/.insteadOf', - GIT_CONFIG_KEY_10: + GIT_CONFIG_KEY_7: 'url.https://gitlab-ci-token:some-gitlab-token@gitlab.enterprise.com/.insteadOf', - GIT_CONFIG_KEY_11: + GIT_CONFIG_KEY_8: 'url.https://gitlab-ci-token:some-gitlab-token@gitlab.enterprise.com/.insteadOf', GIT_CONFIG_VALUE_0: 'ssh://git@github.com/', GIT_CONFIG_VALUE_1: 'git@github.com:', GIT_CONFIG_VALUE_2: 'https://github.com/', - GIT_CONFIG_VALUE_3: 'ssh://git@api.github.com/', - GIT_CONFIG_VALUE_4: 'git@api.github.com:', - GIT_CONFIG_VALUE_5: 'https://api.github.com/', - GIT_CONFIG_VALUE_6: 'ssh://git@github.enterprise.com/', - GIT_CONFIG_VALUE_7: 'git@github.enterprise.com:', - GIT_CONFIG_VALUE_8: 'https://github.enterprise.com/', - GIT_CONFIG_VALUE_9: 'ssh://git@gitlab.enterprise.com/', - GIT_CONFIG_VALUE_10: 'git@gitlab.enterprise.com:', - GIT_CONFIG_VALUE_11: 'https://gitlab.enterprise.com/', + GIT_CONFIG_VALUE_3: 'ssh://git@github.enterprise.com/', + GIT_CONFIG_VALUE_4: 'git@github.enterprise.com:', + GIT_CONFIG_VALUE_5: 'https://github.enterprise.com/', + GIT_CONFIG_VALUE_6: 'ssh://git@gitlab.enterprise.com/', + GIT_CONFIG_VALUE_7: 'git@gitlab.enterprise.com:', + GIT_CONFIG_VALUE_8: 'https://gitlab.enterprise.com/', }), }), }), diff --git a/lib/modules/manager/gomod/artifacts.ts b/lib/modules/manager/gomod/artifacts.ts index 2bc7c2b537311dfe94bd8b4a11178c90214840c5..0bb4cf3aa5397590e88928b8e46817cd2e2979b9 100644 --- a/lib/modules/manager/gomod/artifacts.ts +++ b/lib/modules/manager/gomod/artifacts.ts @@ -4,6 +4,7 @@ import { GlobalConfig } from '../../../config/global'; import { PlatformId } from '../../../constants'; import { TEMPORARY_ERROR } from '../../../constants/error-messages'; import { logger } from '../../../logger'; +import type { HostRule } from '../../../types'; import { exec } from '../../../util/exec'; import type { ExecOptions } from '../../../util/exec/types'; import { @@ -24,6 +25,13 @@ import type { UpdateArtifactsResult, } from '../types'; +const githubApiUrls = new Set([ + 'github.com', + 'api.github.com', + 'https://api.github.com', + 'https://api.github.com/', +]); + function getGitEnvironmentVariables(): NodeJS.ProcessEnv { let environmentVariables: NodeJS.ProcessEnv = {}; @@ -41,9 +49,12 @@ function getGitEnvironmentVariables(): NodeJS.ProcessEnv { } // get extra host rules for other git-based Go Module hosts - const hostRules = getAll() || []; + // filter rules without `matchHost` and `token` and github api github rules + const hostRules = getAll() + .filter((r) => r.matchHost && r.token) + .filter((r) => !githubToken || !githubApiUrls.has(r.matchHost!)); - const goGitAllowedHostType: (string | undefined)[] = [ + const goGitAllowedHostType = new Set<string>([ // All known git platforms PlatformId.Azure, PlatformId.Bitbucket, @@ -51,37 +62,52 @@ function getGitEnvironmentVariables(): NodeJS.ProcessEnv { PlatformId.Gitea, PlatformId.Github, PlatformId.Gitlab, - // plus all without a host type (=== undefined) - undefined, - ]; + ]); - // for each hostRule we add additional authentication variables to the environmentVariables + // for each hostRule without hostType we add additional authentication variables to the environmentVariables for (const hostRule of hostRules) { - if ( - hostRule?.token && - hostRule.matchHost && - goGitAllowedHostType.includes(hostRule.hostType) - ) { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - const httpUrl = createURLFromHostOrURL(hostRule.matchHost!)?.toString(); - if (validateUrl(httpUrl)) { - logger.debug( - // TODO: types (#7154) - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `Adding Git authentication for Go Module retrieval for ${httpUrl} using token auth.` - ); - environmentVariables = getGitAuthenticatedEnvironmentVariables( - httpUrl!, - hostRule, - environmentVariables - ); - } else { - logger.warn( - `Could not parse registryUrl ${hostRule.matchHost} or not using http(s). Ignoring` - ); - } + if (!hostRule.hostType) { + environmentVariables = addAuthFromHostRule( + hostRule, + environmentVariables + ); } } + + // for each hostRule with hostType we add additional authentication variables to the environmentVariables + for (const hostRule of hostRules) { + if (hostRule.hostType && goGitAllowedHostType.has(hostRule.hostType)) { + environmentVariables = addAuthFromHostRule( + hostRule, + environmentVariables + ); + } + } + return environmentVariables; +} + +function addAuthFromHostRule( + hostRule: HostRule, + env: NodeJS.ProcessEnv +): NodeJS.ProcessEnv { + let environmentVariables = env; + const httpUrl = createURLFromHostOrURL(hostRule.matchHost!)?.toString(); + if (validateUrl(httpUrl)) { + logger.debug( + // TODO: types (#7154) + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + `Adding Git authentication for Go Module retrieval for ${httpUrl} using token auth.` + ); + environmentVariables = getGitAuthenticatedEnvironmentVariables( + httpUrl!, + hostRule, + environmentVariables + ); + } else { + logger.warn( + `Could not parse registryUrl ${hostRule.matchHost!} or not using http(s). Ignoring` + ); + } return environmentVariables; } diff --git a/lib/util/git/auth.spec.ts b/lib/util/git/auth.spec.ts index 00b4a8f13a0d33e20a40005bf4be355439963a98..eae5ea34be991475e227c61ab2f427e0493ddce5 100644 --- a/lib/util/git/auth.spec.ts +++ b/lib/util/git/auth.spec.ts @@ -191,6 +191,26 @@ describe('util/git/auth', () => { }); }); + it('returns url with token containing username for GitLab token without hostType', () => { + expect( + getGitAuthenticatedEnvironmentVariables('https://gitlab.com/', { + token: 'token1234', + matchHost: 'gitlab.com', + }) + ).toStrictEqual({ + GIT_CONFIG_COUNT: '3', + GIT_CONFIG_KEY_0: + 'url.https://gitlab-ci-token:token1234@gitlab.com/.insteadOf', + GIT_CONFIG_KEY_1: + 'url.https://gitlab-ci-token:token1234@gitlab.com/.insteadOf', + GIT_CONFIG_KEY_2: + 'url.https://gitlab-ci-token:token1234@gitlab.com/.insteadOf', + GIT_CONFIG_VALUE_0: 'ssh://git@gitlab.com/', + GIT_CONFIG_VALUE_1: 'git@gitlab.com:', + GIT_CONFIG_VALUE_2: 'https://gitlab.com/', + }); + }); + it('returns original environment variables when no token is set', () => { expect( getGitAuthenticatedEnvironmentVariables( diff --git a/lib/util/git/auth.ts b/lib/util/git/auth.ts index e27f3dda6daa61b357b0e3b1a8283cd385c57c62..08a73c63131a2d55bea832d531c632585a237b3f 100644 --- a/lib/util/git/auth.ts +++ b/lib/util/git/auth.ts @@ -1,6 +1,7 @@ import gitUrlParse from 'git-url-parse'; import { PlatformId } from '../../constants'; import { logger } from '../../logger'; +import { detectPlatform } from '../../modules/platform/util'; import type { HostRule } from '../../types'; import { regEx } from '../regex'; import type { AuthenticationRule } from './types'; @@ -66,11 +67,15 @@ export function getGitAuthenticatedEnvironmentVariables( function getAuthenticationRulesWithToken( url: string, - hostType: string | undefined, + hostType: string | undefined | null, authToken: string ): AuthenticationRule[] { let token = authToken; - if (hostType === PlatformId.Gitlab) { + let type = hostType; + if (!type) { + type = detectPlatform(url); + } + if (type === PlatformId.Gitlab) { token = `gitlab-ci-token:${authToken}`; } return getAuthenticationRules(url, token);