The `fxhash` crate has become unmaintained and was a transitive
dependency of `inquire`.
The `inquire` crate moved to use `stdlib` instead of `fxhash`[^0].
Update `inquire` to 0.9.4 to get the latest version of the crate.
`cargo deny check` output:
```
error[unmaintained]: fxhash - no longer maintained
┌─ /home/fintohaps/Developer/heartwood/Cargo.lock:111:1
│
111 │ fxhash 0.2.1 registry+https://github.com/rust-lang/crates.io-index
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unmaintained advisory detected
│
├ ID: RUSTSEC-2025-0057
├ Advisory: https://rustsec.org/advisories/RUSTSEC-2025-0057
├ The fxhash crate is no longer maintained.
The repository is stale and owner is no longer active on GitHub.
Please take a look at [rustc-hash](https://github.com/rust-lang/rustc-hash) instead.
```
├ Announcement: https://github.com/cbreeden/fxhash/issues/20
├ Solution: No safe upgrade is available!
├ fxhash v0.2.1
└── inquire v0.7.5
└── radicle-term v0.17.0
└── radicle-cli v0.19.0
└── radicle-remote-helper v0.15.0
```
[^0]: 3d5b65422a/CHANGELOG.md?plain=1#L72
This version resolves the vulnerability from the `tar-rs` transitive
dependency.
`cargo deny check` output:
```
error[vulnerability]: tar-rs incorrectly ignores PAX size headers if header size is nonzero
┌─ /home/fintohaps/Developer/heartwood/Cargo.lock:362:1
│
362 │ tar 0.4.44 registry+https://github.com/rust-lang/crates.io-index
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
│
├ ID: RUSTSEC-2026-0068
├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0068
├ Versions 0.4.44 and below of tar-rs have conditional logic that skips the PAX
size header in cases where the base header size is nonzero.
As part of [CVE-2025-62518][astral-cve], the [astral-tokio-tar]
project was changed to correctly honor PAX size headers in the case where it
was different from the base header. This is almost the inverse of the
astral-tokio-tar issue.
Any discrepancy in how tar parsers honor file size can be used to create
archives that appear differently when unpacked by different archivers. In this
case, the tar-rs (Rust tar) crate is an outlier in checking for the header size
— other tar parsers (including e.g. Go [`archive/tar`][go-tar]) unconditionally
use the PAX size override. This can affect anything that uses the tar crate to
parse archives and expects to have a consistent view with other parsers.
This issue has been fixed in version 0.4.45.
[astral-cve]: https://www.cve.org/CVERecord?id=CVE-2025-62518
[astral-tokio-tar]: https://github.com/astral-sh/tokio-tar
[go-tar]: https://pkg.go.dev/archive/tar
├ Solution: Upgrade to >=0.4.45 (try `cargo update -p tar`)
├ tar v0.4.44
└── (build) radicle-surf v0.27.0
└── radicle-cli v0.19.0
└── radicle-remote-helper v0.15.0
```
The `paste` crate is no longer maintained, and the `pastey` fork is a
drop-in replacement.
`cargo deny check` output:
```
error[unmaintained]: paste - no longer maintained
┌─ /home/fintohaps/Developer/heartwood/Cargo.lock:239:1
│
239 │ paste 1.0.15 registry+https://github.com/rust-lang/crates.io-index
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unmaintained advisory detected
│
├ ID: RUSTSEC-2024-0436
├ Advisory: https://rustsec.org/advisories/RUSTSEC-2024-0436
├ The creator of the crate `paste` has stated in the [`README.md`](https://github.com/dtolnay/paste/blob/master/README.md)
that this project is not longer maintained as well as archived the repository
## Possible Alternative(s)
- [`pastey`]: a fork of paste and is aimed to be a drop-in replacement with additional features for paste crate
- [`with_builtin_macros`]: crate providing a [superset of `paste`'s functionality including general `macro_rules!` eager expansions](https://docs.rs/with_builtin_macros/0.1.0/with_builtin_macros/macro.with_eager_expansions.html) and `concat!`/`concat_idents!` macros
[`pastey`]: https://crates.io/crates/pastey
[`with_builtin_macros`]: https://crates.io/crates/with_builtin_macros
├ Announcement: https://github.com/dtolnay/paste
├ Solution: No safe upgrade is available!
├ paste v1.0.15
└── (dev) radicle-protocol v0.6.0
└── radicle-node v0.18.0
└── (dev) radicle-cli v0.19.0
└── radicle-remote-helper v0.15.0
```
Each revision now shows a `{base}..{head}` range instead of just the
head. This is meant to clarify when a patch is rebased, and to be
helpful when one might want to observe changes using 'git range-diff'.
Fixes two earlier mistakes:
1. In `fb18083`, `fn null_to_default` was added, which is only
conditionally used if the feature "tor" is enabled, so also
only conditionally compile the function.
2. In `1e13268`, the `impl Arbitrary` for AddressType` was not
properly adjusted for the case where the newly introduced
feature "tor" is disabled.
Instead of passing the signer as an argument to many methods on `Store`,
scope the `Store` itself to a signer.
This further allows to differentiate two different access modes on the
store in `radicle::cob::store::access`: `WriteAs` (which requires signer)
and `ReadOnly` (which does not require a signer).
The caches for issues and patches in `radicle::cob::{issue,patch}::Cache`
are concretised by removing the first type parameter, since it was
specific to issues and patches anyway. This was done in this commit as
it touches very similar usage sites.
Make `Device` less prominent, and instead lean more heavily towards
traits from the `signature` crate, such as `Keypair` and `Verifier`
in addition to `Signer`. Trait bounds regarding `Signer` could be
simplified, but this is left for the future.
In `radicle-cli`, the function `term::cob::patches_mut`, which generates
errors with a hint is used instead of the lower-level `Profile::patches_mut`.
Commands `rad issue cache` and `rad patch cache` now construct a
writeable cache on top of a read-only store.
Many knock-on changes are handled as well, to arrive at a clean state.
The intent to drop outgoing connections is modeled as `Option::None`
which is brittle and easy to miss.
Extend `enum AddressConfig` with a variant that is more explicit.
A timeout of PT3S was empirically found to be too short to allow for the
verification of Signed References, given that this verification is now
potentially much more costly compared to earlier versions.
PT30S should allow fetching reasonably sized histories, even if they
are on feature level "root".
Note that this is not a timeout for the overall fetch process, but
only for inactivity on the channel during an ongoing fetch.
When upgrading Signed References via `fn upgrad_sigrefs`, the value of
`RepositoryInfo::synced_at` was not updated. Thus, the caller could not
continue with migrated repositories as usual.
Now that enough information about Signed References is propagated, such
as the head of Signed References after upgrade, is available, it is
possible to construct `SyncedAt`.
For stable commits, use the same timestamp as the CLI tests do.
This preserves that commits that are created in the Signed References
module appears as "now" in the output.
Instead of repairing downgrades, automatic migration could fail.
This occurs when attempting to load signed references, and a downgrade
is detected while coalescing `RepositoryInfo`.
Similarly to how fetch recovers, automatic migration must also recover
by detecting for the downgrade error, and allowing the migration to
happen in this case.
Teach the `rad sync` and `rad clone` commands to accept the
`--signed-refs-feature-level` option. This option configures that
fetch to use the minimum feature level provided when fetching from
other nodes. This overrides the value of
`node.fetch.signedReferences.featureLevel.minimum`, and should only be
used in scenarios where it is necessary to downgrade the security of a
fetch for backwards compatibility.
To achieve this, the `Handle::fetch` method introduces an optional
parameter for threading through the `FeatureLevel`.
The configuration of the fetch process was only achieved at the setup
of the of the node.
This limits the ability to pass configuration options to the fetch
worker while the node service is running.
This change introduces `radicle_protocol::fetcher::state::FetchConfig`
to allow configuration options to be kept track of. This includes the
previous `timeout` option, but now also includes the
`radicle_fetch::Config`.
The service now produces the `FetchConfig` and passes it through to
the fetch worker.
After feature levels are introduced to Signed References, and downgrade
attack protections are implemented, new errors are encountered when
reading Signed References that are in a downgraded state.
Such downgrade errors are recoverable by advancing history in a way that
restores the feature level that the history requires.
However, the implementation in `radicle-fetch` must be adjusted to not
abort fetching on downgraded histories, but rather inspect the error in
this case and decide whether continuing the fetching process would
actually help recover from the downgraded state.
The two cases are treated slightly differently for non-delegates and
delegates. Since delegates are crucial for evaluating repository
identity, also the fact that they cannot recover from a downgraded state
is logged at the "info" level.
Add a configuration knob `node.fetch.signedReferences.featureLevel.minimum` to
allow node operators to enforce more strict verification when fetching
Signed References.
In order to allow automatic migration to the feature level 'parent',
introduce a way to force writing signed references, even if the
user-controlled refs are unchanged.
To detect the special case of a Signed References history with a single
and root commit (which would otherwise be detected as feature level
'parent', even though the `refs/rad/sigrefs-parent` ref cannot be
written), keep information about the parent commit in `SignedRefs`.
The output of `rad inspect --sigrefs` is changed to match the more
strict interpretation of the feature level for histories with a single
and root commit.
In hopes of nudging users to upgrade, print a warning if older feature
levels are encountered. However, only do this for delegates, as these
are more critical for the repository, to not log too many warnings.
In order for users to be able to inspect the feature level of Signed
References in a repository, have `rad inspect --sigrefs` attempt to
load Signed References, and, if successful, print the feature level.
To prevent from inability to write sigrefs in case of a verification
error, swallow verification errors about the head commit, log, and
carry on writing.
In order to respond to the caller with the correct feature level in
case sigrefs are to be saved but unchanged, the write side needs to
care about feature levels. This is done by sharing more code with the
read side.
To be able to reason about backwards compatibility, downgrade attacks,
and future configurable enforcement of minimum required (security)
features, introduce the concept of a "feature level" in Signed
References.
In this implementation feature levels are assumed to be monotonic, i.e.,
that higher feature levels behave like lower ones, and only add
semantics on top.
Implementing this as an `enum` that is `Ord` flows nicely.
Treatment of the write-side is left for the next commit. Currently,
the write side "promises" `FeatureLevel::Parent`, but is not able
to "keep the promise", since it does not actually inspect the
feature level of the head in case it is unchanged.
CHANGELOG
The scenario A₁ ← B₁ ← A₂ ← B₂ would previously have resulted in A₁
being loaded. This is undesriable, since the latest non-replayed commit
is B₁.
The information regarding the order of duplicates, which is preserved by
`seen`, can be used to recover the first commit.
Due to a bug introduced in `df8e4e6c88a8bfb6c1ec6b07dcda64093b477cbe`, IPv6
addresses in the configuration file might have ended up in the database
tagged with `type = "dns"`, which is incorrect. The bug was fixed in
`a2e72b48e79d090d33f6c13c485239947de0522e`.
However, Radicle 1.7.0 was released in between those two versions, so a
this migration to repair the entries is added.
Tests are added in `test::migration_8` module. This requires some test
setup, mainly a `Database::memory_up_to_migration` constructor that is only
available to test code.
More sigrefs on the network than previously thought actually are missing
the reference `refs/rad/root`. Revert the change to make this an error,
which was part of commit `d3bc868e84c334f113806df1737f52cc57c5453d`.
IPv6 addresses are already persisted in `config.json` files.
The parsing of these old addresses, e.g. `FE80::0202:B3FF:FE1E:8329:5976` should remain valid.
Emit a warning when they are found.
The output of the address will still enclose the host in `[]`.