mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-24 22:48:06 +00:00
1a80c538f8
* build(deps): update dependency got to v16.1.0 | datasource | package | from | to | | ---------- | ------- | ------ | ------ | | npm | got | 16.0.0 | 16.1.0 | * fix(util/http): adapt to got 16.1 types Co-Authored-By: Claude Opus 5.5 <michael.kriese+claude-code@mend.io> --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Michael Kriese <michael.kriese@mend.io> Co-authored-by: Claude Opus 5.5 <michael.kriese+claude-code@mend.io>
281 lines
7.0 KiB
TypeScript
281 lines
7.0 KiB
TypeScript
import { isNonEmptyString } from '@sindresorhus/is';
|
|
import { GlobalConfig } from '../../config/global.ts';
|
|
import { PLATFORM_FAMILIES } from '../../constants/index.ts';
|
|
import { logger } from '../../logger/index.ts';
|
|
import { hasProxy } from '../../proxy.ts';
|
|
import type { CombinedHostRuleWithTrustedHeaders } from '../host-rules.ts';
|
|
import * as hostRules from '../host-rules.ts';
|
|
import { matchRegexOrGlobList } from '../string-match.ts';
|
|
import { parseUrl } from '../url.ts';
|
|
import type { InternalHttpOptions } from './http.ts';
|
|
import { keepAliveAgents } from './keep-alive.ts';
|
|
import type { GotOptions } from './types.ts';
|
|
|
|
export type HostRulesGotOptions = Pick<
|
|
GotOptions & Omit<InternalHttpOptions, 'headers'>,
|
|
| 'hostType'
|
|
| 'noAuth'
|
|
| 'headers'
|
|
| 'token'
|
|
| 'username'
|
|
| 'password'
|
|
| 'context'
|
|
| 'enabled'
|
|
| 'abortOnError'
|
|
| 'abortIgnoreStatusCodes'
|
|
| 'timeout'
|
|
| 'agent'
|
|
| 'http2'
|
|
| 'https'
|
|
| 'readOnly'
|
|
>;
|
|
|
|
export function findMatchingRule<GotOptions extends HostRulesGotOptions>(
|
|
url: string,
|
|
options: GotOptions,
|
|
): CombinedHostRuleWithTrustedHeaders {
|
|
const { hostType, readOnly } = options;
|
|
let res = hostRules.find({ hostType, url, readOnly });
|
|
|
|
if (
|
|
isNonEmptyString(res.token) ||
|
|
isNonEmptyString(res.username) ||
|
|
isNonEmptyString(res.password)
|
|
) {
|
|
// do not fallback if we already have auth infos
|
|
return res;
|
|
}
|
|
|
|
// Fallback to `github` hostType
|
|
if (
|
|
hostType &&
|
|
PLATFORM_FAMILIES.github.apiUsingHostTypes.includes(hostType) &&
|
|
hostType !== 'github'
|
|
) {
|
|
res = {
|
|
...hostRules.find({
|
|
hostType: 'github',
|
|
url,
|
|
}),
|
|
...res,
|
|
};
|
|
}
|
|
|
|
// Fallback to `github` hostType for the GitHub.com API and the host of the GitHub platform endpoint, such as GitHub Enterprise Server or GitHub Enterprise Cloud
|
|
if (hostRules.usesGithubUrlFallback(url)) {
|
|
res = {
|
|
...hostRules.find({ hostType: 'github', url }),
|
|
...res,
|
|
};
|
|
}
|
|
|
|
// Fallback to `gitlab` hostType
|
|
if (
|
|
hostType &&
|
|
PLATFORM_FAMILIES.gitlab.apiUsingHostTypes.includes(hostType) &&
|
|
hostType !== 'gitlab'
|
|
) {
|
|
res = {
|
|
...hostRules.find({
|
|
hostType: 'gitlab',
|
|
url,
|
|
}),
|
|
...res,
|
|
};
|
|
}
|
|
|
|
// Fallback to `bitbucket` hostType
|
|
if (
|
|
hostType &&
|
|
PLATFORM_FAMILIES.bitbucket.apiUsingHostTypes.includes(hostType) &&
|
|
hostType !== 'bitbucket'
|
|
) {
|
|
res = {
|
|
...hostRules.find({
|
|
hostType: 'bitbucket',
|
|
url,
|
|
}),
|
|
...res,
|
|
};
|
|
}
|
|
|
|
// Fallback to `bitbucket-server` hostType
|
|
if (
|
|
hostType &&
|
|
PLATFORM_FAMILIES['bitbucket-server'].apiUsingHostTypes.includes(
|
|
hostType,
|
|
) &&
|
|
hostType !== 'bitbucket-server'
|
|
) {
|
|
res = {
|
|
...hostRules.find({
|
|
hostType: 'bitbucket-server',
|
|
url,
|
|
}),
|
|
...res,
|
|
};
|
|
}
|
|
|
|
// Fallback to `forgejo` hostType
|
|
if (
|
|
hostType &&
|
|
PLATFORM_FAMILIES.forgejo.apiUsingHostTypes.includes(hostType) &&
|
|
hostType !== 'forgejo'
|
|
) {
|
|
res = {
|
|
...hostRules.find({
|
|
hostType: 'forgejo',
|
|
url,
|
|
}),
|
|
...res,
|
|
};
|
|
}
|
|
|
|
// Fallback to `gitea` hostType
|
|
if (
|
|
hostType &&
|
|
PLATFORM_FAMILIES.gitea.apiUsingHostTypes.includes(hostType) &&
|
|
hostType !== 'gitea'
|
|
) {
|
|
res = {
|
|
...hostRules.find({
|
|
hostType: 'gitea',
|
|
url,
|
|
}),
|
|
...res,
|
|
};
|
|
}
|
|
|
|
// Fallback to `go` hostType, which requests to a Go module proxy used until they were split into the `go-proxy` datasource
|
|
if (hostType === 'go-proxy') {
|
|
// only inherit the authentication-related fields
|
|
const {
|
|
token,
|
|
authType,
|
|
username,
|
|
password,
|
|
httpsCertificate,
|
|
httpsPrivateKey,
|
|
httpsCertificateAuthority,
|
|
} = hostRules.find({ hostType: 'go', url });
|
|
res = {
|
|
token,
|
|
authType,
|
|
username,
|
|
password,
|
|
httpsCertificate,
|
|
httpsPrivateKey,
|
|
httpsCertificateAuthority,
|
|
...res,
|
|
};
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
// Apply host rules to requests
|
|
export function applyHostRule<GotOptions extends HostRulesGotOptions>(
|
|
url: string,
|
|
options: GotOptions,
|
|
hostRule: CombinedHostRuleWithTrustedHeaders,
|
|
): GotOptions {
|
|
if (hostRule.enabled === false) {
|
|
options.enabled = false;
|
|
return options;
|
|
}
|
|
|
|
const { username, password, token, authType } = hostRule;
|
|
const host = parseUrl(url)?.host;
|
|
if (options.noAuth) {
|
|
logger.trace({ url }, `Authorization disabled`);
|
|
} else if (
|
|
isNonEmptyString(options.headers?.authorization) ||
|
|
isNonEmptyString(options.password) ||
|
|
isNonEmptyString(options.token)
|
|
) {
|
|
logger.once.debug(`hostRules: authentication already set for ${host}`);
|
|
logger.trace({ url }, `Authorization already set`);
|
|
} else if (password !== undefined) {
|
|
logger.once.debug(`hostRules: applying Basic authentication for ${host}`);
|
|
logger.trace({ url }, `Applying Basic authentication`);
|
|
options.username = username;
|
|
options.password = password;
|
|
} else if (token) {
|
|
logger.once.debug(`hostRules: applying Bearer authentication for ${host}`);
|
|
logger.trace({ url }, `Applying Bearer authentication`);
|
|
options.token = token;
|
|
options.context = { ...options.context, authType };
|
|
} else {
|
|
logger.once.debug(`hostRules: no authentication for ${host}`);
|
|
}
|
|
// Apply optional params
|
|
if (hostRule.abortOnError) {
|
|
options.abortOnError = hostRule.abortOnError;
|
|
}
|
|
|
|
if (hostRule.abortIgnoreStatusCodes) {
|
|
options.abortIgnoreStatusCodes = hostRule.abortIgnoreStatusCodes;
|
|
}
|
|
|
|
if (hostRule.timeout) {
|
|
options.timeout = hostRule.timeout;
|
|
}
|
|
|
|
if (hostRule.headers) {
|
|
const allowedHeaders = GlobalConfig.get('allowedHeaders');
|
|
// headers already known to have come from the self-hosted administrator's own (`trusted`) config bypassed `allowedHeaders` at registration - see `hostRules.add()` - so must not be re-checked, and dropped, here
|
|
const trustedHeaderNames = new Set(hostRule.trustedHeaderNames);
|
|
const filteredHeaders: Record<string, string> = {};
|
|
|
|
for (const [header, value] of Object.entries(hostRule.headers)) {
|
|
if (
|
|
trustedHeaderNames.has(header) ||
|
|
matchRegexOrGlobList(header, allowedHeaders)
|
|
) {
|
|
filteredHeaders[header] = value;
|
|
} else {
|
|
logger.once.error(
|
|
{ allowedHeaders, header },
|
|
'Disallowed hostRules headers',
|
|
);
|
|
}
|
|
}
|
|
|
|
options.headers = {
|
|
...options.headers,
|
|
...filteredHeaders,
|
|
};
|
|
}
|
|
|
|
if (hostRule.keepAlive) {
|
|
options.agent = keepAliveAgents;
|
|
}
|
|
|
|
if (!hasProxy() && hostRule.enableHttp2 === true) {
|
|
options.http2 = true;
|
|
}
|
|
|
|
if (isNonEmptyString(hostRule.httpsCertificateAuthority)) {
|
|
options.https = {
|
|
...options.https,
|
|
certificateAuthority: hostRule.httpsCertificateAuthority,
|
|
};
|
|
}
|
|
|
|
if (isNonEmptyString(hostRule.httpsPrivateKey)) {
|
|
options.https = {
|
|
...options.https,
|
|
key: hostRule.httpsPrivateKey,
|
|
};
|
|
}
|
|
|
|
if (isNonEmptyString(hostRule.httpsCertificate)) {
|
|
options.https = {
|
|
...options.https,
|
|
certificate: hostRule.httpsCertificate,
|
|
};
|
|
}
|
|
|
|
return options;
|
|
}
|