Commit Graph

14433 Commits

Author SHA1 Message Date
secustor c3325bcea8 refactor(workers): share the config file commit between onboarding and config migration
The onboarding and config migration workers each had their own copy of the
dryRun guard plus `scm.commitAndPush()` call that writes a Renovate config
file to its own branch, and only `onboarding/branch/create.ts` compiled
`commitBody` and `commitTrailers`.

Add `model/commit-config-file.ts` with `commitConfigFile()`, which owns the
dryRun guard (the log line stays per call site through `dryRunMessage`), the
commit body and trailer compilation and the `commitAndPush()` call. Its
`getFiles` callback runs only after the guard passes, so a dry run still
neither checks out a branch nor runs Prettier. The same file exports
`createConfigFileCommitMessage()`, which replaces the duplicated "create a
`CommitMessage` and set its subject" step of the two commit message
factories. Extract the body and trailer compilation into
`model/commit-body.ts` as `compileCommitBodyAndTrailers()`, now used by
`update/branch/index.ts` as well.

Move `getOnboardingPrTitle()` into `onboarding/common.ts` so the onboarding
branch create, rebase and PR workers share it.

Behaviour changes:

* Config migration commits and the onboarding rebase commit now honour
  `commitBody` and `commitTrailers`, as the onboarding create commit already
  did. As there, only `gitAuthor` is exposed to those templates.
* `trailers` is left out of the `commitAndPush()` call when no trailer is
  configured, instead of being sent as an empty array by the onboarding
  create commit. Both the Git and the Gerrit commit paths treat the two the
  same.
* The `commitMessage` trace log is now JSON stringified for the onboarding
  create commit, matching the branch worker, and a `commitTrailers` trace log
  was added for all four commits.
2026-09-14 23:29:30 +02:00
secustor a823bd6a05 refactor(workers): share onboarding and config migration PR handling
The onboarding PR, the config migration PR and `ensurePr()` each had their
own copy of the prHeader/prFooter wrapping, the body-hash comparison, the
dryRun-guarded `platform.updatePr()` call, the
prepareLabels/createPr/addParticipants sequence and the "a pull request
already exists" error detection.

Add `update/pr/ensure-simple-pr.ts` with `ensureSimplePr()`, which the
onboarding and config migration workers now call - they only render their
body. Add `update/pr/errors.ts` with `isPrAlreadyExistsError()`, used by all
three. Both simple PRs now wrap their body with the existing
`getPrHeader()`/`getPrFooter()` helpers, and the onboarding rebase checkbox
comes from `body/controls.ts`, which exports `getRebaseCheckbox()`.
`ensurePr()` computes `prepareLabels()` once instead of four times.

`ensureSimplePr()` takes the already looked-up `existingPr` instead of
calling `platform.getBranchPr()` itself: the onboarding worker needs the PR
earlier for its auto-close and conflict checks, and the config migration
worker looks the PR up against `config.baseBranch` while creating it against
`config.defaultBranch`. Keeping the lookup in the callers preserves both.

Behaviour changes, from reconciling the three copies:

* An empty-string `prHeader`/`prFooter` no longer emits the separating
  newlines or the `---` separator in the onboarding and config migration
  PRs, and no newline is appended after the footer. `hashBody()` strips
  whitespace, so no existing PR is rewritten because of this.
* `prFooter` is now compiled with `safeCompile()` in the onboarding and
  config migration PRs, as it already was for update PRs. A broken footer
  template now logs a warning and renders an empty footer instead of
  aborting the repository run.
* The onboarding rebase checkbox now reads "If you want to rebase/retry this
  PR, check this box", the wording used by every other Renovate PR, instead
  of "click this checkbox.". This changes the onboarding PR body hash, so
  repositories with the experimental `onboardingRebaseCheckbox` enabled get
  a one-off PR body update.
* `isPrAlreadyExistsError()` matches on `err.response.statusCode === 422`
  plus any error entry whose message starts with "A pull request already
  exists". For the onboarding and config migration PRs only the first error
  entry used to be inspected. For `ensurePr()` the check used to require
  `err.body.message === 'Validation failed'` without a status code - GitHub
  sends "Validation Failed", so that condition was unlikely to ever match.
  `ensurePr()` still returns `prBlockedBy: 'Error'` and does not delete the
  branch.
* The onboarding PR no longer throws when `platform.createPr()` resolves
  null; `addParticipants()` is skipped instead, as it already was for the
  config migration PR.
* Log message changes: "Onboarding PR created"/"Migration PR created" are
  now "Created onboarding PR"/"Created migration PR" (and likewise for
  updates), the onboarding "PR created" metadata is `{ pr: <number> }`
  rather than `{ pr: 'Pull Request #<number>' }`, the config migration "Pr
  does not need updating, PrNo: N" is now "Pull Request #N does not need
  updating", the "already exists but cannot find it" warning has a static
  message with `{ err, branchName }` metadata, and the onboarding body trace
  logs `{ prBody }` instead of interpolating it.
2026-09-14 23:29:10 +02:00
secustor fceb252ad2 refactor(manager): declare out-of-band file updates instead of special-casing git-submodules
`getUpdatedPackageFiles()` kept an unchanged package file as updated by
comparing the manager name against `git-submodules`, so that
`updateArtifacts()` would still run after `updateDependency()` had changed
the checkout on disk.

Managers now declare that capability themselves through the new optional
`updatesFilesOutOfBand` flag on `ManagerApiBase`, which the branch worker
reads via `get(manager, ...)`. Only `git-submodules` sets it, so there is
no behaviour change.
2026-09-14 23:29:10 +02:00
secustor 3e53bd259d refactor(workers/branch): pass the fetched PR and modified state to the branch helpers
`processBranch()` already fetches the branch PR and asks whether the branch was
modified, but the helpers it calls fetched the same state again:

