diff --git a/bin/core/src/api/read/alert.rs b/bin/core/src/api/read/alert.rs index 612f15f39..8186180ef 100644 --- a/bin/core/src/api/read/alert.rs +++ b/bin/core/src/api/read/alert.rs @@ -13,8 +13,7 @@ use mungos::{ use resolver_api::Resolve; use crate::{ - helpers::query::get_resource_ids_for_non_admin, - state::{db_client, State}, + config::core_config, helpers::query::get_resource_ids_for_non_admin, state::{db_client, State} }; const NUM_ALERTS_PER_PAGE: u64 = 100; @@ -26,7 +25,7 @@ impl Resolve for State { user: User, ) -> anyhow::Result { let mut query = query.unwrap_or_default(); - if !user.admin { + if !user.admin && !core_config().transparent_mode { let server_ids = get_resource_ids_for_non_admin( &user.id, ResourceTargetVariant::Server, diff --git a/bin/core/src/api/read/alerter.rs b/bin/core/src/api/read/alerter.rs index 1c0b5e73e..71b07b6a1 100644 --- a/bin/core/src/api/read/alerter.rs +++ b/bin/core/src/api/read/alerter.rs @@ -14,9 +14,7 @@ use mungos::mongodb::bson::{doc, oid::ObjectId}; use resolver_api::Resolve; use crate::{ - helpers::query::get_resource_ids_for_non_admin, - resource, - state::{db_client, State}, + config::core_config, helpers::query::get_resource_ids_for_non_admin, resource, state::{db_client, State} }; impl Resolve for State { @@ -50,7 +48,7 @@ impl Resolve for State { GetAlertersSummary {}: GetAlertersSummary, user: User, ) -> anyhow::Result { - let query = if user.admin { + let query = if user.admin || core_config().transparent_mode { None } else { let ids = get_resource_ids_for_non_admin( diff --git a/bin/core/src/api/read/build.rs b/bin/core/src/api/read/build.rs index 4bcaed5d0..81df3746f 100644 --- a/bin/core/src/api/read/build.rs +++ b/bin/core/src/api/read/build.rs @@ -1,6 +1,5 @@ use std::{ collections::{HashMap, HashSet}, - str::FromStr, sync::OnceLock, }; @@ -12,23 +11,19 @@ use monitor_client::{ entities::{ build::{Build, BuildActionState, BuildListItem, BuildState}, permission::PermissionLevel, - update::{ResourceTargetVariant, UpdateStatus}, + update::UpdateStatus, user::User, Operation, }, }; use mungos::{ find::find_collect, - mongodb::{ - bson::{doc, oid::ObjectId}, - options::FindOptions, - }, + mongodb::{bson::doc, options::FindOptions}, }; use resolver_api::{Resolve, ResolveToString}; use crate::{ config::core_config, - helpers::query::get_resource_ids_for_non_admin, resource, state::{action_states, build_state_cache, db_client, State}, }; @@ -86,31 +81,18 @@ impl Resolve for State { GetBuildsSummary {}: GetBuildsSummary, user: User, ) -> anyhow::Result { - let query = if user.admin { - None - } else { - let ids = get_resource_ids_for_non_admin( - &user.id, - ResourceTargetVariant::Build, - ) - .await? - .into_iter() - .flat_map(|id| ObjectId::from_str(&id)) - .collect::>(); - let query = doc! { - "_id": { "$in": ids } - }; - Some(query) - }; + let builds = resource::list_full_for_user::( + Default::default(), + &user, + ) + .await + .context("failed to get all builds")?; - let builds = find_collect(&db_client().await.builds, query, None) - .await - .context("failed to find all build documents")?; let mut res = GetBuildsSummaryResponse::default(); let cache = build_state_cache(); let action_states = action_states(); - + for build in builds { res.total += 1; @@ -241,9 +223,7 @@ impl Resolve for State { let versions = find_collect( &db_client().await.updates, filter, - FindOptions::builder() - .sort(doc! { "_id": -1 }) - .build(), + FindOptions::builder().sort(doc! { "_id": -1 }).build(), ) .await .context("failed to pull versions from mongo")? diff --git a/bin/core/src/api/read/builder.rs b/bin/core/src/api/read/builder.rs index 1a8bea5dc..420211d57 100644 --- a/bin/core/src/api/read/builder.rs +++ b/bin/core/src/api/read/builder.rs @@ -51,7 +51,7 @@ impl Resolve for State { GetBuildersSummary {}: GetBuildersSummary, user: User, ) -> anyhow::Result { - let query = if user.admin { + let query = if user.admin || core_config().transparent_mode { None } else { let ids = get_resource_ids_for_non_admin( diff --git a/bin/core/src/api/read/deployment.rs b/bin/core/src/api/read/deployment.rs index e04045eaa..5e9941304 100644 --- a/bin/core/src/api/read/deployment.rs +++ b/bin/core/src/api/read/deployment.rs @@ -1,4 +1,4 @@ -use std::{cmp, collections::HashSet, str::FromStr}; +use std::{cmp, collections::HashSet}; use anyhow::{anyhow, Context}; use monitor_client::{ @@ -10,23 +10,17 @@ use monitor_client::{ }, permission::PermissionLevel, server::Server, - update::{Log, ResourceTargetVariant}, + update::Log, user::User, }, }; -use mungos::{ - find::find_collect, - mongodb::bson::{doc, oid::ObjectId}, -}; use periphery_client::api; use resolver_api::Resolve; use crate::{ - helpers::{ - periphery_client, query::get_resource_ids_for_non_admin, - }, + helpers::periphery_client, resource, - state::{action_states, db_client, deployment_status_cache, State}, + state::{action_states, deployment_status_cache, State}, }; impl Resolve for State { @@ -200,27 +194,12 @@ impl Resolve for State { GetDeploymentsSummary {}: GetDeploymentsSummary, user: User, ) -> anyhow::Result { - let query = if user.admin { - None - } else { - let ids = get_resource_ids_for_non_admin( - &user.id, - ResourceTargetVariant::Deployment, - ) - .await? - .into_iter() - .flat_map(|id| ObjectId::from_str(&id)) - .collect::>(); - let query = doc! { - "_id": { "$in": ids } - }; - Some(query) - }; - - let deployments = - find_collect(&db_client().await.deployments, query, None) - .await - .context("failed to find all deployment documents")?; + let deployments = resource::list_full_for_user::( + Default::default(), + &user, + ) + .await + .context("failed to get deployments from db")?; let mut res = GetDeploymentsSummaryResponse::default(); let status_cache = deployment_status_cache(); for deployment in deployments { diff --git a/bin/core/src/api/read/mod.rs b/bin/core/src/api/read/mod.rs index aa8e5c276..3bc8277bd 100644 --- a/bin/core/src/api/read/mod.rs +++ b/bin/core/src/api/read/mod.rs @@ -211,6 +211,7 @@ impl Resolve for State { .github_webhook_base_url .clone() .unwrap_or_else(|| config.host.clone()), + transparent_mode: config.transparent_mode, }) } } diff --git a/bin/core/src/api/read/procedure.rs b/bin/core/src/api/read/procedure.rs index 772314d93..3e9504389 100644 --- a/bin/core/src/api/read/procedure.rs +++ b/bin/core/src/api/read/procedure.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use anyhow::Context; use monitor_client::{ api::read::{ @@ -11,20 +9,14 @@ use monitor_client::{ entities::{ permission::PermissionLevel, procedure::{Procedure, ProcedureState}, - update::ResourceTargetVariant, user::User, }, }; -use mungos::{ - find::find_collect, - mongodb::bson::{doc, oid::ObjectId}, -}; use resolver_api::Resolve; use crate::{ - helpers::query::get_resource_ids_for_non_admin, resource, - state::{action_states, db_client, procedure_state_cache, State}, + state::{action_states, procedure_state_cache, State}, }; impl Resolve for State { @@ -58,27 +50,12 @@ impl Resolve for State { GetProceduresSummary {}: GetProceduresSummary, user: User, ) -> anyhow::Result { - let query = if user.admin { - None - } else { - let ids = get_resource_ids_for_non_admin( - &user.id, - ResourceTargetVariant::Procedure, - ) - .await? - .into_iter() - .flat_map(|id| ObjectId::from_str(&id)) - .collect::>(); - let query = doc! { - "_id": { "$in": ids } - }; - Some(query) - }; - - let procedures = - find_collect(&db_client().await.procedures, query, None) - .await - .context("failed to find all procedure documents")?; + let procedures = resource::list_full_for_user::( + Default::default(), + &user, + ) + .await + .context("failed to get procedures from db")?; let mut res = GetProceduresSummaryResponse::default(); diff --git a/bin/core/src/api/read/repo.rs b/bin/core/src/api/read/repo.rs index 285b1313f..295890d08 100644 --- a/bin/core/src/api/read/repo.rs +++ b/bin/core/src/api/read/repo.rs @@ -1,25 +1,17 @@ -use std::str::FromStr; - use anyhow::Context; use monitor_client::{ api::read::*, entities::{ permission::PermissionLevel, repo::{Repo, RepoActionState, RepoListItem, RepoState}, - update::ResourceTargetVariant, user::User, }, }; -use mungos::{ - find::find_collect, - mongodb::bson::{doc, oid::ObjectId}, -}; use resolver_api::Resolve; use crate::{ - helpers::query::get_resource_ids_for_non_admin, resource, - state::{action_states, db_client, repo_state_cache, State}, + state::{action_states, repo_state_cache, State}, }; impl Resolve for State { @@ -75,26 +67,11 @@ impl Resolve for State { GetReposSummary {}: GetReposSummary, user: User, ) -> anyhow::Result { - let query = if user.admin { - None - } else { - let ids = get_resource_ids_for_non_admin( - &user.id, - ResourceTargetVariant::Alerter, - ) - .await? - .into_iter() - .flat_map(|id| ObjectId::from_str(&id)) - .collect::>(); - let query = doc! { - "_id": { "$in": ids } - }; - Some(query) - }; + let repos = + resource::list_full_for_user::(Default::default(), &user) + .await + .context("failed to get repos from db")?; - let repos = find_collect(&db_client().await.repos, query, None) - .await - .context("failed to find all repo documents")?; let mut res = GetReposSummaryResponse::default(); let cache = repo_state_cache(); diff --git a/bin/core/src/api/read/server_template.rs b/bin/core/src/api/read/server_template.rs index 3a21aa52b..67c2c9a66 100644 --- a/bin/core/src/api/read/server_template.rs +++ b/bin/core/src/api/read/server_template.rs @@ -68,10 +68,10 @@ impl Resolve for State { }; let total = db_client() .await - .builders + .server_templates .count_documents(query, None) .await - .context("failed to count all builder documents")?; + .context("failed to count all server template documents")?; let res = GetServerTemplatesSummaryResponse { total: total as u32, }; diff --git a/bin/core/src/api/read/update.rs b/bin/core/src/api/read/update.rs index 25d33e87c..a18a3642e 100644 --- a/bin/core/src/api/read/update.rs +++ b/bin/core/src/api/read/update.rs @@ -27,6 +27,7 @@ use mungos::{ use resolver_api::Resolve; use crate::{ + config::core_config, helpers::query::get_resource_ids_for_non_admin, resource, state::{db_client, State}, @@ -40,7 +41,7 @@ impl Resolve for State { ListUpdates { query, page }: ListUpdates, user: User, ) -> anyhow::Result { - let query = if user.admin { + let query = if user.admin || core_config().transparent_mode { query } else { let server_ids = get_resource_ids_for_non_admin( @@ -163,7 +164,7 @@ impl Resolve for State { .await .context("failed to query to db")? .context("no update exists with given id")?; - if user.admin { + if user.admin || core_config().transparent_mode { return Ok(update); } match &update.target { diff --git a/bin/core/src/config.rs b/bin/core/src/config.rs index 902a7d44f..c5e3c27de 100644 --- a/bin/core/src/config.rs +++ b/bin/core/src/config.rs @@ -77,6 +77,10 @@ pub fn core_config() -> &'static CoreConfig { .monitor_logging_opentelemetry_service_name .unwrap_or(config.logging.opentelemetry_service_name); + config.transparent_mode = env + .monitor_transparent_mode + .unwrap_or(config.transparent_mode); + config.local_auth = env.monitor_local_auth.unwrap_or(config.local_auth); diff --git a/bin/core/src/helpers/query.rs b/bin/core/src/helpers/query.rs index bd162b05e..3aec4ae84 100644 --- a/bin/core/src/helpers/query.rs +++ b/bin/core/src/helpers/query.rs @@ -19,7 +19,7 @@ use mungos::{ mongodb::bson::{doc, oid::ObjectId, Document}, }; -use crate::{resource, state::db_client}; +use crate::{config::core_config, resource, state::db_client}; #[instrument(level = "debug")] pub async fn get_user(user_id: &str) -> anyhow::Result { @@ -150,6 +150,11 @@ pub async fn get_user_permission_on_resource( resource_variant: ResourceTargetVariant, resource_id: &str, ) -> anyhow::Result { + let lowest_permission = if core_config().transparent_mode { + PermissionLevel::Read + } else { + PermissionLevel::None + }; let permission = find_collect( &db_client().await.permissions, doc! { @@ -163,7 +168,7 @@ pub async fn get_user_permission_on_resource( .context("failed to query db for permissions")? .into_iter() // get the max permission user has between personal / any user groups - .fold(PermissionLevel::None, |level, permission| { + .fold(lowest_permission, |level, permission| { if permission.level > level { permission.level } else { diff --git a/bin/core/src/resource/mod.rs b/bin/core/src/resource/mod.rs index 188c8aedb..3aac6c6bb 100644 --- a/bin/core/src/resource/mod.rs +++ b/bin/core/src/resource/mod.rs @@ -28,6 +28,7 @@ use serde::{de::DeserializeOwned, Serialize}; use serror::serialize_error_pretty; use crate::{ + config::core_config, helpers::{ create_permission, query::{ @@ -191,7 +192,10 @@ pub async fn get_check_permissions( permission_level: PermissionLevel, ) -> anyhow::Result> { let resource = get::(id_or_name).await?; - if user.admin { + if user.admin + || (permission_level <= PermissionLevel::Read + && core_config().transparent_mode) + { return Ok(resource); } let permissions = get_user_permission_on_resource( @@ -249,7 +253,7 @@ async fn list_full_for_user_using_document( mut filters: Document, user: &User, ) -> anyhow::Result>> { - if !user.admin { + if !user.admin && !core_config().transparent_mode { let ids = get_resource_ids_for_non_admin(&user.id, T::resource_type()) .await? diff --git a/client/core/rs/src/api/read/mod.rs b/client/core/rs/src/api/read/mod.rs index 20173140f..50451b5d0 100644 --- a/client/core/rs/src/api/read/mod.rs +++ b/client/core/rs/src/api/read/mod.rs @@ -85,4 +85,6 @@ pub struct GetCoreInfoResponse { pub monitoring_interval: Timelength, /// The github webhook base url to use with github webhooks. pub github_webhook_base_url: String, + /// Whether transparent mode is enabled, which gives all users read access to all resources. + pub transparent_mode: bool } diff --git a/client/core/rs/src/entities/config/core.rs b/client/core/rs/src/entities/config/core.rs index ba93e663f..1e04720c6 100644 --- a/client/core/rs/src/entities/config/core.rs +++ b/client/core/rs/src/entities/config/core.rs @@ -67,6 +67,9 @@ pub struct Env { /// Override `logging.opentelemetry_service_name` pub monitor_logging_opentelemetry_service_name: Option, + /// Override `transparent_mode` + pub monitor_transparent_mode: Option, + /// Override `local_auth` pub monitor_local_auth: Option, @@ -185,6 +188,9 @@ fn default_config_path() -> String { /// ## if empty, the "docker organization" config option will not be shown. /// ## default: empty /// # docker_organizations = ["your_docker_org1", "your_docker_org_2"] +/// +/// ## allows all users to have read access on all resources +/// # transparent_mode = true /// /// ## allow or deny user login with username / password /// ## default: false @@ -296,6 +302,10 @@ pub struct CoreConfig { #[serde(default)] pub logging: LogConfig, + /// Enable transparent mode, which gives all (enabled) users read access to all resources. + #[serde(default)] + pub transparent_mode: bool, + /// enable login with local auth #[serde(default)] pub local_auth: bool, diff --git a/config_example/core.config.example.toml b/config_example/core.config.example.toml index 2c764ca9a..58108b7c4 100644 --- a/config_example/core.config.example.toml +++ b/config_example/core.config.example.toml @@ -63,6 +63,9 @@ passkey = "a_random_passkey" ## default: empty # docker_organizations = ["your_docker_org1", "your_docker_org_2"] +## allows all users to have read access on all resources +# transparent_mode = true + ## allow or deny user login with username / password ## default: false # local_auth = true