Skip to content
Snippets Groups Projects
Verified Commit be329861 authored by Levente Polyak's avatar Levente Polyak :rocket:
Browse files

feat(gitlab): protect all tags by default

parent e563bf7f
No related branches found
No related tags found
1 merge request!21Protect tags
......@@ -89,7 +89,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.16",
"syn 2.0.18",
]
[[package]]
......@@ -117,9 +117,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.21.0"
version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
[[package]]
name = "bitflags"
......@@ -212,7 +212,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.16",
"syn 2.0.18",
]
[[package]]
......@@ -301,7 +301,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn 2.0.16",
"syn 2.0.18",
]
[[package]]
......@@ -323,7 +323,7 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
dependencies = [
"darling_core 0.20.1",
"quote",
"syn 2.0.16",
"syn 2.0.18",
]
[[package]]
......@@ -541,7 +541,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.16",
"syn 2.0.18",
]
[[package]]
......@@ -593,9 +593,9 @@ dependencies = [
[[package]]
name = "gitlab"
version = "0.1511.0"
version = "0.1600.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4bcbc742604d9b6abff08caf3146031c8914748ffd351f976ce101614ea75a6"
checksum = "58e9efb0f2288b9a23f2b237f228da2c3212ad669f53fb43ed94e33e7cdc5dc1"
dependencies = [
"async-trait",
"base64 0.13.1",
......@@ -912,9 +912,9 @@ dependencies = [
[[package]]
name = "io-lifetimes"
version = "1.0.10"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi 0.3.1",
"libc",
......@@ -990,9 +990,9 @@ checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
[[package]]
name = "linux-raw-sys"
version = "0.3.7"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "lock_api"
......@@ -1006,12 +1006,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.17"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
[[package]]
name = "memchr"
......@@ -1027,14 +1024,13 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mio"
version = "0.8.6"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
checksum = "eebffdb73fe72e917997fad08bdbf31ac50b0fa91cec93e69a0662e4264d454c"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.45.0",
"windows-sys 0.48.0",
]
[[package]]
......@@ -1113,7 +1109,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.16",
"syn 2.0.18",
]
[[package]]
......@@ -1207,18 +1203,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.58"
version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8"
checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.27"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
dependencies = [
"proc-macro2",
]
......@@ -1275,7 +1271,7 @@ version = "0.11.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
dependencies = [
"base64 0.21.0",
"base64 0.21.2",
"bytes",
"encoding_rs",
"futures-core",
......@@ -1392,7 +1388,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
dependencies = [
"base64 0.21.0",
"base64 0.21.2",
]
[[package]]
......@@ -1488,7 +1484,7 @@ checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.16",
"syn 2.0.18",
]
[[package]]
......@@ -1510,7 +1506,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.16",
"syn 2.0.18",
]
[[package]]
......@@ -1550,7 +1546,7 @@ dependencies = [
"darling 0.20.1",
"proc-macro2",
"quote",
"syn 2.0.16",
"syn 2.0.18",
]
[[package]]
......@@ -1648,9 +1644,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.16"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01"
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
dependencies = [
"proc-macro2",
"quote",
......@@ -1707,7 +1703,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.16",
"syn 2.0.18",
]
[[package]]
......@@ -1754,9 +1750,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.28.1"
version = "1.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105"
checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2"
dependencies = [
"autocfg",
"bytes",
......@@ -1777,7 +1773,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.16",
"syn 2.0.18",
]
[[package]]
......@@ -1854,9 +1850,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
[[package]]
name = "unicode-ident"
version = "1.0.8"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
[[package]]
name = "unicode-normalization"
......@@ -1954,7 +1950,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.16",
"syn 2.0.18",
"wasm-bindgen-shared",
]
......@@ -1988,7 +1984,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.16",
"syn 2.0.18",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
......
......@@ -10,7 +10,7 @@ publish = false
[dependencies]
keycloak = "^20.0"
gitlab = "0.1511.0"
gitlab = "0.1600.1"
reqwest = "0.11.14"
tokio = { version = "1.25.0", features = ["rt-multi-thread", "macros", "sync"] }
futures = "0.3.26"
......
......@@ -38,7 +38,7 @@ const GITLAB_OWNER: &str = "archceo";
const GITLAB_BOT: &str = "archbot";
const MAIN_BRANCH: &str = "main";
const ALL_TAGS: &str = "*";
const ALL_TAGS_WILDCARD: &str = "*";
const GROUP_ROOT: &str = "archlinux";
const GROUP_PACKAGES: &str = "archlinux/packaging/packages";
......@@ -258,6 +258,29 @@ impl GitLabGlue {
println!("{}", summary);
println!("{}", util::format_separator());
let label =
format!("GitLab '{}' protected tags", project.name_with_namespace);
let mut summary = PlanSummary::new(&label);
let protected_tags = self.get_protected_tags(&project).await?;
let protected_tag = protected_tags
.iter()
.find(|tag| tag.name.eq(ALL_TAGS_WILDCARD));
self.protect_tag(
action,
&mut summary,
&project,
ALL_TAGS_WILDCARD,
MyProtectedAccessLevel::Developer,
protected_tag,
)
.await?;
println!("{}", summary);
println!("{}", util::format_separator());
}
}
}
......@@ -1063,6 +1086,116 @@ impl GitLabGlue {
}
Ok(true)
}
async fn get_protected_tags(&self, project: &GroupProjects) -> Result<Vec<ProtectedTag>> {
let endpoint = gitlab::api::projects::protected_tags::ProtectedTags::builder()
.project(project.id)
.build()
.unwrap();
let protected_tag: Vec<ProtectedTag> = endpoint.query_async(&self.client).await?;
Ok(protected_tag)
}
async fn get_protected_tag(&self, project: &GroupProjects, tag: &str) -> Result<ProtectedTag> {
let endpoint = gitlab::api::projects::protected_tags::ProtectedTag::builder()
.project(project.id)
.name(tag)
.build()
.unwrap();
let protected_tag: ProtectedTag = endpoint.query_async(&self.client).await?;
Ok(protected_tag)
}
async fn protect_tag(
&self,
action: &Action,
plan: &mut PlanSummary,
project: &GroupProjects,
tag: &str,
allowed_to_create: MyProtectedAccessLevel,
current_tag: Option<&ProtectedTag>,
) -> Result<bool> {
debug!(
"protecting tag {} for project {}",
tag, project.name_with_namespace
);
let mut protect = false;
let mut unprotect = false;
let access_vec = vec![allowed_to_create.clone()];
match current_tag {
Some(current_tag) => {
let current_levels: Vec<MyProtectedAccessLevel> = current_tag
.create_access_levels
.iter()
.map(|level| level.as_gitlab_type())
.collect();
if current_levels.len() > 1 || !current_levels.contains(&allowed_to_create) {
plan.change += 1;
protect = true;
unprotect = true;
util::print_diff(
util::format_gitlab_project_protected_tag(
&project.path_with_namespace,
&current_tag.name,
&current_levels,
)
.as_str(),
util::format_gitlab_project_protected_tag(
&project.path_with_namespace,
tag,
&access_vec,
)
.as_str(),
)?;
}
}
None => {
plan.add += 1;
protect = true;
util::print_diff(
"",
util::format_gitlab_project_protected_tag(
&project.path_with_namespace,
tag,
&access_vec,
)
.as_str(),
)?;
}
}
if let Action::Apply = action {
if protect {
if unprotect {
// TODO: API has to PATCH, remove unprotect if its upstreamed
let endpoint = gitlab::api::projects::protected_tags::UnprotectTag::builder()
.project(project.id)
.name(tag)
.build()
.unwrap();
gitlab::api::ignore(endpoint)
.query_async(&self.client)
.await?;
}
let endpoint = gitlab::api::projects::protected_tags::ProtectTag::builder()
.project(project.id)
.name(tag)
.create_access_level(allowed_to_create.as_gitlab_type())
.build()
.unwrap();
gitlab::api::ignore(endpoint)
.query_async(&self.client)
.await?;
}
}
Ok(true)
}
}
fn is_archlinux_bot(member: &GitLabMember) -> bool {
......@@ -1128,16 +1261,6 @@ fn unprotect_branch(client: &Gitlab, project: &GroupProjects, branch: &str) -> R
Ok(())
}
fn get_protected_tag(client: &Gitlab, project: &GroupProjects, tag: &str) -> Result<ProtectedTag> {
let endpoint = gitlab::api::projects::protected_tags::ProtectedTag::builder()
.project(project.id)
.name(tag)
.build()
.unwrap();
let protected_tag: ProtectedTag = endpoint.query(client)?;
Ok(protected_tag)
}
fn unprotect_tag(client: &Gitlab, project: &GroupProjects, tag: &str) -> Result<()> {
let endpoint = gitlab::api::projects::protected_tags::UnprotectTag::builder()
.project(project.id)
......@@ -1148,18 +1271,6 @@ fn unprotect_tag(client: &Gitlab, project: &GroupProjects, tag: &str) -> Result<
Ok(())
}
fn protect_tag(client: &Gitlab, project: &GroupProjects, tag: &str) -> Result<ProtectedTag> {
debug!("protecting tag * for project {}", project.name);
let endpoint = gitlab::api::projects::protected_tags::ProtectTag::builder()
.project(project.id)
.name(tag)
.create_access_level(gitlab::api::common::ProtectedAccessLevel::Developer)
.build()
.unwrap();
let result: ProtectedTag = endpoint.query(client)?;
Ok(result)
}
#[cfg(test)]
mod tests {
use super::*;
......
......@@ -187,6 +187,21 @@ pub struct ProtectedAccessLevel {
pub access_level_description: String,
}
impl ProtectedAccessLevel {
pub fn as_str(&self) -> &str {
&self.access_level_description
}
pub fn as_gitlab_type(&self) -> MyProtectedAccessLevel {
match self.access_level {
60 => MyProtectedAccessLevel::Admin,
40 => MyProtectedAccessLevel::Maintainer,
30 => MyProtectedAccessLevel::Developer,
_ => MyProtectedAccessLevel::NoAccess,
}
}
}
#[derive(Debug, Deserialize)]
pub struct ProtectedBranch {
pub id: u64,
......@@ -201,7 +216,7 @@ pub struct ProtectedTag {
pub create_access_levels: Vec<ProtectedAccessLevel>,
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub enum MyProtectedAccessLevel {
/// The action is not allowed at all.
NoAccess,
......@@ -213,6 +228,27 @@ pub enum MyProtectedAccessLevel {
Admin,
}
impl MyProtectedAccessLevel {
pub fn as_gitlab_type(&self) -> gitlab::api::common::ProtectedAccessLevel {
match self {
Self::Admin => gitlab::api::common::ProtectedAccessLevel::Admin,
Self::Maintainer => gitlab::api::common::ProtectedAccessLevel::Maintainer,
Self::Developer => gitlab::api::common::ProtectedAccessLevel::Developer,
Self::NoAccess => gitlab::api::common::ProtectedAccessLevel::NoAccess,
}
}
/// The variable type query parameter.
pub(crate) fn as_str(&self) -> &'static str {
match self {
Self::Admin => "admin",
Self::Maintainer => "maintainer",
Self::Developer => "developer",
Self::NoAccess => "no_access",
}
}
}
#[derive(Debug, Deserialize)]
pub struct ProtectedAccess {
pub name: String,
......
use crate::components::gitlab::types::{ProjectFeatureAccessLevel, ProjectMergeMethod};
use crate::components::gitlab::types::{
MyProtectedAccessLevel, ProjectFeatureAccessLevel, ProjectMergeMethod,
};
use anyhow::{Context, Result};
use difference::{Changeset, Difference};
use gitlab::api::common::AccessLevel;
use itertools::Itertools;
pub fn print_diff(text1: &str, text2: &str) -> Result<()> {
let Changeset { diffs, .. } = Changeset::new(text1, text2, "\n");
......@@ -129,6 +132,26 @@ pub fn format_gitlab_group_settings(path: &str, request_access_enabled: bool) ->
)
}
pub fn format_gitlab_project_protected_tag(
namespace: &str,
name: &str,
create_access_level: &[MyProtectedAccessLevel],
) -> String {
format!(
"gitlab_project_protected_tag {{\n\
\tnamespace = {}\n\
\tname = {}\n\
\tcreate_access_level = {}\n\
}}",
namespace,
name,
create_access_level
.iter()
.map(|access| access.as_str())
.join(", ")
)
}
pub fn format_separator() -> String {
"-".repeat(72)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment