Commit Graph

66 Commits

Author SHA1 Message Date
Lorenz Leutgeb ce11f03fe6 radicle/profile: Control socket path for Windows
The `winpipe` crate which is our current best bet for support on Windows
requires that named pipes are at the magical location `\\.pipe\`.

Provide a default on Windows that matches this, and use our freshly
assigned IANA service name for it.

This is a breaking change, as we remove a `pub const`, it should be
reasonably easy to fix by dependents, and probably it was a mistake to
make the default `pub const` as dependents should call `Home::socket`
anyway.
2025-08-22 15:29:08 +01:00
Lorenz Leutgeb 5229fb8a59 fix: Normalize filesystem paths with `dunce`
Microsoft Windows has Universal Naming Convention (UNC) paths, see
<https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats#unc-paths>

The Rust standard library normalizes paths to this form when calling
`std::fs::canonicalize`, see
<https://doc.rust-lang.org/std/fs/fn.canonicalize.html>

However, some programs, do not parse these paths correctly, including
our ally `git`:

    $ git clone \\?\C:\Users\lorenz\tmp
    Cloning into 'tmp'...
    ssh: Could not resolve hostname \\\\?\\c: No such host is known.
    fatal: Could not read from remote repository.

    Please make sure you have the correct access rights
    and the repository exists.

The `dunce` crate solves the problem of having to deal with
normalization and avoiding weird UNC paths for us. Note that on
non-Windows platforms, it *behaves exactly like*
`std::fs::canonicalize`!
2025-08-22 15:11:43 +01:00
Fintan Halpenny a670b6e668 radicle: fix stream tests
The stream tests did not take into account that the tips of previous COB entries
need to be inserted so that a Git history can be formed.

This was surfaced by the added regression test.
2025-08-20 11:43:18 +01:00
Fintan Halpenny 0c6ff06c65 radicle: use repository fixture in cob stream tests
If the tests are run without a global Git config, then the tests will error with
no name or email set for the commits.

Instead, use the test fixture setup to ensure there is a name and email for
running the tests.
2025-08-20 10:45:57 +01:00
Sebastian Martinez 1d7478cd90 radicle: introduce `cob::common::Title`
This patch adds the `cob::common::Title` struct, this allows instead of
using `std::str::String` or generics and traits for it, to define more
precisely what a title should be.
It trims the provided string and makes sure it contains no carriage
return or new line characters.

Where a `std::str::String` makes more sense so it's easier to mutate it,
we keep the code as is.

Co-authored-by: Fintan Halpenny <fintan.halpenny@gmail.com>
2025-08-19 17:05:33 +02:00
Fintan Halpenny 044ff8adde radicle: introduce specialised Stream types
Add type aliases to specialise the `Stream` type for each of `Patch`, `Issue`,
and `Identity`.

An `init` constructor is also added for each to make it easier to construct each
stream.
2025-08-19 14:49:51 +01:00
Fintan Halpenny c0ac228c37 radicle: introduce COB stream
Introduce a new `stream` module to `radicle::cob`. The purpose of this module is
to provide an API for iterating over a COB's operations, given a range of
commits.

The `CobStream` trait provides the generic API for implementing and using, while
`Stream` provides a concrete implementation using the `git2` crate.

The approach is to use a `git2::Revwalk` for walking over each commit in the
range, then loading the `Op` for that commit – skipping any commits that are
unrelated to that COB type, in the case of associated COBs.

The `Stream` is tested using some properties of the API.

The next steps are to introduce specialised types for `Patch` and `Issue` to
ensure that it works for those.
2025-08-19 14:49:51 +01:00
Fintan Halpenny 9b59c0e2c6 radicle: add Op::load method
Adds an `Op::load` helper method for loading an `Entry`, given its `Oid` and the
`store` it is stored in.

This can be useful for downstream consumers to inspect operations on COBs given
a single `Oid`, without having to load the entire object and/or graph.

It can also be useful when looking at implementing COB stream primitives.
2025-08-19 14:27:35 +01:00
Fintan Halpenny dbfcf424d6 radicle: add Op::manifest_of
Add a helper method `Op::manifest_of`, to allow the caller to inspect the
`Manifest` of the entry. This can be used to avoid attempting to call `Op:load`
with a manifest that would not match the expected `Action`s of the `Op`.
2025-08-19 14:27:35 +01:00
Fintan Halpenny bfe8c5234f cob: add method for loading entry manifest
Adds a helper for only loading the manifest of a COB entry. This allows callers
to inspect the manifest without loading the whole entry.
2025-08-19 14:27:35 +01:00
Fintan Halpenny 86119473b7 test: add alphanumeric generator
Add an `alphanumeric` function for generating alphanumeric strings.
2025-08-19 14:27:35 +01:00
Lorenz Leutgeb 9a7c22536b radicle/config/node: Use newtypes 2025-08-19 13:16:19 +02:00
Lorenz Leutgeb c4ff0d8eae radicle/config/node: Granular Default Values
Provide default values not only per struct, but for each individual
struct member. This allows more granular configuration and fallback to
defaults.
2025-08-19 13:16:19 +02:00
Matthias Beyer 9486e751f2 Simplify impl of Display for some types
Micro-optimization, I know. ;-D

Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
2025-08-19 10:57:37 +01:00
Lorenz Leutgeb 0200e84aea bootstrap: Add IPv6, IPv4, Onion addresses
This should allow bootstrapping when DNS is not available or a
connection via Tor is desired.
2025-08-18 17:39:20 +02:00
Matthias Beyer b49ff9e5af radicle: Implement Iterator::size_hint() for optimizations
This patch adds an implementation of the Iterator::size_hint() trait
function so that the compiler can optimize allocations on the collecting
side of the iterator better.

From the trait function docs:

> size_hint() is primarily intended to be used for optimizations such
> as reserving space for the elements of the iterator, but must not be
> trusted to e.g., omit bounds checks in unsafe code. An incorrect
> implementation of size_hint() should not lead to memory safety
> violations.

Source: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.size_hint

And:

> Vec may use any or none of the following strategies, depending on the
> supplied iterator:
>
>  *  preallocate based on Iterator::size_hint() and panic if the number
>     of items is outside the provided lower/upper bounds

Source: https://doc.rust-lang.org/stable/std/iter/trait.FromIterator.html

Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
2025-08-17 20:22:56 +02:00
Lorenz Leutgeb 1cd3ad0784 node: Remove useless caching of node announcement
When initializing the `radicle-node` process, see
`radicle-node/src/runtime.rs`, an attempt is made to read from a node
announcement file.

This file is never written, therefore all of these reads fail.

Even though this caching mechanism might make sense or might have made
sense at some point, it is dead code now, and therefore removed.

Also, the fact that the file name was defined in the `radicle` crate is
ugly.
2025-08-13 10:27:00 +01:00
Fintan Halpenny efa7efacc4 radicle: Announcer test set constructions
Ensures that preferred seeds that are not synced are made part of the `to_sync`
set, and the Announcer is constructed without an error.

As well as this, ensure that the `synced` and `to_sync` sets do not overlap by
constructing the `to_sync` and removing any `synced` elements from it.
2025-08-13 11:09:49 +02:00
Fintan Halpenny c15288a690 radicle: note about Announcer::can_continue
Making a note of that `Announcer::can_continue` might never be able to hit the
`Break` case. It could be defensive programming, so I'm going to leave it in for
the time being.
2025-08-13 11:09:49 +02:00
Fintan Halpenny 1b33229dd2 radicle: test Announcer::timed_out on success
Ensure that if the Announcer has reached a success case, that if
`Announcer::timed_out` is called, it will still return the success.
2025-08-13 11:09:49 +02:00
Fintan Halpenny 11156619b3 radicle: Announcer test repeated sync
The Announcer should ensure that repeated syncs maintain the sync and unsynced
sets correctly.

The second sync will update the `Duration` of the sync.
2025-08-13 11:09:49 +02:00
Fintan Halpenny ce2d3eb071 radicle: Announcer test synced with unknown node
Adds a test case to show that the Announcer is allowed to mark an "unknown" node
as synced.

There may be a case where gossip reached a node that the current node was not
aware of. This should be allowed and should count towards the final replication
factor.
2025-08-13 11:09:49 +02:00
Fintan Halpenny ca7231e652 radicle: Announcer test adapting the replication target
The replication target should be constrained to the number of nodes to sync
with, if the original value exceeds that number.
2025-08-13 11:09:49 +02:00
Fintan Halpenny 685c84e598 radicle: Announcer with replication factor of 0
Ensures that the Announcer will still announce to preferred seeds when the
replication factor is 0.
2025-08-13 11:09:49 +02:00
Fintan Halpenny 4307eb35b5 radicle: Announcer test AlreadySynced for preferred seeds 2025-08-13 11:09:49 +02:00
Fintan Halpenny 376a5566c2 radicle: Announcer test preferred seeds only 2025-08-13 11:09:49 +02:00
Fintan Halpenny 84f11f5e31 radicle: Announcer ensures local node is ignored
Adds test cases to ensure that the local node is ignored from the announcement
process.
2025-08-13 11:09:49 +02:00
Fintan Halpenny 8a6e55502c radicle: Announcer can exit on preferred seeds or replication factor
The `Announcer` logic was subtly different to the fetching logic, where the
preferred seeds need to be announced to *and* the replication factor had to be
reached.

This patch relaxes that constraint, and allows it to hit either targets before
exiting.

This also surfaced an issue with the with the `Progress` calculation, where
calculating the `unsynced` used the `synced` value to subtract. However, this
was not required because `to_sync` is mutated, so the value is simply
`to_sync.len()`. A test case was added to ensure this is correct by checking
that invariant that the total between synced and unsynced nodes always matches
the total of synced and unsynced progress.
2025-08-13 11:09:49 +02:00
Fintan Halpenny d147094812 fix: upgrade radicle-crypto
The upgrade of the `radicle-crypto` crate was missed when upgrading
semver versions.

Unfortunately, since it is at the base of the dependency tree, all
crates that depend on it require an additional upgrade.
2025-08-13 09:20:42 +01:00
Fintan Halpenny 0e48723b41 release: prepare crates
The `radicle` crate required a bump `0.16.1 -> 0.17`.

Due to this, all its dependents are also bumped
- `radicle-cli`: `0.14.0` -> `0.15.0`
- `radicle-fetch`: `0.12.0` -> `0.13.0`
- `radicle-node`: `0.12.0` -> `0.13.0`
- `radicle-remote-helper`: `0.11.0` -> `0.12.0`
- `radicle-schemars`: `0.1.0` -> `0.2.0`

The following also required upgrading:
- `radicle-ssh`: `0.9.0` -> `0.10.0`
- `radicle-systemd`: `0.9.0` -> `0.10.0`
- `radicle-term`: `0.13.0` -> `0.14.0`
2025-08-12 12:13:49 +02:00
Lorenz Leutgeb d7b48b9e29 radicle: Move logging setup calls to binaries 2025-08-07 08:30:59 +01:00
Lorenz Leutgeb b2a41025ce node: Enable logging via systemd journal 2025-08-07 08:30:59 +01:00
Fintan Halpenny 7a9d4512f9 radicle: fix Canonical::quorum doc link 2025-08-05 15:00:26 +01:00
Lorenz Leutgeb 3d352f23e6 canonical: Support Annotated Tags
The logic for computing canonical references conflated the semantics of
annotated and lighweight tags, yielding confusing/wrong results. The
main culprit was the call to `peel_to_commit` in
`impl ReadRepository for Repository`, peeling tag objects away.

To resolve this, we separate out quroum computation per object type: one
implementation for commits, and one for tags.

Also move  move canonical error types and methods into their own
module to have a cleaner file structure for the main logic.

Capture the `BTreeMap<Oid, u8>` type into a `Votes` struct, with its own API.

We were getting the objects from the repository twice – once in `Canonical::new`
and once again in `ensure_commit_or_tag` – so the latter was removed.

Use an `enum CanonicalObject` to specify which object types the canonical
process supports.

During `converges`, separate commits and tags, and ensure that we are only
looking at objects of one type. Note, that Fintan think this is actually the
*wrong* place to do it because we already filter the objects – so we should
keep track of that information higher up the callstack.

Co-authored-by: Fintan Halpenny <fintan.halpenny@gmail.com>
2025-08-04 17:00:54 +02:00
Lorenz Leutgeb fdb1ac4e3a radicle: Fix clippy::result_large_err
After upgrading from Rust 1.85 to 1.88 in 586eefc, clippy started
warning about large error types. Box action to make
`radicle::cob::patch::Error` lighter.
2025-07-27 23:32:39 +02:00
Lorenz Leutgeb 5bab3f9cc0 clippy: Allow doc_overindented_list_items
After upgrading from Rust 1.85 to 1.88 in 586eefc3e4,
clippy now warns about "overindented" lines in comments. I did not
manage to fix this by hand without breaking the second level of the
lists in question.

See
 - https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items
 - https://github.com/rust-lang/rust-clippy/issues/14275
2025-07-27 23:32:02 +02:00
Lorenz Leutgeb 9068033789 chore: Automated fixes generated by clippy 2025-07-25 11:25:05 +02:00
Lorenz Leutgeb 8224819fed radicle/profile: Enable home detection on Windows
To avoid that users on Windows have to explcitly set `HOME`, also accept
`USERPROFILE` which is considered equivalent.

To avoid repeating to join `.radicle`, split the logic up into two
phases. Also take care to provide a good error message, as this error is
fatal and user-facing.
2025-07-23 10:31:15 +02:00
Lorenz Leutgeb 0705501537 radicle: Depend on winpipe for Windows support 2025-07-23 10:31:15 +02:00
Lorenz Leutgeb 08b535d567 radicle: Only set file limits on Unix 2025-07-23 10:31:13 +02:00
Sekhat Temporus 37ea81766e cli: improve default branch pick
When using `rad init` the default branch for the project can be predetermined by
inspecting the working copy repository.

To improve the experience, it will first check `init.defaultBranch` in the Git
configuration file.

If it does not find this, it falls back to choosing the default head of the
repository at the time. This may be HEAD, and in this case it will error and
provide helpful information.

The repository may also not have any default head at the time, and this also
results in an error and hint.
2025-07-23 07:43:27 +01:00
Tobias Hunger 7c4b71ab82 radicle: Keep pinned repos ordered in config
Do not return them in a random order in radicle-httpd,
so that we can have them in a defined order in
radicle-explorer.
2025-07-19 12:59:02 +01:00
Fintan Halpenny afe64d5175 remote-helper: improve canonical handling
This set of changes refactors the canonical handling by isolating the business
logic into another type, `Canonical`.

The functionality remains the same, but certain error scenarios are better
handled. Primarily, the commits of the inner `Canonical` type are checked to see
if they exist in the working copy, and if not, provide a more useful message
about which commit was missing or invalid for which DID.
2025-07-19 12:32:31 +01:00
Lorenz Leutgeb 0e3f3f03d2 cli: Improve formatting of Node IDs and addresses
Pay more attention to when a Node ID is displayed in compact form. As
this was sometimes used to save space, e.g. in `rad node status` in
combination with long node addresses (like .onion names), also implement
a compact format for node addresses and use that instead in some cases.
Progress notifications in spinners keep the short form.
2025-07-18 21:44:06 +01:00
Lorenz Leutgeb b9759c5868 radicle: Make `node::Link` copy and add `is_*`
This will allow us to replace `netservices::LinkDirection` with
`radicle::node::Link` in a drop-in manner.
2025-07-16 21:12:42 +02:00
Fintan Halpenny ff365e2d8b radicle: disallow default branch
Ensure that the default branch is only ever synthesized from the `Doc`'s
`threshold` and `delegates` value. If the rule is ever written into a `RawDoc`,
then the update of the that `RawDoc` must go through the `update::veryify`
function, which checks that the rule is not present.
2025-07-16 16:41:16 +02:00
Fintan Halpenny a69397386a cli: extract document update logic
The business logic of modifying the identity document should not live in the CLI
code for updating said document.

Instead, we extract out that logic into separate update functions and these are
using from the CLI instead.
2025-07-16 16:41:16 +02:00
Fintan Halpenny 7f646666bc radicle: canonical references payload 2025-07-16 16:41:16 +02:00
Fintan Halpenny af6cf03acd radicle: canonical reference rules
Introduce the `rules` module beneath `canonical`. The implementation follows
the Canonical References RIP[^0].

A `Rule` defines the DIDs and threshold required to get the canonical tip
for a reference (or set of references). Since a `Rule` has some specific
validation rules, there can be two versions of a `Rule`. The `RawRule` is one
that can be easily constructed, serialized, and deserialized. It must then be
validated into a `ValidRule`, which validates any constraints, and can be used
in the computing of a canonical tip.

For convenience, a set of `ValidRule`s is wrapped into the `Rules` type, which
also has a further constraint that each rule refers to a specific `refspec`.

[0]: 1d1ce874f7
2025-07-16 16:41:16 +02:00
Fintan Halpenny 29043134a3 radicle: hotfix release 0.16.1
Releasing a hotfix version for the inclusion of `ReviewEdit` and
`ReviewReaction` changes.
2025-07-15 15:18:05 +01:00