- `shouldReuseExistingBranch()` and `tryBranchAutomerge()` now take the
  `branchPr` the orchestrator holds instead of calling `platform.getBranchPr()`
  themselves. `shouldKeepUpdated()` is replaced by `hasKeepUpdatedLabel()`,
  which index.ts and `decideBranchReuse()` also use in place of their own
  copies of the same expression.
- The `scm.isBranchModified()` result is stored in `config.isModified`, and
  reuse.ts reads `result.isModified ??= await scm.isBranchModified(...)` so it
  still works when reached without the orchestrator.
- The closed-PR lookup for a modified branch without an open PR moves out of
  index.ts into `findClosedPrForModifiedBranch()` next to its siblings in
  check-existing.ts.

No behaviour change. `BranchConfig.isModified` is now also set to `false` on
two paths of `shouldReuseExistingBranch()` which previously left it undefined;
nothing reads that field.

`update/pr/automerge.ts` deliberately keeps its own `scm.isBranchModified()`
call: it runs after `commitFilesToBranch()`, which resets the branch's modified
state, so the value computed before the commit is not the one it needs.
2026-09-14 23:29:09 +02:00
secustor 2e5bfd5748 refactor(workers/branch): split processBranch into testable stages
processBranch() spanned more than a thousand lines with 34 return points.
Move the stages which do not need the orchestrator's scope into modules of
their own:

- `computeInternalChecksStatus()` in status-checks.ts computes the stability
  and merge confidence status of the upgrades
- `decideBranchReuse()` in reuse.ts decides whether an existing branch may be
  reused, before `shouldReuseExistingBranch()` inspects the branch itself
- `handleBranchError()` in errors.ts maps a thrown error either to a rethrow
  or to a branch result
- `prBlockedByToResult()` in pr-blocked-by.ts replaces five near-identical
  return blocks with a table
- `rebaseCheck()` and `userChangedTargetBranch()` move next to their siblings
  in check-existing.ts

`ProcessBranchResult` moves to types.ts and is re-exported from index.ts so
that errors.ts can use it without an import cycle.

No behaviour change. Every stage gets its own unit tests, which also cover the
error paths that were previously excluded from coverage.
2026-09-14 22:49:18 +02:00
Jamie Tanna 826541b266 fix(datasource/go): don't cache private modules (#45949)
Previously, we were caching private Go modules' information, even when
`cachePrivatePackages=false`.

This leads to the module path, versions, and possibly the `go`
directive being cached unintentionally.

Instead of doing so, we should make sure that we're intentionally
caching packages.

To do this, we can use a mix of the `GOPRIVATE`/`GONOPROXY` to determine
which packages shouldn't be fetched in the public Go proxy, given
they're private, following how the Go toolchain itself does this.

When interacting with the public Go proxy, we treat these packages as
public (as the public Go proxy has no means to authenticate) and so
anything outside of this should be treated as private.

When `GOPROXY` contains `direct`, we only treat a package as public only
when the public proxy is in the list too, the way Go's own default is
written. This is used to imply that `direct` is the fallback for
whatever the public proxy doesn't have.

When thre is no Go proxy set, `GOPROXY=direct` means everything comes
from source, which tells us nothing about who is allowed to read it.

This doesn't catch everything: with the default `GOPROXY`, a private
package the public proxy doesn't have falls through to `direct` and is
still cached by Renovate, unless `GOPRIVATE` says otherwise. We only
learn that no proxy served it after we've fetched it, which is after
`cacheable` is determined.

When using Renovate with a private Go proxy mirror, such as Artifactory,
this will result in no cached packages until `cachePrivatePackages:
true` is set.

