import { logger } from '../../../../logger/index.ts'; import { getDatasourceList } from '../../../../modules/datasource/index.ts'; import type { HostRule } from '../../../../types/index.ts'; import { regEx } from '../../../../util/regex.ts'; type AuthField = 'token' | 'username' | 'password'; type HttpsAuthField = 'httpscertificate' | 'httpsprivatekey' | 'httpscertificateauthority'; function isAuthField(x: unknown): x is AuthField { return x === 'token' || x === 'username' || x === 'password'; } function isHttpsAuthField(x: unknown): x is HttpsAuthField { return ( x === 'httpscertificate' || x === 'httpsprivatekey' || x === 'httpscertificateauthority' ); } function restoreHttpsAuthField(x: HttpsAuthField | AuthField): string { switch (x) { case 'httpsprivatekey': return 'httpsPrivateKey'; case 'httpscertificate': return 'httpsCertificate'; case 'httpscertificateauthority': return 'httpsCertificateAuthority'; } return x; } function setHostRuleValue( rule: HostRule, key: string, value: string | undefined, ): void { if (value !== undefined) { switch (key) { case 'token': case 'username': case 'password': case 'httpsCertificateAuthority': case 'httpsCertificate': case 'httpsPrivateKey': rule[key] = value; } } } export function hostRulesFromEnv(env: NodeJS.ProcessEnv): HostRule[] { const datasources = new Set(getDatasourceList()); const platforms = new Set(['github']); const hostRules: HostRule[] = []; const npmEnvPrefixes = ['npm_config_', 'npm_lifecycle_', 'npm_package_']; for (const envName of Object.keys(env).sort()) { if (['GITHUB_COM_TOKEN', 'RENOVATE_GITHUB_COM_TOKEN'].includes(envName)) { continue; } if (npmEnvPrefixes.some((prefix) => envName.startsWith(prefix))) { logger.trace(`Ignoring npm env: ${envName}`); continue; } // Double underscore __ is used in place of hyphen - const splitEnv = envName .replace(regEx(/^RENOVATE_/), '') .toLowerCase() .replace(regEx(/__/g), '-') .split('_'); const hostType = splitEnv.shift()!; if ( datasources.has(hostType) || (platforms.has(hostType) && splitEnv.length > 1) ) { let suffix = splitEnv.pop()!; if (isAuthField(suffix) || isHttpsAuthField(suffix)) { suffix = restoreHttpsAuthField(suffix); let matchHost: string | undefined = undefined; const rule: HostRule = {}; setHostRuleValue(rule, suffix, env[envName]); if (splitEnv.length === 0) { // host-less rule } else if (splitEnv.length === 1) { logger.warn({ env: envName }, 'Cannot parse env'); continue; } else { matchHost = splitEnv.join('.'); } const existingRule = hostRules.find( (hr) => hr.hostType === hostType && hr.matchHost === matchHost, ); logger.debug(`Converting ${envName} into a global host rule`); if (existingRule) { // Add current field to existing rule setHostRuleValue(existingRule, suffix, env[envName]); } else { // Create a new rule const newRule: HostRule = { hostType, }; if (matchHost) { newRule.matchHost = matchHost; } setHostRuleValue(newRule, suffix, env[envName]); hostRules.push(newRule); } } } } return hostRules; }