356 Commits
Author SHA1 Message Date
Fintan Halpenny 8677fd9ef0 treewide: Update gix-packetline to 0.21.5
[Advisory Report].

[Advisory Report]: https://github.com/GitoxideLabs/gitoxide/security/advisories/GHSA-2vh6-hw4j-32ww
2026-09-02 08:17:16 +01:00
Lorenz Leutgeb 3054779bfa windows: Set process creation flags
When executing programs on Windows, we suppress creating a new window,
and, if the process should continue to run in the background, we
explicitly create a new process group and detach.
2026-08-25 22:58:56 +02:00
David Sommerseth 2a9b5e72e9 cargo/spin: 0.9.8 → 0.9.9
Version 0.9.8 of `spin` was yanked. See also
<https://rustsec.org/advisories/RUSTSEC-2023-0031.html>.
and <https://github.com/zesterer/spin-rs/issues/148>.
2026-08-14 15:07:05 +02:00
Lars Wirzenius 9f05038234 cli/debug: Output /etc/os-release if available 2026-08-12 16:42:18 +02:00
Lorenz Leutgeb 4e3c274468 crypto, node: Randomly generate ephemeral keys 2026-08-12 15:28:40 +02:00
Lorenz Leutgeb 71a91042d9 cargo/workspace: Bump crate versions
In topological order:

 - radicle-git-metadata     0.2.0 →  0.2.1
 - radicle-git-ref-format   0.1.0 →  0.2.0
 - radicle-oid              0.2.1 →  0.2.2
 - radicle-crypto          0.18.0 → 0.19.0
 - radicle-surf            0.28.0 → 0.29.0
 - radicle-cob             0.21.0 → 0.21.1
 - radicle-core             0.4.0 →  0.4.1
 - radicle                 0.25.0 → 0.25.1
 - radicle-signals         0.12.0 → 0.12.1
 - radicle-fetch           0.21.0 → 0.21.1
 - radicle-term            0.19.0 → 0.19.1
 - radicle-protocol         0.9.0 →  0.9.1
 - radicle-cli-test        0.14.0 → 0.14.1
 - radicle-node            0.21.0 → 0.21.1
 - radicle-cli             0.22.0 → 0.23.0
 - radicle-schemars         0.9.0 →  0.9.1
 - radicle-remote-helper   0.18.0 → 0.18.1
2026-07-24 21:37:41 +02:00
Lorenz Leutgeb ac607c8cad git-ref-format: Integrate with workspace
Instead of depending on `git-ref-format-core`, the
`radicle-git-ref-format` crate succeeds it.
2026-07-24 16:31:30 +02:00
Lorenz Leutgeb 36fc031da2 surf: Switch to crate in workspace
Now that `radicle-surf` lives in this workspace, use it.
2026-07-24 16:27:02 +02:00
Lorenz Leutgeb f8b5bde40a surf: Refactor
Refactor the `radicle-surf` crate to use OIDs from `radicle-oid` instead
of `radicle-git-ext`, and `radicle-git-ref-format` instead of re-exports
from `radicle-git-ext`. Also remove the dependency `radicle-std-ext`.

This requires changing `use`s, and an ad-hoc reimplementation of
`ResultExt::or_matches`.

The remaining changes (excl. tests) are automatic via `rustfmt` and
`cargo clippy`.

For testing, implement reconstruction of

    https://github.com/radicle-dev/git-platinum

in particular of the commits
 - a0dd9122d33dff2a35f564d564db127152c88e02
 - 27acd68c7504755aa11023300890bb85bbd69d45
 - e972683fe8136bf8a5cb2378cf50303554008049
and some tags.

`…/src/test/roundtrip.rs` was copied from the `test-helpers` crate in
the radicle-git workspace.

`…/src/test/{repository.rs,gen*}` was copied from the `radicle-git-ext`
crate in the radicle-git workspace.
2026-07-24 16:27:02 +02:00
Lorenz Leutgeb caf45f1525 cli: Tighten visibility and minimize pub use
In `radicle-cli`, which is a binary crate (!) a few `pub use`s can be
removed. This forces `radicle-remote-helper` to depend on the library
crate `radicle-term` to access some of the types that were re-exported
from `radicle-cli`, making the dependency more obvious, and minimizing
the public symbols on `radicle-cli`.

