To prevent potential SSRF attempts, we can ignore a
misconfigured/malicious `next` link, and log a warning.
Co-authored-by: Claude Opus 4.8 <jamie.tanna+claude-code@mend.io>
To prevent potential SSRF attempts, we can ignore a
misconfigured/malicious `next` link, and log a warning.
For self-hosted users, we can provide an experimental override if they
need to opt back in.
Co-authored-by: Claude Opus 4.8 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* fix(datasource/go): resolve sourceUrl from goproxy Origin
Use the Origin field from the existing @latest proxy response so vanity
modules get a sourceUrl without a go-get request to the vanity host.
* Rework some comments
* Update lib/modules/datasource/go/releases-goproxy.spec.ts
Co-authored-by: Jamie Tanna <github@jamietanna.co.uk>
---------
Co-authored-by: Jamie Tanna <github@jamietanna.co.uk>
* feat(lint): add renovate/prefer-fs-util and renovate/prefer-luxon rules
Two shared-util substitution rules, both at warn level:
- renovate/prefer-fs-util flags value imports of fs, node:fs,
fs/promises, node:fs/promises, fs-extra and fs-extra/esm in lib/
source files outside lib/util/fs/, pointing to the scoped helpers
from lib/util/fs. Spec files and type-only imports are exempt.
A config-only change via no-restricted-imports was considered but
rejected: that rule is at error severity globally and per-path warn
severity is not expressible, so the 13 existing call sites would
break the baseline.
- renovate/prefer-luxon flags new Date(...) and Date.now() in lib/
source files, pointing to Luxon per best-practices. Date/time
utility modules (lib/util/date, lib/util/pretty-time,
lib/util/timestamp) and spec files (vi.setSystemTime etc.) are
exempt.
Baseline: 13 prefer-fs-util and 45 prefer-luxon warnings, zero errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: use Luxon instead of new Date() at remaining call sites
Fixes all renovate/prefer-luxon violations for `new Date(...)`:
- `new Date().toISOString()` -> `DateTime.utc().toISO()` (byte-identical
output) in the http cache provider, schedule logging and PR cache.
- `new Date()` -> `DateTime.now().toJSDate()` for the git commit-date
fallback and the rubygems `syncedAt` markers (same `Date` values).
- rust-release-channel now computes the Rust 1.0 release date and nightly
version dates via `DateTime.utc(...)`; previously `new Date(y, m, d)`
used the local timezone while the epoch used UTC, so the comparison was
timezone-dependent at the boundary date. Tests run with TZ=UTC, where
behavior is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: use lib/util/fs helpers in repository worker
Fixes renovate/prefer-fs-util violations outside bootstrap code:
- `fs.ensureDir()` -> `ensureDir()` from lib/util/fs (same fs-extra call
underneath; it no-ops on an empty dir name, so the repository worker
spec now simulates the init failure via a rejected `initRepo` instead
of relying on `fs.ensureDir('')` throwing).
- `fs.remove(privateCacheDir())` -> `cachePathExists()` + `rmCache()`,
keeping the remove-if-present semantics while asserting cacheDir
containment.
Two call sites keep raw imports with reasoned disable comments:
- lib/util/modules.ts synchronously enumerates Renovate's own installed
module directories at import time.
- lib/util/cache/package/impl/sqlite.ts receives cacheDir as an explicit
argument during global initialization, before GlobalConfig (which the
scoped cache helpers resolve against) contains cacheDir.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(lint): promote prefer-fs-util and prefer-luxon to error
Both rules are narrowed to what is actually accepted practice before
being promoted:
prefer-luxon no longer flags `Date.now()`: it returns UTC-based epoch
milliseconds used for elapsed-time measurement and TTL arithmetic, which
is timezone-independent by construction. The mined reviewer feedback
behind this rule ("use Luxon for date arithmetic outside util") targets
timezone-dependent date construction/formatting, which cannot occur with
a raw millis number; the rule keeps flagging `new Date(...)`.
prefer-fs-util exempts code that legitimately needs raw fs access
because the scoped lib/util/fs helpers resolve against GlobalConfig
localDir/cacheDir, which does not exist yet or does not apply there:
- lib/logger/: log-file streams at user-configured system paths during
bootstrap; lib/util/fs also depends on the logger (import cycle).
- lib/workers/global/: creates baseDir/cacheDir themselves and
reads/writes user-supplied paths before GlobalConfig is seeded.
- lib/config-validator.ts: standalone CLI without GlobalConfig.
- lib/util/git/: owns the localDir lifecycle (clone, emptyDir, symlinks)
and private-key files with sync cleanup on process exit.
Also fixes a pre-existing tsc error in prefer-fs-util.js: `importKind`
is a TypeScript-ESTree extension missing from eslint's base AST types.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(fs): make rmCache ignore missing paths
All rmCache callers use it for cleanup, where a missing path is a
no-op, so bake force: true in instead of guarding call sites with
an existence check.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(linters): exempt lib/instrumentation from prefer-fs-util
`lib/instrumentation/file-exporter.ts` landed on main while this branch
was open and imports `node:fs/promises` directly.
The exporter writes to a user-configured system path
(`RENOVATE_TRACING_FILE_EXPORTER_PATH`) outside `localDir`/`cacheDir`,
so the scoped helpers do not apply. `lib/instrumentation` is also
deliberately kept out of the module graph of instrumented libraries
(see the `⚠️` note in `lib/renovate.ts`), so it must not pull in
`lib/util/fs` and its config/logger dependencies. Exempt the directory,
as is already done for `lib/logger`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs: shorten doc
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(lint): add renovate/zod-schema-location and renovate/prefer-json-pipe rules
Backlog item #23: reviewers repeatedly ask for consistent Zod schema
structure. Two new oxlint JS-plugin rules, both at "warn":
- renovate/zod-schema-location flags `export const X = <zod schema>` at
module scope in lib/modules/**/ files that aren't schema.ts (or a
colocated schema/ directory), reusing the leftmost-identifier schema
detection from zod-schema-naming.js / prefer-nullish-util.js. Only
exported top-level schemas are flagged — non-exported ones are treated
as intentionally local/trivial (e.g. tightly coupled to file-local
helpers), which keeps the rule's signal high.
- renovate/prefer-json-pipe flags `Schema.parse(JSON.parse(x))` /
`Schema.safeParse(JSON.parse(x))` and suggests `Json.pipe(Schema)` from
lib/util/schema-utils instead.
A third mined slice (require a matching `z.infer` type export for every
exported schema) was evaluated and skipped: ~275+ exported schema-like
consts in schema.ts files vs. 231 existing z.infer exports repo-wide is
too high a mismatch to flag mechanically without heavy per-site
judgment, so it would be mostly false positives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: fix a clean subset of renovate/zod-schema-location and renovate/prefer-json-pipe violations
renovate/prefer-json-pipe: fixed all 5 safe `.parse(JSON.parse(...))`
call sites (bazel datasource, generate-mise-registry script, a hook
spec) by switching to `Json.pipe(Schema).parse(...)`. Left the 2
`.safeParse(JSON.parse(...))` sites (pretooluse-check.ts,
github-query-items.ts) unfixed: JSON.parse throwing before safeParse is
reached today crashes the script, whereas Json.pipe folds the bad-JSON
case into a graceful `{ success: false }`, which is an observable
behavior change, not just a mechanical rewrite.
renovate/zod-schema-location: fixed the one clean, self-contained
violation (platform/github's GithubIssue schema, moved into the
already-existing platform/github/schema.ts) as a representative
example. Left the other 20: they require moving exported schemas out of
files where they're built from local helper functions/config tables
(manager/github-actions/community.ts) or restructuring an entire
directory into a new schema.ts with import-graph updates across many
files (manager/bazel/rules/*.ts, manager/bazel-module/parser/*.ts) —
real refactors needing per-site judgment, not mechanical fixes.
Both rules stay at "warn": renovate/prefer-json-pipe has 2 remaining
violations that shouldn't be auto-fixed, and renovate/zod-schema-location
has 20.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: resolve remaining prefer-json-pipe and zod-schema-location findings
- github-actions: move the derived `CommunityActions` union into the
existing colocated `schema.ts`; the action config table and the
`actionSchema` builder stay in `community.ts` and are now exported.
- tools/docs: fold `JSON.parse` + `safeParse`/rethrow of the `gh` CLI
output into `Json.pipe(...)`. Invalid JSON now surfaces as a ZodError
instead of a SyntaxError; the only consumer catches generically, so
behavior is preserved.
- tools/agents/hooks: keep `JSON.parse` + `safeParse` with a reasoned
disable comment — hook scripts must stay dependency-light, and the
`Json` helper lives in lib/util/schema-utils, which drags in the full
lib import graph (logger, yaml, toml).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(lint): enforce zod-schema-location and prefer-json-pipe as errors
Narrow `renovate/zod-schema-location` to files whose directory already
contains a colocated `schema.ts`. The mined reviewer feedback ("move
this to schema.ts") presumes the module follows that convention and the
schema leaked into a logic file. Modules that deliberately export
schemas from differently-named schema-only files — bazel `rules/*.ts`
Target schemas, bazel-module `parser/fragments.ts` — are a different,
accepted layout, not "schema mixed into logic", and are no longer
flagged.
With that narrowing and the preceding migrations, both rules are clean
repo-wide, so promote them from "warn" to "error".
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: drop GithubIssue re-export from issue.ts
Consumers now import the schema directly from schema.ts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(lint): register zod-schema-location rule
The rule registration was lost while merging main, so oxlint failed to
parse .oxlintrc.json with "Rule 'zod-schema-location' not found in plugin
'renovate'". Re-add the import and rules entry, and restore alphabetical
ordering for prefer-json-pipe.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(lint): allow sync fs in zod-schema-location rule
ESLint rules execute synchronously, so the sibling `schema.ts` lookup
cannot use async fs. Silence `no-sync` with a justification.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): add renovate/no-sync-io rule
Flags calls to a fixed list of Node.js sync I/O APIs (readFileSync,
writeFileSync, mkdirSync, rmSync, readdirSync, statSync, existsSync,
copyFileSync, execSync, spawnSync, execFileSync) in tools/** and
**/*.spec.ts only; production lib code is not targeted.
Set to "warn" instead of "error": the repo has 40 pre-existing
violations, exceeding the agreed fix threshold of 30, so violations
are left in place for follow-up rather than mass-fixed here.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): enforce renovate/no-sync-io at error
Promote the rule from warn to error now that the codebase has been
migrated off synchronous I/O in tools/ and spec files.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(tools): migrate synchronous fs calls to async equivalents
Replace *Sync fs calls with their async/promise-based counterparts in
tools/ scripts (generate-imports, check runner, utils, cwdchanged hook)
now that renovate/no-sync-io is enforced at error there.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test: migrate synchronous fs calls in specs to async equivalents
Replace *Sync fs calls (readdirSync, writeFileSync, existsSync, etc.)
with their async/promise-based counterparts across affected spec
files, making the enclosing it()/module-scope initializers async as
needed, to satisfy renovate/no-sync-io now enforced at error.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): replace custom no-sync-io rule with built-in node/no-sync
The oxc built-in covers a superset of the custom fixed-name list.
Migrate the additionally flagged sites: async glob in test-shards,
async execa in prepare-deps, promisified gzip/generateKeyPair in
rpm/hex specs, and rename the misleading execSync mock alias
(it mocks the async rawExec).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): add renovate/v8-ignore-reason rule
Flag coverage-ignore comments ("v8 ignore") that carry no justification.
Accepted forms: "-- reason" / "--- reason" (recommended) and the legacy
colon form "v8 ignore <kind>[ <count>]: reason", which is already
widespread in the codebase (29 sites). Bare "v8 ignore stop" markers are
exempt because the justification lives on the paired "start" marker. The
"v8 ignore next <N>" count form remains allowed; this rule only requires
a justification.
Registered as "warn" instead of "error": the repo currently has 119
reason-less v8 ignore comments, too many to fix mechanically in one PR,
so existing sites are left untouched and can be fixed incrementally.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): promote renovate/v8-ignore-reason to error
Record the empirical verdict on the contested "v8 ignore next <N>" count
semantics in the rule doc: verified against vitest 4 with
ast-v8-to-istanbul that the count is not honored - the ignore hint always
exempts exactly the next AST node regardless of N. Counts are therefore
inert and stay allowed; the rule keeps requiring only a justification.
Promoting to error so all remaining reason-less coverage-ignore comments
must be fixed; the burndown follows in subsequent commits.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor: add justifications to coverage-ignore comments (batch 1)
Give every reason-less "v8 ignore" comment outside the large platform
index files a site-specific justification explaining why the exempted
branch is untestable or defensive, as now required by the
renovate/v8-ignore-reason rule.
Also guard against a nullish comment.loc in the rule itself; the
merged-in stricter tools typechecking flagged the unguarded access.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor: add justifications to coverage-ignore comments (batch 2)
Cover the five large platform index files (github, bitbucket,
bitbucket-server, codecommit, gitlab) with site-specific reasons on
every "v8 ignore" comment, completing the renovate/v8-ignore-reason
burndown. Two meaningless ignore hints inside commented-out CodeCommit
mergePr code are dropped instead of annotated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* Apply suggestions from code review
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
* Update lib/util/regex.ts
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
* refactor(types): document `localDir` isn't a `globalOnly` option
To make sure that it's clear when reviewing `GlobalConfig`, as well as
working with our types, we can move the `localDir` definition into a
separate type.
* fixup! refactor(types): document `localDir` isn't a `globalOnly` option
* fixup! refactor(types): document `localDir` isn't a `globalOnly` option
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* fixup! refactor(types): document `localDir` isn't a `globalOnly` option
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* fixup! refactor(types): document `localDir` isn't a `globalOnly` option
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
---------
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* 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-host-rules-mock rule
Flags vi.mock()/vi.doMock() calls whose module specifier contains
"host-rules" in spec files. Tests should configure real rules via
hostRules.add() instead of mocking the host-rules module.
Enabled at "warn" severity instead of "error": the repo currently has
35 pre-existing violations across 34 spec files, which exceeds the
agreed fix threshold of 12 files. No violation fixes are included;
migrating each spec to real hostRules.add()/clear() setup is a
semantic test rewrite that should be done incrementally, after which
the rule can be promoted to "error".
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): enforce renovate/no-host-rules-mock at error
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(datasource): use real host-rules instead of mocking
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(manager): use real host-rules instead of mocking
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(platform): use real host-rules instead of mocking
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(util,workers): use real host-rules instead of mocking
Also narrow renovate/no-host-rules-mock to the host-rules module itself so that mocking e.g. host-rules-from-env is not flagged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): mention '~test/host-rules.ts' util in no-host-rules-mock message
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
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>
* ci(linter): add renovate/codeblock-in-spec-fixtures rule
Add a custom oxlint rule that requires the codeBlock (or stripIndent)
template helper from common-tags for multi-line string fixtures in spec
files (enabled for **/*.spec.ts and test/** only).
The rule only flags shapes whose value can round-trip through the
common-tags helpers unchanged, since both codeBlock and stripIndent trim
the end result and strip the shortest line indentation:
- only literals spanning multiple source lines are flagged (escaped \n
one-liners are left alone: tagging them is not value-preserving in
general and gains nothing)
- values with leading/trailing whitespace (e.g. fixtures ending in a
newline) are not flagged
- tagged templates, describe/it titles, and inline snapshot arguments
are skipped
All 55 pre-existing violations (22 files) were fixed with a one-off
codemod that re-emits each fixture indented to the statement depth and
verifies value preservation by evaluating codeBlock on the rewritten
template (substitutions kept as opaque placeholders). One site
(pip_requirements/artifacts.spec.ts) mixes line continuations with
escaped newlines and was tagged verbatim instead of re-indented.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): address review findings
Make getSimpleRequirementsFile in pip-compile/extract.spec.ts
value-preserving again: tagging the whole template with codeBlock
trimmed the trailing blank line when deps is empty (the headerOnly.txt
case), silently changing the fixture from ending in '#\n\n' to '#'.
Tag only the static header and append the deps section via a
single-line template, which reproduces the original string exactly
for both empty and non-empty deps (verified by executing old vs new
in node).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Enable the unicorn/prefer-at rule as error in .oxlintrc.json and fix all
43 pre-existing violations (arr[arr.length - 1] -> arr.at(-1)) via oxlint
autofix. Where .at() widened the type to T | undefined, non-null
assertions were added at sites where surrounding logic guarantees the
element exists (length guards, split results), preserving the original
runtime behavior and typing.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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>
refactor(oxlint): enable vitest/consistent-test-it
Enforce `it` over `test` in spec files via
vitest/consistent-test-it (fn: "it"), matching repo convention.
Renamed all 52 pre-existing `test(`/`test.each` usages across
13 spec files to `it(`/`it.each` using oxlint --fix.
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>
* ci(linter): add renovate/prefer-zod-nullish rule
Add a custom oxlint rule that flags zod chains calling .optional() and
.nullable() adjacently (in either order) and suggests .nullish(), which
is equivalent (both accept undefined | null in zod v4).
Fix all 26 pre-existing violations across 6 schema files.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): prefer schema-utils Nullish over zod .nullish()
Rename prefer-zod-nullish to prefer-nullish-util and extend it to flag
.nullish() itself, including the standalone forms z.nullish(x) and
z.optional(z.nullable(x)). Migrate all call sites to Nullish() and
DeepNullish() from schema-utils, which normalize null to undefined in
parsed output. Schemas with more than one nullish position are wrapped
in DeepNullish(); nullish object properties with nullish members use
Nullish(DeepNullish(...)) to keep the optional property type marker.
Spec files are exempt (result.spec.ts intentionally tests
null-preserving parses). Spec assertions expecting null in parsed
output were updated to undefined. Note: docker manifests with an
explicit "mediaType": null are now accepted and treated like an absent
mediaType instead of failing the discriminated union.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(datasource/npm): require public Cache-Control to cache responses
The npm datasource opts out of the authorization-header privacy check
(checkAuthorizationHeader: false) and relies on Cache-Control alone to
classify responses. Previously, when a registry omitted Cache-Control
entirely, cacheAllowed fell through to "cache it" — so private packages
served by GitHub Packages (which sends no Cache-Control header) were
cached in the shared package cache.
Flip the semantic of checkCacheControlHeader: true to require an
affirmative Cache-Control: public signal. Missing or non-public headers
now disallow caching. registry.npmjs.org is unaffected because it
already sends Cache-Control: public, max-age=...
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(cache): avoid renewing disallowed package cache on 304
* Revert "fix(cache): avoid renewing disallowed package cache on 304"
This reverts commit 64801bb036269352465aac580b9861c5b7716cc1.
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(datasource/crate): tolerate null metadata fields
crates.io returns `null` for unset crate metadata fields. `z.string().optional()`
rejects `null`, so a single null field (e.g. `documentation` on the `sentry` crate)
failed the whole metadata parse and discarded the valid `repository`, leaving
`sourceUrl` unset and breaking monorepo grouping. Use `.nullish()` so null fields
are tolerated.
* datasource/crate: Use `Nullish()` for metadata
* datasource/crate: Use `sentry` for null metadata test
* datasource/crate: Use `DeepNullish()` for metadata
When attempting to perform dependency updates on the `tmp` package,
parsing a previous version's Zod schema results in a lookup failure, as
it had an incorrect form of `repository` as of tmp@0.0.4.
We can handle this by treating it more loosely to convert an array of
repositories into a single element, and handle this on both a
per-version and per-package lookup.
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* feat(datasource/packagist): mark abandoned packages as deprecated
Parse Packagist's `abandoned` field and surface it via `isDeprecated`
and `deprecationMessage`, matching how the npm datasource handles npm's
`deprecated` field. When `abandoned` is a replacement package name, the
message suggests it.
This is an official registry signal, so it maps to Renovate's
deprecation mechanism, not the timestamp-based abandonment heuristic.
* test(datasource/packagist): drop incorrect output-type annotation on raw input
* update tests
* Update lib/modules/datasource/packagist/schema.ts
Co-authored-by: Jamie Tanna <github@jamietanna.co.uk>
---------
Co-authored-by: Jamie Tanna <github@jamietanna.co.uk>
* fix(docker): handle 405 maxResults error on auth probe for ECR-compatible proxies
Some private Docker registries that front ECR reject `n=10000` on the tags
URL even during the auth-probe request, returning a 405 with the ECR-style
"Member must have value less than or equal to 1000" error body.
`getAuthHeaders` had no handler for this case and returned null, so the
lookup aborted before the main fetch loop's existing n=1000 retry could fire.
Fix: extract `isECRMaxResultsResponse` from `isECRMaxResultsError` in ecr.ts
and use it in `getAuthHeaders` to detect the 405 pattern. When matched, fall
back to probing the base `/v2/` endpoint for auth, then let the existing
`isECRMaxResultsError` retry in the tag-fetch loop handle the n=1000 fallback.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(docker): address PR review comments on ECR proxy auth probe fix
- Shorten test token to 'abc' to avoid CodeQL secret-detection false positive
- Replace HttpResponse<any> with HttpResponse<unknown> in common.ts and ecr.ts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(docker): replace HttpResponse<any> with HttpResponse<unknown> in isECRMaxResultsResponse
Cast body to a typed shape inline instead of widening the whole response to any.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(docker): replace toMatchInlineSnapshot with toEqual in ECR auth probe test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(docker): replace getJsonUnchecked with validated getJson
Replace all getJsonUnchecked calls in the Docker datasource with
Zod-validated getJson calls. Add RegistryAuthToken, RegistryTagsList,
and QuayTagsResponse schemas to schema.ts and add unit tests for them.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* do not use getJson if we do not look at the body
* chore: default to false for safety
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(datasource/github-runners): add macOS Intel labels
Add `macos-15-intel` and `macos-26-intel` runner labels to the datasource.
* feat(datasource/github-runners): add tests
Add test for upgrading macos-*-intel runners.
* chore(datasource/github-runners): split tests
Split-up the tests into different operating system families.
Add regression tests for the fix that allows a null or missing
home_page in PyPI JSON responses (#43814). Covers both the schema
parser and the datasource, asserting that homepage is left unset and
sourceUrl/changelogUrl fall back to project_urls when home_page is null.
* fix(datasource/pypi): allow null home_page in PyPI JSON response
PyPI returns "home_page": null for projects that declare only
project_urls. The strict z.string().optional() schema threw a ZodError
in getDependency, aborting the JSON-API lookup and resolving such
packages to no-result. Use .nullish() to accept null, matching how
requires_python already handles PyPI's nulls.
* fix(datasource/pypi): allow missing home_page in PyPI JSON response
Apply the suggestion to chain `.optional()` and `.nullish()`.
* fix(datasource/npm): tolerate non-string `time` entries in packument
JFrog Artifactory npm registries emit `"unpublished": null` under the
packument `time` field. Since the schema declared `time` values as
`z.string()`, the `null` failed validation and Zod rejected the entire
packument, so every package lookup returned no-result.
Strip non-string `time` entries via a shared `PackumentTime` transform so
a stray metadata key cannot invalidate the whole packument, while keeping
the real version->timestamp entries the datasource relies on.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(datasource/npm): use LooseRecord for packument time
Per PR review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* 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>