* refactor(manager/helmv3): share generateHelmEnvs with kustomize
Move kustomize's generateHelmEnvs into helmv3/common.ts and delete the
kustomize copy. The merged function always sets the three HELM_*
path variables and sets HELM_EXPERIMENTAL_OCI unless a helm
constraint is present and proves helm >= 3.8 (which ignores the
variable).
Behaviour change: kustomize now sets HELM_EXPERIMENTAL_OCI when the
helm constraint is unknown (previously it only set it for a known
constraint below 3.8). helmv3 and helmfile now omit the variable
once a resolved helm constraint proves helm >= 3.8.
* refactor(manager/helmv3): share OCI registry login helper with helmfile
Extract a shared generateRegistryLoginCmd(name, registry) helper in
helmv3/common.ts that strips the oci:// prefix, derives the host and
looks up the matching host rule before delegating to generateLoginCmd.
helmv3/artifacts.ts and helmfile/artifacts.ts now both call this
helper instead of each building a RepositoryRule inline, removing the
stale oci:// TODO. helmfile/utils.ts loses its duplicate
generateRegistryLoginCmd, and its unrelated isOCIRegistry(repository)
(checking the oci flag) is renamed to isOciRepositoryFlagSet so it no
longer collides in name with helmv3/oci.ts's prefix-based
isOCIRegistry(string), which helmfile/extract.ts also imports.
Addresses audit finding M8. Generated `helm registry login` commands
are unchanged, proved by the existing artifacts specs passing with
their original expectations untouched.
* fix(manager): share one local Helm chart path check
helmfile, flux, fleet and terraform each decided differently whether a Helm chart reference points at a local path. fleet and terraform used terraform's checkIfStringIsPath, whose regex was unanchored with unescaped dots, so it matched any string containing a slash followed by a non-slash character.
Add isLocalChartPath to helmv3/utils.ts with helmfile's prefix check and use it in all four managers. This drops the fleet to terraform dependency and removes checkIfStringIsPath, which had no other users.
* refactor(manager/helm-requirements): reuse helmv3 alias and repository helpers
Replace the duplicated alias-resolution and repository-classification logic in helm-requirements/extract.ts with the shared isAlias, resolveAlias and parseRepository helpers from helmv3/utils.ts (audit finding M9). Behaviour is unchanged: same skipReasons, same registryUrls, same handling of a missing repository or missing registryAliases config.
* refactor(manager/dockerfile): add an options form of getDep for CI managers
`getDep()` gains an overload taking a `GetDepOptions` object with
`specifyReplaceString`, `registryAliases` and `depType`, replacing the
opaque boolean second positional argument at the CI manager call sites.
The positional form keeps working for all other callers.
Migrated: bitbucket-pipelines, droneci, circleci, github-actions,
azure-pipelines and woodpecker.
Behaviour changes:
- azure-pipelines container resources now honour `registryAliases`, which
`extractContainer()` previously ignored
- woodpecker dependencies now carry `depType: 'docker'`, matching the
other CI managers
* refactor(manager/woodpecker): do not set depType on docker image deps
* refactor(manager/dockerfile): drop the positional getDep signature
* refactor(manager/helm-requirements): reuse helmv3 alias and repository helpers
Replace the duplicated alias-resolution and repository-classification logic in helm-requirements/extract.ts with the shared isAlias, resolveAlias and parseRepository helpers from helmv3/utils.ts (audit finding M9). Behaviour is unchanged: same skipReasons, same registryUrls, same handling of a missing repository or missing registryAliases config.
If we don't discover the image family for a given image, instead of
suggesting a package update that may not exist - as we may look up a
`defaultRegistryUrls` entry that doesn't match the distro we're using -
we should not suggest any update.
In these cases, we can specify the `skipReason: unknown-registry`.
In #45706, we'll try and auto-detect this where possible.
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
* feat(manager/dockerfile): extract `apt install` packages from `RUN` instructions
Similar to the support we've recently added for extracting `apk`
packages in `Dockerfile`s, we can also extract `apt install` and
`apt-get install`s.
We can build on top of our shared extraction layer, and:
- preserving an `:arch` qualifier when replacing the version
- skipping versions/constraints we can't update
Co-Authored-By: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
* docs(manager/dockerfile): clarify where to find skipped logs
---------
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
As part of future changes, we want to extract system package managers'
packages in `Dockerfile`s more generally.
Instead of an `apk`-specific file, we can introduce a shared file for
extracting commands from `RUN`s.
From here, it can then be used by `apk` and follow-up tools by providing
the `names` to look for.
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
In the Wolfi undistribution, which Chainguard Images are built upon,
it is common to use a fuzzy constraint rather than exact versions[0]:
RUN apk update && apk add --no-cache libcurl-openssl4=~8.12.1
curl=~8.12.1 make
which we previously skipped as `unsupported-version` when we started
extracting `apk add` packages.
As the `apk` version resolves these, we should extract the constraint as
the `currentValue`, and let the lookup evaluate it.
A constraint of `~8.12.1` matches every `8.12.1-rN` version, so we don't
need to update these constraints.
However, when the `newVersion` is i.e. `8.13.0-r0`, the constraint is
rewritten to `curl=~8.13.0`.
If using an exact pin, the version is upgraded with the same precision
i.e. `curl=8.12.1` -> `curl=8.13.0`.
We still skip constraints we can't handle with i.e. `contains-variable`
or `unsupported-version`.
[0]: https://github.com/elastic/crawler/blob/bc15328fb808affd00dff0cd92527bbe402f5ded/Dockerfile.wolfi#L7
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
* feat(manager/dockerfile): extract `apk add` packages from `RUN` instructions
As noted in #43711, users pin APK packages in their Dockerfiles and want
Renovate to update them, which so far has needed a custom manager[0].
Now that we have the `apk` datasource, we can extract these ourselves,
and parse the `RUN` instruction more effectively than a regex can.
We can do this by:
- extracting `apk add` dependencies when processing a `Dockerfile`
- ignoring common flags to `apk` before we extract the dependency names,
which wasn't straightforward with a Custom Manager
- ignoring i.e. `--virtual .build-deps`
- handle example cases from [0] and other usages i.e. with a comment in
between lines
- ensure that `final` doesn't run against the final `apk` install
- removing the docs for how to do this with a Custom Manager, as that
complexity is no longer needed
- skipping `unspecified-version` and `contains-variable`
We inform the user that they will need to override the `registryUrls`,
as we already have a default on the `apk` datasource and can't override
it in a straightforward means.
[0]: https://www.jvt.me/posts/2025/03/24/renovate-regex-dockerfile-apk/
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
* fixup! feat(manager/dockerfile): extract `apk add` packages from `RUN` instructions
Co-Authored-By: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* fixup! feat(manager/dockerfile): extract `apk add` packages from `RUN` instructions
Co-Authored-By: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
* fixup! feat(manager/dockerfile): extract `apk add` packages from `RUN` instructions
Find the command by name wherever it sits in the tokens, rather than
skipping an allowlist of shell keywords and variable assignments, so that
a wrapper program like `sudo`, `chroot /mnt` or `timeout 30` is handled
too.
Co-Authored-By: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* fixup! feat(manager/dockerfile): extract `apk add` packages from `RUN` instructions
---------
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
* test(manager): close azure-pipelines, bundler and cocoapods gaps
Adds a pipeline whose step task is not versioned, so nothing is
extracted, and a gem lock line carrying no version, which is skipped.
Marks four guards that cannot be false: `extractContainer()` always
returns a dep, `getLockFilePath()` always returns a path, and the
cocoapods dep name, spec name and git account all derive from values
their enclosing check already proved present.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager): close cargo, composer and cpanfile gaps
Adds a composer repository map that disables something other than
packagist, which is dropped rather than recorded.
Marks five guards: the cargo warning only fires for a crate dep and its
retry only runs when a dep was already current, a gitlab rule without a
token never passes the auth check, and both cpanfile handlers run only
once their match produced a value.
Two implicit elses stay counted, in the cargo version resolver and the
composer repository mapper, since a coverage-ignore hint does not attach
to an `else if`.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager): close deps-edn, docker-compose and dockerfile gaps
Adds three extractions: a deps.edn alias whose value is not a map, a
compose extension carrying no image, and a dockerfile escape directive
naming a character other than a backtick, which leaves the default in
place.
Marks the deps-edn repository name check, since object keys are always
strings, and notes the repository spec chain, where a coverage-ignore
hint does not attach to an `else if`.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager/flux): close the flux coverage gaps
Adds two GitRepository resources whose url is ssh rather than http, one
pinned to a tag and one to a commit. Neither yields a source url, since
only http urls can be turned into one.
Marks the Kustomization image guard: the schema rejects an image without
a name, so `extractImage()` cannot return null there.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager): mark github-actions, gitlabci and glasskube guards
None of these six needs a test. A parsed action ref is either a docker
or a repository ref, `getDep()` always returns a dep for a job container
and a service, and the remaining three need a listed file that cannot be
read, a listed file that yields no deps, or a manifest whose
repositories match no name.
The glasskube resource kind chain stays counted, since a coverage-ignore
hint does not attach to an `else if`.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager): mark gomod and gradle-wrapper guards
Four guards that need setups no test provides: a removed dep that is not
added back, a go.mod the replace massaging leaves unchanged, and a
daemon-jvm file carrying no toolchain version. A parsed go directive
always yields a version.
The additional-dependency count chain stays counted, since a
coverage-ignore hint does not attach to an `else if`.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
---------
Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
fix(manager/dockerfile): only relabel last `stage` as `final`
If using a Docker image that only declares a `syntax`, with no base
image, we would incorrectly set the `depType: final`, when this isn't
actually an image.
Instead, we should make sure that we find the last `stage` dependency,
and then override that.
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
* fix(manager): handle registryAliases with shell variable defaults
Allows `registryAliases` keys to contain shell-style variables with
empty (or other) defaults, e.g. `${DEPENDENCY_PROXY:-}` or
`${CI_REGISTRY:-}`. The same image string is then resolved both
online (variable expanded) and offline (variable empty).
Changes in `dockerfile/extract.ts` (used by `gitlabci` too):
* Match the alias key as either `${name}/...` (existing) or `${name}...`
when `name` already ends in a non-identifier boundary character such
as `}`. Bare-identifier keys like `$CI_REGISTRY` continue to require
the slash boundary so they no longer overmatch keys that begin with
the same prefix (e.g. `$CI_REGISTRY` vs `$CI_REGISTRY_IMAGE`).
* Use `ensureTrailingSlash` to handle alias values that already include
a trailing slash.
* Preserve the original `name` and path structure in `dep.depName`
instead of substringing only after the alias `value`. This keeps the
variable in the depName so it survives a `splitImageParts` round-trip
and the resulting branch name comes out clean.
Adds `sanitizeDepName` regex passes in
`lib/workers/repository/updates/flatten.ts` so any leftover
`${VAR}`/`${VAR:-...}` placeholder is stripped from the depName before
it becomes a branch name (otherwise we'd get
`renovate/${dependency_proxy}python-3.x` instead of
`renovate/python-3.x`).
Tests cover:
* `${VAR:-}/image` (with slash) and `${VAR:-}image` (no slash, requires
the boundary form).
* Overlapping prefixes: `$CI_REGISTRY` vs `$CI_REGISTRY_IMAGE`.
* Registry alias with port (`localhost:5000/repo`).
* `sanitizeDepName` strips `${VAR}` / `${VAR:-}` / bare `$VAR`.
Reproducer: https://github.com/Wayneoween/renovate-36293-repro
* revert(manager/gitlabci): keep regex group name as 'prefix'
Reverting the unrelated `prefix` -> `rawPrefix` rename in `depProxyRe`.
Per review on #36293, this rename is out of scope for the registry-alias
fix and just adds review surface.
* refactor(manager/dockerfile): narrow alias boundary check to '}'
Per review on #36293. The previous regex `/[^A-Za-z0-9_]$/` matched any
non-word ending, which is broader than the documented case (alias keys
ending in `}` from `${VAR}` / `${VAR:-...}`). Replace with a plain
`name.endsWith('}')` check, which also avoids re-building a regex on
every iteration of the alias loop.
Existing tests (`'variables with default and slash'`,
`'variables with default no slash'`, `'alias with digest only'`)
continue to exercise the `}`-boundary path; the `'overlapping prefixes'`
case continues to exercise the slash-only path.
* chore(manager/dockerfile): trim comment and TODO library/ strip edge
Per review on #36293:
* Drop the verbose explanation block above the depName-restore branch;
the spec rows already document the expected shape.
* Add a TODO above the `dep.depName?.startsWith(valueWithSlash)` guard
noting a pre-existing edge case: when the inner `getDep` strips a
`library/` prefix (or similar) the depName no longer starts with
`valueWithSlash`, so the alias-rooted depName is not restored. Out of
scope for this PR.
* fix(manager/dockerfile): handle empty registry alias value
- strip trailing slash after ${VAR} placeholders in sanitizeDepName
- treat an empty registry alias value as Docker Hub instead of '/'
- clarify registry alias docs wording
* refactor(manager/dockerfile): drop redundant alias boundary guard
- `matchedAtBoundary` is only read behind `!matchedWithSlash`
- add docker-compose test for `${VAR:-}` registry aliases
* test(manager/dockerfile): pin special-prefix registry alias behavior
`getDep` strips `library/`, `amd64/` and `arm64/` as special prefixes, so
an alias whose value is one of those loses its alias-rooted `depName`.
Both the slash form and the variable form behave this way on `main`.
Refs #45216
The object counterpart to `prefer-coerce-array`: `x ?? {}` becomes
`coerceObject(x)`. The rule flags a `??` whose default is a bare `{}`
literal, so a populated default or an asserted `({} as Foo)` still
passes; a `x ?? y ?? {}` chain maps onto `coerceObject(x, y)`.
Every hit across `lib/` converted cleanly, so no disable comments were
needed.
* fix(lint): use `parseInt` over `Number`
As a code review comment that comes up every so often, we can add a
linting rule to enforce this check.
This also fixes any existing usages.
As this could be breaking, we can release it as a `fix`.
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* fixup! fix(lint): use `parseInt` over `Number`
* fixup! fix(lint): use `parseInt` over `Number`
---------
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* ci(linter): add renovate/require-regex-util rule
Adds a custom oxlint rule that flags raw RegExp usage in lib/
production code: any `new RegExp(...)` call and any regex literal
that is not the direct first argument of `regEx(...)`. The regEx()
helper from lib/util/regex.ts uses the RE2 engine for ReDoS-safe
matching and caches compiled patterns. lib/util/regex.ts itself is
exempt.
The rule is disabled for **/*.spec.ts, test/**, and tools/** via
config overrides, because vitest APIs such as expect.stringMatching
need bare RegExp instances (a past commit reverted regEx() there).
Severity is set to "warn" instead of "error": the repo currently has
197 pre-existing violations (above the agreed mechanical-fix
threshold of 80), and a number of them are deliberately
RE2-incompatible patterns (lookahead/lookbehind/named backreferences,
see TODO #12872/#12875 markers in e.g. lib/modules/versioning/rez/
pattern.ts and lib/modules/manager/dockerfile/extract.ts) that need
per-site judgment before they can be wrapped in regEx() or suppressed
with a justified disable comment. No violation fixes are included in
this commit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): enforce renovate/require-regex-util at error
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: use regEx() for regex literals and RegExp construction in lib
Burn down all renovate/require-regex-util violations (197):
- wrap RE2-compatible regex literals and RegExp constructions in regEx()
- rewrite lookaround patterns where behavior is provably preserved:
goproxy separator split, sbt-package link extraction, leiningen
comment stripping and keyword search, npm GitHub owner validation
(unit-count bound replaced by an explicit length check)
- keep native RegExp with disable comments where RE2 cannot be used:
moo / good-enough-parser lexer patterns (moo rejects RE2 instances),
MigrationsService propertyName (matched via isRegExp, which RE2
instances fail), rez named backreferences and lookaheads, GitHub
markdown link negative lookbehind, emoji astral-plane matching
- drop stale TODO #12875 comments for patterns current re2 handles
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: reduce require-regex-util disable comments
Rewrite the github massage-markdown-links URL regex to capture an
optional `api.` prefix in a named group (skipped in code) instead of
relying on a negative lookbehind, so both the base and global variants
can use regEx()/RE2 and their two disable comments are removed. Add
spec cases for api-prefixed URLs that match the URL shape.
Consolidate the four related line disables in rez/pattern.ts (bound and
range patterns emulating Python conditional patterns via named
backreferences and lookaheads, which RE2 cannot express) into a single
block disable/enable pair, matching the treatment of the lexer files.
Disable comment count drops from 13 to 8.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(datasource/sbt-package): use named capture group in link regex
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(manager/cake): restore original multiLineComment regex spelling
The [^] -> [\\s\\S] rewrite was only needed for an RE2 wrap that was
later reverted; keep the diff minimal.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(datasource/go): skip empty GOPROXY segments
The switch from a lookahead split to a capture-group split (needed because
RE2 has no lookahead support) changed how empty GOPROXY segments parse:
`a|,b` yielded `{ url: ',', fallback: '|' }` before and
`{ url: '', fallback: ',' }` after. The comma fallback only continues on
404/410, so a failing proxy ahead of an empty segment silently stopped the
lookup instead of falling through to the remaining proxies.
Empty segments carry no url to query, so drop them.
* refactor(datasource/go): use isTruthy for empty segment filter
* fix(datasource/go): filter empty segments before mapping
Filtering after the map broke the contextual typing from the
GoproxyItem[] annotation, widening fallback to string.
* refactor(platform/github): use regEx() for merge queue query stripping
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
ARG value unquoting only stripped double quotes, so ARG FOO='' kept the
literal '' and resolved FROM ${FOO}node to ''node. Strip single quotes too.
Co-authored-by: youdie006 <youdie006@users.noreply.github.com>
Enable the unicorn/prefer-at rule as error in .oxlintrc.json and fix all
43 pre-existing violations (arr[arr.length - 1] -> arr.at(-1)) via oxlint
autofix. Where .at() widened the type to T | undefined, non-null
assertions were added at sites where surrounding logic guarantees the
element exists (length guards, split results), preserving the original
runtime behavior and typing.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* docs: explicitly document `depTypes` each manager supports
A long-standing question we receive is "what `depTypes` can I match
against in my project".
Although the best recommendation we usually have is "check the
`packageFiles with updates" log line (as a very key log line for users),
we can go one step further and try and create a stronger contract.
To do this, I've used Claude Sonnet 4.6 to work through the codebase,
determine areas that a `depType` is set in a manager (statically or
dynamically) and generate a structured, typed, means to document how
they're used.
Through a few iterations of the process, and attempts at human-written
documentation, we've settled on:
- prioritising autogenerated documentation (for humans to read) to note
what `depTypes` are known, and what they are
- `knownDepTypes`, to describe any known, static, `depType`s and their
human-readable meaning
- with the `prettyDepType`, if used
- `supportsDynamicDepTypesNote`, to add a Markdown note to the generated
documentation
While here, we also:
- make sure to note this in the "adding a new package manager"
documentation
- remove any hand-written references to `depTypes` in each manager's
documentation page
- correct the Gleam `depTypes`
- make sure to use the `knownDepTypes`'s `prettyDepType` definition if
we know it, for a given `depType`
The descriptions have been generated by Claude Sonnet, with some
human-written tweaks where appropriate.
[0]: https://github.com/renovatebot/renovate/discussions/15176
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* fixup! docs: explicitly document `depTypes` each manager supports
* docs(manager): display `depTypes` documentation if none present
For consistency, and to make it more explicit.
---------
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>