The dependency on `radicle-cli` cannot be removed from
`radicle-remote-helper` easily, so is kept.
2026-07-22 16:43:34 +02:00
Lorenz Leutgeb 2ae6301f86 cargo/workspace: Bump crate versions
In topological order:

 - radicle-crypto         0.17.0 → 0.18.0
 - radicle-oid             0.2.0 →  0.2.1
 - radicle-cob            0.20.0 → 0.21.0
 - radicle-core            0.3.0 →  0.4.0
 - radicle                0.24.0 → 0.25.0
 - radicle-signals        0.11.0 → 0.12.0
 - radicle-fetch          0.20.0 → 0.21.0
 - radicle-log             0.1.0 →  0.2.0
 - radicle-term           0.18.0 → 0.19.0
 - radicle-protocol        0.8.0 →  0.9.0
 - radicle-cli-test       0.13.0 → 0.14.0
 - radicle-node           0.20.0 → 0.21.0
 - radicle-cli            0.21.0 → 0.22.0
 - radicle-schemars        0.8.0 →  0.9.0
 - radicle-remote-helper  0.17.0 → 0.18.0
2026-07-22 13:12:19 +02:00
Lorenz LeutgebandFintan Halpenny df6524e7e2 crypto: Rewrite
Reasons for the rewrite:
 - Migrate away from `ec25519` as our implementation of Ed25519,
   because that crate is unmaintained.
   Instead of `ec25519` we use `ed25519-dalek` which is the most popular
   implementation of Ed25519 in Rust.
 - Migrate away from `amplify`, because we make very little use of its
   features. Here, we only use `amplify::Bytes32`, which is just a thin
   wrapper of `[u8; 32]`.
   Instead of `amplify::Bytes32` we use `type PublicKeyBytes = [u8; 32]`.

The realization that `ExtendedSignature` is not really tied to SSH, but
is merely a representation of a key together with a signature, allows to
relax the bounds on traits in `radicle-cob`.

Separating out uses of "public key" (a rather simple model of a key,
just 32 bytes) and "verifying key" (an actual point on the Edwards
curve, ready to verify signatures, using more memory than just 32 bytes)
allows a more sensible definition of `crypto::Signer`, which propagates
to `radicle-cob`, `radicle`, `radicle-cli`, `radicle-node` and
simplifies trait bounds.

In `radicle-node`, make the fact clearer that actually the secret key
itself is required (for our implementation of Diffie-Hellman) not
"just" signing. This results in removal of the generic argument
(usually called `G`) of multiple types.

Concretizing the types in `radicle-node` this way, i.e. by (morally)
setting `G = radicle_crypto::SigningKey`, leads to removal of
`MemorySigner` and `MockSigner`, as they really just wrap a signing
key.

Re-exporting `ed25519::Signature` (via re-export in `ed25519-dalek`)
is hopefully more future-proof than using our own type for signatures.
However, the fact that `ed25519::Signature` is not serializable and
does not implement `std::hash::Hash` means that we have to resort to
ad-hoc solutions in `radicle`:
 1. The Identity COB requires serialization of signatures. These are
    generally questionable, since the security of the Identity COB
    should rely on the security of Signed References. In the medium
    term we might even want to consider ignoring signatures in actions.
 2. When reading Signed References, detection of Replay Attacks uses
    a `HashMap` keyed by signatures. This detection only exists for
    backwards compatibility.
These two use cases are exotic enough to warrant ad-hoc implementations.
By not wrapping `ed25519::Signature`, we encourage writing more widely
compatible code in the future.

Co-authored-by: Fintan Halpenny <fintan.halpenny@gmail.com>
2026-07-21 09:19:01 +02:00
Lorenz Leutgeb 0fd0104e87 radicle, cli/auth: Let binary crate generate seed
In preparation of a rewrite of `radicle-crypto`, move the
responsibility for generating a cryptographically secure
seed from `radicle` (transitively via dependency on
`radicle-crypto` and `ec25519`) to the dependent of `radicle`.

Applications should decide how to obtain randomness, not `radicle` via
some far-removed dependency.

Within the workspace, the only dependent using `Profile::seed` is
`radicle-cli`, in particular for the `rad auth` subcommand. To obtain
random bytes, `radicle-cli` depends on `getrandom` and uses
`getrandom::fill`.
2026-07-17 16:52:33 +01:00
Lorenz Leutgeb 41d776be41 treewide: Use channels from std, not Crossbeam
For most use-cases, i.e., except some in `radicle-node`, the channels
in `std::sync::mpsc` suffice, allowing us to get rid of the dependency
`crossbeam-channel`.

