Commit Graph

3185 Commits

Author SHA1 Message Date
Fintan Halpenny 8f4b90db7b cli/test: Add broken pipe (SIGPIPE) tests
Add tests that verify the `rad` binary does not panic when its stdout
is a broken pipe (e.g., `rad config | head -1`).

Rust (since 1.62) ignores SIGPIPE by default (see [Rust #62569]),
causing `println!` to panic with "failed printing to stdout: Broken
pipe" instead of exiting silently. This is the standard Unix behaviour
expected of CLI tools.

These tests currently fail on `rad config` and `rad self`, and are set to `ignore`, to be enabled when fixed.

[Rust #62569]: https://github.com/rust-lang/rust/issues/62569
2026-04-29 10:57:24 +02:00
Lorenz Leutgeb 7b07e57b9c treewide/test: Use `impl Arbitrary for Oid`
Many usages of `Oid::from_sha1` are actually in the context of
generating arbitrary `Oid`s. In these cases, `impl Arbitrary for Oid`
may be used directly.
2026-04-28 14:35:38 +02:00
Lorenz Leutgeb 88a7252e33 oid: Fix `impl Arbitrary for Oid`
`fill` would cause the OID to consist of 20 repetitions of the same
byte every time, not an arbitrary OID.
2026-04-28 14:35:38 +02:00
Lorenz Leutgeb deabe6d2ce oid: Nicer panic message
The panic message that `unimplemented!` generates is more appropriate.
2026-04-28 14:35:38 +02:00
Lorenz Leutgeb 60f42bff53 protocol: Minimize scope of `radicle::git::raw`
A tiny refactoring to make it less inviting to use
`radicle::git::raw`.
2026-04-28 14:35:38 +02:00
Lorenz Leutgeb 8dba3ca9de protocol: Decode `radicle_oid::Oid` without `git2`
`impl Decode for Oid` uses `git2` via `radicle::git::raw`.
This is unnecessarily complex.
2026-04-28 14:35:38 +02:00
Lorenz Leutgeb 3d1b37fcbb oid: Make `Oid::SHA1_LEN` public
The length of a SHA-1 object identifier is defined in various locations.
Instead of this redundancy, make the definition in `radicle-oid` public, and
use it in `radicle{-{core,protocol},}`.
2026-04-28 14:35:38 +02:00
Lorenz Leutgeb f46624b81c oid: SHA1_DIGEST_LEN → Oid::LEN_SHA1
A small refactor to move this constant closer to the `enum` that it is
about. An associated constant constant fits more nicely.

Reason for changing the name from `SHA1_*_LEN` to `LEN_SHA1`: As we
think about the object format in the future becoming variable, we
would have that the length of an OID is parameterized by the object
format. So, we imagine a function `fn len(format: ObjectFormat)`, to
be called as `Oid::len(ObjectFormat::Sha1)`. This is the new order
we use.
2026-04-28 14:35:38 +02:00
Lorenz Leutgeb 4c605c0671 radicle: Avoid comparison with `ZERO_SHA1`
When the underlying hash function is not important, but only the fact
whether the OID is the zero sentinel, use `Oid::is_zero`. This is more
flexible, as it is forward compatible with the SHA-256 object format.
2026-04-28 14:35:38 +02:00
Lorenz Leutgeb ecca50a5f9 treewide: Avoid `git2::Oid::zero`
In multiple instances, `git2::Oid::zero` is used to obtain an OID that
is equivalent to `radicle_oid::Oid::SHA1_ZERO`. This is needlessly
complex.
2026-04-28 14:35:38 +02:00
Lorenz Leutgeb f65175397f oid: `const ZERO_SHA1` instead of `fn sha1_zero`
`fn sha1_zero` can be `const fn`, and since it does not take arguments,
it can just be a `const`. There is no good reason to not have a constant.

Justification for changing the order to first specify "zero" and then
"SHA1": In the future we will support multiple object formats. A
function that produces a zero OID would be parameterized by the object
format then. Imagine `fn zero(format: ObjectFormat)` which would be
called as `Oid::zero(ObjectForma::Sha1)`. In anticipation, we change the
ordering to match.
2026-04-28 14:35:38 +02:00
Lorenz Leutgeb aa177b0400
treewide: radicle.{xyz → dev,network}
We have moved to radicle.dev, so adjust the domain name in various
places.

Not changed:
 - COB type names
 - systemd secret identifiers
2026-04-27 18:34:30 +02:00
Lorenz Leutgeb cb57e6560f
node: Rename systemd Credentials
Because we changed our main domain from radicle.xyz to radicle.dev, we
should also change our systemd credential identifiers.

Handling is move into a new function, which also checks the old names
for backwards compatibility.
2026-04-27 18:21:26 +02:00
Lorenz Leutgeb 06ff36ebc4
cli: Update warning for new bootstrap node names 2026-04-27 18:20:25 +02:00
Lorenz Leutgeb 22287fd94a
radicle: Change names of bootstrap nodes 2026-04-27 18:19:47 +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
Fintan Halpenny 099722dd08 radicle: Propagate `radicle-oid/qcheck`
The `radicle-oid/qcheck` feature was not added for `radicle`'s
`qcheck` feature.
Add this so that it propagates for use in downstream crates.
2026-04-24 08:29:34 +01:00
Adrian Duke 5d8988b1a2 CONTRIBUTING/HACKING: Add note on direnv
Add a note on the use of `direnv`, and the availability of the
`.envrc.sample` file.
2026-04-23 08:56:48 +01:00
Richard Levitte 8af0b623fe .envrc: Replace .envrc with .envrc.sample
The `.envrc` file acts as a personal setup file, and should not be checked in.

The team provides `.envrc.sample` where contributors can choose to:

    echo 'source_env .envrc.sample' >> .envrc

To bootstrap their own `.envrc` file.
2026-04-23 08:56:48 +01:00
Adrian Duke bdd991a5f1 e2e: Fix race condition in test_non_fastforward_identity_doc
Fixes an intermittent failure caused by a race condition with background
gossip messages.

Previously Eve's `RefsAnnounced` message could be processed by Bob
after the test updated the identity document to include Alice-Laptop
as a delegate. This caused Bob to unexpectedly fetch the issue in the
background, failing the `!has_issue` assertion.

We now explicitly wait for Bob to receive Eve's announcement before
updating the identity document.
2026-04-23 08:45:06 +01:00
Adrian Duke 802e4726e3 e2e: Replace the hardcoded 1-second sleep in `test_connection_crossing` with polling loop
Avoid relying on a thread sleep to wait for the nodes to connect.

Instead rely on the connection condition being established by using a polling loop.
The loop is controlled by a number of iterations, panicking if the
number of iterations is exceeded.
2026-04-23 08:42:32 +01:00
Adrian Duke bfb54bf4be e2e: Fix flakiness in `test_connection_crossing` test
Addresses intermittent failures in the `test_connection_crossing` e2e test,
which were particularly prevalent on slower CI environments (such as
`rust:trixie`).

Previously, the test spawned two threads to make Alice and Bob dial each
other concurrently and strictly asserted that the "preferred" peer (the
one with the higher Node ID) would always win the `Outbound` link direction.
However, this assumption is flawed in real-world, OS-level network execution
due to two race conditions:

1. Thread Scheduling: One thread could execute and fully establish a
   connection before the other thread even began processing its dial command.
2. Reactor Event Ordering: A node's reactor might wake up and process an
   incoming TCP connection from its peer *before* it processes the `Connect`
   command sent by the test. When it finally processes the `Connect` command,
   it sees a session already exists and skips dialing entirely.

In both scenarios, a true "simultaneous crossing" never occurs. Instead, a
standard sequential connection happens, meaning the link direction is dictated
by whoever dialed first, not by the "preferred" peer logic. This caused the
strict `left: Outbound, right: Inbound` assertions to panic.

To fix this, two changes were made:
- Introduced a `std::sync::Barrier` to synchronize the two test threads.
  This forces both threads to wait for each other before calling `.connect()`,
  maximizing the probability of a true simultaneous dial.
- Relaxed the final assertions. Because OS-level TCP handshakes and reactor
  polling can never guarantee perfect simultaneity, we no longer assert
  *which* peer gets the `Outbound` link. Instead, we assert the core invariant:
  that exactly one connection is established between the nodes, and that their
  link directions are opposite (`s1.link != s2.link`).
2026-04-23 08:39:03 +01:00
Lorenz Leutgeb bbb1279604 cli/config: Obsolete `{get,set,push,remove,unset}` 2026-04-22 15:45:57 +01:00
Lorenz Leutgeb f83eb57719 ci: Update GitHub action `actions/cache`
Version 4 uses Node.js 22, which GitHub warns about and suggests to
update.

Changelog is at <https://github.com/actions/cache#v5>.
2026-04-22 15:31:31 +01:00
Lorenz Leutgeb 224c03daf1 node: Expand `target_os` condition for keep-alive
`KeepAlive::with_retries` is not just unavailable on Windows, but on a
bunch of other operating systems. Copy the condition over from
`socket2`.
2026-04-22 12:06:12 +01:00
Lorenz Leutgeb 4a81673d0e node: Fix conditions for socket activation
The implementation of socket activation requires not only the `systemd`
feature, but also `socket2`.
2026-04-22 12:03:05 +01:00
Richard Levitte 354805aeb3 cli/test: Fix failures related to remote HEAD
Two tests assumed that `refs/remotes/rad/HEAD` would automatically be
crated.  It turns out, however, that this only the case if executed
with Git 2.48.0 or newer. Git versions older than 2.48.0 do not touch
'refs/remotes/<remote>/HEAD'.

Git 2.48.0 and newer will update `refs/remotes/<remote>/HEAD` by
default. This can be disabled by setting
`remote.<remote>.followRemoteHEAD` to "never". Thus, with these
versions, setting that configuration to "never" emulates the behaviour
of older versions.

Therefore, to ensure that test results are consistent across Git
versions before and after 2.48.0, the fixture of test repositories
now include setting 'remote.rad.followRemoteHEAD = never'.

The affected tests are adjusted accordingly.

This change can possibly be reverted once Radicle requires usage of Git
2.48.0 or newer.

Co-authored-by: Lorenz Leutgeb <lorenz.leutgeb@radicle.xyz>
2026-04-21 23:15:34 +02:00
Lorenz Leutgeb 6ce2d00be2 flake: Set `RUST_BACKTRACE` in development shell 2026-04-20 09:24:12 +01:00
Lorenz Leutgeb 2d20e249fd cli/init: Deduplicate `ScopeParser` 2026-04-20 09:21:00 +01:00
Richard Levitte f8ec40a33f just: Make it possible to give your own cargo command
Do it by setting the environment variable 'CARGO_CMD' when running
'just', or by overriding the justfile variable 'cargo_cmd', like so:

    CARGO_CMD='cargo --locked' just ...

or:

    just cargo_cmd='cargo --locked' ...
2026-04-20 09:11:07 +01:00
Lorenz Leutgeb 4f647b2a10 Spell "Radicle" with a captial R
In documentation and output, spell the name of the project with a
captial "R".
2026-04-17 17:15:31 +01:00
Lorenz Leutgeb bb97414a2d cli: Deduplicate RID Argument Handling
Multiple commands take an RID as a command line argument. However, the
handling, which usually involves falling back to detection of the
repository associated with the current directory, is duplicated many
times over.

Introduce `fn rid_or_cwd` which can be used by many commands.
2026-04-17 17:09:15 +01:00
Lorenz Leutgeb f2e96c96ce cli: Rename all `RepoId` args to `repo`
Many commands take RIDs as arguments. Most of them call the
corresponding struct member `repo`, some call it `rid`.

For consistency, name these members `repo` for all commands.

This change is intended to be invisible to the user. That is why,
in some cases, the "long" version of the argument must be renamed to
match `--rid`.
2026-04-17 17:09:15 +01:00
Fintan Halpenny 07c624499c just: Check for Git and Jujutsu-VCS conflict markers 2026-04-17 14:36:58 +01:00
Fintan Halpenny f00a1624df codespell: Add .direnv to skip list 2026-04-17 14:36:58 +01:00
Fintan Halpenny 8a38fa8c73 typos: Rule for ... -> …
Extend the typos rules to include `"..." = "…"`.
2026-04-17 14:36:58 +01:00
Fintan Halpenny fe353ea7e9 codespell: Rule for ... -> …
Creates a new .codespell-dictionary.txt to extend the default set of rules.

The first rule is `...|…`.
2026-04-17 14:36:58 +01:00
Adrian Duke 179a080867 just: Introduce commit-msg hook for typos
Add a `commit-msg` hook to continuously run `typos` against the COMMIT_MSG.
2026-04-17 14:36:58 +01:00
Adrian Duke f6bf13422d just: Fix doublestar expansion in check-scripts 2026-04-17 14:36:58 +01:00
Adrian Duke 083c9d1abc just: Replace inline scripts with script file calls 2026-04-17 14:36:58 +01:00
Adrian Duke 421a43376d just: Drop underline from output styline 2026-04-17 14:36:58 +01:00
Adrian Duke 6744384acf just: Extract inline bash scripts out to files
Enables `shellcheck` checking.
2026-04-17 14:36:58 +01:00
Lorenz Leutgeb df31702b8b flake: Add `just` to development shell 2026-04-17 14:36:58 +01:00
Lorenz Leutgeb fc12414778 just: Rename `HOOK_NAME` to just `HOOK` 2026-04-17 14:36:58 +01:00
Fintan Halpenny 112c901de8 flake: Add codespell
Nix users may not have `codespell` installed globally.
Introduce it in the `devShell` so they have it locally in `heartwood`.
2026-04-17 14:36:58 +01:00
Fintan Halpenny 69ccabacdd just: Use bash to perform install-hook confirmation
The `[confirm()]` tag had issues on linux with string interpolation,
switches to using a bash based read for confirmation.
2026-04-17 14:36:58 +01:00
Adrian Duke 1f4de60bac just: Add minimum version to CONTRIBUTING and HACKING 2026-04-17 14:36:58 +01:00
Fintan Halpenny 11e80d3094 just: Check for file before removing in install-hooks
The `rm` command would fail if the hook did not exist.
First check for existence and then remove.
2026-04-17 14:36:58 +01:00
Fintan Halpenny a74befd2a7 just: Expand shellcheck glob to all shell scripts 2026-04-17 14:36:58 +01:00
Fintan Halpenny 983e5e19d9 just: Use full argument names for codespell 2026-04-17 14:36:58 +01:00