As part of recent changes to harden Host Rules, a test case was noticed
to be missing - we assume that a preset string doesn't include something
that looks like a host, but we didn't previously have a test to enforce
this.
This wasn't exploitable before our recent changes, but this test is here
to ensure we have a test covering this existing functionality.
Co-authored-by: Claude Fable 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
With the new hardening on blocking internal hosts with outbound HTTP
calls, we should build on top of this to ensure that the UX is better
when a preset is blocked.
We can do this by making sure that when `HOST_BLOCKED`, we report a more
targeted config validation error.
We can also make sure to pass around our `internalGrants`, similar to
how we currently allow an admin's `headers` are handled.
Co-authored-by: Claude Fable 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
To harden Renovate from being able to access internal hosts, we can add
a level of enforcement on all outgoing requests.
We can split this into two types of traffic:
- where the response becomes configuration (i.e. `extends`)
- where the response does not become configuration (i.e.
`customDatasources`)
To harden this, we enforce on every outbound HTTP request:
- check the resolved URL before anything, including cache lookups, can
proceed
- catching IP-literal hosts in every spelling the WHATWG URL parser normalizes
- blocking known Cloud metadata IPs, too
- a `dnsLookup` wrapper validates every address a hostname resolves to,
on every new connection, which also defeats DNS rebinding
- a `beforeRedirect` hook re-runs the URL check on each redirect
target, with the new host getting its own grant lookup rather than
inheriting the original host's verdict
We default this enforcement to `warn`, to not break existing deployments
and instead give them visibility into required configuration before a
future major version (major+1) enables `block` by default.
We'll also remove allow in a future major version (major+2), to give
time for admins to migrate over.
When a request is blocked, this degrades like an unreachable registry,
so a Renovate run isn't aborted by a blocked request.
As part of this, we can also provide a worked example of the different
cases that do/do not need allowing via `hostRules`.
Requests through an admin-configured proxy resolve DNS at the proxy, so
`dnsLookup` never runs for them, so we can resolve the hostname locally
and validate every address before the request instead.
This doesn't catch everything, especially as the proxy may resolve the
name to a different result, and if we can't resolve the name - possible
in locked-down corporate environments - we fail open.
Child processes aren't currently able to route traffic through
Renovate's HTTP layer, so are unrestricted.
Co-authored-by: Claude Fable 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* feat(presets): vale package versions custom manager
Co-Authored-By: Claude Code
* fix(presets): fix lint and type errors in valeVersions tests
Co-Authored-By: Claude Code
* fix(presets): fix vale.ini file pattern to use regex delimiter syntax
Co-Authored-By: Claude Code
* test(presets): update valeVersions examples and add non-pinned case
Co-Authored-By: Claude Code
The internal preset validation ran `validateConfig()` with `isPreset`,
which allows selectors such as `matchManagers` at the top level of a
preset. That is how #39738 shipped `helpers:goXPackages*` with a bare
`matchManagers` and broke `inheritConfig` users: the real resolution
paths validate the resolved config without that leniency.
Resolve each preset through `extends`, as a repository or inherited
config would, and validate the result without `isPreset`. `packages:`
and `monorepo:` presets are selector-only `packageRules` fragments, so
they are resolved from within a `packageRules` entry instead.
* test(core): replace file snapshots with explicit assertions
* test(core): replace inline snapshots with explicit assertions
* test(core): assert on relevant sections instead of full bodies
* test(core): drop assertions implied by full equality
* test(core): address review feedback
* test(core): use resolves instead of awaiting inside expect
* refactor(lint): enable oxlint prefer-named-capture-group at error
Numbered capture groups (m[1], $1) break silently when a regex is
edited and group order shifts. Named groups (?<name>...) make intent
explicit and accesses (m.groups.name) resilient to reordering.
This enables the built-in eslint rule prefer-named-capture-group,
surfacing 321 pre-existing unnamed-group violations across ~121
files to be burned down incrementally in follow-up commits.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor(versioning): name capture groups for prefer-named-capture-group
Burns down all prefer-named-capture-group violations in
lib/modules/versioning/. Unused capture groups (only reachable via
.test() or whole-match) become non-capturing (?:...); groups whose
value is read become named (?<name>...), with accesses rewritten to
match.groups!.<name> (or destructured from .groups!) instead of
positional match[n]/$n so a future edit that reorders groups cannot
silently break the reader.
Two cases needed extra care to preserve behavior:
- semver/common.ts and poetry/patterns.ts split() on a regex whose
capture group is relied upon by String.prototype.split to keep the
separator in the output array; the group is kept capturing and
named, not converted to non-capturing.
- hashicorp/convertor.ts's semverRegex is only ever embedded via
.source into a named `(?<version>...)` group elsewhere and never
matched directly, so its internal groups are safe to make
non-capturing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor(datasource): name capture groups for prefer-named-capture-group
Burns down all prefer-named-capture-group violations under
lib/modules/datasource/. Same treatment as the versioning module:
unused groups become non-capturing, used groups get names, and
positional match[n] reads move to match.groups!.<name>.
docker/ecr.ts and pypi/common.ts keep their positional destructuring
(`const [, region] = ...`, `!!m &&`) working unchanged since a named
capture group is still addressable by its numeric index in
JavaScript — only pypi/common.ts's access was rewritten to
m.groups!.owner for clarity since it read a single group directly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor(platform): name capture groups for prefer-named-capture-group
Burns down all prefer-named-capture-group violations under
lib/modules/platform/. Uses the repo's established idiom of
`match.groups?.<name>` after an optional-chained exec()/match() (see
bitbucket/index.ts hostnameWithoutApiPrefix, gerrit/utils.ts
extractSourceBranch) and `$<name>` in String.replace replacement
strings. Unused groups (markdown/HTML massaging regexes matched only
to be stripped) become non-capturing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor(manager): name capture groups in ansible-galaxy for prefer-named-capture-group
Burns down prefer-named-capture-group violations in
lib/modules/manager/ansible-galaxy/. newBlockRegEx and blockLineRegEx
dropped their unused outer wrapping group (only the inner key/value
groups were ever read) and named the key/value groups; nameMatchRegex's
remaining unused groups (protocol/user-info/port alternatives) become
non-capturing since only source/hostname/depName/version are read via
.groups. Accesses in collections.ts and roles.ts move from
lineMatch[2]/lineMatch[3] to lineMatch.groups!.key/value.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor(manager): name capture groups for prefer-named-capture-group (batch 1)
Burns down prefer-named-capture-group violations across the first
alphabetical slice of lib/modules/manager/ (ansible through mix).
Used groups get names with accesses rewritten to match.groups!.<name>
(or $<name> in replacement strings); groups whose value is never read
become non-capturing (?:...). Two String.split() call sites
(git-submodules/extract.ts, meteor/extract.ts) keep the established
"named group still readable positionally from the split() result
array" idiom instead of restructuring the destructuring.
bazel/rules/go.ts and buildpacks/extract.ts dockerRef verified
byte-for-byte equivalent before/after via a quick node script since
several nested groups collapsed to non-capturing at once.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor(manager): name capture groups for prefer-named-capture-group (batch 2)
Burns down prefer-named-capture-group violations across the remaining
alphabetical slice of lib/modules/manager/ (npm through terragrunt).
Same treatment as batch 1: used groups get names with accesses moved
to match.groups!.<name> or $<name> replacement strings; unused groups
(wrapping alternations, quantifier repetition groups only consumed via
.test(), or values never read from a match) become non-capturing.
terraform/extractors/others/modules.ts and terragrunt/modules.ts share
near-identical URL-parsing regexes (github/bitbucket/git/azure-devops
ref matchers) — the same set of always-unused `depth=`/`&depth=`
query-string groups is converted to non-capturing in both files.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor(config): name capture groups for prefer-named-capture-group
Burns down prefer-named-capture-group violations in lib/config/.
Used groups get names with replacement strings switched from $1/$2 to
$<name>; the unused separator group in schedule-migration.ts's
afterBeforeRegex becomes non-capturing. presets/parse.ts keeps
assigning through the already-declared `repo` variable rather than
array-destructuring the exec() result, matching this file's existing
style for the other named-group regexes just above it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor(util): name capture groups for prefer-named-capture-group
Burns down prefer-named-capture-group violations across lib/util/ and
lib/logger/. Same treatment as previous batches: named groups for
values that are read (via $<name> replacement strings, .groups!.<name>,
or destructured from .groups), non-capturing groups where nothing reads
the captured value (e.g. semantic.ts's angular-commit .test()-only
regex). www-authenticate.ts's tokenizer entries each get their own
named group but keep accessing the match generically via match[1],
since a positionally-indexed named group is still readable by index.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor(workers): name capture groups for prefer-named-capture-group
Burns down prefer-named-capture-group violations in lib/workers/.
Used groups get names with $<name> replacement strings; unused
wrapper/alternation groups (e.g. semantic-commit-message.ts's optional
scope/issue wrappers, release-notes.ts's date-heading and
horizontal-rule matchers that are only probed with .search()/replaced
wholesale) become non-capturing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor(test,tools): name capture groups for prefer-named-capture-group
Finishes the prefer-named-capture-group burndown: test/, tools/, and
vitest.config.mts. Groups whose value is read get names ($<name>
replacement strings or .groups.<name> access); groups only used via
.test()/.search() or that feed a .match(/…/g) call (whose return value
is the array of whole matches, not captured groups) become
non-capturing.
This is the last remaining slice of pre-existing violations, so the
rule (already enabled at error repo-wide) now passes with zero
findings across the whole codebase.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* fix prettier failure
* refactor(lint): use a named capture group in `v8-ignore-no-count`
New rule from main trips the newly enabled `prefer-named-capture-group` oxlint rule.
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* refactor(linters): add prefer-coerce-array rule
Refs #45217
`x ?? []` and `coerceArray(x)` say the same thing, but only the second
one is searchable and consistent. The rule flags a `??` whose default is
a bare `[]` literal; a non-empty default or an asserted `([] as Foo[])`
still passes.
Applying it across `lib/` surfaced three spots the helper cannot cover,
which keep `?? []` with a disable comment or a narrower fix:
- `package-files.ts` destructures a tuple, which `coerceArray()` widens
- `generate.spec.ts` defaults `matchAll()`, an iterator rather than an array
- `mise/upgradeable-tooling.ts` declares a `Record` return, so its
`?? []` fallback was wrong to begin with and becomes `coerceObject()`
* refactor(platform/github): hoist the GHE version header lookup
`Object.entries(...).find()` returns a tuple, and defaulting it with
`?? []` only to destructure the second element reads as an array
default when it is not one. Name the found entry instead, which drops
the `?? []` rather than routing a tuple through `coerceArray()`.
* feat(presets): add @oxlint/* packages to packages:linters
Groups oxlint plugin packages together with oxlint itself.
* feat(presets): add @oxlint/plugins to monorepo:oxlint
* test(presets): update linters snapshots for @oxlint/**
* feat(manager/github-actions): add `workflow` depType for reusable workflow calls
A job-level `uses:` pointing at `owner/repo/.github/workflows/<file>.yml@<ref>`
calls a reusable workflow rather than running an action, but both got the
`action` depType, so `matchDepTypes` could not tell them apart.
Give a reference whose sub-path is exactly `.github/workflows/<file>.yml|.yaml`
the new `workflow` depType. Every other sub-path, such as
`github/codeql-action/init`, stays an action.
The existing depType-keyed sites now accept both values, so nothing else
changes behaviour: the `actions.lock` file records reusable workflow calls too,
and `helpers:pinGitHubActionDigests` pinned them before this split.
* Apply suggestions from code review
Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
* feat(config): add `overrideDescription` option
Presets which extend many other presets used an `ignoreDeps: []` sentinel
to keep their own one-line summary in the onboarding PR instead of one line
per extended preset. Replace that hack with an explicit `overrideDescription`
option, which is consumed and removed while presets are resolved.
The resolved descriptions are unchanged. Repositories which set
`ignoreDeps: []` in their own config no longer lose all preset descriptions
in their onboarding PR.
* fixup! feat(config): add `overrideDescription` option
* fixup! feat(config): add `overrideDescription` option
* fixup! feat(config): add `overrideDescription` option
* feat(presets): support relative `extends` references inside presets
Presets which are fetched from a repository can now reference sibling
presets relatively, instead of repeating their own source, repository and
tag:
- `./x` resolves against the directory of the preset file with the
reference
- `../x` resolves against the parent directory of that file
- `/x` resolves against the root of the preset repository
The source, repository and tag of the preset which holds the reference are
inherited, so `./system/registries` inside `github>org/repo#v2.0.0`
resolves to `github>org/repo//system/registries#v2.0.0`. A reference which
resolves to the `default` preset at the repository root is emitted in the
plain repository form, so `github>org/repo#v2.0.0`, which keeps it
deduplicated against the way consumers spell the very same preset.
A reference must stay inside its repository, its final path segment must
name a preset file rather than a directory, and it can carry parameters
but neither its own `#tag` nor a `:subPreset`. Parameters may contain a
Handlebars template, including a sub-expression such as
`./group({{ lower (env.TEAM) }})`, while a templated path cannot be
resolved and is left alone. A reference must also not carry a source
prefix, so strings such as `local>./x` or `github>../x` are rejected as
invalid.
References are canonicalized lazily, while the preset which holds them is
fetched in `getPreset()`, after migration and massaging. Only presets from
a repository hosted source, so `github`, `gitlab`, `gitea`, `forgejo` and
`local`, are walked. A relative reference which has no parent preset, for
example in a repository config, an inherited config or in `globalExtends`,
is reported as a validation error for that entry.
Relative entries of a preset's `ignorePresets` are resolved in the same
way, so a preset can neutralize a preset which it references relatively,
as long as the consuming repository does not set `ignorePresets` itself.
A reference which cannot be resolved is kept raw and logged, which lets
consumers neutralize it with `ignorePresets`, and it only fails per entry.
Because relative references cannot be resolved while a config is
validated, they are stripped from a `packageRules` entry before its
presets are resolved. A rule which is then left without any selector is
reported as a warning rather than as an error, since the stripped preset
may still provide the missing selectors. Rules without relative references
keep failing hard as before.
The `renovate-config` manager reports relative and unparsable `extends`
entries with a skipReason, instead of dropping them, and ignores templated
entries which can only be resolved at runtime.
Behavior change: an `extends` string which starts with `./`, `../` or `/`,
such as `./x`, `../x` or `/x`, is now read as a relative reference. Before
it was parsed as a local repository name, which in rare cases could
accidentally resolve through the dot segment normalization of the request
URL. For the same reason a source prefixed relative looking string, such
as `local>/org/repo`, `github>./x` or `npm>./x`, is now rejected as an
invalid preset.
* fix(presets): parse scoped npm presets with explicit `npm>` prefix
`npm>@scope/name` was parsed as a local preset, because the heuristic for
local presets matched before the `npm>` prefix was stripped.
Every other use of `npm>` keeps its current behavior, so `npm>foo` still
falls back to the npm package `renovate-config-foo`, `npm>owner/repo` is
still resolved as a local preset and nested prefixes such as
`local>npm>foo` keep working.
* refactor: remove duplicated preset source
* docs: streamline new docs
* add more docs for skipReason and add requested changes
* Apply suggestions from code review
Co-authored-by: Jamie Tanna <github@jamietanna.co.uk>
* test(presets): drop object literal type casts in relative preset spec
---------
Co-authored-by: Jamie Tanna <github@jamietanna.co.uk>
* test(config): ensure that `errors` and `warnings` are always checked
As a follow-up to 6e411730a0, we can make
sure that we have a linter rule to make sure that this is consistently
checked.
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* test(config/validation): ensure we don't use length checks
As it hides the actual messages, and makes it harder to know what is
being checked.
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
---------
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
As these have been out-of-sync with what is and is not currently
supported per our documentation.
Co-authored-by: Claude Opus 4.8 <jamie.tanna+claude-code@mend.io>
As a means to make it easier - in the future - to add new
`security:minimumReleaseAge*` presets, we can refactor the 2 mostly
duplicated presets into dynamically generated presets.
Although this is not quite a "rule of 3" scenario, this shape does look
consistent, and so we can perform an early refactor.
Although this should be like-for-like, we can release this as a `fix` to
get early feedback on whether it changes anything.
Co-authored-by: Claude Opus 4.8 <jamie.tanna+claude-code@mend.io>
* feat(presets): add `security:minimumReleaseAgeCrates` preset
This adds a three-day minimum release age for the `crate` datasource and preserves the existing exception for pin updates.
The preset is based on the existing `security:minimumReleaseAgeNpm` preset, with its exceptions limited to update types relevant to crates.io.
It accounts for the initial 72-hour crates.io deletion window and gives scanners time to identify malicious releases.
* fix(presets): scope crate release age by update type
This replaces the pin-specific override with one package rule for `major`, `minor`, and `patch` crate updates. It keeps updates without release timestamps out of the cooldown.
The focused tests cover included and excluded update types.
* fix(presets): warn about unsupported crate update types
This exempts lock file maintenance, replacement, and pin updates from the crate minimum release age policy. It adds PR body notes that explain why each update requires manual age validation.
* fix(presets): use singular crate release age name
This renames `security:minimumReleaseAgeCrates` to `security:minimumReleaseAgeCrate`. It aligns the preset with the `crate` datasource name before release.
* Update lib/config/presets/internal/security.preset.ts
Co-authored-by: Jamie Tanna <github@jamietanna.co.uk>
---------
Co-authored-by: Jamie Tanna <jamie.tanna@mend.io>
Co-authored-by: Jamie Tanna <github@jamietanna.co.uk>
* feat(config): add commitTrailers option
Renovate's only way to add git trailers today is `commitBody`, but it's
broken on Gerrit: Renovate appends its own `Renovate-Branch`/`Change-Id`
block after the body, so user trailers end up in a non-final message
block and are not real trailers per git-interpret-trailers rules.
This adds a `commitTrailers: string[]` option (each entry a full
`Key: value` line), standardizes Gerrit's own trailers through the same
mechanism so user trailers and platform trailers merge into one final
block, and verifies the result at runtime with `git interpret-trailers`
(commitlint's trailer-exists rule uses the same approach). The
`:gitSignOff` preset is migrated from `commitBody` to `commitTrailers`
so sign-off works correctly on Gerrit too.
* Simplify a bit
* Simplify docs even more
* Simplify another bit
* Add comment about rawExec
* Drop runtime commit trailer verification
Bypass simple-git only to emit a proactive warn log is not worth the
extra surface area. Config validation already enforces Key: value form.
* test(git): cover string commit message with trailers
Codecov patch failed on the partial ternary branch that normalizes a
string message before appending trailers.
* test(gerrit): fix trailers test after scm rework
Align the commitTrailers merge test with the post-rework Gerrit SCM:
use fakeSha helpers and drop the removed force flag.
* Improve wording on gitSignOff docs
* Validate compiled commitTrailers as well
* Improve trailers example
* Use isString instead
* Update lib/util/git/index.ts
Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
* Update lib/workers/repository/onboarding/branch/create.ts
Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
* Format code
* Fix type-check
* Fix tests
---------
Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
* refactor(oxlint): enable func-style
Enable the built-in func-style rule as ["warn", "declaration"] so that
named functions are written as function declarations instead of arrow or
function expressions assigned to variables, matching the convention in
docs/development/best-practices.md (Functions section). Inline arrow
callbacks are unaffected; prefer-arrow-callback continues to cover the
callback direction.
Severity is "warn" instead of "error" as a fallback: a repo-wide run
found 196 pre-existing violations (70 in spec files, 126 in production
code), exceeding the 80-violation fix threshold for this change, so no
violations were fixed here. Follow-up work can convert the offenders
(largest clusters: lib/modules/versioning/ruby, lib/util/cache/package,
lib/modules/versioning/maven, lib/modules/versioning/gradle) and then
raise the rule to "error". Note oxlint 1.72 also supports an
allowTypeAnnotation option if typed consts should remain arrows.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): enforce func-style at error
* refactor(func-style): convert const-arrow functions to declarations in with-cache spec and ruby versioning
* refactor(func-style): convert const-arrow functions to declarations in maven/gradle modules
* refactor(func-style): convert const-arrow functions to declarations in remaining versioning modules
* refactor(func-style): convert const-arrow functions to declarations in platform modules
Discriminated-union closures (ensureCommentRemoval byTopic/byContent
helpers in github, gitlab, bitbucket, bitbucket-server) needed the
narrowed field passed explicitly as a parameter, since function
declarations are hoisted and lose the outer if-narrowing that inline
arrow-function closures previously relied on.
* refactor(func-style): convert const-arrow functions to declarations across util/manager/datasource modules
One case (logger/renovate-logger.ts logOnceFn) is kept as an arrow
function with a documented oxlint-disable: it is stored on
this.logger.once[level] and relies on lexically-bound this, which a
hoisted function declaration would not preserve.
* refactor(func-style): convert remaining const-arrow test helpers to declarations
get-updated.spec.ts: hoisted expectPipCompilePackageAndLockFile to
module scope (it only closes over the module-level pipCompile mock)
and added a documented oxlint-disable for vitest/expect-expect on its
caller test, since oxlint's expect-expect check does not trace
assertions through an externally-defined helper function.
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
ci(linter): add renovate/no-redundant-mock-reset rule
Vitest sets mockReset: true globally in vitest.config.mts, which resets
all mocks before each test. This makes vi.resetAllMocks() /
vi.clearAllMocks() and per-mock .mockReset() / .mockClear() calls inside
beforeEach/afterEach hooks redundant. Add a custom oxlint rule (enabled
for **/*.spec.ts and test/**) flagging such calls, and remove the 40
redundant calls it found. restoreAllMocks/mockRestore are not flagged
because restoreMocks is not enabled globally.
Two sites keep an inline disable with a reason: nested beforeEach hooks
in filter-checks.spec.ts and onboarding/pr/index.spec.ts intentionally
call mockReset() to discard once-values queued by an outer beforeEach.
Requested by maintainer review feedback (review comment 3052324877).
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- Convert `param: T | undefined = undefined` to optional `param?: T`.
- Drop dead `= false` defaults on the required cache-provider options.
- Make `GraphqlPaginatedContent.nodes/edges` optional so the `= []`
fallbacks (load-bearing for partial GraphQL connections) are valid.
- Type the unchecked `default_branch` response field as optional so
the `'HEAD'` fallback is retained.
- Drop `tag = undefined` from the Forgejo/Gitea/GitLab preset configs.
Part of #43845
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Add distinct hints to the multi-snapshot tests flagged by the rule
and regenerate the affected snapshot files, then re-enable the rule.
Part of #43845
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(platform/forgejo): replace getJsonUnchecked with validated getJson
Migrate all getJsonUnchecked calls in the Forgejo platform module to use
getJson with Zod schemas for response validation. Add comprehensive Zod
schemas to schema.ts and update test mocks to use proper data formats.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* simplify by using infered types
* first pass on reducing duplications
* move PrStatus and CommitStatus to schema
* remove code handling BranchStatus values now ensured by schema
* remove now unreachable code
* fix coverage
* use forgejo schemas instead gitea for changelog fetching
* feat: do not abort repo on unrecognized default merge style
* refactor: instead of usages of `?? {}` with a default parameter
* tighten required parameters and move contentString generation to schema
* refactor: merge both content schemas and use a discriminated union
* refactor: move patchJson and postJson to schema validation
* Make body field required
* make schema more strict
* use DeepNullish
* simplify catch
* revert the gitea Content type change
* unify User
* log more nicely if accidentally not a file has been referenced
* Use fakeSha and LongCommitSha schema
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Stylelint come with two official config packages maintained separately.
However, some major release of one of the config packages require the
latest major release of the stylelint tool and vice versa.
On that case, Renovate will propose separated update merge requests that
will never be solvable because of dependencies conflict during npm
install.
Also, as stylelint is not a mono-repo and use a completly different
releases history from its related config package, we MUST ensure
major/minor separation is deactivated to get the group process working
correctly.
* fix(datasource): replace getJsonUnchecked with validated getJson in npm/Node/PyPI/Go
Replace all getJsonUnchecked calls in npm, Node.js, PyPI, and Go datasources
with Zod-validated getJson calls:
- datasource/npm: add NpmResponseSchema to schema.ts (shared with presets)
- config/presets/npm: migrate to NpmResponseSchema with passthrough version fields
- datasource/node-version: add NodeReleasesSchema using LooseArray
- datasource/pypi: add PypiJSONSchema (nullable+catch for lenient empty-body handling)
- datasource/go: add VersionInfoSchema for both versionInfo and getLatestVersion calls
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* some manual cleaning up
* removing schema level catch
* removing some more types
* refactor: rename schema
* fix linter errors
* remove schema suffix which hasn't been catched by linter
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(presets): link to Octochangelog for updates to Renovate itself
Related to #41809, and a recommendation I personally have for folks
updating their version of Renovate via Renovate, we can use
Octochangelog to provide a nicer breakdown of Renovate CLI release
notes, grouping them by headers i.e. "Features" and "Bug Fixes" across
all version(s) being updated.
This overrides the default link i.e.
```
https://app.renovatebot.com/package-diff?name=renovate&from=43.198.0&to=43.206.1
```
to:
```
https://octochangelog.com/compare?repo=renovatebot%2Frenovate&from=43.198.0&to=43.206.1
```
As this is a strong recommendation, we add it into `config:recommended`.
* fixup! feat(presets): link to Octochangelog for updates to Renovate itself
* test(presets): validate filename construction
Ahead of future changes to add JSONC support, we should cover explicitly
how the filename is constructed.
* feat(presets): support fetching `.jsonc` files
Similar to 6fb540d494, as we now support a
`.jsonc` file for configuration, we should make sure that we can also
use it for a preset.
We can also add additional tests across a few presets to make sure that
we have sufficient coverage.
* fix(config/global): return default values for `GlobalConfig.get`
As noted in #39949, it can be awkward working with in `GlobalConfig.get`, where
we would previously need to specify the default value when calling `.get`,
which could lead to drift with the defaults for a given config option.
To reduce this risk, we can rely on a given `default` for a configuration
option, providing that as a default.
Because this now definitely returns a value that matches the config option, it
now allows us to remove `!` assertions.
* fixup! fix(config/global): return default values for `GlobalConfig.get`
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* fixup! fix(config/global): return default values for `GlobalConfig.get`
* test(presets): remove impossible test
As it's now not possible to set a value as `undefined` (as
`GlobalConfig` will then use the default), this test no longer validates
anything.
* test(workers/repository): add mock
Now `platform` defaults to `github`, we need to mock out the call to
fetch config.
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* test: coverage
* test: coverage
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
As noted in #15827, it would be useful to log the "shallow"
configuration for a given repository - that is, the resolved
configuration, but without any Renovate internal presets being included.
This will be very useful for debugging, as it shows the final resulting
configuration, but without the - often very - verbose internal presets.
In the case that only this log line is shared, we can make sure to
reference the version of the Renovate CLI in the log line.
This requires building on top of changes in
6a4fa3f245 to be able to return a `merged`
and `unmerged` list of presets, and uses helpers from
c8f42e86b4, and
66b84dd12b to process the internal presets
accordingly.
Since we first worked on this, we've worked on improvements to caching
which should provide a require no additional performance overhead
performing this resolution twice.
This can also lead to being able to understand more clearly how Renovate
configuration is being used[0], as we have the final resolved configuration.
We want to make sure we don't try and merge or visit any internal
presets if we're not going to merge them, so we can avoid verbose
`config` or `visitedPresets` results.
[0]: https://www.jvt.me/posts/2024/04/14/renovate-config-sql/
As found in #40942, we've been seeing increased memory usage by pnpm and
Yarn in recent months on Mend-hosted apps.
As a way to provide more control to test + validate fixes, as well as
provide self-serve for other environments, we can allowlist
`PNPM_WORKERS`/`PNPM_MAX_WORKERS` in both the "basic env vars" and the
allowed `global:safeEnv`.
* feat(datasource/npm): extract defaultRegistryUrl constant
* Fix some other places
* Remove useless defaultRegistryUrls export
* Fix another place
* Undo rules.spec.ts changes, which are not related
* Fix npm presets
* Restore line removed by mistake
* Fix another test file
* Restore changes to a file which is not relevant
* Fix another small place