feat: add the AnyDelegate filter

This commit is contained in:
Lars Wirzenius
2025-11-10 17:13:15 +02:00
parent 31543ca1db
commit 94fbd9f72f
2 changed files with 63 additions and 1 deletions
+37
View File
@@ -1234,6 +1234,43 @@ sed -i "s/NODEID/$rid/g" "$yaml"
~~~
## Filter predicate `AnyDelegate`
_Want:_ We can allow an event that originates in a node for any delegate.
_Why:_ We want to constrain CI to privileged developers for a repository.
~~~scenario
given a Radicle node, with CI configured with broker.yaml and adapter dummy.sh
given a Git repository xyzzy in the Radicle node
given a Git repository other in the Radicle node
given file config.yaml from filter-anydelegate.yaml
given file update-nodeid.sh
when I run bash update-nodeid.sh xyzzy config.yaml
when I run cibtool --db ci-broker.db trigger --repo xyzzy --commit HEAD
when I run cibtool --db ci-broker.db trigger --repo other --commit HEAD --node z6MkgEMYod7Hxfy9qCvDv5hYHkZ4ciWmLFgfvm3Wn1b2w2FV
when I run ./env.sh cib --config config.yaml queued
when I run cibtool --db ci-broker.db run list --json
then stdout contains ""repo_name": "xyzzy""
then stdout doesn't contain ""repo_name": "other""
~~~
~~~{#filter-anydelegate.yaml .file .json}
db: ci-broker.db
adapters:
default:
command: ./adapter.sh
triggers:
- adapter: default
filters:
- !AnyDelegate
~~~
## Filter predicate `Tag`
_Want:_ We can allow an event that is about a specific tag.
+26 -1
View File
@@ -1,5 +1,6 @@
use std::path::{Path, PathBuf};
use radicle_crypto::PublicKey;
use regex::Regex;
use serde::{Deserialize, Serialize};
@@ -8,7 +9,7 @@ use radicle::{
git::{BranchName, Oid, raw::ObjectType},
node::NodeId,
prelude::{Profile, RepoId},
storage::git::Repository,
storage::{ReadRepository, git::Repository},
};
use crate::{
@@ -92,6 +93,11 @@ pub enum EventFilter {
/// Change originated from specific node.
Node(NodeId),
/// Change originated from any delegate node. Note that will change to
/// "from delegate" once Radicle separates the "user" and "node"
/// concepts.
AnyDelegate,
/// Commit in change contains a file or directory with this name.
HasFile(PathBuf),
@@ -147,6 +153,25 @@ impl EventFilter {
format!("wanted={wanted} actual={actual:?}"),
)
}
#[allow(clippy::unwrap_used)]
Self::AnyDelegate => {
let repo_id = event.repository().unwrap();
let radicle = crate::ergo::Radicle::new().unwrap();
let repo = radicle.repository(repo_id).unwrap();
let origin = event.from_node().unwrap();
let delegates: Vec<PublicKey> = repo
.delegates()
.iter()
.flatten()
.map(|d| *d.as_key())
.collect();
let allowed = delegates.contains(origin);
Decision::string(
"AnyDelegate",
allowed,
format!("wanted={origin} delegates={delegates:?}",),
)
}
Self::Repository(wanted) => {
let actual = event.repository();
let allowed = Some(wanted) == actual;