As part of looking to allow Inherit Config to manage Host Rules' grants,
we need to perform a prefactor to create an additional trust tier
between the global self-hosted administrator's config, and presets/repo
config.
The `find()` method already resolves sensitive fields - `headers`,
`enabled`, and the computed internal-host grant - a "trust tier" at a
time, so that the outcome cannot depend on how specific a rule from a
less trusted tier makes itself. The new `inherit` tier slots in between
the two we had:
- `headers` are applied untrusted first, then inherited, then the
administrator's, so theirs still win outright
- `enabled` is taken from the administrator's rules, falling back to
inherited config's, then a repository's
- an administrator's `allowInternal: false` acts as a veto: it is
resolved before inherited config's rules, and clears the scoped
and implicit grants too, so inherited config cannot re-grant the
host in any shape by out-scoping it. Meanwhile any inherited rule
naming a host in its `matchHost` - credentialed or not - now
implicitly permits it, like the admin's own rules do
We introduce a separate field than `trusted` to avoid Inherit Config
gaining the same precedence as the admin themselves.
Co-authored-by: Claude Fable 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
As part of follow-up changes, we're looking to tighten the way that
Renovate handles outgoing HTTP traffic.
Before we do this, we can introduce a new config option,
`hostRules[].allowInternal`, that allows a self-hosted administrator to
mark an internal host as "trusted" for access.
This wires in the new global-only config option, `allowInternal`, which
implies a new internal field `internalHostGrant`.
We'll add full documentation in a future commit, when the full
enforcement is in place, as there are some wider changes to enforce it
fully.
Co-authored-by: Claude Fable 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
As part of follow-up changes, we're looking to tighten the way that
Renovate handles outgoing HTTP traffic, and a self-hosted administrator
disabling a host needs to be something a repository cannot undo.
In a similar change to
4732da7d2b, we can resolve `enabled` per
trust tier, so that a repository or preset rule can no longer re-enable
- or disable - a host the administrator's own rules set, which was
previously possible with a longer `matchHost`.
Within a tier nothing changes: the most specific rule still wins, so a
repository disabling a host of its own keeps working, as does an
administrator masking their own broad rule with a narrower one.
This is a behaviour change for repository config that previously relied
on overriding an admin rule's `enabled`.
Co-authored-by: Claude Fable 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
As part of changes we've recently made to the merging of
`hostRules[].headers`, it highlighted that a repository - or a preset
it extends - could lead to a header an admin has configured for one host
to be sent to another.
This happened due to the way we additively merged i.e.
`Object.assign({}, ...matchedHeaders)`.
This doesn't require the repository to know a credential is being
set (for a specific host), or to act maliciously - any header of their
own for that host is enough to bring the administrator's masked one
back, with nothing logged or failing to show it happened.
To fix this, we can:
- apply admin headers last, as they are "trusted"
- stop repositories from being able to unset an admin-set header
- retain the existing logic for the "most specific rule" being used
- make sure that `trusted` isn't a field that could be injected by a
repository, and make sure we explicitly only set it where we know
we're using self-hosted administrator config
- make `filterAllowedHeaders` drop `headers` if every header name was
denied, so `{}` isn't returned and used to suppress headers when
merged
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
We previously enforced `allowedHeaders` by making sure that each
`hostRules.add()` call had `filterAllowedHeaders`.
This isn't super future proofed, and although we could add a linting
rule, we should instead enforce this by making sure that
`hostRules.add()` applies the filtering.
This also catches cases like host rules from `.npmrc` which wasn't
currently being filtered - albeit there was no means to bypass
`allowedHeaders`.
Moving `filterAllowedHeaders` into `lib/util` removes a dependency from
the global bootstrap and `config-validator` importing from
`lib/workers/repository/init/`.
While doing so, we can also make sure that:
- we log only one WARN for global `hostRules` being invalid, rather than
once per `repositories[]`
- `renovate-config-validator` validates a global config file's
`hostRules` against that file's own `allowedHeaders`, like a real run
would after parsing it
Co-authored-by: Claude Fable 5 <jamie.tanna+claude-code@mend.io>
Previously, if there was a `hostRule[].headers` value for a given host
set in both global self-hosted configuration and repo config, the repo
config would overwrite /all/ headers set by the admin.
To resolve this, we can now correctly merge the keys, with the repo
config taking priority.
This still only takes into account the `allowedHeaders`, so a repository
cannot bypass admin settings.
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
As noticed while working on this branch, we currently do not merge an
admin's `hostRules` settings, if a user has (in repo or preset config)
specified `hostRules` themselves, when targeting the same `matchHost`.
To cover the existing (broken) functionality, we can document this with
a test.
Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
* chore(util): note that `httpsCertificate` and `httpsCertificateAuthority` aren't secret
Although we're currently treating them as such, they're not technically
unsafe to appear in the logs, as a Certificate (and the authority) are
public.
* fix(util/host-rules): sanitise TLS credential fields in hostRules
We previously noted that the `httpsPrivateKey`, `httpsCertificate`, and
`httpsCertificateAuthority` fields would be marked as confidential, but
we weren't correctly sanitising them.
We can make sure that these fields are correctly flagged as secret
("confidential") and that they need to be sanitised when referenced.
Although the `httpsCertificate` and `httpsCertificateAuthority` aren't
secret, we can keep them sanitised for consistency with how we've
currently documented them as being sanitised.
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
* test(util/host-rules): ensure that all secret fields are marked as secret
As a way to make sure that new fields being added `HostRule`s are
considered as to whether the field should be marked as secret
("confidential") or not, we can add a test (and a compile-time
exhaustive check) to validate that `redactedFields` and
`confidentialFields` are kept in sync.
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 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>
Moves datasource, manager, platform and versioning code from lib/ into new lib/modules/
BREAKING CHANGE: External tools must update paths to datasource, manager, platform and versioning
* refactor(datasource/nuget): Convert to class
* Fix strict nulls and obsolete URL
* Fixes
* Fix mutability
Co-authored-by: Rhys Arkins <rhys@arkins.net>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>