This is a similar change to #45348.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-14 16:39:36 +00:00
Gregor Zeitlinger 2e951d2254 feat(mise): support selector lockfile updates (#44615)
* mise: support selector lockfile updates

* fix(mise): handle empty lockfile AST

* test(mise): use valid empty TOML AST fixture

* fix(mise): support current regex utility

* fix: clarify lockfile-only lookup handling

* fix(mise): handle selector lockfile updates correctly

* test(mise): cover selector lockfile review fixes

* fix(mise): scope selector artifact refresh

* chore: retrigger CI

* fix(mise): remove unreachable lockfile guard

* refactor(lookup): clarify lockfile-only value handling

* refactor(mise): use shared TOML utilities

* fix(mise): handle selector lockfile edge cases

* fix(mise): satisfy selector CI coverage

* fix(mise): require dependency names

* fix(mise): preserve configured dependency names

* fix(mise): address selector lockfile review feedback

* test(mise): cover major selector lockfile updates

* chore(static-data): auto-update Java LTS versions

So we don't have a hardcoded set of data in the mise manager.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>

* fix(mise): address selector lockfile feedback

* test(manager/mise): cover nonnumeric current version prefix

formatLockedVersion()'s currentPrefix fallback to '' only runs when
the current version has no leading numeric match, which no existing
test reached.

Co-Authored-By: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>

---------

Co-authored-by: Jamie Tanna <jamie.tanna@mend.io>
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-14 15:57:22 +00:00
Michael Kriese ed285cc4c1 perf(manager/maven-wrapper): avoid matching each line twice (#46027)
refactor(maven-wrapper): avoid matching each line twice

`extractLineInfo` ran `line.match(regex)` only to re-run `regex.exec(line)`
on the same line immediately afterwards. None of the regexes are global,
so `exec` alone is equivalent and halves the regex work per line.

Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
2026-09-14 15:11:01 +00:00
Jamie Tanna 3e099dd645 feat(manager/github-actions): support aws-actions/amazon-ecs-render-task-definition's image (#45940)
* feat(manager/github-actions): support aws-actions/amazon-ecs-render-task-definition's `image`

Per #43038, and following the existing pattern for Docker image
extraction.

Co-Authored-By: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>

* fixup! feat(manager/github-actions): support aws-actions/amazon-ecs-render-task-definition's `image`

Co-Authored-By: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>

---------

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-14 14:42:54 +00:00
renovate[bot] 69d6f9dedc fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.13 (main) (#45953)
fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.13

| datasource | package                        | from     | to       |
| ---------- | ------------------------------ | -------- | -------- |
| docker     | ghcr.io/renovatebot/base-image | 13.97.12 | 13.97.13 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 13:17:29 +00:00
ST-DDT 43bc8c807f feat(replacements): xlsx to scoped (#43461)
* replacements: xlsx to scoped

* fix: typo

* chore: fix formatting

* chore: sorting is hard

* chore: sorting is hard

* Update lib/data/replacements.json

* Update lib/data/replacements.json

Co-authored-by: Michael Kriese <michael.kriese@gmx.de>

---------

Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
2026-09-14 13:03:30 +00:00
Michael Kriese 7aedcb24d2 test(workers/lookup): cover untested branches under lookup/ (#45930)
* test(workers/lookup): cover the remaining generateUpdate branches

Adds a unit spec for `generateUpdate()` exercising the branches that the
surrounding lookup tests never reached: a release carrying `checksumUrl`,
`downloadUrl` and `newDigest`, a versioning api whose `getNewValue`
throws, and an update with no current version.

With those covered, the last istanbul ignores in the file can go, so
`generate.ts` now reports full statement and branch coverage with
nothing suppressed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(workers/lookup): cover two untested lookup branches

Adds tests for two paths flagged by the `TODO: add test #40625` markers
that no existing test reached:

- `filterInternalChecks()` with a release that has no `releaseTimestamp`
  while `minimumReleaseAgeBehaviour` is unset. The existing tests only
  cover `timestamp-required` and `timestamp-optional`, so the release is
  now checked to be accepted without being reported under either.
- `lookupUpdates()` when no current version can be resolved but a
  `lockedVersion` is set, which must return without marking the
  dependency `invalid-value`.

The ignore comments are left in place, so these branches stay excluded
from the coverage report; each test instead asserts an outcome that only
holds on the intended path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(workers/lookup): cover error paths in bucket, current and rollback

Adds unit specs for three exported helpers whose guard clauses no test
reached: `getBucket()` when the versioning api cannot determine a major
or a minor, `getCurrentVersion()` when the current value is not a string,
and `getRollbackUpdate()` when the versioning api lacks
`isLessThanRange()`, when `isLessThanRange()` throws, and when there is
nothing older to roll back to.

The ignore comments on those branches are left in place, so the coverage
report is unchanged; each test asserts the return value that is only
produced by the guard it targets.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(workers/lookup): cover filter and rollback guards

Covers three more guards that no test reached: `filterVersions()` with
no current version, and `filterByMaxMajorIncrement()` when the versioning
api cannot determine the current major or a release's major. Adds a
`lookupUpdates()` test for the case where rollbacks are enabled but
nothing older exists to roll back to, which warns instead of updating.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(workers/lookup): cover the vulnerability alert range strategy fallback

A vulnerability alert configured with `rangeStrategy=update-lockfile` but
no locked version falls back to `bump`, which no test covered. The new
test asserts the range is widened and the update is marked as a bump,
which only happens once the fallback has been applied.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(workers/lookup): explain the remaining coverage ignores

Each ignore left under `lookup/` now records why the branch it hides is
not reached, instead of pointing at a TODO with no detail. No ignore is
added or removed, and the coverage report is unchanged.

The explanation goes above the hint rather than after it: a hint only
applies to the statement on the line immediately below, so trailing
comment lines silently stop it from suppressing anything.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(workers/lookup): cover three more unreached lookup branches

Covers the guards behind three of the remaining ignore hints:

- `getRollbackUpdate()` when the release it falls back to carries an
  empty version, so there is nothing to roll back to after all
- `filterVersions()` coercing a release version that the configured
  versioning accepts but semver cannot parse, which happens once
  `allowedVersions` falls back to semver range syntax
- `lookupUpdates()` when the datasource rejects every candidate release
  during postprocessing, leaving a bucket with no release to update to

The ignore comments stay in place, so the coverage report is unchanged;
each test asserts an outcome that only holds on the intended path.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* docs(workers/lookup): correct the ignore reasons this branch disproves

Three of the reasons added alongside the previous batch of tests claimed
their branch was unreachable, which the tests in this branch disprove:
`getRollbackUpdate()` can pop a versionless release, `filterVersions()`
does coerce a version semver cannot parse, and `filterInternalChecks()`
yields no release when a datasource rejects every candidate. Each now
describes what actually reaches it.

Also sharpens two of the reasons that still stand. The `getBucket()`
else contradicts the `isVersion()` filter every release has already
passed, so it reads as unreachable rather than untested; and a lookup
whose releases are all unversioned tags never reaches the empty-version
block, because a configured digest routes it to the digest-only path
first.

No ignore is added or removed, and the coverage report is unchanged.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
2026-09-14 12:29:39 +00:00
Michael Kriese ec4ba7b381 refactor(workers/lookup): drop stale istanbul ignores in generateUpdate (#45929)
Vitest uses the v8 coverage provider, and v8-to-istanbul still honours
istanbul hints, so these comments suppress real branch coverage rather
than being inert. The `releaseTimestamp` and `registryUrl` branches are
both exercised by the existing lookup tests, so their ignores only hid
coverage that was already there.

The remaining ignores in this file stay: no datasource used in these
tests reports a checksum url, and the `getNewValue` catch block and the
missing-currentVersion guard are still unreachable.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 12:29:38 +00:00
Michael Kriese 3a723b7891 test(datasource): close branch coverage gaps (#45943)
* test(versioning/aws-machine-image): cover the empty version guard

`_parse()` returns null for a falsy version before it tries the AMI id
regex, and no test passed one. Checking that an empty string is not
valid closes the only branch the module was missing.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* test(datasource/buildpacks-registry): cover a response without a homepage

`latest.homepage` is optional in the registry response, but every test
supplied one, so the release result was never built without it. A
buildpack whose latest entry carries no homepage now checks that the
releases still come back and no source url is derived.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* test(datasource): cover optional-field branches in four datasources

Each of these datasources builds its release result by attaching fields
only when the registry supplies them, and the "not supplied" path was
never exercised:

- cdnjs: a library with neither homepage nor repository
- cpan: a search result where no release is marked latest, so no tag
- dart: a latest release carrying no pubspec
- ruby-version: a release table row whose first column is not a version

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* test(datasource): cover missing-metadata branches in hex and pypi

Two more datasources only attached fields when the registry supplied
them, and the absent case was untested: a hex package with neither an
html_url nor a github link in its meta, and a pypi response carrying no
releases at all.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* test(datasource): cover galaxy and repology fallbacks, mark unreachable guards

Adds a galaxy role with empty github fields, so no source url is
derived, and a repology lookup where the api fallback after a 403 finds
no matching package.

Marks four guards that are not worth a test: cpan and dart both check a
variable that is only null when the request threw, and
`handleGenericErrors()` always rethrows; conan's registry url is always
supplied by the datasource layer; and repology's resolver either returns
a body or throws.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* test(datasource): cover pod CDN branches, mark the sbt listing guards

Adds two pod lookups: an empty CDN body, and a CDN index that lists no
matching pod.

Marks the guards whose tests would need multi-level directory listing
fixtures: both sbt datasources walk nested index pages, and pod's github
helper checks a body that an empty json response never produces because
parsing throws first.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* test(datasource): cover maven metadata without a latest tag

Adds maven metadata carrying a release but no latest, so respectLatest
is left alone. Marks the three deb guards, which would each need a
crafted package index: a block missing a required key, a repeated
package in the final block, and two component indexes whose meta agrees.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* test(datasource): cover npmrc registry fallback, mark cache-bound guards

Adds a resolveRegistryUrl lookup for a package no npmrc rule matches.

Marks the guards whose tests would need a primed cache or a specific
blob shape: nuget's services index, deno's release cache, the docker hub
cache window, docker's manifest and config handling, go's pseudo-version
fallback, and both rubygems cache layers.

Three implicit elses are left counted: a coverage-ignore hint does not
attach to an `else if`, so the registry strategy chain, the npmrc reset
and docker's digest-header branch carry a plain note instead.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* fix(datasource/repology): pass the mock body as a string

`ResponseMock.body` is typed as a string, and every other call in the
spec passes `'[]'`. The new api fallback test passed an array literal,
which tsc rejected.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

---------

Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
2026-09-14 12:11:52 +00:00
Sebastian Poxhofer 4b4d14ec00 feat(manager): pass extracted constraints to updateArtifacts (#45826)
* feat(manager): pass extracted constraints to updateArtifacts

`extractedConstraints` were collected during extraction but only ever read
by `fetch.ts` for the lookup. At artifact time every manager had to derive
the same tool constraints a second time, and when the updated package file
no longer carried the constraint there was nothing to fall back to.

`generateBranchConfig()` now merges the `extractedConstraints` of all
upgrades of a branch onto the branch config, which reaches `updateArtifacts()`
through `patchConfigForArtifactsUpdate()`. `UpdateArtifactsConfig` declares
the field and documents what it contains.

The new `resolveToolConstraint()` helper implements the ladder once:
user `constraints` > an optional artifact-time derivation > the extracted
value. The derivation is ranked above the extracted value on purpose: it
reads the package files as the branch changed them, so poetry (python is an
updatable dependency there), composer, pipenv (`pipenv` can be a dev
package) and pep621 (`requires-python` is an updatable dependency) would
otherwise regress to a stale constraint. pipenv, pep621 uv/pdm, poetry and
composer are migrated to the helper and keep their derivation.

Behaviour change: these managers now use the extract-time constraint as a
last resort instead of running unconstrained, for example on lock file
maintenance where pipenv deletes `Pipfile.lock` before deriving.

`execute-post-upgrade-commands.ts` is unaffected: it reads
`upgrade.constraints` per upgrade, and the extracted values are kept in a
separate field rather than folded into `constraints`, so post-upgrade task
tool constraints still come from user config only.

Not migrated, because their constraints are never extracted, so the
fallback would be dead code: bundler (`ruby`/`bundler`), pixi (`pixi`),
pep621 uv (`required-version`) and npm's node ladder, whose last step
already reads `package.json` engines.

* refactor(manager): resolve tool constraints through resolveToolConstraint()

Every manager now obtains the constraint of a tool it runs through
`resolveToolConstraint()` instead of reading `config.constraints` itself, so
the precedence "user config, then a value derived from the updated files, then
the constraints collected during extraction" applies everywhere. The helper
treats an empty string as not set at every step and accepts the
`PostUpdateConfig` shape, whose `constraints` may be `null`.

Behaviour changes that go beyond the new fallback to extracted constraints:

- `mix` applies its hardcoded erlang default only after the extracted
  constraint, so an erlang version collected at extraction can win over it.
- `kustomize` decides `HELM_EXPERIMENTAL_OCI` from the fully resolved helm
  constraint; `generateHelmEnvs()` takes that value instead of the config.
- `npm` (yarn): an upgrade of yarn without a new value now consults the user
  constraint before deriving one from package.json or the lock file.
- The "Using <tool> constraint from config" debug lines in bundler, composer,
  copier and pip-compile are gone, as the helper is the only reader of the
  config now.

Helpers that read the config synchronously became async: bundler
`getBundlerConstraint()`, copier `getPythonVersionConstraint()` and
`getCopierVersionConstraint()`, pip-compile `get*VersionConstraint()` and
`getToolVersionConstraint()`, gomod `deriveGoToolchainConstraints()` and
`getUpdateImportPathCmds()`, mise `getMiseLockToolConstraints()`. composer
`getPhpConstraint()` is removed.

Each converted manager has a test showing the extracted constraint reaching
the executed tool, and, where a derive callback exists, that the derived value
still wins over it.

* refactor(linters): add prefer-resolve-tool-constraint rule

Reports member reads and destructuring of `constraints` and
`extractedConstraints` from a manager config in `lib/modules/manager/**`, so
that tool constraints are resolved through `resolveToolConstraint()` in
`lib/modules/manager/util.ts` only. Writes and the same properties on package
files, which extraction has to populate, are not reported. The helper itself
and spec files are exempt in `.oxlintrc.json`.

* refactor(manager): inline thin resolveToolConstraint wrappers

Drop copier/utils.ts and the pip-compile getPipToolsVersionConstraint /
getUvVersionConstraint helpers, which only forwarded to
resolveToolConstraint(). Callers now call it directly.

* docs(development): note lock file maintenance in tool constraints section

* refactor(manager): address review on tool constraint resolution

composer only runs extractConstraints() when a user constraint is missing,
via Lazy. UpdateArtifactsConfig no longer re-declares constraints and
extractedConstraints, which ToolConstraintsConfig already provides.
2026-09-14 11:09:07 +00:00
MFietze 96e72f6a93 fix(platform/gitlab): skip projects marked for deletion (#45928) 2026-09-14 10:40:41 +00:00
Michael Kriese 874060f7ee refactor(lookup): remove redundant currentValue check (#45933)
* refactor(lookup): remove redundant currentValue check

The inner `if (config.currentValue)` was already guaranteed by the
enclosing condition, so the `v8 ignore else` comment was hiding an
unreachable branch rather than an untested one. Drop both; the
`invalid-value` path remains fully covered by existing tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Update lib/workers/repository/process/lookup/index.ts

Co-authored-by: Jamie Tanna <jamie.tanna@mend.io>

* refactor(lookup): use safeStringify for invalid currentValue log

Template interpolation of a non-string `currentValue` yields
`[object Object]`, which hides the value that made it invalid. Use
`safeStringify` so objects and arrays are logged readably.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Jamie Tanna <jamie.tanna@mend.io>
Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
2026-09-14 09:59:37 +00:00
Sebastian Poxhofer 44160755f9 feat(platform): validate gitea responses with schemas and share the implementation with forgejo (#45825)
* refactor(platform): share one implementation between gitea and forgejo

The `forgejo` platform was copied from `gitea` in #37075 and the two have
drifted since: fixes landed on one side only (zod validation #43900, empty
email #44068, null issues #44048, team reviewers #39533, merge-style fallback
#37768 vs #38040), and lint sweeps had to be applied to both copies by hand.

Both platforms now build on `lib/modules/platform/gitea-common/`, which holds
the zod schemas, API helpers, utils, PR cache and the platform object itself.
`createPlatform()` closes over its own state, so `gitea` and `forgejo` keep
separate config, caches and host types. `gitea/index.ts` and `forgejo/index.ts`
are thin wrappers that supply the platform id, default endpoint, http client
and the version gates that genuinely differ.

Reconciliations, forgejo's behaviour adopted for gitea:

- Responses are validated with zod instead of `getJsonUnchecked` casts. Gitea
  therefore tolerates empty emails, null PRs in list responses and lenient
  repo/issue payloads the same way Forgejo already did.
- `getRepoContents` returns a discriminated union, so `getRawFile` returns null
  for dir/symlink/submodule entries instead of reading a missing field. The
  gitea preset resolver now throws PRESET_INVALID for non-file entries, like
  the forgejo one.
- An unknown `default_merge_style` (e.g. `manually-merged`) is caught by the
  schema and skipped, instead of aborting the repository with
  REPOSITORY_BLOCKED from `isAllowed()`.
- `initRepo()` resolves whether the repo owner is an org and only fetches org
  labels when it is, adding one `/orgs/{owner}` request and an `orgs` entry in
  the gitea repository cache.
- Reviewers prefixed with `team:` are sent as `team_reviewers`. Gitea keeps its
  `v1.14.0` guard for requesting reviewers at all.
- `getBranchStatusCheck()` maps unknown commit status values through the
  schema's `unknown` fallback rather than warning and returning yellow.

Gitea's behaviour is kept where it is deliberately different: the Forgejo
instance detection and its deprecation notice, the `1.24.0` (or `10.0.0` for a
detected Forgejo) native automerge gate, and the reviewer version guard are
passed in as options.

Two shared log messages became static so they can be grouped in metrics:
`{platform}-native automerge: fail` is now `Platform-native automerge: fail`
and `{Platform} getRepos() error` is now `Error auto-discovering repositories`,
both with the platform id in the metadata. The dead `defaults.hostType` field
is gone.

* refactor(platform): keep the shared gitea implementation under gitea/

Drop the `gitea-common/` folder. The zod schemas, API helpers, utils, PR
cache and `createPlatform()` live in `lib/modules/platform/gitea/` under
their original file names, and `forgejo/` imports them from there.

The preset resolvers pass `giteaHttp` and `forgejoHttp` to
`getRepoContents()` directly, which removes the two bound wrappers. The
gitea changelog source uses the shared `RepoContents` type like the
forgejo one already does.

* refactor(http): derive ForgejoHttp from GiteaHttp

The two clients were identical apart from the default `hostType`.
`ForgejoHttp` now extends `GiteaHttp` and only keeps its own base url,
so the pagination logic exists once. The platform helpers accept
`GiteaHttp` directly instead of the `HttpBase` alias.

Also covers the `updatePr()` branch where the updated pull request
cannot be converted and therefore is not cached.

* refactor(platform): create the gitea and forgejo http clients in index.ts

`forgejo-helper.ts` only held the `ForgejoHttp` instance, so it is gone
and `forgejo/index.ts` creates the client next to the platform. Gitea
does the same for symmetry, which leaves `gitea-helper.ts` with only the
shared API helpers.

* refactor(platform): fetch gitea labels and issues with await

`getLabelList()` and `getIssueList()` still memoize the in-flight
promise, but build it from small async functions instead of `.then()`
and `.catch()` chains.

* refactor(platform): keep declaration order of gitea/index.ts

Order the module the way it was before `createPlatform()` so the diff
against main aligns: platform id and http client after the repo config
interface, pure helpers before the factory, and `maxBodyLength()` after
the platform object.

* refactor(platform): move gitea label fetching to labels.ts

`fetchLabelList()` takes the http client and the repository details
instead of closing over the platform state, and gets its own spec. The
factory only keeps the memoizing `getLabelList()`.

* refactor(platform): move gitea label lookup to labels.ts

* refactor(platform): create the gitea pr cache per platform

`GiteaPrCache` is now created once per platform with its http client and
platform id, and `initRepo()` records the repository. The per-repository
state moves to a private `RepoPrCache` which is bound to the repository
cache on first use and reused until the next `initRepo()`, instead of
being rebuilt on every lookup.
2026-09-14 08:45:04 +00:00
Jamie Tanna 58cd82c060 feat(manager/github-actions): support actions/setup-java's java-version (#45878)
Where we are able to support Java distributions that follow a
straightforward release cadence, we opt these distributions in, and skip
others as `unsupported`.

As the Temurin/Adopt distributions can be reliably tracked by the
`java-version` Datasource, backed by Adoptium, we can support them.

We can also use the `java-package` key to look up whether we want a JRE
or JDK.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-14 08:07:26 +00:00
Jamie Tanna e6c6f2914a feat(manager/github-actions): support actions/setup-dotnet's dotnet-version (#45877)
In the case a multi-line `dotnet-version` is specified to install
multiple SDKs at once, we skip it as `invalid-version`, as we don't
currently have a way to update multiple values in the field.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-14 08:07:25 +00:00
Jamie Tanna 343fed8955 docs(manager/github-actions): generate one combined first-party and community table (#45875)
Similar to how we already generate a list of the community actions we
support, we should also generate which first-party Actions from GitHub
are supported, and simplify some of the wording in the docs.

Instead of duplicating this, we can instead move them into a single
section in the documentation.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-14 08:07:25 +00:00
Jamie Tanna 03906a7cbf refactor(manager/github-actions): don't duplicate parsing logic for first-party Actions (#45887)
* refactor(manager/github-actions): don't duplicate parsing logic for first-party Actions

Instead of having a separate set of Action parsing and their
configuration between first-party GitHub-owned Actions and those of
third-party Actions, we can merge them into a single collection.

This also leads to `https://<host>/` handling noted in #35777 now being
handled out-of-the-box, as it was already supported on third-party
actions.

Co-Authored-By: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>

* fixup! refactor(manager/github-actions): don't duplicate parsing logic for first-party Actions

---------

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-14 08:07:24 +00:00
RahulGautamSingh 405c32b88e docs: clarify extractVersion and add artifactory example (#45926) 2026-09-14 06:44:03 +00:00
Thomas Andersen 86890d2142 refactor(git): extract runtime config appending (#45165)
* refactor(git): centralize runtime config environment

Preserve caller-supplied and inherited GIT_CONFIG_KEY_n and GIT_CONFIG_VALUE_n entries when appending runtime Git configuration.

Co-authored-by: Jamie Tanna <jamie.tanna@mend.io>

* refactor(git): extract runtime config appending

* style(git): format runtime config tests

* test(git): remove superseded environment cases

* Apply suggestion from `@RahulGautamSingh`

Co-authored-by: RahulGautamSingh <rahultesnik@gmail.com>

* test(git): align invalid config count warning

---------

Co-authored-by: MrVampy <4302946+MrVampy@users.noreply.github.com>
Co-authored-by: Jamie Tanna <jamie.tanna@mend.io>
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
Co-authored-by: RahulGautamSingh <rahultesnik@gmail.com>
2026-09-14 06:42:38 +00:00
Jan Vollmer 26903f4324 fix(managers/pep621): use lowest locked version from uv (#40208)
* fix(managers/pep621): use lowest locked version from uv

* reduce diff

* add file extension to import

* use correct file path in import

Co-authored-by: Michael Kriese <michael.kriese@gmx.de>

---------

Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
2026-09-14 06:36:16 +00:00
renovate[bot] 9dfdac3fae fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.12 (main) (#45923)
fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.12

| datasource | package                        | from     | to       |
| ---------- | ------------------------------ | -------- | -------- |
| docker     | ghcr.io/renovatebot/base-image | 13.97.11 | 13.97.12 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 02:24:58 +00:00
renovate[bot] be7b0a69d5 fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.11 (main) (#45920)
fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.11

| datasource | package                        | from     | to       |
| ---------- | ------------------------------ | -------- | -------- |
| docker     | ghcr.io/renovatebot/base-image | 13.97.10 | 13.97.11 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 01:25:55 +00:00
renovate[bot] b6ffadc70c docs: update references to astral-sh/setup-uv to v10.1.0 (main) (#45921)
docs: update references to astral-sh/setup-uv to v10.1.0

| datasource  | package            | from    | to      |
| ----------- | ------------------ | ------- | ------- |
| github-tags | astral-sh/setup-uv | v10.0.1 | v10.1.0 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 01:25:43 +00:00
renovate[bot] fa393c49d0 docs: update references to python to e06cc11 (main) (#45918)
docs: update references to python to e06cc11

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 00:25:02 +00:00
github-actions[bot] acfaa88a50 feat(data): automatic update of static data (#45911)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-09-13 10:43:02 +00:00
renovate[bot] 28019a4db9 fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.10 (main) (#45913)
fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.10

| datasource | package                        | from    | to       |
| ---------- | ------------------------------ | ------- | -------- |
| docker     | ghcr.io/renovatebot/base-image | 13.97.9 | 13.97.10 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-13 01:24:05 +00:00
Adam Setch 65f803630e fix(dashboard): keep abandoned note outside the <details> block (#45902)
fix(dashboard): keep abandoned note outside the <details> block

GitHub only renders alert callouts at the top level of a body, not
inside collapsible <details> sections. Move the abandoned-dependencies
note above the details block so it renders as a styled note.
2026-09-12 14:51:51 +00:00
Christopher Plieger 41e2689b18 fix: exit non-zero after an unhandled rejection (#45895)
* fix: exit non-zero after an unhandled rejection

A rejection before start() runs, such as a missing production dependency at import time, was logged and then exited 0. Discussion: https://github.com/renovatebot/renovate/discussions/45894

* fix: use nullish assignment for the exit code
2026-09-12 08:07:20 +00:00
renovate[bot] 4bbe614b67 fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.9 (main) (#45899)
fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.9

| datasource | package                        | from    | to      |
| ---------- | ------------------------------ | ------- | ------- |
| docker     | ghcr.io/renovatebot/base-image | 13.97.8 | 13.97.9 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-12 07:27:19 +00:00
renovate[bot] 2352b670cf fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.8 (main) (#45898)
fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.8

| datasource | package                        | from    | to      |
| ---------- | ------------------------------ | ------- | ------- |
| docker     | ghcr.io/renovatebot/base-image | 13.97.7 | 13.97.8 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-12 01:23:37 +00:00
renovate[bot] 282a0f365b fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.7 (main) (#45882)
fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.7

| datasource | package                        | from    | to      |
| ---------- | ------------------------------ | ------- | ------- |
| docker     | ghcr.io/renovatebot/base-image | 13.97.6 | 13.97.7 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-11 11:01:28 +00:00
Jamie Tanna 6580ef4f97 feat(manager/github-actions): support renovatebot/github-action renovate-image (#45873)
While looking at [0], I noticed that we didn't have support for our own
GitHub Action's configuration.

We can make sure that we support upgrading the `renovate-image` for
folks specifying an image (with optional digest) for the Renovate CLI
version to upgrade.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-11 10:47:21 +00:00
Jamie Tanna e4307d526a feat(manager/github-actions): support renovatebot/github-action's renovate-version (#45872)
While looking at [0], I noticed that we didn't have support for our own
GitHub Action's configuration.

We can make sure that we support upgrading the `renovate-version` for
the CLI version in use, whether it's quoted or unquoted (which YAML
parses as a number).

Co-Authored-By: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>

[0]: https://github.com/renovatebot/github-action/issues/1035
2026-09-11 10:47:21 +00:00
Matthew Nitschke ac22678812 feat(datasource/npm): integrity and tarball extraction (#44315)
* added support for extracting integrity and tarball from npm datasource

* test(datasource/npm): keep integrity and tarball in packument shape assertions

The packument-trimming tests on main pinned a cached shape that dropped
`dist.tarball`, so they broke once the schema started retaining
`integrity` and `tarball`. Update both expectations to the new shape and
cover `integrity` alongside `tarball`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(workers/lookup): expect integrity and tarball on npm updates

`generateUpdate` copies `downloadUrl` and `newDigest` from the release
onto the update, so every npm lookup in these tests now carries the
tarball URL and, where the packument fixture has one, the integrity
hash. Pin and rollback updates are built without those release fields,
so their expectations are unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Michael Kriese <michael.kriese@mend.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 10:09:59 +00:00
Pieter Willekens 141e136869 feat(manager/mise): support gitlab backend (#44116)
* feat(manager/mise): support gitlab backend

Maps the mise `gitlab` backend (e.g. `gitlab:gitlab-org/cli`) to the gitlab-releases datasource, mirroring the github backend including version_prefix support.

* refactor(manager/mise): use optional instead of Nullish for tool options

TOML has no null type, so MiseToolOptions values are only ever a string or absent. .optional() models that exactly; Nullish only adds value for sources that can emit explicit null.

* fix(manager/mise): use RegExp.escape in gitlab backend

Main switched `createGithubToolConfig` from the `escapeRegExp` util to
`RegExp.escape` and dropped the import, which left the newly added
`createGitlabToolConfig` referencing an undefined symbol after the merge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Michael Kriese <michael.kriese@mend.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 10:04:37 +00:00
Michael Kriese c23e9f0fe5 test: close remaining line coverage gaps (#45870)
* test: close remaining line coverage gaps

A full coverage run reported three uncovered lines:

- `rez` versioning: `rez2pep440()` was never called with a plain version,
  because `getNewValue()` short-circuits via `matchVersionPrecision()`
  whenever the new version is valid for npm. A four-component rez version
  is not, so it reaches the pep440 path.
- `nuget` v3: only the inner nuspec 404 was covered, never a 404 escaping
  from the `.nupkg` download into the outer catch.
- `github` platform: the statement after `await` in the GitHub App branch
  is a v8/source-map false negative - it runs, but is counted zero. The
  branch used to carry the `v8 ignore` comment, which moved away with the
  `ghHostname` block in #44587.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* build: ratchet coverage thresholds

A full run now reports 100% statements (49776/49776), 100% lines
(49256/49256), 100% functions and 98.72% branches (25756/26089), so the
thresholds move up accordingly. Branches keep the same rounding-down
margin as before.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>

---------

Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
2026-09-11 10:03:46 +00:00
Sebastian Poxhofer e5ef25bbba feat(datasource/gitlab-tags): replace getJsonUnchecked with validated getJson (#44144)
* fix(datasource/gitlab-tags): replace getJsonUnchecked with validated getJson

The go datasource embeds GitlabTagsDatasource, so its test mocks are
updated to satisfy the stricter GitlabTag schema (commit.id/created_at).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test: fixup tests

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-11 08:54:01 +00:00
Sebastian Poxhofer da4cbf6d80 feat(datasource/gitlab-releases): replace getJsonUnchecked with validated getJson (#44145)
fix(datasource/gitlab-releases): replace getJsonUnchecked with validated getJson

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-11 08:53:20 +00:00
renovate[bot] 0e552f99fd fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.6 (main) (#45866)
fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.6

| datasource | package                        | from    | to      |
| ---------- | ------------------------------ | ------- | ------- |
| docker     | ghcr.io/renovatebot/base-image | 13.97.5 | 13.97.6 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-11 01:26:48 +00:00
renovate[bot] 0b88a0ead1 fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.5 (main) (#45865)
fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.5

| datasource | package                        | from    | to      |
| ---------- | ------------------------------ | ------- | ------- |
| docker     | ghcr.io/renovatebot/base-image | 13.97.4 | 13.97.5 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-10 23:25:09 +00:00
renovate[bot] cd6d5a8d3d fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.4 (main) (#45864)
fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.4

| datasource | package                        | from    | to      |
| ---------- | ------------------------------ | ------- | ------- |
| docker     | ghcr.io/renovatebot/base-image | 13.97.3 | 13.97.4 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-10 22:24:29 +00:00
renovate[bot] 7facc6e966 fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.3 (main) (#45862)
fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.3

| datasource | package                        | from    | to      |
| ---------- | ------------------------------ | ------- | ------- |
| docker     | ghcr.io/renovatebot/base-image | 13.97.1 | 13.97.3 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-10 21:27:48 +00:00
renovate[bot] f4ceee491d fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.1 (main) (#45854)
fix(deps): update ghcr.io/renovatebot/base-image docker tag to v13.97.1

| datasource | package                        | from    | to      |
| ---------- | ------------------------------ | ------- | ------- |
| docker     | ghcr.io/renovatebot/base-image | 13.97.0 | 13.97.1 |

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-10 16:32:13 +00:00
Jamie Tanna 238e15a498 feat(config): add inheritConfigTrusted to trust inherited-config hostRules
Renovate deployments that are deployed across multiple organisations may
take advantage of Inherited Config as a means to decentralise some
decisions and/or preferences that their organisations would like to use
for some self-hosted configuration.

Similarly, the decision of which hosts to allowlist may be something
that a self-hosted administrator /may/ want to allow their organisation
admins to decide.

We can make this an opt-in capability to indicate that the self-hosted
administrator trusts the Inherited Config moreso, and allows someone who
can write to it the ability to allowlist access to internal hosts that
may not be intended.

If a self-hosted administrator sets `allowInternal: false`, this takes
precedence, allowing a "veto", and a self-hosted admin's `headers` are
still preferred, too.

It's not possible for Inherited Config to set grants for `extends`, as
config resolution has already occurred, so this still needs to be
performed at the self-hosted config level.

This trust is transitive: `hostRules` defined in presets the
inherited config `extends` are registered at the same inherited
tier once resolved, so this option must only be enabled when those
preset sources are trusted too.

Co-authored-by: Claude Fable 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-10 14:52:01 +01:00
Jamie Tanna 270a3b7719 fix(workers/repository/init): surface inherited-config validation errors
Indirectly related to our changes to Host Rules, it was noticed that we
previously did not provide as helpful an error when a config validation
error occurs with Inherited Config.

Instead of throwing a `CONFIG_VALIDATION`, without a `validationSource`,
`validationError` or `validationMessage`, we can instead throw it
accordingly.

Co-authored-by: Claude Fable 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-10 14:52:01 +01:00