Commit Graph

2959 Commits

Author SHA1 Message Date
Lorenz Leutgeb ffc81154e4
clippy: Disallow lint `enum_variant_names`
We just need one exception.
2026-04-15 10:06:05 +02:00
Lorenz Leutgeb ae55d935bc
cargo/workspace/lints: Shorten notation
Also sort lints by name.
2026-04-15 10:05:56 +02:00
Adrian Duke 547a753768 simulation: Add README with overview and plan
Introduce the `simulation` directory in anticipation of migrating the
`radicle simulation network` repository. Introduce a loose plan and
explainer of how it will work.
2026-04-15 08:51:03 +01:00
Lorenz Leutgeb 94f65a71db
cargo: Remove unused dependencies
A number of dependencies were unused, causing confusion. Remove them.
2026-04-15 01:50:14 +02:00
Richard Levitte adfd89f609 cli-test: Respect `CARGO_TARGET_DIR`
`radicle-cli-test` initiates `cargo` builds under the assumption
that the target directory is always within the source directory.
However, the user may have a different idea, specified with the
environment variable `CARGO_TARGET_DIR` (supported by `cargo`, see
https://doc.rust-lang.org/cargo/reference/environment-variables.html).

Add support for `CARGO_TARGET_DIR`, with a fallback to 'target'
at the top of the source tree if `CARGO_TARGET_DIR` is undefined.
2026-04-15 00:18:39 +02:00
Lorenz Leutgeb 80c1bba76f
radicle: Prevent `RAD_SOCKET` from polluting tests
The value of `RAD_SOCKET` influences the outcome of `cargo test`.

Users that set this environment variable to, e.g. point `rad` at
a socket at a custom location, were surprised that execution of
tests would interact with their node.

Split `Home::socket` into two functions. `Home::socket_default` is
"pure" and only dependent on the path represented by `Home`. On the
other hand, `Home::socket_from_env` interprets the environment.

Most users will want to use `Home::socket_from_env`.
2026-04-09 17:53:49 +02:00
Lorenz Leutgeb a2de55cbb9 radicle/crefs: Use `GetPayload` to load
Using `GetPayload`, `GetRawCanonicalRefs` can be implemented
generically.
2026-04-08 11:17:46 +01:00
Lorenz Leutgeb 5167367918 radicle: Introduce `trait GetPayload`
This new trait can be implemented by any struct that allows loading of
payloads. Currently, this only applies to the identity document.
2026-04-08 11:13:28 +01:00
Lorenz Leutgeb aa28567035 radicle/crefs: Refactor `GetCanonicalRefs`
There is only one type that can really construct canonical references,
which is the the identity document. Remove the corresponding method
from the trait and rename it to `GetRawCanonicalRefs` accordingly.
2026-04-08 11:13:28 +01:00
Lorenz Leutgeb ef101d9ab9 radicle/crefs/protect: Module for protected refs
Separate module for the concern of protecting `refs/rad`.

Note that this also fixes a bug, as previously all refs
*starting with* `refs/rad`, such as `refs/radieschen` were protected.
2026-04-08 11:02:25 +01:00
Lorenz Leutgeb e822623dc1 radicle/crefs/rules: Exact patterns for branches
Allows avoiding `try_from`, thus also get rid of one error variant.
2026-04-08 11:02:07 +01:00
Lorenz Leutgeb bfb2858054 radicle/storage: Split `WriteRepository::set_head`
The method `set_head` does two things:
 1. Compute the canonical head and set the default branch to target.
 2. Set the symbolic reference `HEAD` to target the default branch.

Split these two concerns into:
 1. `set_default_branch_to_canonical_head`
 2. `set_head_to_default_branch`
2026-04-08 11:02:07 +01:00
Lorenz Leutgeb 0eba6caf9f radicle: More convenience methods to get default branch 2026-04-08 11:02:07 +01:00
Lorenz Leutgeb 22b2871f64 radicle: Add Version to User Agent
The main motivation behind this change is to get just a little
telemetry information from nodes on the network, namely the version
of Radicle they are running.

This is achieved by rewriting `impl Default for UserAgent` which now
uses the version information provided by the build script also used
in other crates.

Also, a new configuration option `node.userAgent` is added, which
allows users to override the user agent if they so please, or set
the value `null`, which will in turn send the user agent
`/radicle/`, which is not really helpful, and the default prior to
this commit.

Creations of `UserAgent` in the whole workspace is cleaned up. In
order to do that `UserAgent::test` is introduced.
2026-04-02 16:26:46 +01:00
Wiktor Kwapisiewicz 48551cde93 crypto: Use `ssh-agent-lib` for SSH Agent
This makes the `radicle-ssh` crate obsolete.

Signed-off-by: Wiktor Kwapisiewicz <wiktor@metacode.biz>
Co-authored-by: Lorenz Leutgeb <lorenz.leutgeb@radicle.xyz>
2026-04-02 16:03:23 +01:00
Fintan Halpenny 0080813c91 term: Update inquire to 0.9.4
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
2026-04-02 14:46:41 +01:00
Fintan Halpenny 5b6ae0ac4a Update radicle-surf to 0.27.1
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
```
2026-04-02 14:46:41 +01:00
Fintan Halpenny 546001253a protocol: Use pastey fork
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
```
2026-04-02 14:46:41 +01:00
Lorenz Leutgeb 96f573b767 cargo: Update dependencies with `cargo update` 2026-04-02 14:46:41 +01:00
Richard Levitte 91590a3287 cli/patch: Show Commit Ranges of Revisions
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'.
2026-04-02 14:08:44 +01:00
Richard Levitte b8f8cfb319 cli/terminal: Formatting Functions for Ranges
These allow convenient formatting of long/full object identifiers,
as well as formatting ranges.
2026-04-02 14:08:44 +01:00
Lorenz Leutgeb b54fc820e9
radicle/tor: Fixes
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.
2026-03-31 23:58:03 +02:00
Lorenz Leutgeb f223afd9d7 radicle: Refactor COB Storage Access
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.
2026-03-31 17:57:14 +01:00
Lorenz Leutgeb 10a82958ca
node: Explicit default for `AddressConfig`
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.
2026-03-31 16:24:22 +02:00
Lorenz Leutgeb fb1808395e
radicle/serde_ext: `fn null_to_default`
This function, taken from
<https://github.com/serde-rs/serde/issues/1098#issuecomment-760711617>,
allows to serialize `null` as the value provided by `Default::default`
for any type that also implements `serde::Deserialize`.
2026-03-31 16:24:22 +02:00
Lorenz Leutgeb 1e132685bc
cargo: Add feature for Tor support 2026-03-31 16:24:22 +02:00
Lorenz Leutgeb 8bac24d6ab
rust/edition/fmt: 2021 → 2024
Reformat code with `rustfmt`, now that the edition changed from
Rust 2021 to Rust 2024.
2026-03-30 16:57:51 +02:00
Lorenz Leutgeb 0494227e75
rust/edition: 2021 → 2024
Switch from Rust 2021 to Rust 2024.

See <https://doc.rust-lang.org/edition-guide/rust-2024/>.

Regarding the added bound `use<>`, see
<https://blog.rust-lang.org/2024/09/05/impl-trait-capture-rules/>.
2026-03-30 16:56:58 +02:00
Fintan Halpenny edde15d9ea Release 1.8.0 2026-03-26 15:39:22 +00:00
Fintan Halpenny 263d04b5ea schemars: Update to 0.7.0 2026-03-26 15:32:50 +00:00
Fintan Halpenny 597b514d6c remote-helper: Update to 0.16.0 2026-03-26 15:32:43 +00:00
Fintan Halpenny d685d6f91d cli: Update to 0.20.0 2026-03-26 15:32:43 +00:00
Fintan Halpenny 78908682df node: Update to 0.19.0 2026-03-26 15:32:43 +00:00
Fintan Halpenny 6e40a617de protocol: Update to 0.7.0 2026-03-26 15:28:39 +00:00
Fintan Halpenny 5a2e7841c7 fetch: Update to 0.19.0 2026-03-26 15:28:39 +00:00
Fintan Halpenny 9f91817d25 radicle: Update to 0.23.0 2026-03-26 15:25:11 +00:00
Lorenz Leutgeb 46f4c0f38f
protocol/service: Increase timeout for fetches
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.
2026-03-25 19:50:27 +01:00
Lorenz Leutgeb e7467fb15f protocol: SignedRefs upgrades provide `SyncedAt`
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`.
2026-03-25 08:19:36 +00:00
Lorenz Leutgeb 6d771abfcc radicle/storage/refs: Remove `RefAt::load`
This is a very thin wrapper around `SignedRefs::load_at` which only
has a single usage in all of the workspace. Remove it.
2026-03-25 08:19:36 +00:00
Lorenz Leutgeb ec36d1c3ae radicle/sigrefs: Merge `SignedRefs{,At}`
Since now all callers expect `SignedRefsAt`, merge the two structs
and name the result just `SignedRefs`.
2026-03-25 08:07:49 +00:00
Lorenz Leutgeb 07011233eb radicle/sigrefs: Use `SignedRefsAt` everywhere
To make more information available to callers, prefer returning
`SignedRefsAt` everywhere.
2026-03-25 08:07:49 +00:00
Lorenz Leutgeb d25fb7f672 radicle/sigrefs/git: Refactor `Committer`
Just slightly more code reuse and a constant.
2026-03-25 08:07:49 +00:00
Lorenz Leutgeb 5d583338c8 radicle/sigrefs/git: Use stable `RAD_LOCAL_TIME`
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.
2026-03-25 08:07:49 +00:00
Lorenz Leutgeb 86cacfb846 radicle: Have migration repair downgrades
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.
2026-03-25 08:01:29 +00:00
Fintan Halpenny 33db6637b4 radicle: Teach `rad sync` and `rad clone` to accept feature levels
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`.
2026-03-24 15:07:18 +00:00
Fintan Halpenny ef4ddf06c3 node: Remove `radicle_fetch::Config` from `worker::Config`
The configuration options are now passed through to the worker, and
are no longer needed to initialise.
2026-03-24 14:40:42 +00:00
Fintan Halpenny 07f3d56559 protocol: Allow configuration of `radicle_fetch::Config`
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.
2026-03-24 14:40:42 +00:00
Lorenz Leutgeb 81ca4b9eda fetch: Allow upgrading Signed References
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.
2026-03-24 14:40:42 +00:00
Lorenz Leutgeb e245e3115b fetch: Configure Minimum Feature Level
Add a configuration knob `node.fetch.signedReferences.featureLevel.minimum` to
allow node operators to enforce more strict verification when fetching
Signed References.
2026-03-24 14:40:42 +00:00
Lorenz Leutgeb 47063057a8 radicle/sigrefs: Automatically Migrate
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.
2026-03-24 14:40:42 +00:00