cli: Consolidate policy/scope variants

* Policy::Track -> Policy::Allow
* Scope::Trusted -> Scope::Followed
This commit is contained in:
cloudhead 2023-12-01 13:13:23 +01:00
parent 4605348d68
commit f453090e27
No known key found for this signature in database
25 changed files with 128 additions and 132 deletions

View File

@ -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

View File

@ -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
```

View File

@ -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..

View File

@ -37,7 +37,7 @@ $ rad config
}
},
"policy": "block",
"scope": "trusted"
"scope": "followed"
}
}
```

View File

@ -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)

View File

@ -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 .

View File

@ -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
╰───────────────────────────────────────────────────────────────────────────╯
```

View File

@ -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'
```

View File

@ -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!(

View File

@ -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
"#,

View File

@ -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"))
});

View File

@ -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())

View File

@ -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 })
}
},
}

View File

@ -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 {

View File

@ -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!(

View File

@ -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();

View File

@ -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(),
},
})),

View File

@ -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,

View File

@ -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();

View File

@ -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)

View File

@ -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))
}
}
},

View File

@ -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;

View File

@ -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);
}

View File

@ -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())
}
}

View File

@ -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();