* test(manager): replace file snapshots with explicit assertions
* test(manager): replace inline snapshots with explicit assertions
* test(manager): assert on relevant sections instead of full bodies
* test(manager): drop assertions implied by full equality
* test(manager): address review feedback
* test(manager): assert depType and versioning in the regex matcher
Refs #45216
The object counterpart to `prefer-coerce-array`: `x ?? {}` becomes
`coerceObject(x)`. The rule flags a `??` whose default is a bare `{}`
literal, so a populated default or an asserted `({} as Foo)` still
passes; a `x ?? y ?? {}` chain maps onto `coerceObject(x, y)`.
Every hit across `lib/` converted cleanly, so no disable comments were
needed.
* test: replace manual process.env mutation with vi.stubEnv
Enable Vitest's `unstubEnvs` so env stubs are reverted automatically
before every test, and convert the manual `process.env.X = ...` /
`delete process.env.X` pairs in specs to `vi.stubEnv()`.
This removes the hand-written `afterEach` cleanup blocks and the
`const OLD_ENV = process.env` / `process.env = { ...OLD_ENV }`
save-restore dance, which silently leaked state between tests when a
test set a variable without a matching delete.
Left as-is (incompatible with `unstubEnvs`, which unstubs before each
test, not after):
- module top-level env writes (cocoapods, gomod, post-update, pip-compile
and bundler artifacts specs)
- `beforeAll` env writes -- the two in `util/http` moved to `beforeEach`
* test: stop asserting on ambient environment variables
Three specs asserted on values that the surrounding environment can
override, so they only passed on a machine that happened not to set them:
- `util/exec/env`: `getChildProcessEnv()` forwards every entry of
`basicEnvVars`, but the spec only seeded a subset. Any other forwarded
variable that was set ambiently (e.g. a lowercase `http_proxy`) leaked
into the `toEqual` assertion. Clear all of them first.
- `util/git/index`: `process.env.GIT_SSH_COMMAND` deliberately overrides
the default that the two env-inheritance tests assert on. Clear it.
- `logger/pretty-stdout`: the colorized level strings are built at import
time, so the `beforeEach` setting `FORCE_COLOR` could never affect them
-- it was dead code, and the test silently assumed a terminal without
colour support. Derive the expectation the same way the module does.
* test(datasource/nuget): use a throwaway cache dir for nupkg downloads
The `determine source URL from nupkg` tests do not mock the filesystem,
so they really wrote downloaded packages into a fixed `/tmp/cache` path.
That fails wherever the system tmpdir is not writable, and two checkouts
running the suite at once would share the same directory.
Use `tmp.dir({ unsafeCleanup: true })` and clean it up afterwards, which
is the pattern the other specs that touch disk already use.
* feat(lint): add renovate/prefer-stub-env rule
Enforces in specs what the migration to `vi.stubEnv` established:
- assigning to or deleting `process.env.X` inside `beforeEach`, `afterEach`,
`it` or `test` is reported, with a fixer that rewrites it to `vi.stubEnv()`
- module scope, `describe` bodies and `beforeAll` / `afterAll` are left alone:
`unstubEnvs` reverts stubs *before* each test, so a stub created there is
gone by the time the first test runs, and those must keep assigning directly
- replacing the `process.env` object is reported everywhere and never fixed.
`vi.stubEnv()` captures the original object when the worker starts, so after
a reassignment its deletes silently target the old object
The rule found 28 further violations in specs the earlier sweep missed, since
that one was anchored on `delete process.env`. Twelve were auto-fixed; the
rest replaced `process.env` wholesale and are now `clearEnv()` from test/util.
`util/exec/index.spec.ts` opts out with a comment: it asserts on the whole
child env, and `vi.stubEnv()` cannot express that because it maps `PROD`,
`DEV` and `SSR` onto '' instead of deleting them.
As noted in #43761, we had recently set `CI=true` for the Renovate and
Containerbase orgs on Mend-hosted apps due to a pnpm v11 requirement:
ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY Aborted removal of
modules directory due to no TTY
If you are running pnpm in CI, set the CI environment variable to
"true", or set "confirmModulesPurge" to "false".
Similarly in #43606, it was noted that we should do this for `mise lock`
to mark the workspace as "trusted".
Although we went with a different situation, there will be cases where
this is useful for tools being executed, for instance when we invoke `yarn`.
We also make sure to keep our documentation up-to-date as we add to the
specific overrides.
With help from Claude Sonnet and Opus to:
- perform some of the mechanical updates as part of this change
- ensure that the Docker sidecar always has `hardcodedProcessEnv` passed
into it
- catch a needed change to `exposeAllEnv` handling
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
When executing commands for `binarySource=docker`, we have two areas
that a command could have shell expansion/injection:
- on the host (when constructing the `bash -l -c`)
- in the container (when running a manager-specific command)
When constructing the host's command, we previously would escape the
`"`, which allows Bash syntax for `${VAR}` and `$(...)` syntax inside
it.
While managers use `quote()` to make the inputs safer, the use of `"`
around that would not provide any protection, and lead to cases where
the `quote()` could be expanded on the host, before `docker run`
executes.
After recent changes to each manager - and removal of `shell: true` -
this doesn't seem to be exploitable, but this hardens it further.
Additionally, we never escaped `\`, so a value containing `\"` produces
a command that `shlex.split` rejects, and the update fails rather than
running.
Instead, we can quote the whole `-c` argument with `quote()`, which
round-trips through both `shlex.split` - the default, no-shell path - and
a real shell.
This removes the `lgtm [js/incomplete-sanitization]` suppression as
we're now correctly sanitising this.
Note this doesn't remove the need for the managers to quote their own
values, as the second area above is still a real shell.
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
As found with recent changes to the Terraform manager, although we
generally have `lockFileMaintenance` being executed by an external
package manager being invoked by `exec(...)`, there are a few package
managers that do not do so.
To make it very clear how this happens, we can add a new field to the
Manager API, which will provide a means to document this.
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* 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>
* 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 prefer-partial-in-specs oxlint rule
Flags object literals cast to `any` (`{...} as any`) in spec/test files and steers toward `partial<T>()` from `test/util`. Enabled at error in the spec-files override so CI blocks new occurrences.
Closes#44646
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test: drop unnecessary object-literal `as any` casts
The casts masked values already assignable to the expected type (migration configs accepted as Record<string, unknown>, all-optional param types, etc.); removing them restores real type checking.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test: replace object-literal `as any` casts with partial<T>()
Uses partial<T>() from test/util so incomplete mock/config objects keep proper typing. Azure API mocks switch to mockResolvedValue(partial<T>()) and their inner method mocks to mockResolvedValue(), matching the sibling-file idiom.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test: suppress prefer-partial-in-specs for intentionally-invalid inputs
Some tests deliberately pass malformed or legacy data to exercise validation/error paths, where no real type fits; keep the cast with a reasoned oxlint-disable-next-line.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <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>
* 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
* test: ensure we set `binarySource=global`
As part of future changes, we'll correctly return the default value from
`GlobalConfig.get`, instead of `undefined` if no default is provided in
the `get` call.
As `binarySource=install` is the default, this then leads to these tests
failing, as they're intended to run with `binarySource=global`.
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* fixup! test: ensure we set `binarySource=global`
* fixup! fixup! test: ensure we set `binarySource=global`
---------
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
As `fileName` makes more sense (as it's not always a lock file we're
updating).
Also, if you set `fileName`, it would never actually output the
filename.
This renames the usages of `lockFile` to `fileName`.
Co-authored-by: Claude Sonnet 4.5 <jamie.tanna+github-copilot@mend.io>
* feat(nuget): add supportsLockFileMaintenance flag
The NuGet manager supports lock file maintenance via `packages.lock.json`
but was missing the `supportsLockFileMaintenance` export.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(manager): add lockFileNames metadata to all lock file managers
Add `lockFileNames` field to `ManagerApi` interface and export it from
all 24 managers that support lock file maintenance. This metadata will
be used to auto-generate the lock file support table in docs.
Also adds a validation test ensuring managers with
`supportsLockFileMaintenance` always provide `lockFileNames`.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(util/exec): migrate to `execa` for command execution
As part of a future change, we need to make sure that we have
cross-platform support for specific command executions.
By using `execa`'s functionality on top of `node:child_process`, we can
provide this functionality, as well as retain a consistent API with
internal users.
We need to make a couple of small tweaks to setting the `RawExecOptions`
as we're now bound by `readonly` properties.
As the `stdio` property's type is not exported, we can replace this with
an explicit setting of `stdin`, `stdout` and `stderr`.
This requires a number of test changes to make sure that the `stdin`,
`stdout` and `stderr` are set.
This doesn't migrate any calls under `tools`, as they can remain using
`node:child_process`.
* chore(util/exec): ignore floating promises `.on` calls
Since moving to use `execa`, we now have "floating promises" for the
`.on` method calls.
As we aren't handling them here, we can now mark them as `void` (as an
alternative to ignoring the ESLint rule).
This has been deprecated since 2022-07, and is unused as we only ever
use UTF-8.
In `tools/utils/exec.ts` we make sure to specify it explicitly, so we
don't get a Buffer returned.
* Fix Cargo with Git dependencies with a custom hostname
PR #36444 doesn't work for Git dependencies which use a custom hostname because the `registryUrl` is extracted incorrectly (e.g. `https://example.com` rather than `https://git.example.com`).
* Remove stray `console.log`
* Add test
* Apply suggestions
* Fix lint
* Update lib/modules/manager/cargo/extract.spec.ts
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
* Update lib/modules/manager/cargo/extract.spec.ts
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
---------
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>