Crossbeam is sometimes mentioned to offer higher performance compared
to `std::sync::mpsc`.
For usage in `radicle-signals` (and the counterparts in `radicle-node`
and `radicle-term`) performance is irrelevant, as these channels are
used to send a singular message (to the effect of shutting down the
node or stopping the spinner). These could potentially use
`std::sync::oneshot` in the future, which is nightly-only as of
2026-06-17, see <https://github.com/rust-lang/rust/issues/143674>.
Usage in `radicle-protocol` and `radicle`, is a heavier duty.
The channels pass commands to the service (arriving e.g. via the
control socket in `radicle-node`), events from the service to other
listeners (e.g. the control socket), and fetch results from workers to
the service. For user interaction, performance is irrelevant, since
the messages are in the tens or hundreds per second. Even for delivering
events and programmatic usage of commands, thousands to hundreds of
thousands of messages per second are plenty.

Note that these channel implementations are benchmarked in the millions
of operations per second, see e.g.:
 - <https://github.com/crossbeam-rs/crossbeam/tree/b23b7e8eca2efdad9bdc1ceb1aee1207a852c03b/crossbeam-channel/benchmarks#results>
 - <https://github.com/fereidani/rust-channel-benchmarks/blob/b4c979a94482e5012734657c2ee153b528bc56d6/README.md>

Also, `crossbeam-channel` was merged into `std` in 2022-11, and we do
not believe that performance of the implementations has siginifcantly
drifted since then, see <https://github.com/rust-lang/rust/pull/93563>.

One minor downside is that the channels in the standard library do not
expose the number of pending messages.
2026-07-17 10:58:58 +02:00
Lorenz Leutgeb e4775edf41 radicle: Remove dependency amplify
The `amplify` crate is only used in a handful places to derive `impl`s
that are not very complex.

Provide the required `impl`s directly, and remove the dependency.
2026-07-17 10:06:48 +02:00
Lorenz Leutgeb 564c167de1 git2: 0.20 → 0.21
Update `git2` due to
 - https://rustsec.org/advisories/RUSTSEC-2026-0008.html
 - https://rustsec.org/advisories/RUSTSEC-2026-0183.html
 - https://rustsec.org/advisories/RUSTSEC-2026-0184.html
2026-07-16 14:37:32 +02:00
Fintan Halpenny f897cbbf2f protocol: Remove unused radicle-crypto dev-dependency 2026-07-15 13:05:46 +02:00
Fintan Halpenny fa14b68e27 cli-test: Remove unused radicle dependency 2026-07-15 13:05:46 +02:00
Fintan Halpenny bdbe1e407b cli: Remove unused dependencies
`tree-sitter` and `pretty-assertions` are no longer used.
2026-07-15 13:05:46 +02:00
Rūdolfs Ošiņš cd57affc36 cargo: Bump zlib-rs to 0.6.5
Fetching a large repository looped with

    Failed to consume the pack sent by the remote

even though the pack appears valid (Git indexes it in full).

The cause appears to be a bug in zlib-rs 0.6.3 according to
<https://github.com/trifectatechfoundation/zlib-rs/pull/504>.
2026-07-09 16:19:33 +02:00
Fintan Halpenny b397b1a249 workspace: Update snapbox to 1.2 2026-06-03 09:40:26 +02:00
Lorenz Leutgeb cf108311dc node: Heap Profiling with DHAT 2026-05-27 12:07:52 +01:00
Lorenz Leutgeb 7ed9d50ab6 crypto: Update ssh-agent-lib from 0.5.2 to 0.6
This should fix issues handling SSH certificates.

See
<https://radicle.zulipchat.com/#narrow/channel/369873-Support/topic/1.2E9.2E0.3A.20rad.20auth.20fails.20with.20SSH.20certificate.20in.20agent/with/596358640>.
2026-05-21 13:10:35 +02:00
Fintan Halpenny ac5fc67428 fetch: Update gix packages
Several vulnerabilities were found in the gix packages[^1][^2][^3].

Update the packages to their latest versions which include the fixes.

The only required change is in `ls_refs`.
`RefPrefixes` was introduced and this fixes the issue with `ref-prefix`.
This should now improve the ls-refs stage and only return references
that the client is asking for, as opposed to all references.

[^1]: https://github.com/radicle-dev/heartwood/security/dependabot/38
[^2]: https://github.com/radicle-dev/heartwood/security/dependabot/39
[^3]: https://github.com/radicle-dev/heartwood/security/dependabot/36
2026-05-18 14:57:33 +02:00
stefan 1000402536 node: upgrade cyphernet to fix a panic in socks5-client when using artix
cyphernet 0.5.4 upgrades socks5-client to 0.4.3, which fixes a panic
that occurred when using tor's new artix implementation via socks5.

