diff --git a/lib/manager/bundler/artifacts.spec.ts b/lib/manager/bundler/artifacts.spec.ts index 56ce54ee60af41..b898ab6edbe10b 100644 --- a/lib/manager/bundler/artifacts.spec.ts +++ b/lib/manager/bundler/artifacts.spec.ts @@ -229,11 +229,11 @@ describe('bundler.updateArtifacts()', () => { { hostType: 'bundler', hostName: 'gems.private.com', + resolvedHost: 'gems.private.com', username: 'some-user', password: 'some-password', }, ]); - bundlerHostRules.getDomain.mockReturnValue('gems.private.com'); bundlerHostRules.getAuthenticationHeaderValue.mockReturnValue( 'some-user:some-password' ); diff --git a/lib/manager/bundler/artifacts.ts b/lib/manager/bundler/artifacts.ts index a02d7263b796b7..16cfb0a01eba25 100644 --- a/lib/manager/bundler/artifacts.ts +++ b/lib/manager/bundler/artifacts.ts @@ -19,7 +19,6 @@ import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; import { findAllAuthenticatable, getAuthenticationHeaderValue, - getDomain, } from './host-rules'; import { getGemHome } from './utils'; @@ -56,7 +55,7 @@ async function getRubyConstraint( function buildBundleHostVariable(hostRule: HostRule): Record { const varName = hostConfigVariablePrefix + - getDomain(hostRule) + hostRule.resolvedHost .split('.') .map((term) => term.toUpperCase()) .join('__'); diff --git a/lib/manager/bundler/host-rules.spec.ts b/lib/manager/bundler/host-rules.spec.ts index 8df6aa5d6f2c08..f1fe2538616cea 100644 --- a/lib/manager/bundler/host-rules.spec.ts +++ b/lib/manager/bundler/host-rules.spec.ts @@ -5,47 +5,12 @@ import { add, clear } from '../../util/host-rules'; import { findAllAuthenticatable, getAuthenticationHeaderValue, - getDomain, } from './host-rules'; describe(getName(), () => { beforeEach(() => { clear(); }); - describe('getDomain()', () => { - it('returns the hostName if hostName is present', () => { - expect( - getDomain({ - hostName: 'api.github.com', - }) - ).toEqual('api.github.com'); - }); - it('returns the domainName if domainName is present and hostName is not present', () => { - expect( - getDomain({ - domainName: 'github.com', - }) - ).toEqual('github.com'); - }); - it('returns the hostName if hostName and domainName are present', () => { - expect( - getDomain({ - hostName: 'api.github.com', - domainName: 'github.com', - }) - ).toEqual('api.github.com'); - }); - it('returns the baseUrl host if hostName and domainName are not present', () => { - expect( - getDomain({ - baseUrl: 'https://github.com', - }) - ).toEqual('github.com'); - }); - it('returns undefined if hostName, domainName and baseUrl are not present', () => { - expect(getDomain({})).toBeNull(); - }); - }); describe('getAuthenticationHeaderValue()', () => { it('returns the authentication header with the password', () => { expect( @@ -105,36 +70,36 @@ describe(getName(), () => { delete hostRule.token; add(hostRule); - expect(findAllAuthenticatable({ hostType: 'nuget' } as any)).toEqual([ - hostRule, - ]); + expect( + findAllAuthenticatable({ hostType: 'nuget' } as any) + ).toMatchObject([hostRule]); }); it('returns the hostRule if using domainName and password', () => { delete hostRule.hostName; delete hostRule.token; add(hostRule); - expect(findAllAuthenticatable({ hostType: 'nuget' } as any)).toEqual([ - hostRule, - ]); + expect( + findAllAuthenticatable({ hostType: 'nuget' } as any) + ).toMatchObject([hostRule]); }); it('returns the hostRule if using hostName and token', () => { delete hostRule.domainName; delete hostRule.password; add(hostRule); - expect(findAllAuthenticatable({ hostType: 'nuget' } as any)).toEqual([ - hostRule, - ]); + expect( + findAllAuthenticatable({ hostType: 'nuget' } as any) + ).toMatchObject([hostRule]); }); it('returns the hostRule if using domainName and token', () => { delete hostRule.hostName; delete hostRule.password; add(hostRule); - expect(findAllAuthenticatable({ hostType: 'nuget' } as any)).toEqual([ - hostRule, - ]); + expect( + findAllAuthenticatable({ hostType: 'nuget' } as any) + ).toMatchObject([hostRule]); }); it('returns the hostRule if using baseUrl and password', () => { hostRule.baseUrl = 'https://nuget.com'; @@ -142,9 +107,9 @@ describe(getName(), () => { delete hostRule.hostName; add(hostRule); - expect(findAllAuthenticatable({ hostType: 'nuget' } as any)).toEqual([ - hostRule, - ]); + expect( + findAllAuthenticatable({ hostType: 'nuget' } as any) + ).toMatchObject([hostRule]); }); it('returns the hostRule if using baseUrl and token', () => { hostRule.baseUrl = 'https://nuget.com'; @@ -152,9 +117,9 @@ describe(getName(), () => { delete hostRule.domainName; add(hostRule); - expect(findAllAuthenticatable({ hostType: 'nuget' } as any)).toEqual([ - hostRule, - ]); + expect( + findAllAuthenticatable({ hostType: 'nuget' } as any) + ).toMatchObject([hostRule]); }); }); }); diff --git a/lib/manager/bundler/host-rules.ts b/lib/manager/bundler/host-rules.ts index 69b5f07cb01239..832cb5f73db0f4 100644 --- a/lib/manager/bundler/host-rules.ts +++ b/lib/manager/bundler/host-rules.ts @@ -1,10 +1,9 @@ -import URL from 'url'; import { HostRule } from '../../types'; import { findAll } from '../../util/host-rules'; function isAuthenticatable(rule: HostRule): boolean { return ( - (!!rule.hostName || !!rule.domainName || !!rule.baseUrl) && + !!rule.resolvedHost && ((!!rule.username && !!rule.password) || !!rule.token) ); } @@ -17,20 +16,6 @@ export function findAllAuthenticatable({ return findAll({ hostType }).filter(isAuthenticatable); } -export function getDomain(hostRule: HostRule): string { - if (hostRule.hostName) { - return hostRule.hostName; - } - if (hostRule.domainName) { - return hostRule.domainName; - } - if (hostRule.baseUrl) { - return URL.parse(hostRule.baseUrl).host; - } - - return null; -} - export function getAuthenticationHeaderValue(hostRule: HostRule): string { if (hostRule.username) { return `${hostRule.username}:${hostRule.password}`; diff --git a/lib/manager/composer/artifacts.spec.ts b/lib/manager/composer/artifacts.spec.ts index fca585b9583432..c5d0e61667ed1d 100644 --- a/lib/manager/composer/artifacts.spec.ts +++ b/lib/manager/composer/artifacts.spec.ts @@ -94,7 +94,7 @@ describe('.updateArtifacts()', () => { }); hostRules.add({ hostType: datasourcePackagist.id, - endpoint: 'https://artifactory.yyyyyyy.com/artifactory/api/composer/', + baseUrl: 'https://artifactory.yyyyyyy.com/artifactory/api/composer/', username: 'some-other-username', password: 'some-other-password', }); diff --git a/lib/manager/composer/artifacts.ts b/lib/manager/composer/artifacts.ts index bffbe7510c707e..14ab61ff31c8ec 100644 --- a/lib/manager/composer/artifacts.ts +++ b/lib/manager/composer/artifacts.ts @@ -1,4 +1,3 @@ -import url from 'url'; import is from '@sindresorhus/is'; import { quote } from 'shlex'; import upath from 'upath'; @@ -13,7 +12,6 @@ import { } from '../../constants/platforms'; import * as datasourcePackagist from '../../datasource/packagist'; import { logger } from '../../logger'; -import { HostRule } from '../../types'; import { ExecOptions, exec } from '../../util/exec'; import { deleteLocalFile, @@ -40,25 +38,6 @@ interface AuthJson { 'http-basic'?: Record; } -function getHost({ - hostName, - domainName, - endpoint, - baseUrl, -}: HostRule): string | null { - let host = hostName || domainName; - if (!host) { - try { - host = endpoint || baseUrl; - host = url.parse(host).host; - } catch (err) { - logger.warn(`Composer: can't parse ${host}`); - host = null; - } - } - return host; -} - function getAuthJson(): string | null { const authJson: AuthJson = {}; @@ -85,11 +64,10 @@ function getAuthJson(): string | null { hostRules .findAll({ hostType: datasourcePackagist.id }) ?.forEach((hostRule) => { - const { username, password } = hostRule; - const host = getHost(hostRule); - if (host && username && password) { + const { resolvedHost, username, password } = hostRule; + if (resolvedHost && username && password) { authJson['http-basic'] = authJson['http-basic'] || {}; - authJson['http-basic'][host] = { username, password }; + authJson['http-basic'][resolvedHost] = { username, password }; } }); diff --git a/lib/manager/npm/post-update/index.ts b/lib/manager/npm/post-update/index.ts index aa992b653e70e8..d08f86cb14fc80 100644 --- a/lib/manager/npm/post-update/index.ts +++ b/lib/manager/npm/post-update/index.ts @@ -443,26 +443,14 @@ export async function getAdditionalFiles( hostType: 'npm', }); for (const hostRule of npmHostRules) { - if (hostRule.token) { - if (hostRule.baseUrl) { - additionalNpmrcContent.push( - `${hostRule.baseUrl}:_authToken=${hostRule.token}` - .replace('https://', '//') - .replace('http://', '//') - ); - } else if (hostRule.hostName) { - additionalNpmrcContent.push( - `//${hostRule.hostName}/:_authToken=${hostRule.token}` - ); - } - } else if (is.string(hostRule.username) && is.string(hostRule.password)) { - const password = Buffer.from(hostRule.password).toString('base64'); - if (hostRule.baseUrl) { - const uri = hostRule.baseUrl.replace(/^https?:/, ''); - additionalNpmrcContent.push(`${uri}:username=${hostRule.username}`); - additionalNpmrcContent.push(`${uri}:_password=${password}`); - } else if (hostRule.hostName) { - const uri = `//${hostRule.hostName}/`; + if (hostRule.resolvedHost) { + const uri = hostRule.baseUrl + ? hostRule.baseUrl.replace(/^https?:/, '') + : `//${hostRule.resolvedHost}/`; + if (hostRule.token) { + additionalNpmrcContent.push(`${uri}:_authToken=${hostRule.token}`); + } else if (is.string(hostRule.username) && is.string(hostRule.password)) { + const password = Buffer.from(hostRule.password).toString('base64'); additionalNpmrcContent.push(`${uri}:username=${hostRule.username}`); additionalNpmrcContent.push(`${uri}:_password=${password}`); } diff --git a/lib/types/host-rules.ts b/lib/types/host-rules.ts index 72c7aef6fff4b7..27a606a31a15fb 100644 --- a/lib/types/host-rules.ts +++ b/lib/types/host-rules.ts @@ -19,4 +19,5 @@ export interface HostRule { enabled?: boolean; enableHttp2?: boolean; concurrentRequestLimit?: number; + resolvedHost?: string; } diff --git a/lib/util/host-rules.spec.ts b/lib/util/host-rules.spec.ts index ac6b91c0d9e53b..0401b419fd7545 100644 --- a/lib/util/host-rules.spec.ts +++ b/lib/util/host-rules.spec.ts @@ -159,11 +159,10 @@ describe(getName(), () => { hostName: 'nuget.org', username: 'root', password: 'p4$$w0rd', - token: undefined, }; add(hostRule); expect(findAll({ hostType: 'nuget' })).toHaveLength(1); - expect(findAll({ hostType: 'nuget' })[0]).toEqual(hostRule); + expect(findAll({ hostType: 'nuget' })[0]).toMatchObject(hostRule); }); }); }); diff --git a/lib/util/host-rules.ts b/lib/util/host-rules.ts index 111ccd47f3ea58..d5bbfdf265229f 100644 --- a/lib/util/host-rules.ts +++ b/lib/util/host-rules.ts @@ -2,6 +2,7 @@ import URL from 'url'; import merge from 'deepmerge'; import { logger } from '../logger'; import { HostRule } from '../types'; +import { clone } from './clone'; import * as sanitize from './sanitize'; let hostRules: HostRule[] = []; @@ -17,8 +18,9 @@ export function add(params: HostRule): void { throw new Error('hostRules cannot contain both a hostName and baseUrl'); } const confidentialFields = ['password', 'token']; - const resolvedHost = params.baseUrl || params.hostName || params.domainName; + let resolvedHost = params.baseUrl || params.hostName || params.domainName; if (resolvedHost) { + resolvedHost = URL.parse(resolvedHost).hostname || resolvedHost; confidentialFields.forEach((field) => { if (params[field]) { logger.debug( @@ -39,7 +41,11 @@ export function add(params: HostRule): void { ).toString('base64'); sanitize.add(secret); } - hostRules.push(params); + const hostRule = clone(params); + if (resolvedHost) { + hostRule.resolvedHost = resolvedHost; + } + hostRules.push(hostRule); } export interface HostRuleSearch { @@ -150,6 +156,7 @@ export function find(search: HostRuleSearch): HostRule { delete res.domainName; delete res.hostName; delete res.baseUrl; + delete res.resolvedHost; return res; }