mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-31 09:41:46 +00:00
4e1553583c
* feat(terraform): add OCI protocol support for modules and providers Adds support for Terraform modules and providers hosted in OCI-compatible container registries using the `oci://` protocol. Delegates OCI sources to Docker datasource for version resolution. Supports both version in separate field and embedded in URL. Closes https://github.com/renovatebot/renovate/discussions/38927 * refactor(terraform): address code review feedback for OCI support cd - Move ociRefMatchRegex to shared location in base.ts cd - Extract OCI parsing into parseOciRef function to reduce duplication cd - Remove unnecessary registryUrls assignments cd - Add skipReason when OCI tag is unspecified cd - Inline oci.tf fixture to avoid triggering vulnerability scanners cd - Refactor OCI regex tests to use it.each * refactor(terraform): address PR review, round 2 - Replace custom ociRefMatchRegex/parseOciRef with getDep pattern, reusing isOCIRegistry/removeOCIPrefix from helmv3/oci.ts - Remove docs/development/oci-terraform-support.md - Remove ociRefMatchRegex/parseOciRef from base.ts and modules.ts - Simplify OCI test in extract.spec.ts - Remove ociRefMatchRegex describe block from modules.spec.ts * refactor(terraform): address PR review, round 3 extract duplicate function Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> * fix: only allow valid oci urls oci sources only support query params for versioning * feat: pass through registryaliases * fix: fix broken tests * fix: address PR review round 4 * fix: replace new URL with parseUrl Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> * fix: add tests for new path Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com> --------- Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
103 lines
3.3 KiB
TypeScript
103 lines
3.3 KiB
TypeScript
import { isNonEmptyString } from '@sindresorhus/is';
|
|
import { logger } from '../../../logger/index.ts';
|
|
import { regEx } from '../../../util/regex.ts';
|
|
import { TerraformProviderDatasource } from '../../datasource/terraform-provider/index.ts';
|
|
import { isOCIRegistry } from '../helmv3/oci.ts';
|
|
import type { ExtractConfig, PackageDependency } from '../types.ts';
|
|
import type { TerraformDefinitionFile } from './hcl/types.ts';
|
|
import type { ProviderLock } from './lockfile/types.ts';
|
|
import {
|
|
applyOciDependency,
|
|
getLockedVersion,
|
|
massageProviderLookupName,
|
|
} from './util.ts';
|
|
|
|
export abstract class DependencyExtractor {
|
|
/**
|
|
* Get a list of signals which can be used to scan for potential processable content
|
|
* @return a list of content signals
|
|
*/
|
|
abstract getCheckList(): string[];
|
|
|
|
/**
|
|
* Extract dependencies from a HCL object
|
|
* @param hclRoot HCL parsing artifact.
|
|
* @param locks currently existing locks
|
|
*/
|
|
abstract extract(
|
|
hclRoot: TerraformDefinitionFile,
|
|
locks: ProviderLock[],
|
|
config: ExtractConfig,
|
|
): PackageDependency[];
|
|
}
|
|
|
|
export abstract class TerraformProviderExtractor extends DependencyExtractor {
|
|
sourceExtractionRegex = regEx(
|
|
/^(?:(?<hostname>(?:[a-zA-Z0-9-_]+\.+)+[a-zA-Z0-9-_]+)\/)?(?:(?<namespace>[^/]+)\/)?(?<type>[^/]+)/,
|
|
);
|
|
|
|
protected analyzeTerraformProvider(
|
|
dep: PackageDependency,
|
|
locks: ProviderLock[],
|
|
depType: string,
|
|
config: ExtractConfig,
|
|
): PackageDependency {
|
|
dep.depType = depType;
|
|
dep.depName = dep.managerData?.moduleName;
|
|
dep.datasource = TerraformProviderDatasource.id;
|
|
|
|
if (isNonEmptyString(dep.managerData?.source)) {
|
|
// TODO #22198
|
|
if (isOCIRegistry(dep.managerData.source)) {
|
|
applyOciDependency(dep, dep.managerData.source, config.registryAliases);
|
|
return dep;
|
|
}
|
|
|
|
const source = this.sourceExtractionRegex.exec(dep.managerData.source);
|
|
if (!source?.groups) {
|
|
dep.skipReason = 'unsupported-url';
|
|
return dep;
|
|
}
|
|
|
|
// buildin providers https://github.com/terraform-providers
|
|
if (source.groups.namespace === 'terraform-providers') {
|
|
dep.registryUrls = [TerraformProviderDatasource.hashicorpReleaseUrl];
|
|
} else if (source.groups.hostname) {
|
|
dep.registryUrls = [`https://${source.groups.hostname}`];
|
|
dep.packageName = `${source.groups.namespace}/${source.groups.type}`;
|
|
} else {
|
|
dep.packageName = dep.managerData?.source;
|
|
const foundLocks = locks.filter(
|
|
(lock) => lock.packageName === dep.packageName,
|
|
);
|
|
|
|
if (
|
|
foundLocks.length === 1 &&
|
|
foundLocks[0].registryUrl !==
|
|
TerraformProviderDatasource.terraformRegistryUrl
|
|
) {
|
|
logger.debug(
|
|
{ dep, foundLocks },
|
|
'Terraform: Single lock found for provider with non-default registry URL',
|
|
);
|
|
dep.registryUrls = [foundLocks[0].registryUrl];
|
|
} else if (foundLocks.length > 1) {
|
|
logger.debug(
|
|
{ dep, foundLocks },
|
|
'Terraform: Multiple locks found for provider unable to determine registry URL',
|
|
);
|
|
}
|
|
}
|
|
}
|
|
massageProviderLookupName(dep);
|
|
|
|
dep.lockedVersion = getLockedVersion(dep, locks);
|
|
|
|
if (!dep.currentValue) {
|
|
dep.skipReason = 'unspecified-version';
|
|
}
|
|
|
|
return dep;
|
|
}
|
|
}
|