cli: Consolidate policy/scope variants
* Policy::Track -> Policy::Allow * Scope::Trusted -> Scope::Followed
This commit is contained in:
parent
4605348d68
commit
f453090e27
|
|
@ -153,8 +153,8 @@ You can see all replicated and locally-available repositories using:
|
|||
$ rad ls
|
||||
|
||||
By default, your node will subscribe to updates from _all_ peers. This
|
||||
behavior can be changed by passing *--scope trusted* when cloning. It can
|
||||
also be changed later via the *rad track* command.
|
||||
behavior can be changed by passing *--scope followed* when cloning. It can
|
||||
also be changed later via the *rad seed* command.
|
||||
|
||||
=== Publishing a repository on Radicle
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
Trying to clone a repository that is not in our routing table returns an error:
|
||||
|
||||
``` (fail)
|
||||
$ rad clone rad:zVNuptPuk5XauitpCWSNVCXGGfXW --scope trusted
|
||||
✓ Tracking relationship established for rad:zVNuptPuk5XauitpCWSNVCXGGfXW with scope 'trusted'
|
||||
$ rad clone rad:zVNuptPuk5XauitpCWSNVCXGGfXW --scope followed
|
||||
✓ Tracking relationship established for rad:zVNuptPuk5XauitpCWSNVCXGGfXW with scope 'followed'
|
||||
✗ Error: no seeds found for rad:zVNuptPuk5XauitpCWSNVCXGGfXW
|
||||
```
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ To create a local copy of a repository on the radicle network, we use the
|
|||
`clone` command, followed by the identifier or *RID* of the repository:
|
||||
|
||||
```
|
||||
$ rad clone rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --scope trusted
|
||||
✓ Tracking relationship established for rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji with scope 'trusted'
|
||||
$ rad clone rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --scope followed
|
||||
✓ Tracking relationship established for rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji with scope 'followed'
|
||||
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6MknSL…StBU8Vi..
|
||||
✓ Forking under z6Mkt67…v4N1tRk..
|
||||
✓ Creating checkout in ./heartwood..
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ $ rad config
|
|||
}
|
||||
},
|
||||
"policy": "block",
|
||||
"scope": "trusted"
|
||||
"scope": "followed"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ Given a private repo `rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu` belonging to Alice,
|
|||
Bob tries to fetch it, and even though he's connected to Alice, it fails.
|
||||
|
||||
``` ~bob
|
||||
$ rad seed rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu --scope trusted
|
||||
✓ Seeding policy updated for rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu with scope 'trusted'
|
||||
$ rad seed rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu --scope followed
|
||||
✓ Seeding policy updated for rad:z2ug5mwNKZB8KGpBDRTrWHAMbvHCu with scope 'followed'
|
||||
$ rad ls
|
||||
```
|
||||
``` ~bob (fail)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ To create your first radicle project, navigate to a git repository, and run
|
|||
the `init` command:
|
||||
|
||||
```
|
||||
$ rad init --name heartwood --description "Radicle Heartwood Protocol & Stack" --no-confirm --public --scope trusted
|
||||
$ rad init --name heartwood --description "Radicle Heartwood Protocol & Stack" --no-confirm --public --scope followed
|
||||
|
||||
Initializing public radicle 👾 project in .
|
||||
|
||||
|
|
|
|||
|
|
@ -34,11 +34,11 @@ repository that was already created:
|
|||
|
||||
```
|
||||
$ rad node seeding
|
||||
╭──────────────────────────────────────────────────────╮
|
||||
│ RID Scope Policy │
|
||||
├──────────────────────────────────────────────────────┤
|
||||
│ rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji trusted track │
|
||||
╰──────────────────────────────────────────────────────╯
|
||||
╭───────────────────────────────────────────────────────╮
|
||||
│ RID Scope Policy │
|
||||
├───────────────────────────────────────────────────────┤
|
||||
│ rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji followed allow │
|
||||
╰───────────────────────────────────────────────────────╯
|
||||
```
|
||||
|
||||
If we wish to see which nodes we are following:
|
||||
|
|
@ -48,7 +48,7 @@ $ rad node following
|
|||
╭───────────────────────────────────────────────────────────────────────────╮
|
||||
│ DID Alias Policy │
|
||||
├───────────────────────────────────────────────────────────────────────────┤
|
||||
│ did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk Bob track │
|
||||
│ did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk Bob allow │
|
||||
╰───────────────────────────────────────────────────────────────────────────╯
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@ $ rad follow did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --alias ev
|
|||
Now let's track one of Eve's repositories:
|
||||
|
||||
```
|
||||
$ rad seed rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --scope trusted --no-fetch
|
||||
✓ Seeding policy updated for rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji with scope 'trusted'
|
||||
$ rad seed rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --scope followed --no-fetch
|
||||
✓ Seeding policy updated for rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji with scope 'followed'
|
||||
```
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
|||
let tracking = profile.tracking()?;
|
||||
if let Some(repo) = tracking.repo_policy(&rid)? {
|
||||
let tracking = match repo.policy {
|
||||
Policy::Track => term::format::positive("tracked"),
|
||||
Policy::Allow => term::format::positive("tracked"),
|
||||
Policy::Block => term::format::negative("blocked"),
|
||||
};
|
||||
println!(
|
||||
|
|
|
|||
|
|
@ -25,15 +25,15 @@ Usage
|
|||
To delete a policy, use the `--delete` flag.
|
||||
|
||||
When seeding a repository, a scope can be specified: this can be either `all` or
|
||||
`trusted`. When using `all`, all remote nodes will be followed for that repository.
|
||||
On the other hand, with `trusted`, only the repository delegates will be followed,
|
||||
`followed`. When using `all`, all remote nodes will be followed for that repository.
|
||||
On the other hand, with `followed`, only the repository delegates will be followed,
|
||||
plus any remote that is explicitly followed via `rad follow <nid>`.
|
||||
|
||||
Options
|
||||
|
||||
--delete, -d Delete the seeding policy
|
||||
--[no-]fetch Fetch repository after updating seeding policy
|
||||
--scope <scope> Peer follow scope for a repository
|
||||
--scope <scope> Peer follow scope for this repository
|
||||
--verbose, -v Verbose output
|
||||
--help Print help
|
||||
"#,
|
||||
|
|
|
|||
|
|
@ -700,7 +700,7 @@ fn rad_clean() {
|
|||
let mut bob = bob.spawn();
|
||||
let mut eve = eve.spawn();
|
||||
alice.handle.track_repo(acme, Scope::All).unwrap();
|
||||
eve.handle.track_repo(acme, Scope::Trusted).unwrap();
|
||||
eve.handle.track_repo(acme, Scope::Followed).unwrap();
|
||||
|
||||
bob.connect(&alice).converge([&alice]);
|
||||
eve.connect(&alice).converge([&alice]);
|
||||
|
|
@ -769,7 +769,7 @@ fn rad_clone() {
|
|||
let mut alice = alice.spawn();
|
||||
let mut bob = bob.spawn();
|
||||
// Prevent Alice from fetching Bob's fork, as we're not testing that and it may cause errors.
|
||||
alice.handle.track_repo(acme, Scope::Trusted).unwrap();
|
||||
alice.handle.track_repo(acme, Scope::Followed).unwrap();
|
||||
|
||||
bob.connect(&alice).converge([&alice]);
|
||||
|
||||
|
|
@ -873,8 +873,8 @@ fn rad_clone_connect() {
|
|||
|
||||
let eve = eve.spawn();
|
||||
|
||||
alice.handle.track_repo(acme, Scope::Trusted).unwrap();
|
||||
bob.handle.track_repo(acme, Scope::Trusted).unwrap();
|
||||
alice.handle.track_repo(acme, Scope::Followed).unwrap();
|
||||
bob.handle.track_repo(acme, Scope::Followed).unwrap();
|
||||
alice.connect(&bob);
|
||||
bob.routes_to(&[(acme, alice.id)]);
|
||||
eve.routes_to(&[(acme, alice.id), (acme, bob.id)]);
|
||||
|
|
@ -1257,7 +1257,7 @@ fn test_replication_via_seed() {
|
|||
let alice = environment.node(Config::test(Alias::new("alice")));
|
||||
let bob = environment.node(Config::test(Alias::new("bob")));
|
||||
let seed = environment.node(Config {
|
||||
policy: Policy::Track,
|
||||
policy: Policy::Allow,
|
||||
scope: Scope::All,
|
||||
..Config::test(Alias::new("seed"))
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
//! delegate data for the repository.
|
||||
//! 2. [`SpecialRefs`]: fetches the special references, `rad/id` and
|
||||
//! `rad/sigrefs`, for each configured namespace, i.e. tracked
|
||||
//! and delegate peers if the scope is trusted and all peers is the
|
||||
//! and delegate peers if the scope is "followed" and all peers is the
|
||||
//! scope is all.
|
||||
//! 3. [`DataRefs`]: fetches the `Oid`s for each reference listed in
|
||||
//! the `rad/sigrefs` for each fetched peer in the
|
||||
|
|
@ -241,7 +241,7 @@ impl ProtocolStage for SpecialRefs {
|
|||
fn ls_refs(&self) -> Option<NonEmpty<BString>> {
|
||||
match &self.tracked {
|
||||
tracking::Tracked::All => Some(NonEmpty::new("refs/namespaces".into())),
|
||||
tracking::Tracked::Trusted { remotes } => NonEmpty::collect(
|
||||
tracking::Tracked::Followed { remotes } => NonEmpty::collect(
|
||||
remotes
|
||||
.iter()
|
||||
.chain(self.delegates.iter())
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ pub use radicle::node::tracking::{Policy, Scope};
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum Tracked {
|
||||
All,
|
||||
Trusted { remotes: HashSet<PublicKey> },
|
||||
Followed { remotes: HashSet<PublicKey> },
|
||||
}
|
||||
|
||||
impl Tracked {
|
||||
|
|
@ -23,17 +23,17 @@ impl Tracked {
|
|||
log::error!(target: "fetch", "Attempted to fetch untracked repo {rid}");
|
||||
Err(error::Tracking::BlockedPolicy { rid })
|
||||
}
|
||||
Policy::Track => match entry.scope {
|
||||
Policy::Allow => match entry.scope {
|
||||
Scope::All => Ok(Self::All),
|
||||
Scope::Trusted => {
|
||||
Scope::Followed => {
|
||||
let nodes = config
|
||||
.node_policies()
|
||||
.map_err(|err| error::Tracking::FailedNodes { rid, err })?;
|
||||
let trusted: HashSet<_> = nodes
|
||||
.filter_map(|node| (node.policy == Policy::Track).then_some(node.id))
|
||||
let followed: HashSet<_> = nodes
|
||||
.filter_map(|node| (node.policy == Policy::Allow).then_some(node.id))
|
||||
.collect();
|
||||
|
||||
Ok(Tracked::Trusted { remotes: trusted })
|
||||
Ok(Tracked::Followed { remotes: followed })
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@ where
|
|||
self.filter = Filter::new(
|
||||
self.tracking
|
||||
.repo_policies()?
|
||||
.filter_map(|t| (t.policy == tracking::Policy::Track).then_some(t.id)),
|
||||
.filter_map(|t| (t.policy == tracking::Policy::Allow).then_some(t.id)),
|
||||
);
|
||||
Ok(updated)
|
||||
}
|
||||
|
|
@ -570,7 +570,7 @@ where
|
|||
self.filter = Filter::new(
|
||||
self.tracking
|
||||
.repo_policies()?
|
||||
.filter_map(|t| (t.policy == tracking::Policy::Track).then_some(t.id)),
|
||||
.filter_map(|t| (t.policy == tracking::Policy::Allow).then_some(t.id)),
|
||||
);
|
||||
// Try to establish some connections.
|
||||
self.maintain_connections();
|
||||
|
|
@ -1266,7 +1266,7 @@ where
|
|||
"Service::handle_announcement: error accessing repo tracking configuration",
|
||||
);
|
||||
|
||||
if repo_entry.policy == tracking::Policy::Track {
|
||||
if repo_entry.policy == tracking::Policy::Allow {
|
||||
let (fresh, stale) = match self.refs_status_of(message, &repo_entry.scope) {
|
||||
Ok(RefsStatus { fresh, stale }) => (fresh, stale),
|
||||
Err(e) => {
|
||||
|
|
@ -1424,13 +1424,13 @@ where
|
|||
// Second, check the scope.
|
||||
match scope {
|
||||
tracking::Scope::All => Ok(refs),
|
||||
tracking::Scope::Trusted => {
|
||||
tracking::Scope::Followed => {
|
||||
match self.tracking.namespaces_for(&self.storage, &message.rid) {
|
||||
Ok(Namespaces::All) => Ok(refs),
|
||||
Ok(Namespaces::Trusted(mut trusted)) => {
|
||||
// Get the set of trusted nodes except self.
|
||||
trusted.remove(self.nid());
|
||||
refs.fresh.retain(|r| trusted.contains(&r.remote));
|
||||
Ok(Namespaces::Followed(mut followed)) => {
|
||||
// Get the set of followed nodes except self.
|
||||
followed.remove(self.nid());
|
||||
refs.fresh.retain(|r| followed.contains(&r.remote));
|
||||
|
||||
Ok(refs)
|
||||
}
|
||||
|
|
@ -1817,7 +1817,7 @@ where
|
|||
|
||||
/// Return a new filter object, based on our tracking policy.
|
||||
fn filter(&self) -> Filter {
|
||||
if self.config.policy == tracking::Policy::Track {
|
||||
if self.config.policy == tracking::Policy::Allow {
|
||||
// TODO: Remove bits for blocked repos.
|
||||
Filter::default()
|
||||
} else {
|
||||
|
|
@ -1920,7 +1920,7 @@ where
|
|||
let missing = self
|
||||
.tracking
|
||||
.repo_policies()?
|
||||
.filter_map(|t| (t.policy == tracking::Policy::Track).then_some(t.id))
|
||||
.filter_map(|t| (t.policy == tracking::Policy::Allow).then_some(t.id))
|
||||
.filter(|rid| !inventory.contains(rid));
|
||||
|
||||
for rid in missing {
|
||||
|
|
|
|||
|
|
@ -420,7 +420,7 @@ impl<G: cyphernet::Ecdh<Pk = NodeId> + Signer + Clone> Node<G> {
|
|||
|
||||
assert!(self
|
||||
.tracking
|
||||
.track_repo(&id, node::tracking::Scope::Trusted)
|
||||
.track_repo(&id, node::tracking::Scope::Followed)
|
||||
.unwrap());
|
||||
|
||||
log::debug!(
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ where
|
|||
config.config.external_addresses.push(local_addr.into());
|
||||
|
||||
for rid in storage.inventory().unwrap() {
|
||||
tracking.track_repo(&rid, Scope::Trusted).unwrap();
|
||||
tracking.track_repo(&rid, Scope::Followed).unwrap();
|
||||
}
|
||||
let announcement = service::gossip::node(&config.config, config.local_time.as_secs());
|
||||
let emitter: Emitter<Event> = Default::default();
|
||||
|
|
|
|||
|
|
@ -422,7 +422,7 @@ impl<S: WriteStorage + 'static, G: Signer> Simulation<S, G> {
|
|||
radicle::test::fetch(
|
||||
&repo,
|
||||
&nid,
|
||||
Namespaces::Trusted(namespaces.clone()),
|
||||
Namespaces::Followed(namespaces.clone()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
|
@ -655,7 +655,7 @@ impl<S: WriteStorage + 'static, G: Signer> Simulation<S, G> {
|
|||
Rc::new(Ok(fetch::FetchResult {
|
||||
updated: vec![],
|
||||
namespaces: match namespaces {
|
||||
Namespaces::Trusted(hs) => hs,
|
||||
Namespaces::Followed(hs) => hs,
|
||||
Namespaces::All => HashSet::new(),
|
||||
},
|
||||
})),
|
||||
|
|
|
|||
|
|
@ -742,7 +742,7 @@ fn test_refs_announcement_fetch_trusted_no_inventory() {
|
|||
let bob_inv = bob.storage().inventory().unwrap();
|
||||
let rid = bob_inv[0];
|
||||
|
||||
alice.track_repo(&rid, tracking::Scope::Trusted).unwrap();
|
||||
alice.track_repo(&rid, tracking::Scope::Followed).unwrap();
|
||||
alice.connect_to(&bob);
|
||||
|
||||
// Alice receives Bob's refs.
|
||||
|
|
@ -755,11 +755,11 @@ fn test_refs_announcement_fetch_trusted_no_inventory() {
|
|||
/// Alice and Bob both have the same repo.
|
||||
///
|
||||
/// First, Alice will not fetch from Bob's `RefsAnnouncement` as Alice does not
|
||||
/// track Bob as `Trusted`.
|
||||
/// track Bob as `Followed`.
|
||||
///
|
||||
/// Later Alice tracks Bob, and will be able to fetch Bob's refs.
|
||||
/// Later Alice follows Bob, and will be able to fetch Bob's refs.
|
||||
#[test]
|
||||
fn test_refs_announcement_trusted() {
|
||||
fn test_refs_announcement_followed() {
|
||||
logger::init(log::Level::Debug);
|
||||
|
||||
// Create MockStorage for Alice and Bob. Both will have repo with `rid`.
|
||||
|
|
@ -796,9 +796,9 @@ fn test_refs_announcement_trusted() {
|
|||
},
|
||||
);
|
||||
|
||||
// Alice uses Scope::Trusted, and did not track Bob yet.
|
||||
// Alice uses Scope::Followed, and did not track Bob yet.
|
||||
alice.connect_to(&bob);
|
||||
alice.track_repo(&rid, tracking::Scope::Trusted).unwrap();
|
||||
alice.track_repo(&rid, tracking::Scope::Followed).unwrap();
|
||||
|
||||
// Alice receives Bob's refs
|
||||
alice.receive(bob.id(), bob.refs_announcement(rid));
|
||||
|
|
@ -1538,14 +1538,14 @@ fn test_push_and_pull() {
|
|||
assert!(eve.get(proj_id).unwrap().is_none());
|
||||
assert!(bob.get(proj_id).unwrap().is_none());
|
||||
|
||||
// Bob tracks Alice's project.
|
||||
// Bob seeds Alice's project.
|
||||
let (sender, _) = chan::bounded(1);
|
||||
bob.command(service::Command::TrackRepo(
|
||||
proj_id,
|
||||
tracking::Scope::default(),
|
||||
sender,
|
||||
));
|
||||
// Eve tracks Alice's project.
|
||||
// Eve seeds Alice's project.
|
||||
let (sender, _) = chan::bounded(1);
|
||||
eve.command(service::Command::TrackRepo(
|
||||
proj_id,
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ fn test_replication_invalid() {
|
|||
converge([&alice, &bob]);
|
||||
|
||||
alice.handle.track_node(*carol.public_key(), None).unwrap();
|
||||
alice.handle.track_repo(acme, Scope::Trusted).unwrap();
|
||||
alice.handle.track_repo(acme, Scope::Followed).unwrap();
|
||||
let result = alice.handle.fetch(acme, bob.id, DEFAULT_TIMEOUT).unwrap();
|
||||
|
||||
// Fetch is successful despite not fetching Carol's refs, since she isn't a delegate.
|
||||
|
|
@ -367,7 +367,7 @@ fn test_dont_fetch_owned_refs() {
|
|||
alice.connect(&bob);
|
||||
converge([&alice, &bob]);
|
||||
|
||||
assert!(bob.handle.track_repo(acme, Scope::Trusted).unwrap());
|
||||
assert!(bob.handle.track_repo(acme, Scope::Followed).unwrap());
|
||||
|
||||
let result = bob.handle.fetch(acme, alice.id, DEFAULT_TIMEOUT).unwrap();
|
||||
assert!(result.is_success());
|
||||
|
|
@ -380,7 +380,7 @@ fn test_dont_fetch_owned_refs() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_trusted_remotes() {
|
||||
fn test_fetch_followed_remotes() {
|
||||
logger::init(log::Level::Debug);
|
||||
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
|
|
@ -402,18 +402,18 @@ fn test_fetch_trusted_remotes() {
|
|||
alice.connect(&bob);
|
||||
converge([&alice, &bob]);
|
||||
|
||||
let trusted = signers
|
||||
let followed = signers
|
||||
.iter()
|
||||
.map(|s| *s.public_key())
|
||||
.take(2)
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
assert!(
|
||||
trusted.len() < signers.len(),
|
||||
followed.len() < signers.len(),
|
||||
"Bob is only trusting a subset of peers"
|
||||
);
|
||||
assert!(bob.handle.track_repo(acme, Scope::Trusted).unwrap());
|
||||
for nid in &trusted {
|
||||
assert!(bob.handle.track_repo(acme, Scope::Followed).unwrap());
|
||||
for nid in &followed {
|
||||
assert!(bob.handle.track_node(*nid, None).unwrap());
|
||||
}
|
||||
|
||||
|
|
@ -429,8 +429,8 @@ fn test_fetch_trusted_remotes() {
|
|||
.collect::<Result<HashSet<_>, _>>()
|
||||
.unwrap();
|
||||
|
||||
assert!(bob_remotes.len() == trusted.len() + 1);
|
||||
assert!(bob_remotes.is_superset(&trusted));
|
||||
assert!(bob_remotes.len() == followed.len() + 1);
|
||||
assert!(bob_remotes.is_superset(&followed));
|
||||
assert!(bob_remotes.contains(&alice.id));
|
||||
}
|
||||
|
||||
|
|
@ -450,7 +450,7 @@ fn test_missing_remote() {
|
|||
alice.connect(&bob);
|
||||
converge([&alice, &bob]);
|
||||
|
||||
assert!(bob.handle.track_repo(acme, Scope::Trusted).unwrap());
|
||||
assert!(bob.handle.track_repo(acme, Scope::Followed).unwrap());
|
||||
assert!(bob.handle.track_node(*carol.public_key(), None).unwrap());
|
||||
let result = bob.handle.fetch(acme, alice.id, DEFAULT_TIMEOUT).unwrap();
|
||||
assert!(result.is_success());
|
||||
|
|
@ -477,7 +477,7 @@ fn test_fetch_preserve_owned_refs() {
|
|||
alice.connect(&bob);
|
||||
converge([&alice, &bob]);
|
||||
|
||||
assert!(bob.handle.track_repo(acme, Scope::Trusted).unwrap());
|
||||
assert!(bob.handle.track_repo(acme, Scope::Followed).unwrap());
|
||||
assert!(bob.handle.track_node(alice.id, None).unwrap());
|
||||
|
||||
let result = bob.handle.fetch(acme, alice.id, DEFAULT_TIMEOUT).unwrap();
|
||||
|
|
|
|||
|
|
@ -25,12 +25,12 @@ pub struct Node {
|
|||
pub policy: Policy,
|
||||
}
|
||||
|
||||
/// Tracking policy.
|
||||
/// Resource policy.
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Policy {
|
||||
/// The resource is tracked.
|
||||
Track,
|
||||
/// The resource is allowed.
|
||||
Allow,
|
||||
/// The resource is blocked.
|
||||
#[default]
|
||||
Block,
|
||||
|
|
@ -39,7 +39,7 @@ pub enum Policy {
|
|||
impl fmt::Display for Policy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Track => write!(f, "track"),
|
||||
Self::Allow => write!(f, "allow"),
|
||||
Self::Block => write!(f, "block"),
|
||||
}
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ impl FromStr for Policy {
|
|||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"track" => Ok(Self::Track),
|
||||
"allow" => Ok(Self::Allow),
|
||||
"block" => Ok(Self::Block),
|
||||
_ => Err(s.to_owned()),
|
||||
}
|
||||
|
|
@ -64,7 +64,7 @@ impl sqlite::BindableWithIndex for Policy {
|
|||
i: I,
|
||||
) -> sqlite::Result<()> {
|
||||
match self {
|
||||
Self::Track => "track",
|
||||
Self::Allow => "allow",
|
||||
Self::Block => "block",
|
||||
}
|
||||
.bind(stmt, i)
|
||||
|
|
@ -78,7 +78,7 @@ impl TryFrom<&sqlite::Value> for Policy {
|
|||
let message = Some("sql: invalid policy".to_owned());
|
||||
|
||||
match value {
|
||||
sqlite::Value::String(s) if s == "track" => Ok(Policy::Track),
|
||||
sqlite::Value::String(s) if s == "allow" => Ok(Policy::Allow),
|
||||
sqlite::Value::String(s) if s == "block" => Ok(Policy::Block),
|
||||
_ => Err(sqlite::Error {
|
||||
code: None,
|
||||
|
|
@ -88,21 +88,21 @@ impl TryFrom<&sqlite::Value> for Policy {
|
|||
}
|
||||
}
|
||||
|
||||
/// Tracking scope of a repository tracking policy.
|
||||
/// Follow scope of a seeded repository.
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Scope {
|
||||
/// Track remotes of nodes that are already tracked.
|
||||
/// Seed remotes that are explicitly followed.
|
||||
#[default]
|
||||
Trusted,
|
||||
/// Track all remotes.
|
||||
Followed,
|
||||
/// Seed all remotes.
|
||||
All,
|
||||
}
|
||||
|
||||
impl fmt::Display for Scope {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Scope::Trusted => f.write_str("trusted"),
|
||||
Scope::Followed => f.write_str("followed"),
|
||||
Scope::All => f.write_str("all"),
|
||||
}
|
||||
}
|
||||
|
|
@ -117,7 +117,7 @@ impl FromStr for Scope {
|
|||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"trusted" => Ok(Self::Trusted),
|
||||
"followed" => Ok(Self::Followed),
|
||||
"all" => Ok(Self::All),
|
||||
_ => Err(ParseScopeError(s.to_string())),
|
||||
}
|
||||
|
|
@ -131,7 +131,7 @@ impl sqlite::BindableWithIndex for Scope {
|
|||
i: I,
|
||||
) -> sqlite::Result<()> {
|
||||
let s = match self {
|
||||
Self::Trusted => "trusted",
|
||||
Self::Followed => "followed",
|
||||
Self::All => "all",
|
||||
};
|
||||
s.bind(stmt, i)
|
||||
|
|
|
|||
|
|
@ -16,21 +16,21 @@ pub use crate::node::tracking::{Alias, Node, Policy, Repo, Scope};
|
|||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NamespacesError {
|
||||
#[error("Failed to find tracking policy for {rid}")]
|
||||
#[error("failed to find tracking policy for {rid}")]
|
||||
FailedPolicy {
|
||||
rid: Id,
|
||||
#[source]
|
||||
err: Error,
|
||||
},
|
||||
#[error("Cannot fetch {rid} as it is not tracked")]
|
||||
#[error("cannot fetch {rid} as it is not tracked")]
|
||||
BlockedPolicy { rid: Id },
|
||||
#[error("Failed to get tracking nodes for {rid}")]
|
||||
#[error("failed to get tracking nodes for {rid}")]
|
||||
FailedNodes {
|
||||
rid: Id,
|
||||
#[source]
|
||||
err: Error,
|
||||
},
|
||||
#[error("Failed to get delegates for {rid}")]
|
||||
#[error("failed to get delegates for {rid}")]
|
||||
FailedDelegates {
|
||||
rid: Id,
|
||||
#[source]
|
||||
|
|
@ -38,8 +38,8 @@ pub enum NamespacesError {
|
|||
},
|
||||
#[error(transparent)]
|
||||
Git(#[from] crate::git::raw::Error),
|
||||
#[error("Could not find any trusted nodes for {rid}")]
|
||||
NoTrusted { rid: Id },
|
||||
#[error("could not find any followed nodes for {rid}")]
|
||||
NoFollowed { rid: Id },
|
||||
}
|
||||
|
||||
/// Tracking configuration.
|
||||
|
|
@ -77,13 +77,13 @@ impl<T> Config<T> {
|
|||
/// Check if a repository is tracked.
|
||||
pub fn is_repo_tracked(&self, id: &Id) -> Result<bool, Error> {
|
||||
self.repo_policy(id)
|
||||
.map(|entry| entry.policy == Policy::Track)
|
||||
.map(|entry| entry.policy == Policy::Allow)
|
||||
}
|
||||
|
||||
/// Check if a node is tracked.
|
||||
pub fn is_node_tracked(&self, id: &NodeId) -> Result<bool, Error> {
|
||||
self.node_policy(id)
|
||||
.map(|entry| entry.policy == Policy::Track)
|
||||
.map(|entry| entry.policy == Policy::Allow)
|
||||
}
|
||||
|
||||
/// Get a node's tracking information.
|
||||
|
|
@ -120,14 +120,14 @@ impl<T> Config<T> {
|
|||
error!(target: "service", "Attempted to fetch untracked repo {rid}");
|
||||
Err(NamespacesError::BlockedPolicy { rid: *rid })
|
||||
}
|
||||
Policy::Track => match entry.scope {
|
||||
Policy::Allow => match entry.scope {
|
||||
Scope::All => Ok(Namespaces::All),
|
||||
Scope::Trusted => {
|
||||
Scope::Followed => {
|
||||
let nodes = self
|
||||
.node_policies()
|
||||
.map_err(|err| FailedNodes { rid: *rid, err })?;
|
||||
let mut trusted: HashSet<_> = nodes
|
||||
.filter_map(|node| (node.policy == Policy::Track).then_some(node.id))
|
||||
let mut followed: HashSet<_> = nodes
|
||||
.filter_map(|node| (node.policy == Policy::Allow).then_some(node.id))
|
||||
.collect();
|
||||
|
||||
if let Ok(repo) = storage.repository(*rid) {
|
||||
|
|
@ -135,15 +135,15 @@ impl<T> Config<T> {
|
|||
.delegates()
|
||||
.map_err(|err| FailedDelegates { rid: *rid, err })?
|
||||
.map(PublicKey::from);
|
||||
trusted.extend(delegates);
|
||||
followed.extend(delegates);
|
||||
};
|
||||
if trusted.is_empty() {
|
||||
if followed.is_empty() {
|
||||
// Nb. returning All here because the
|
||||
// fetching logic will correctly determine
|
||||
// trusted and delegate remotes.
|
||||
// followed and delegate remotes.
|
||||
Ok(Namespaces::All)
|
||||
} else {
|
||||
Ok(Namespaces::Trusted(trusted))
|
||||
Ok(Namespaces::Followed(followed))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,30 +2,30 @@
|
|||
-- Service configuration schema.
|
||||
--
|
||||
|
||||
-- Node tracking policy.
|
||||
create table if not exists "node-policies" (
|
||||
-- Node follow policies.
|
||||
create table if not exists "following" (
|
||||
-- Node ID.
|
||||
"id" text primary key not null,
|
||||
-- Node alias. May override the alias announced by the node.
|
||||
"alias" text default '',
|
||||
-- Tracking policy for this node.
|
||||
"policy" text default 'track'
|
||||
"policy" text default 'allow'
|
||||
--
|
||||
) strict;
|
||||
|
||||
-- Repository tracking policy.
|
||||
create table if not exists "repo-policies" (
|
||||
-- Repository seeding policies.
|
||||
create table if not exists "seeding" (
|
||||
-- Repository ID.
|
||||
"id" text primary key not null,
|
||||
-- Tracking scope for this repository.
|
||||
--
|
||||
-- Valid values are:
|
||||
--
|
||||
-- "trusted" track repository delegates and remotes in the `node-policies` table.
|
||||
-- "all" track all remotes.
|
||||
-- "followed" seed repository delegates and remotes in the `following` table.
|
||||
-- "all" seed all remotes.
|
||||
--
|
||||
"scope" text default 'trusted',
|
||||
"scope" text default 'followed',
|
||||
-- Tracking policy for this repository.
|
||||
"policy" text default 'track'
|
||||
"policy" text default 'allow'
|
||||
--
|
||||
) strict;
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ impl Config<Write> {
|
|||
/// Track a node.
|
||||
pub fn track_node(&mut self, id: &NodeId, alias: Option<&str>) -> Result<bool, Error> {
|
||||
let mut stmt = self.db.prepare(
|
||||
"INSERT INTO `node-policies` (id, alias)
|
||||
"INSERT INTO `following` (id, alias)
|
||||
VALUES (?1, ?2)
|
||||
ON CONFLICT DO UPDATE
|
||||
SET alias = ?2 WHERE alias != ?2",
|
||||
|
|
@ -134,7 +134,7 @@ impl Config<Write> {
|
|||
/// Track a repository.
|
||||
pub fn track_repo(&mut self, id: &Id, scope: Scope) -> Result<bool, Error> {
|
||||
let mut stmt = self.db.prepare(
|
||||
"INSERT INTO `repo-policies` (id, scope)
|
||||
"INSERT INTO `seeding` (id, scope)
|
||||
VALUES (?1, ?2)
|
||||
ON CONFLICT DO UPDATE
|
||||
SET scope = ?2 WHERE scope != ?2",
|
||||
|
|
@ -150,7 +150,7 @@ impl Config<Write> {
|
|||
/// Set a node's tracking policy.
|
||||
pub fn set_node_policy(&mut self, id: &NodeId, policy: Policy) -> Result<bool, Error> {
|
||||
let mut stmt = self.db.prepare(
|
||||
"INSERT INTO `node-policies` (id, policy)
|
||||
"INSERT INTO `following` (id, policy)
|
||||
VALUES (?1, ?2)
|
||||
ON CONFLICT DO UPDATE
|
||||
SET policy = ?2 WHERE policy != ?2",
|
||||
|
|
@ -166,7 +166,7 @@ impl Config<Write> {
|
|||
/// Set a repository's tracking policy.
|
||||
pub fn set_repo_policy(&mut self, id: &Id, policy: Policy) -> Result<bool, Error> {
|
||||
let mut stmt = self.db.prepare(
|
||||
"INSERT INTO `repo-policies` (id, policy)
|
||||
"INSERT INTO `seeding` (id, policy)
|
||||
VALUES (?1, ?2)
|
||||
ON CONFLICT DO UPDATE
|
||||
SET policy = ?2 WHERE policy != ?2",
|
||||
|
|
@ -181,9 +181,7 @@ impl Config<Write> {
|
|||
|
||||
/// Untrack a node.
|
||||
pub fn untrack_node(&mut self, id: &NodeId) -> Result<bool, Error> {
|
||||
let mut stmt = self
|
||||
.db
|
||||
.prepare("DELETE FROM `node-policies` WHERE id = ?")?;
|
||||
let mut stmt = self.db.prepare("DELETE FROM `following` WHERE id = ?")?;
|
||||
|
||||
stmt.bind((1, id))?;
|
||||
stmt.next()?;
|
||||
|
|
@ -193,9 +191,7 @@ impl Config<Write> {
|
|||
|
||||
/// Untrack a repository.
|
||||
pub fn untrack_repo(&mut self, id: &Id) -> Result<bool, Error> {
|
||||
let mut stmt = self
|
||||
.db
|
||||
.prepare("DELETE FROM `repo-policies` WHERE id = ?")?;
|
||||
let mut stmt = self.db.prepare("DELETE FROM `seeding` WHERE id = ?")?;
|
||||
|
||||
stmt.bind((1, id))?;
|
||||
stmt.next()?;
|
||||
|
|
@ -212,7 +208,7 @@ impl<T> Config<T> {
|
|||
Ok(matches!(
|
||||
self.node_policy(id)?,
|
||||
Some(Node {
|
||||
policy: Policy::Track,
|
||||
policy: Policy::Allow,
|
||||
..
|
||||
})
|
||||
))
|
||||
|
|
@ -223,7 +219,7 @@ impl<T> Config<T> {
|
|||
Ok(matches!(
|
||||
self.repo_policy(id)?,
|
||||
Some(Repo {
|
||||
policy: Policy::Track,
|
||||
policy: Policy::Allow,
|
||||
..
|
||||
})
|
||||
))
|
||||
|
|
@ -233,7 +229,7 @@ impl<T> Config<T> {
|
|||
pub fn node_policy(&self, id: &NodeId) -> Result<Option<Node>, Error> {
|
||||
let mut stmt = self
|
||||
.db
|
||||
.prepare("SELECT alias, policy FROM `node-policies` WHERE id = ?")?;
|
||||
.prepare("SELECT alias, policy FROM `following` WHERE id = ?")?;
|
||||
|
||||
stmt.bind((1, id))?;
|
||||
|
||||
|
|
@ -259,7 +255,7 @@ impl<T> Config<T> {
|
|||
pub fn repo_policy(&self, id: &Id) -> Result<Option<Repo>, Error> {
|
||||
let mut stmt = self
|
||||
.db
|
||||
.prepare("SELECT scope, policy FROM `repo-policies` WHERE id = ?")?;
|
||||
.prepare("SELECT scope, policy FROM `seeding` WHERE id = ?")?;
|
||||
|
||||
stmt.bind((1, id))?;
|
||||
|
||||
|
|
@ -277,7 +273,7 @@ impl<T> Config<T> {
|
|||
pub fn node_policies(&self) -> Result<Box<dyn Iterator<Item = Node>>, Error> {
|
||||
let mut stmt = self
|
||||
.db
|
||||
.prepare("SELECT id, alias, policy FROM `node-policies`")?
|
||||
.prepare("SELECT id, alias, policy FROM `following`")?
|
||||
.into_iter();
|
||||
let mut entries = Vec::new();
|
||||
|
||||
|
|
@ -301,7 +297,7 @@ impl<T> Config<T> {
|
|||
pub fn repo_policies(&self) -> Result<Box<dyn Iterator<Item = Repo>>, Error> {
|
||||
let mut stmt = self
|
||||
.db
|
||||
.prepare("SELECT id, scope, policy FROM `repo-policies`")?
|
||||
.prepare("SELECT id, scope, policy FROM `seeding`")?
|
||||
.into_iter();
|
||||
let mut entries = Vec::new();
|
||||
|
||||
|
|
@ -412,8 +408,8 @@ mod test {
|
|||
|
||||
assert!(db.track_repo(&id, Scope::All).unwrap());
|
||||
assert_eq!(db.repo_policy(&id).unwrap().unwrap().scope, Scope::All);
|
||||
assert!(db.track_repo(&id, Scope::Trusted).unwrap());
|
||||
assert_eq!(db.repo_policy(&id).unwrap().unwrap().scope, Scope::Trusted);
|
||||
assert!(db.track_repo(&id, Scope::Followed).unwrap());
|
||||
assert_eq!(db.repo_policy(&id).unwrap().unwrap().scope, Scope::Followed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -422,7 +418,7 @@ mod test {
|
|||
let mut db = Config::open(":memory:").unwrap();
|
||||
|
||||
assert!(db.track_repo(&id, Scope::All).unwrap());
|
||||
assert_eq!(db.repo_policy(&id).unwrap().unwrap().policy, Policy::Track);
|
||||
assert_eq!(db.repo_policy(&id).unwrap().unwrap().policy, Policy::Allow);
|
||||
assert!(db.set_repo_policy(&id, Policy::Block).unwrap());
|
||||
assert_eq!(db.repo_policy(&id).unwrap().unwrap().policy, Policy::Block);
|
||||
}
|
||||
|
|
@ -433,7 +429,7 @@ mod test {
|
|||
let mut db = Config::open(":memory:").unwrap();
|
||||
|
||||
assert!(db.track_node(&id, None).unwrap());
|
||||
assert_eq!(db.node_policy(&id).unwrap().unwrap().policy, Policy::Track);
|
||||
assert_eq!(db.node_policy(&id).unwrap().unwrap().policy, Policy::Allow);
|
||||
assert!(db.set_node_policy(&id, Policy::Block).unwrap());
|
||||
assert_eq!(db.node_policy(&id).unwrap().unwrap().policy, Policy::Block);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ pub enum Namespaces {
|
|||
/// All namespaces.
|
||||
#[default]
|
||||
All,
|
||||
/// The trusted set of namespaces.
|
||||
Trusted(HashSet<PublicKey>),
|
||||
/// The followed set of namespaces.
|
||||
Followed(HashSet<PublicKey>),
|
||||
}
|
||||
|
||||
impl Namespaces {
|
||||
|
|
@ -48,7 +48,7 @@ impl Namespaces {
|
|||
dst: (*NAMESPACES_GLOB).clone(),
|
||||
force: true,
|
||||
}],
|
||||
Namespaces::Trusted(pks) => pks
|
||||
Namespaces::Followed(pks) => pks
|
||||
.iter()
|
||||
.map(|pk| {
|
||||
let ns = pk.to_namespace().with_pattern(git::refspec::STAR);
|
||||
|
|
@ -65,7 +65,7 @@ impl Namespaces {
|
|||
|
||||
impl FromIterator<PublicKey> for Namespaces {
|
||||
fn from_iter<T: IntoIterator<Item = PublicKey>>(iter: T) -> Self {
|
||||
Self::Trusted(iter.into_iter().collect())
|
||||
Self::Followed(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ pub fn fetch<W: WriteRepository>(
|
|||
) -> Result<Vec<RefUpdate>, crate::storage::FetchError> {
|
||||
let namespace = match namespaces.into() {
|
||||
Namespaces::All => None,
|
||||
Namespaces::Trusted(trusted) => trusted.into_iter().next(),
|
||||
Namespaces::Followed(followed) => followed.into_iter().next(),
|
||||
};
|
||||
let mut updates = Vec::new();
|
||||
let mut callbacks = git2::RemoteCallbacks::new();
|
||||
|
|
|
|||
Loading…
Reference in New Issue