The upstream fix (authored by me):
https://github.com/cyphernet-labs/cyphernet.rs/pull/18

Diff:
https://github.com/cyphernet-labs/cyphernet.rs/compare/v0.5.3...v0.5.4
2026-05-15 09:06:46 +01:00
Adrian DukeandLorenz Leutgeb caee776c38 log: New crate for logger implementations
Move logging-related module `radicle::logging` into its own crate.

While at it, remove the "logger" feature flag from `radicle`.

Co-authored-by: Lorenz Leutgeb <lorenz.leutgeb@radicle.dev>
2026-05-11 16:44:37 +01:00
Fintan Halpenny 53db994146 schemars: Release 0.8.0 2026-05-06 21:15:54 +01:00
Fintan Halpenny ad068309c9 fetch: Release 0.20.0 2026-05-06 21:15:54 +01:00
Fintan Halpenny ab3621d5d4 remote-helper: Release 0.17.0 2026-05-06 21:15:54 +01:00
Fintan Halpenny f5c39dd603 cob: Release 0.20.0 2026-05-06 21:15:54 +01:00
Fintan Halpenny baf533b37b cli: Release 0.21.0 2026-05-06 21:15:54 +01:00
Fintan Halpenny 342b4d963a node: Release 0.20.0 2026-05-06 21:00:14 +01:00
Fintan Halpenny 622f3827b5 protocol: Release 0.8.0 2026-05-06 21:00:14 +01:00
Fintan Halpenny 2707f6b4b1 radicle: Release 0.24.0 2026-05-06 21:00:14 +01:00
Fintan Halpenny 3486c028ea term: Release 0.18.0 2026-05-06 21:00:14 +01:00
Fintan Halpenny 5991bdfa9a systemd: Release 0.13.0 2026-05-06 21:00:14 +01:00
Fintan Halpenny 2871417808 oid: Release 0.2.0 2026-05-06 21:00:14 +01:00
Fintan Halpenny 4ca2098cb7 core: Release 0.3.0 2026-05-06 21:00:14 +01:00
Fintan Halpenny 64a419d79c crypto: Release 0.17.0 2026-05-06 21:00:14 +01:00
Fintan Halpenny 1a31a9f541 cli: Handle broken pipe (SIGPIPE) gracefully
Prevent `rad` from panicking when its stdout is a closed pipe, e.g.
when running `rad config | head`.

The broken pipes are handled at the output boundaries using three
layers of defence:

1. Inner: Route all stdout output through `term::print()` and
   `term::print_inline()`, which use explicit `writeln!`/`write!` to
   a locked stdout and silently ignore write errors. All `println!`
   calls in `radicle-cli` and `radicle-term` are converted.
2. Middle: Catch `BrokenPipe` errors that propagate up via `anyhow`
   from subcommands in `main::run()`, and exit cleanly with code 0.
3. Outer: Install a panic hook that intercepts `println!` panics
   containing "Broken pipe" (from dependencies like clap) and exits
   cleanly, chained in front of human_panic's hook.

To prevent regressions, `#![deny(clippy::print_stdout)]` is added to
`radicle-cli`, requiring all future stdout output to go through the
safe `term::` functions.

Note: `eprintln!` calls (stderr) are not handled, as broken stderr
pipes are extremely rare in practice.
2026-04-29 10:57:24 +02:00
Lorenz Leutgeb 3bc8abdc29 radicle/node/config: Use IndexSet
With `connect: std::collections::HashSet`, we suffer unpredictable reordering
of values in our test cases.

Use `connect: indexmap::IndexSet` instead, which preserves insertion
order for iteration.
2026-04-27 17:36:20 +02:00
Lorenz Leutgeb 9b9b5ca996 cargo: Update cyphernet from 0.5.2 to 0.5.3
The main change that needs adjustment on our side is that
`impl EcPk for ec25519::PublicKey` changed from `Compressed = [u8; 32]`
to `Compressed = amplify::Bytes32`.

Also remove `impl Deref for PublicKey` to avoid dependents of
`radicle-crypto` depend on a particular implementation, and make the
anonymous member private.

See
<https://github.com/cyphernet-labs/cyphernet.rs/commit/f42396139a6321615dd651bc09073052add14a05>.
2026-04-15 11:59:15 +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
Wiktor KwapisiewiczandLorenz Leutgeb 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]: https://github.com/mikaelmello/inquire/blob/3d5b65422a247acc773d767558e34fcb69ab04bf/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
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