From 0af233cceb28c8049d6909c974f8145644347750 Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Fri, 24 Nov 2023 15:42:51 +0000 Subject: [PATCH] cli: prevent missing delegate being added It's necessary for a delegate's references to be present, e.g. verification, calculating of canonical data, etc. To ensure that a user does not get themselves into a state where they have added a delegate without their references, prevent adding a delegate to the identity document if their `rad/sigrefs` is not present. As well as this, it ensures that if there is a `rad/sigrefs` that it has the default branch -- since it's possible for a peer to have created `rad/sigrefs` through COBs without a default branch. This change meant that the `rad-id` tests required the test scenarios to be set up with all nodes having each other's references. A test case to add a missing delegate was also added to `rad-id.md`. Signed-off-by: Fintan Halpenny X-Clacks-Overhead: GNU Terry Pratchett --- radicle-cli/examples/rad-id-multi-delegate.md | 65 ++++++------- radicle-cli/examples/rad-id.md | 58 ++++++----- radicle-cli/src/commands/id.rs | 62 +++++++++++- radicle-cli/tests/commands.rs | 95 +++++++++++++++---- 4 files changed, 205 insertions(+), 75 deletions(-) diff --git a/radicle-cli/examples/rad-id-multi-delegate.md b/radicle-cli/examples/rad-id-multi-delegate.md index 02d6f36c..6d0e5309 100644 --- a/radicle-cli/examples/rad-id-multi-delegate.md +++ b/radicle-cli/examples/rad-id-multi-delegate.md @@ -7,12 +7,12 @@ $ rad id update --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --title "Add Bob" --des $ rad sync --fetch rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji ✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6MknSL…StBU8Vi.. ✓ Fetched repository from 1 seed(s) -$ rad id update --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --title "Add Eve" --description "" --delegate did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn --no-confirm -✓ Identity revision 9e5aceb50f9307ddcb29923dbaeb5ccbfd07766c created +$ rad id update --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --title "Add Eve" --description "" --delegate did:key:z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z --no-confirm +✓ Identity revision 3cd3c7f9900de0fcb19705856a7cc339a38fb0b3 created ╭────────────────────────────────────────────────────────────────────────╮ │ Title Add Eve │ -│ Revision 9e5aceb50f9307ddcb29923dbaeb5ccbfd07766c │ -│ Blob 4c7fd4c7b7d7fd5d7088a7c952556fab99a034e9 │ +│ Revision 3cd3c7f9900de0fcb19705856a7cc339a38fb0b3 │ +│ Blob 74581605d1f75396c331487a10ca61c4815ed685 │ │ Author did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk │ │ State active │ │ Quorum no │ @@ -34,7 +34,7 @@ $ rad id update --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --title "Add Eve" --des "did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi", - "did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk" + "did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk", -+ "did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn" ++ "did:key:z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z" ], "threshold": 2 } @@ -43,16 +43,17 @@ $ rad id update --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --title "Add Eve" --des ``` ~alice $ rad sync --fetch rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji ✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkt67…v4N1tRk.. -✓ Fetched repository from 1 seed(s) +✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkux1…nVhib7Z.. +✓ Fetched repository from 2 seed(s) $ rad inspect rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --delegates did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (alice) did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (bob) -$ rad id accept 9e5aceb50f9307ddcb29923dbaeb5ccbfd07766c --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --no-confirm -✓ Revision 9e5aceb50f9307ddcb29923dbaeb5ccbfd07766c accepted +$ rad id accept 3cd3c7f9900de0fcb19705856a7cc339a38fb0b3 --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --no-confirm +✓ Revision 3cd3c7f9900de0fcb19705856a7cc339a38fb0b3 accepted ╭────────────────────────────────────────────────────────────────────────╮ │ Title Add Eve │ -│ Revision 9e5aceb50f9307ddcb29923dbaeb5ccbfd07766c │ -│ Blob 4c7fd4c7b7d7fd5d7088a7c952556fab99a034e9 │ +│ Revision 3cd3c7f9900de0fcb19705856a7cc339a38fb0b3 │ +│ Blob 74581605d1f75396c331487a10ca61c4815ed685 │ │ Author did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk │ │ State accepted │ │ Quorum yes │ @@ -63,12 +64,12 @@ $ rad id accept 9e5aceb50f9307ddcb29923dbaeb5ccbfd07766c --repo rad:z42hL2jL4XNk $ rad inspect rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --delegates did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (alice) did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (bob) -did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn +did:key:z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z (eve) ``` ``` ~alice $ rad id update --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --title "Make private" --description "" --visibility private --no-confirm -q -efb8cdd368b9745396f832386f9c7d46988f6bd5 +e6bf10593b78384eb2b281cbb18a605668a6d1f7 ``` We can list all revisions: @@ -78,8 +79,8 @@ $ rad id list ╭────────────────────────────────────────────────────────────────────────────────╮ │ ● ID Title Author Status Created │ ├────────────────────────────────────────────────────────────────────────────────┤ -│ ● efb8cdd Make private alice (you) active now │ -│ ● 9e5aceb Add Eve bob z6Mkt67…v4N1tRk accepted now │ +│ ● e6bf105 Make private alice (you) active now │ +│ ● 3cd3c7f Add Eve bob z6Mkt67…v4N1tRk accepted now │ │ ● 069e7d5 Add Bob alice (you) accepted now │ │ ● 0656c21 Initial revision alice (you) accepted now │ ╰────────────────────────────────────────────────────────────────────────────────╯ @@ -88,24 +89,24 @@ $ rad id list Despite being a delegate, Bob can't edit or redact Alice's revision: ``` ~bob (fail) -$ rad id redact efb8cdd368b9745396f832386f9c7d46988f6bd5 +$ rad id redact e6bf10593b78384eb2b281cbb18a605668a6d1f7 [..] ``` ``` ~bob (fail) -$ rad id edit --title "Boo!" --description "Boo!" efb8cdd368b9745396f832386f9c7d46988f6bd5 +$ rad id edit --title "Boo!" --description "Boo!" e6bf10593b78384eb2b281cbb18a605668a6d1f7 [..] ``` Alice can edit: ``` ~alice -$ rad id edit --title "Make private" --description "Privacy is cool." efb8cdd368b9745396f832386f9c7d46988f6bd5 -✓ Revision efb8cdd368b9745396f832386f9c7d46988f6bd5 edited -$ rad id show efb8cdd368b9745396f832386f9c7d46988f6bd5 +$ rad id edit --title "Make private" --description "Privacy is cool." e6bf10593b78384eb2b281cbb18a605668a6d1f7 +✓ Revision e6bf10593b78384eb2b281cbb18a605668a6d1f7 edited +$ rad id show e6bf10593b78384eb2b281cbb18a605668a6d1f7 ╭────────────────────────────────────────────────────────────────────────╮ │ Title Make private │ -│ Revision efb8cdd368b9745396f832386f9c7d46988f6bd5 │ -│ Blob 79bc5c39103e811a3c9f11744f9a4029f063a5de │ +│ Revision e6bf10593b78384eb2b281cbb18a605668a6d1f7 │ +│ Blob c533865b2846ca6c5b4436ec6872257293380c3b │ │ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │ │ State active │ │ Quorum no │ @@ -114,7 +115,7 @@ $ rad id show efb8cdd368b9745396f832386f9c7d46988f6bd5 ├────────────────────────────────────────────────────────────────────────┤ │ ✓ did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi alice (you) │ │ ? did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk bob │ -│ ? did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn │ +│ ? did:key:z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z eve │ ╰────────────────────────────────────────────────────────────────────────╯ @@ -1,15 +1,18 @@ @@ -129,7 +130,7 @@ $ rad id show efb8cdd368b9745396f832386f9c7d46988f6bd5 "delegates": [ "did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi", "did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk", - "did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn" + "did:key:z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z" ], - "threshold": 2 + "threshold": 2, @@ -142,29 +143,29 @@ $ rad id show efb8cdd368b9745396f832386f9c7d46988f6bd5 And she can redact her revision: ``` ~alice -$ rad id redact efb8cdd368b9745396f832386f9c7d46988f6bd5 -✓ Revision efb8cdd368b9745396f832386f9c7d46988f6bd5 redacted +$ rad id redact e6bf10593b78384eb2b281cbb18a605668a6d1f7 +✓ Revision e6bf10593b78384eb2b281cbb18a605668a6d1f7 redacted ``` ``` ~alice (fail) -$ rad id show efb8cdd368b9745396f832386f9c7d46988f6bd5 -✗ Error: revision `efb8cdd368b9745396f832386f9c7d46988f6bd5` not found +$ rad id show e6bf10593b78384eb2b281cbb18a605668a6d1f7 +✗ Error: revision `e6bf10593b78384eb2b281cbb18a605668a6d1f7` not found ``` Finally, Alice can also propose to remove Bob: ``` ~alice $ rad id update --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --title "Remove Bob" --description "" --rescind did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --no-confirm -✓ Identity revision faf5fb018803d2883e9906bb9c08b6ec83aa55dd created +✓ Identity revision 8ba242a80bc1181f41f9ea7a19286038c7948994 created ╭────────────────────────────────────────────────────────────────────────╮ │ Title Remove Bob │ -│ Revision faf5fb018803d2883e9906bb9c08b6ec83aa55dd │ -│ Blob 7109c1c201c223dd4e9fdb10f7330dc6f0310258 │ +│ Revision 8ba242a80bc1181f41f9ea7a19286038c7948994 │ +│ Blob 254d62de237117e7d7b9ceff85c47f5e3b610c1e │ │ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │ │ State active │ │ Quorum no │ ├────────────────────────────────────────────────────────────────────────┤ │ ✓ did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi alice (you) │ │ ? did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk bob │ -│ ? did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn │ +│ ? did:key:z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z eve │ ╰────────────────────────────────────────────────────────────────────────╯ @@ -1,15 +1,14 @@ @@ -179,7 +180,7 @@ $ rad id update --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --title "Remove Bob" -- "delegates": [ "did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi", - "did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk", - "did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn" + "did:key:z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z" ], "threshold": 2 } diff --git a/radicle-cli/examples/rad-id.md b/radicle-cli/examples/rad-id.md index d720cc90..33a27227 100644 --- a/radicle-cli/examples/rad-id.md +++ b/radicle-cli/examples/rad-id.md @@ -10,24 +10,24 @@ command. For now, since we are the only delegate, and `treshold` is `1`, we can update the identity ourselves. Let's add Bob as a delegate using their DID, -`did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn`, and update the +`did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk`, and update the threshold to `2`. ``` -$ rad id update --title "Add Bob" --description "Add Bob as a delegate" --delegate did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn --threshold 2 -✓ Identity revision 07829cdd1993295cd6be18de6219fead428b4a5e created -╭───────────────────────────────────────────────────────────────────╮ -│ Title Add Bob │ -│ Revision 07829cdd1993295cd6be18de6219fead428b4a5e │ -│ Blob 7109c1c201c223dd4e9fdb10f7330dc6f0310258 │ -│ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │ -│ State accepted │ -│ Quorum yes │ -│ │ -│ Add Bob as a delegate │ -├───────────────────────────────────────────────────────────────────┤ -│ ✓ did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (you) │ -╰───────────────────────────────────────────────────────────────────╯ +$ rad id update --title "Add Bob" --description "Add Bob as a delegate" --delegate did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --threshold 2 +✓ Identity revision 0ca42d376bd566631083c8913cf86bec722da392 created +╭────────────────────────────────────────────────────────────────────────╮ +│ Title Add Bob │ +│ Revision 0ca42d376bd566631083c8913cf86bec722da392 │ +│ Blob 053541ba7b90534b35dd8718e0ceaa408979b02b │ +│ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │ +│ State accepted │ +│ Quorum yes │ +│ │ +│ Add Bob as a delegate │ +├────────────────────────────────────────────────────────────────────────┤ +│ ✓ did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi alice (you) │ +╰────────────────────────────────────────────────────────────────────────╯ @@ -1,13 +1,14 @@ { @@ -41,7 +41,7 @@ $ rad id update --title "Add Bob" --description "Add Bob as a delegate" --delega "delegates": [ - "did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi" + "did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi", -+ "did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn" ++ "did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk" ], - "threshold": 1 + "threshold": 2 @@ -56,7 +56,7 @@ the delegates and threshold: "delegates": [ - "did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi" + "did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi", - + "did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn" + + "did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk" ], ... - "threshold": 1 @@ -85,7 +85,7 @@ $ rad inspect --identity }, "delegates": [ "did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi", - "did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn" + "did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk" ], "threshold": 2 } @@ -94,16 +94,16 @@ $ rad inspect --identity We can also look at the document's COB directly: ``` $ rad cob show --object 0656c217f917c3e06234771e9ecae53aba5e173e --type xyz.radicle.id --repo rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji -commit 07829cdd1993295cd6be18de6219fead428b4a5e +commit 0ca42d376bd566631083c8913cf86bec722da392 parent 0656c217f917c3e06234771e9ecae53aba5e173e author z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi date Thu, 15 Dec 2022 17:28:04 +0000 { - "blob": "7109c1c201c223dd4e9fdb10f7330dc6f0310258", + "blob": "053541ba7b90534b35dd8718e0ceaa408979b02b", "description": "Add Bob as a delegate", "parent": "0656c217f917c3e06234771e9ecae53aba5e173e", - "signature": "z3sne3sdReZ4AtgxQmn7R1pQnz7E9ZEUoRfCJDJ8ytgnBMFW4DJqRHuBz2h1NK4QdGEy3QCpyVoJKfE95tNoivXwz", + "signature": "z3AyzixN2eWLtRfQWowtBXwWyRH3iJ8oJ25W6KFYFw5ANLntbzfavge15muNU6AVAUkxSxQvgg9yh2gupbUecavQY", "title": "Add Bob", "type": "revision" } @@ -126,14 +126,24 @@ Note that once a revision is accepted, it can't be edited, redacted or otherwise acted upon: ``` (fail) -$ rad id redact 07829cdd1993295cd6be18de6219fead428b4a5e +$ rad id redact 0ca42d376bd566631083c8913cf86bec722da392 ✗ Error: [..] ``` ``` (fail) -$ rad id reject 07829cdd1993295cd6be18de6219fead428b4a5e +$ rad id reject 0ca42d376bd566631083c8913cf86bec722da392 ✗ Error: [..] ``` ``` (fail) -$ rad id accept 07829cdd1993295cd6be18de6219fead428b4a5e +$ rad id accept 0ca42d376bd566631083c8913cf86bec722da392 ✗ Error: [..] ``` + +If we attempt to add a delegate that we do not have locally, then we +will be told that they are missing in our repository: + +``` (fail) +$ rad id update --title "Add Eve" --description "Add Eve as a delegate" --delegate did:key:z6MkedTZGJGqgQ2py2b8kGecfxdt2yRdHWF6JpaZC47fovFn +✗ Error: failed to verify delegates for rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji +✗ Error: missing delegate z6MkedT…47fovFn in local storage +✗ Error: fatal: refusing to update identity document +``` diff --git a/radicle-cli/src/commands/id.rs b/radicle-cli/src/commands/id.rs index 8e5db04b..a85f9465 100644 --- a/radicle-cli/src/commands/id.rs +++ b/radicle-cli/src/commands/id.rs @@ -6,7 +6,8 @@ use nonempty::NonEmpty; use radicle::cob::identity::{self, IdentityMut, Revision, RevisionId}; use radicle::identity::{doc, Identity, Visibility}; use radicle::prelude::{Did, Doc, Id, Signer}; -use radicle::storage::{ReadStorage as _, WriteRepository}; +use radicle::storage::refs; +use radicle::storage::{ReadRepository, ReadStorage as _, WriteRepository}; use radicle::{cob, Profile}; use radicle_crypto::Verified; use radicle_surf::diff::Diff; @@ -356,6 +357,14 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { "at lease one delegate must be present for the identity to be valid" ))?; + if let Some(errs) = verify_delegates(&proposal.delegates, &repo)? { + term::error(format!("failed to verify delegates for {rid}")); + for e in errs { + e.print(); + } + anyhow::bail!("fatal: refusing to update identity document"); + } + for (id, key, val) in payload { if let Some(ref mut payload) = proposal.payload.get_mut(&id) { if let Some(obj) = payload.as_object_mut() { @@ -643,3 +652,54 @@ fn print_diff( } Ok(()) } + +enum VerificationError { + Missing(Did), + MissingDefaultBranch { + branch: radicle::git::RefString, + did: Did, + }, +} + +impl VerificationError { + fn print(&self) { + match self { + VerificationError::Missing(did) => term::error(format!( + "missing delegate {} in local storage", + term::format::did(did) + )), + VerificationError::MissingDefaultBranch { branch, did } => term::error(format!( + "missing {} for {} in local storage", + term::format::secondary(branch), + term::format::did(did) + )), + } + } +} + +fn verify_delegates( + dids: &NonEmpty, + repo: &S, +) -> anyhow::Result>> +where + S: ReadRepository, +{ + let (canonical, _) = repo.canonical_head()?; + let mut errors = Vec::with_capacity(dids.len()); + for did in dids { + match refs::SignedRefsAt::load((*did).into(), repo)? { + None => { + errors.push(VerificationError::Missing(*did)); + } + Some(refs::SignedRefsAt { sigrefs, .. }) => { + if sigrefs.get(&canonical).is_none() { + errors.push(VerificationError::MissingDefaultBranch { + branch: canonical.to_ref_string(), + did: *did, + }) + } + } + } + } + Ok((!errors.is_empty()).then_some(errors)) +} diff --git a/radicle-cli/tests/commands.rs b/radicle-cli/tests/commands.rs index 829dfab9..b5a48bd3 100644 --- a/radicle-cli/tests/commands.rs +++ b/radicle-cli/tests/commands.rs @@ -255,20 +255,6 @@ fn rad_checkout() { #[test] fn rad_id() { - let mut environment = Environment::new(); - let profile = environment.profile("alice"); - let working = tempfile::tempdir().unwrap(); - let home = &profile.home; - - // Setup a test repository. - fixtures::repository(working.path()); - - test("examples/rad-init.md", working.path(), Some(home), []).unwrap(); - test("examples/rad-id.md", working.path(), Some(home), []).unwrap(); -} - -#[test] -fn rad_id_multi_delegate() { let mut environment = Environment::new(); let alice = environment.node(Config::test(Alias::new("alice"))); let bob = environment.node(Config::test(Alias::new("bob"))); @@ -288,10 +274,11 @@ fn rad_id_multi_delegate() { .unwrap(); let mut alice = alice.spawn(); - let mut bob = bob.spawn(); + let bob = bob.spawn(); - bob.handle.track_repo(acme, Scope::All).unwrap(); + alice.handle.track_repo(acme, Scope::All).unwrap(); alice.connect(&bob).converge([&bob]); + let events = alice.handle.events(); test( "examples/rad-clone.md", @@ -300,6 +287,74 @@ fn rad_id_multi_delegate() { [], ) .unwrap(); + alice.has_inventory_of(&acme, &bob.id); + + // Alice must have Bob to try add them as a delegate + events + .wait( + |e| matches!(e, Event::RefsFetched { .. }).then_some(()), + time::Duration::from_secs(6), + ) + .unwrap(); + + test( + "examples/rad-id.md", + working.join("alice"), + Some(&alice.home), + [], + ) + .unwrap(); +} + +#[test] +fn rad_id_multi_delegate() { + let mut environment = Environment::new(); + let alice = environment.node(Config::test(Alias::new("alice"))); + let bob = environment.node(Config::test(Alias::new("bob"))); + let eve = environment.node(Config::test(Alias::new("eve"))); + let working = tempfile::tempdir().unwrap(); + let working = working.path(); + let acme = Id::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap(); + + // Setup a test repository. + fixtures::repository(working.join("alice")); + + test( + "examples/rad-init.md", + working.join("alice"), + Some(&alice.home), + [], + ) + .unwrap(); + + let mut alice = alice.spawn(); + let mut bob = bob.spawn(); + let mut eve = eve.spawn(); + + alice.handle.track_repo(acme, Scope::All).unwrap(); + bob.handle.track_node(eve.id, None).unwrap(); + alice.connect(&bob).converge([&bob]); + eve.connect(&alice).converge([&alice]); + + test( + "examples/rad-clone.md", + working.join("bob"), + Some(&bob.home), + [], + ) + .unwrap(); + bob.has_inventory_of(&acme, &alice.id); + alice.has_inventory_of(&acme, &bob.id); + + test( + "examples/rad-clone-all.md", + working.join("eve"), + Some(&eve.home), + [], + ) + .unwrap(); + eve.has_inventory_of(&acme, &bob.id); + alice.has_inventory_of(&acme, &eve.id); // TODO: Have formula with two connected nodes and a tracked project. @@ -340,9 +395,8 @@ fn rad_id_conflict() { .unwrap(); let mut alice = alice.spawn(); - let mut bob = bob.spawn(); + let bob = bob.spawn(); - bob.handle.track_repo(acme, Scope::All).unwrap(); alice.connect(&bob).converge([&bob]); test( @@ -352,6 +406,7 @@ fn rad_id_conflict() { [], ) .unwrap(); + alice.has_inventory_of(&acme, &bob.id); formula(&environment.tmp(), "examples/rad-id-conflict.md") .unwrap() @@ -1553,6 +1608,7 @@ fn git_push_diverge() { let alice = environment.node(Config::test(Alias::new("alice"))); let bob = environment.node(Config::test(Alias::new("bob"))); let working = environment.tmp().join("working"); + let acme = Id::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap(); fixtures::repository(working.join("alice")); @@ -1576,6 +1632,7 @@ fn git_push_diverge() { [], ) .unwrap(); + alice.has_inventory_of(&acme, &bob.id); formula(&environment.tmp(), "examples/git/git-push-diverge.md") .unwrap() @@ -1599,6 +1656,7 @@ fn rad_push_and_pull_patches() { let alice = environment.node(Config::test(Alias::new("alice"))); let bob = environment.node(Config::test(Alias::new("bob"))); let working = environment.tmp().join("working"); + let acme = Id::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap(); fixtures::repository(working.join("alice")); @@ -1624,6 +1682,7 @@ fn rad_push_and_pull_patches() { [], ) .unwrap(); + alice.has_inventory_of(&acme, &bob.id); formula(&environment.tmp(), "examples/rad-push-and-pull-patches.md") .unwrap()