Commit Graph

677 Commits

Author SHA1 Message Date
Lorenz Leutgeb f87d254395
clippy: Disallow lint `identity_op` 2026-04-15 10:06:05 +02:00
Lorenz Leutgeb 33a8c09f78
clippy: Disallow lint `match_like_matches_macro` 2026-04-15 10:06:05 +02:00
Lorenz Leutgeb ca732015fb
clippy: Disallow lints `collapsible_*`
The three lints `collapsible_{if,else_if,match}` are disallowed.
2026-04-15 10:06:05 +02:00
Lorenz Leutgeb 44244dc00f
clippy: Disallow lint `type_complexity`
We just need two exceptions.
2026-04-15 10:06:05 +02:00
Lorenz Leutgeb ffc81154e4
clippy: Disallow lint `enum_variant_names`
We just need one exception.
2026-04-15 10:06:05 +02: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 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 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
Lorenz Leutgeb 8b166b2327 fetch: Log on old sigrefs
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.
2026-03-24 14:40:42 +00:00
Lorenz Leutgeb 7fb032da9b cli/inspect: Show feature level of sigrefs
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.
2026-03-24 14:40:42 +00:00
Lorenz Leutgeb 404fe33a88 radicle/sigrefs: Remove `MissingIdentity` error
Feature levels now treat this situation.
2026-03-24 14:40:42 +00:00
Lorenz Leutgeb 7f19044a72 radicle/sigrefs/write: Treat error to verify head
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.
2026-03-24 14:40:42 +00:00
Lorenz Leutgeb 8bc3ffc0b0 radicle/sigrefs: Detect features when 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.
2026-03-24 14:40:42 +00:00
Lorenz Leutgeb 372a78754a radicle/sigrefs: Implement feature detection
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
2026-03-24 14:40:42 +00:00
Lorenz Leutgeb 9a4539fe82 radicle/sigrefs: Find first non-replayed commit
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.
2026-03-24 14:40:42 +00:00
Lorenz Leutgeb b5dc3486db node/wire: Remove `FetchResult` log
Logs produced by this log statement are very hard to decipher, remove
in favour of other logs in the service.
2026-03-24 14:40:10 +00:00
Lorenz Leutgeb 14493cbfbf core: Enable `radicle-oid/qcheck`
Dependents likely expect this.
2026-03-24 13:01:25 +00:00
Fintan Halpenny 9fda8c6d8f radicle: Update to 0.22.1 2026-03-20 16:15:32 +00:00
Adrian Duke c627e68fdb node/reactor: Demote reactor lag log to DEBUG
Demote from WARN to DEBUG as no actions to remedy can be taken by users.
2026-03-19 21:07:51 +00:00
Lorenz Leutgeb a6a3716f5d radicle/node/db: Fix type of IPv6 addresses
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.
2026-03-19 21:07:51 +00:00
Lorenz Leutgeb fa1699e5d0 radicle/sigrefs: Revert strict verification of `refs/rad/root`
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`.
2026-03-19 21:07:46 +00:00
Fintan Halpenny d01ff2e79d radicle/node: Do not error on IPv6 without `[]`
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 `[]`.
2026-03-19 11:52:04 +01:00
Lorenz Leutgeb c237a3fe47
radicle: Fix JSON Schema for `node::Address`
JSON Schema generation via `schemars` was accidentally broken in
`a2e72b4`. Restore the schema.
2026-03-19 00:38:03 +01:00
Fintan Halpenny 9fd4f00c23 remote-helper: Update to 0.15.0 2026-03-18 20:53:00 +00:00
Fintan Halpenny d7e7db35ed cli: Update to 0.19.0 2026-03-18 20:53:00 +00:00
Fintan Halpenny 026dcdb24a node: Update 0.18.0 2026-03-18 20:53:00 +00:00
Fintan Halpenny a9c1c6ef54 protocol: Update to 0.6.0 2026-03-18 20:53:00 +00:00
Fintan Halpenny 8660b2f004 fetch: Update to 0.18.0 2026-03-18 20:53:00 +00:00
Fintan Halpenny 4a731e34e1 radicle: Update to 0.22.0 2026-03-18 20:52:18 +00:00
Fintan Halpenny dafd3527ee git-metadata: Update to 0.2.0 2026-03-18 20:52:18 +00:00
Fintan Halpenny c9450fe84a cob: Update to 0.19.0 2026-03-18 20:44:25 +00:00
Fintan Halpenny 244be71596 core: Update to 0.2.0 2026-03-18 20:44:25 +00:00
Fintan Halpenny 6745865197 crypto: Update to 0.16.0 2026-03-18 20:44:25 +00:00
Defelo a2e72b48e7
node: Serialize and deserialize ipv6 addresses in square brackets 2026-03-18 21:07:10 +01:00
Fintan Halpenny addce859f5 sigrefs/read: fix typo in doc string 2026-03-18 18:03:42 +00:00
Lorenz Leutgeb c824d317e4
radicle: Fix `storage::refs::Error::is_not_found`
Detection of errors of the "not found" kind does not account for the
respective variant in `sigrefs::read::error::Read`. Fix this by adding
it.
2026-03-18 18:55:28 +01:00
Lorenz Leutgeb 748ddade2f
fetch: Make `RemoteRefs` an alias 2026-03-17 21:31:42 +01:00
Lorenz Leutgeb 35d71f5909
fetch: Remove `DelegateStatus`
This `enum` is only used in `state.rs` and a very thin wrapper around
`delegates.contains`.
2026-03-17 21:31:42 +01:00
Lorenz Leutgeb 363a7231e5
fetch: Remove dead code from `DataRefs` 2026-03-17 21:31:42 +01:00
Fintan Halpenny 725ced09d5 fetch: Prune remotes with sigrefs failures
Previously, trying to load `SignedRefs` for any given remote would
result in a fetch failure.

Teach the fetch to be more resilient by pruning remotes that result in
an error when loading `SignedRefs`, and add the error to the
validation failures.
2026-03-17 21:31:42 +01:00
Lorenz Leutgeb 6967bf8fca
radicle: Automatically upgrade sigrefs
When enumerating repositories in storage, gracefully handle the
case where the identity root is missing from sigrefs and automatically
migrate.
2026-03-17 21:31:42 +01:00
Lorenz Leutgeb 20598d39a0
radicle: Remove unused `SyncedAt::load`
This function is unused in heartwood and returns a `git2::Error`. Remove
it.
2026-03-17 21:31:42 +01:00
Lorenz Leutgeb 0f9eace839
crypto: Remove markers `Verified` and `Unverified`
These are now unused in heartwood.
2026-03-17 21:31:42 +01:00
Lorenz Leutgeb 304a66311a
radicle: Remove generics for verification markers
`SignedRefs` are now always verified.
2026-03-17 21:31:42 +01:00
Fintan Halpenny 393eca3976 node/e2e: `rad/sigrefs-parent` is not fetched
Introduce a test to ensure that the `SIGREFS_PARENT` reference is
never created during a fetch from another node.
2026-03-17 21:31:42 +01:00
Fintan Halpenny d40fa9a347 radicle/sigrefs: Switch to new implementation 2026-03-17 21:31:42 +01:00
Fintan Halpenny d3bc868e84 radicle/sigrefs: Rewrite Signed References
Split up signed references into its read and write components.

On the write side:
 - Preserve the old behavior of writing references to the blob `/refs`
   and sign over the blob.
 - Ensure `refs/rad/root` is contained in the `/refs` blob.
 - Ensure `refs/rad/sigrefs` is *not* contained in the `/refs` blob.
 - Introduce a new (internal) reference `refs/rad/sigrefs-parent`
   so that no two `/refs` blob are equal, even if they contain
   the same set of (non-internal) refs.

On the read side:
 - Preserve the verification of the signature in `/signature` and
   the reference `refs/rad/root` (if present).
 - Fail verification of `refs/rad/root` is not present.
 - Protect against replay attacks by walking the history of the
   head of `refs/rad/sigrefs`, skipping interpretation of `/refs`
   blobs in case they are identical to a previous `/refs` blob.
   This is achieved by searching for repeated contents of the
   `/signature` blob.

The reference `refs/rad/sigrefs-parent` is never read from or written to
the Git repository in storage.

The pre-existing implementation of signed references did not include
a nonce, thus duplicate but legitimate sets of references could not
be distinguished from maliciously replayed sets of references.

The new implementation uses `radicle-git-metadata` which is moved from
`dev-dependencies` to `dependencies`.
2026-03-17 21:31:42 +01:00
Lorenz Leutgeb 52a660fd3b
node/test: Set `RAD_RNG_SEED` 2026-03-17 19:17:03 +01:00
Matthias Beyer 99d9242122 Use humantime to parse timeouts
In issue

    29c6c6fc8171287faa0079798ba2d6e3e7fd86f3

was noted that it would be nice to use value parsers for the timeouts in
the CLI.

This patch implements this.

Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
Co-Authored-by: Fintan Halpenny <fintan.halpenny@gmail.com>
2026-03-17 11:39:09 +00:00
Defelo 52e5581228 cli: Don't override existing seeding scope in `rad seed` 2026-03-17 10:31:29 +00:00
Defelo 281f92e9ff cli/tests: Add test for `rad clone --scope` 2026-03-17 10:31:29 +00:00
justarandomgeek eea3617781 use `CONIN$` instead of `/dev/tty` on windows 2026-03-17 10:27:30 +00:00
Lorenz Leutgeb 0736977170
node: Migrate IPv6 addresses in database
The format for IPv6 addresses was changed in
df8e4e6c88 to require '[' and ']'.

IPv6 addresses that were stored in the database in the past must be
migrated.
2026-03-16 23:12:58 +01:00
Fintan Halpenny 0c47d06f2d radicle/storage/refs: Strengthen Encapsulation
`radicle::storage::Refs` carries a map from reference names to OIDs, and
there are some invariants.
2026-03-16 14:30:48 +01:00
Lorenz Leutgeb f4495e92bc
radicle/device: `impl Keypair for BoxedSigner`
Most consumers of `Device` are interested in the public key of the
device, and `Keypair` is the trait from `signature` which captures
this, so implement it.

Further, for boxing a signer, introduce a new trait `BoxableSigner`
(to remain dyn-compatible) which additionally requires `Keypair`.
2026-03-16 14:30:48 +01:00
Lorenz Leutgeb 74fa4425a1
crypto: Require `Signer: signature::Signer`
All implementations of `radicle_crypto::Signer` are also
`signature::Signer`. Also, the implementations of `Signer::sign` and
`Signer::try_sign` call each other.

To simplify, make `signature::Signer` a requirement for
`radicle_crypto::Signer`.
2026-03-16 14:30:48 +01:00
Lorenz Leutgeb 06fae85e67
crypto: `impl Signer` based on `Keypair`
Since all signers implement `signature::Keypair`, we can simplify the
implementations of `signature::Signer<ExtendedSignature>`. A blanket
implementation is not possible, because we do not control
`signature::Signer`.
2026-03-16 14:30:48 +01:00
Lorenz Leutgeb f2ad54542e
crypto: `impl signature::KeypairRef` for Signers
The various signers defined in `radicle-crypto` all allow borrowing
the corresponding public key a.k.a. "verifying key". This is captured
by implementing `signature::KeypairRef`, so implement it in addition
to `signature::Signer`.
2026-03-16 14:30:48 +01:00