* 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>
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>
* 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>
* 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>
* test: validate minimumReleaseAge does not apply to security updates
* test: add end-to-end coverage for security-update minimumReleaseAge bypass
Drive the real vulnerability flow (appendVulnerabilityPackageRules) through the
real lookupUpdates, instead of only simulating the generated packageRule. Also
reword the inline comment and use luxon/asTimestamp for timestamps.
* test: fix type-check on e2e lookup config
Cast the spread config to satisfy partial() overload resolution, matching the
existing `getConfig() as never` idiom in the lookup spec.
* test: drop redundant inline lookup test in favor of end-to-end coverage
The simulated lookup test hand-built the security packageRule; the end-to-end
test plus the generated-rule assertion in vulnerabilities.spec.ts cover the same
behavior against the real flow, so the inline test added no unique coverage.
* test(vulnerability): align lookup config types
* fix: preserve current compatibility after lookup
* fix: expose current compatibility in lookup result
* test: preserve current compatibility after lookup
* test: preserve compatibility through fetch
* test: isolate current compatibility regression
* test: isolate current compatibility regression
* test: isolate current compatibility regression
* test: isolate current compatibility regression
* refactor(onboarding): return repository result from ensureOnboarding
Rename ensureOnboardingPr to ensureOnboarding and have it return a new
'onboarding' RepositoryResult. renovateRepository now branches on
repoIsOnboarded, so exactly one of ensureOnboarding/updateRepo produces
the repository result and the non-null assertion on the update result
(TODO #22198) is no longer needed. updateRepo/update no longer return
undefined for non-onboarded repositories.
* refactor(onboarding): keep ensureOnboardingPr name
* 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()`.
Adds a custom oxlint rule renovate/v8-ignore-no-count that flags the
count form '/* v8 ignore next <N> */'. The count is not honored by
vitest's ast-v8-to-istanbul hint parser, which captures only the
keyword (if/else/next/file); 'next' always exempts exactly the next
AST node. Trailing counts therefore suggest a line range that is never
applied and mislead readers.
The rule is autofixable (drops the count, preserving actual behavior)
and has been applied to all existing occurrences.
* fix(vulnerabilities): scope Go stdlib OSV remediation to the `toolchain` directive
The module `go` directive was already excluded from OSV alerts, but the toolchain
rule still matched it via shared datasource/packageName and go-mod-directive ranges.
* fix(vulnerabilities): scope OSV remediation rules to the vulnerable depType
Remediation rules are generated per dependency. When that dep has a depType,
constrain the rule so it cannot match another dep that shares datasource and
packageName.
* fix(vulnerabilities): set matchDepTypes only for Go toolchain OSV rules
A generic matchDepTypes would stop an npm `dependencies` rule from also
matching `overrides` of the same package. Only the existing toolchain path
sets depType on the generated rule.
Allow osvVulnerabilityAlerts to match OSV sub-ecosystems such as
Packagist:https://packages.drupal.org/8, based on #40004. Adds a
negative test so unrelated prefixes like PackagistSomething do not match.
Co-authored-by: Stephan Zeidler <stephan@ramsalt.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
As part of future changes in #45190, we have found that when using
GitHub Actions' dependency lockfile, the digest pinning is manged by the
lockfile, rather than being specified in the package file itself.
To avoid a "flip flop" where using the manager removes the digest from
the package file (relying on the lockfile itself) and then a `pinDigest`
update re-adds it to the package file, we can instead follow how
`digestOneAndOnly` works and add a means to note
`digestManagedExternally`.
This isn't currently used, but allows an opt out for github-actions in
the future.
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
* refactor(workers): allow extractedConstraints on PackageDependency
Mirror the existing PackageFileContent.extractedConstraints field on
PackageDependency so managers can attach per-dep constraints (e.g.
python_version markers from PEP 508 dependencies) without overloading
the user-facing constraints field. In fetch.ts these dep-level
constraints are merged on top of the file/global constraints before
lookup, so the most specific source wins while user packageRules can
still override afterwards.
Extracted from #42701 at the reviewer's request so the type-level
change can land independently of the pep621/poetry feature work that
consumes it.
* fix(workers): prefer configured constraints over extracted values
Preserve configured constraints when extraction provides values for
the same names.
User configuration must take precedence over metadata discovered during
package extraction so users retain control over dependency lookup
behavior.
---------
Co-authored-by: wwade <wwade@users.noreply.github.com>
As per #44820, `pinDigest` updates currently don't get
`minimumReleaseAge` checks applied to them.
We can extend the recent support for `digest`s being handled by also
introducing support for `pinDigest`s to receive `minimumReleaseAge`
enforcement.
This will:
- enforce `minimumReleaseAge` on all updates that `pinDigest`s has
pending
- consider the newest resolved version's timestamp, ignoring
`rangeStrategy`-related logic
- allow unversioned releases like `latest` to /not/ be bound by
`minimumReleaseAge`, as they'll potentially not have a release
timestamp and will be unpinned forever, which is less safe (and
reduces reproducibility)
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
In some cases, we hadn't correctly wired in the `minimumReleaseAge`
checks for `digest`, due to the `currentValue` not changing.
To handle this, we need to:
- use our helper methods for calculating whether the `minimumReleaseAge`
has passed
- handle a new digest's new `releaseTimestamp`
the current timestamp
- intentionally not gate `minimumConfidence`, as this is only computed
per-release, not at the digest level
- note the fixed behaviour, and clarify when it will/will not work
- add coverage for all generated updates for `digest`s, including when
remapping a Go Modules update as a `digest`
- clarify that `filterInternalChecks` and
`applyMinimumReleaseAgeToDigestUpdate` should stay in sync
Co-authored-by: Claude Fable 5 <jamie.tanna+claude-code@mend.io>
As part of follow-up changes, we'll need to call the checks in multiple
places, so should prefactor these into helper methods.
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
As part of follow-up changes, we'll use these functions to centrally
determine as to whether to execute `minimumReleaseAge` or
`minimumConfidence` checks against a given updateType.
For now, we can wire this into our documentation tests, to make sure
that this stays in sync with `isMinimumReleaseAgeApplicable`.
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* feat(platform): get all branch update dates in a more performant manner
When Renovate is working on a repository with many /potential/ branches,
as well as some actually created branches, it's possible for the
calculation for `commitHourlyLimit` to end up taking significant time.
This can lead to a less performant job generally, but can sometimes lead
to the Renovate job failing to complete, and then timing out when
executed by a job runner.
To handle this, we can instead use use `git for-each-ref` to look up
each Git ref (remotely) and request the commit date, which leads to a
much more performant lookup.
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* fixup! feat(platform): get all branch update dates in a more performant manner
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* fixup! Merge remote-tracking branch 'origin/HEAD' into wip/commit-hourly-slow
---------
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* test: add linter for `as LongCommitSha` in test files
Adds a custom oxlint rule `renovate/prefer-fake-sha-in-specs` that flags
`as LongCommitSha` casts in spec files and suggests the deterministic
`fakeSha()` helper from `test/util` instead. Enabled at error level for
`**/*.spec.ts` and `test/**`; all 131 pre-existing casts across 22 spec
files replaced.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Update lib/modules/platform/bitbucket-server/index.spec.ts
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): add renovate/logger-static-message rule
Adds a custom oxlint rule that enforces a static msg component for
logger.warn/error/fatal calls (including logger.once variants) so the
messages can be grouped in metrics and error catching services, per
docs/development/best-practices.md. It also flags metadata properties
named 'error' that hold error-ish values, because the bunyan serializer
only handles the 'err' key.
The rule is enabled as an error for lib/ production code and disabled
for spec files. All 33 pre-existing violations are fixed by moving
interpolated values into the metadata object, making messages static,
and renaming 'error' metadata keys to 'err'. Affected log-message
assertions in co-located specs are updated accordingly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci: ignore validator output
* fixup new merged in log messages
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
As part of an investigation around `commitHourlyLimit` performing slowly
on a repository with many branches, we can introduce more
instrumentation to be able to debug further.
Enable the type-aware typescript/no-unnecessary-type-arguments rule as
error and remove all 44 pre-existing redundant type arguments (type
arguments identical to the type parameter default), e.g.
HttpResponse<string>, ZodError<unknown>,
PackageDependency<Record<string, any>>.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Enable no-else-return (with allowElseIf: false) and unicorn/no-lonely-if
as errors in .oxlintrc.json and fix all 131 pre-existing violations
(91 no-else-return, 40 unicorn/no-lonely-if) across 98 files.
The no-else-return violations were fixed with the oxlint autofix
(iterated to a fixpoint, plus two else-if chains that required
--fix-dangerously) followed by Prettier formatting. One comment dropped
by the autofix in lib/modules/manager/pub/artifacts.ts was restored
manually. The unicorn/no-lonely-if violations were merged by hand,
preserving comments and coverage-ignore hints.
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>
* feat(git): validate length commit shas
* test: adapt test mocks
* chore: update import paths
* feat(git): make the validation more strict and support repositories using sha256
* test: add fakeSha function for deterministic git commit shas in tests
* chore: migrate from zod/v3 to zod/v4
This commit contains the logic changes
* chore: migrate imports from zod/v3 to zod/v4
This contains import updates and adds explicit record keys as zod/v4 requires these now
* ci: enforce usage of zod/v4
As noted in #43304, when using `osvVulnerabilityAlerts`, we can
sometimes produce an `allowedVersions` that is valid for the ecosystem,
but without setting the `versioning`, we produce an invalid rule, which
then results in a `config-validation` result, breaking any updates on
the repo.
When this happens, it's unclear which `versioning` is used to validate
this, so we should add this to the error message.
As noted in #43304, when using `osvVulnerabilityAlerts`, we can
sometimes produce an `allowedVersions` that is valid for the ecosystem,
but without setting the `versioning`, we produce an invalid rule, which
then results in a `config-validation` result, breaking any updates on
the repo.
We should therefore wire in the default `versioning` for the given
datasource.
* feat(vulnerability): Add vulnerability alerts to deps-end + lein
deps-edn and lein both essentially use maven upstream for several
packages. Some packages come from clojars directly but others are
typical java packages. If there is an OSV alert for a maven package
however, it will not propagate to the deps-edn or lein dependency update
from renovate. This tries to adjust that so that clojure can derive
dependency alerts from maven as well so that those dependencies are
treated the same way.
* chore: Code review feedback
* chore: Make ecosystem to datasource one to many
Technically datasource to ecosystem was already many to one in a way, as
maven appeared in the values twice. Once for clojure and once for maven
itself. This changes it so that the ecosystem to datasource is the same
way and looking up by ecosystem you will get multiple datasources
(should match the map above the modified code).
Then to make this work, instead of keying off of datasource for
vulnerabilities we key off of ecosystem so that all of the datasources
that are part of that ecosystem inherit the vulnerabilities for the same
dependency.
* chore: Tweaking to try to force CI/CD retry
* feat: allow separate versioning for constraints
As noted in #31831, there are times where it can be useful to override
the version that a given datasource uses, when performing
`constraintsFiltering=strict.`
This should only be applicable to the "additional" constraints, so we
make sure to validate this.
As this is new functionality, any misconfiguration should be marked as
an error.
We can make sure to provide a real-world usecase for this (taking
inspiration from `rails`' versioning of the `rubygems` constraint).
This will be used in the future by the extraction of the `go` directive,
which requires a different versioning to the default `semver`.
* fixup! feat: allow separate versioning for constraints
* fixup! feat: allow separate versioning for constraints
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* extra-log-context
---------
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* 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
* chore(workers/repository): provide more detail when rolling back
To help debug the case where rollbacks are being initiated, we can:
- add slightly more information to the `Filtered out ...` log line
- add `prBodyNotes` to the resulting PR
This requires we expose the `prBodyNotes` field to `LookupUpdate`, and
the `packageName` and `datasource` to `RollbackConfig`, so we can log
them.
* chore(modules/datasource): log `datasource` and `packageName` when filtering
For more context when reviewing the logs.
So all lookups downstream can be performed in `O(1)` time.
Suggested by Claude Sonnet.
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>