path_acls: parse repo regions configuration in Mononoke

Summary: Adding a new field to the `RepoConfig`. Not used anywhere yet.

Reviewed By: markbt

Differential Revision: D34555579

fbshipit-source-id: cba8e3eeeb1ebbc2341f1bf55cc741bdfa7a1279
This commit is contained in:
Ilia Medianikov 2022-03-16 03:41:42 -07:00 committed by Facebook GitHub Bot
parent d13ba93dd2
commit 188d65defb
7 changed files with 236 additions and 16 deletions

View File

@ -1,4 +1,4 @@
// @generated SignedSource<<b2d2c0d4013f8eb421d0be15b74a2a75>>
// @generated SignedSource<<9d8514cd3c8cd9adab4e3a6a50f2b688>>
// DO NOT EDIT THIS FILE MANUALLY!
// This file is a mechanical copy of the version in the configerator repo. To
// modify it, edit the copy in the configerator repo instead and copy it over by
@ -43,6 +43,7 @@ struct RawRepoConfigs {
2: RawCommonConfig common,
3: map<string, RawRepoConfig> (rust.type = "HashMap") repos, # to be renamed to repo_configs
4: map<string, RawStorageConfig> (rust.type = "HashMap") storage, # to be renamed to storage_configs
6: map<string, RawAclRegionConfig> (rust.type = "HashMap") acl_region_configs,
5: RawRepoDefinitions repo_definitions,
} (rust.exhaustive)
@ -86,6 +87,10 @@ struct RawRepoDefinition {
// In case this is a backup repo, what's the origin repo name?
10: optional string backup_source_repo_name,
// Key into RawRepoConfigs.acl_region_configs for the definition of
// ACL regions for this repo.
11: optional string acl_region_config,
} (rust.exhaustive)
struct RawRepoConfig {
@ -650,3 +655,51 @@ struct RawSegmentedChangelogConfig {
// ancestors to the reseeded segmented changelog.
8: optional list<string> bonsai_changesets_to_include,
} (rust.exhaustive)
// Describe ACL Regions for a repository.
//
// This is a set of rules which define regions of the repository (commits and paths)
struct RawAclRegionConfig {
// List of rules that grant access to regions of the repo.
1: list<RawAclRegionRule> allow_rules,
// List of regions to which default access to the repository is denied.
// 2: list<RawAclRegion> deny_default_regions, (not yet implemented)
} (rust.exhaustive)
struct RawAclRegionRule {
// The name of this region rule. This is used in error messages and diagnostics.
1: string name,
// A list of regions that this rule applies to.
2: list<RawAclRegion> regions,
// The hipster ACL that defines who is permitted to access the regions of
// the repo defined by this rule.
3: string hipster_acl,
} (rust.exhaustive)
// Define a region of the repository, in terms of commits and path prefixes.
//
// The commit range is equivalent to the Mercurial revset
// descendants(roots) - descendants(heads)
//
// If the roots and heads lists are both empty then this region covers the
// entire repo.
struct RawAclRegion {
// List of roots that begin this region. Any commit that is a descendant of any
// root, including the root itself, will be included in the region. If this
// list is empty then all commits are included (provided they are not the
// descendant of a head).
1: list<string> roots,
// List of heads that end this region. Any commit that is a descendant of
// any head, includin the head itself, will NOT be included in the region.
// If this list is empty then all commits that are descendants of the roots
// are included.
2: list<string> heads,
// List of path prefixes that apply to this region. Prefixes are in terms of
// path elements, so the prefix a/b applies to a/b/c but not a/bb.
3: list<string> path_prefixes,
} (rust.exhaustive)

View File

@ -27,5 +27,6 @@ toml = "=0.5.8"
[dev-dependencies]
maplit = "1.0"
mononoke_types-mocks = { version = "0.1.0", path = "../../mononoke_types/mocks" }
pretty_assertions = "0.6"
tempdir = "0.3"

View File

@ -23,7 +23,10 @@ use metaconfig_types::{
StorageConfig,
};
use mononoke_types::RepositoryId;
use repos::{RawCommonConfig, RawRepoConfig, RawRepoConfigs, RawRepoDefinition, RawStorageConfig};
use repos::{
RawAclRegionConfig, RawCommonConfig, RawRepoConfig, RawRepoConfigs, RawRepoDefinition,
RawStorageConfig,
};
const LIST_KEYS_PATTERNS_MAX_DEFAULT: u64 = 500_000;
const HOOK_MAX_FILE_SIZE_DEFAULT: u64 = 8 * 1024 * 1024; // 8MiB
@ -59,6 +62,7 @@ pub fn load_repo_configs(
common,
repos,
storage,
acl_region_configs,
repo_definitions,
} = crate::raw::read_raw_configs(config_path.as_ref(), config_store)?;
let repo_definitions = repo_definitions.repo_definitions;
@ -70,8 +74,12 @@ pub fn load_repo_configs(
let mut repoids = HashSet::new();
for (reponame, raw_repo_definition) in repo_definitions.into_iter() {
let repo_config =
parse_with_repo_definition(raw_repo_definition, &repo_configs, &storage_configs)?;
let repo_config = parse_with_repo_definition(
raw_repo_definition,
&repo_configs,
&storage_configs,
&acl_region_configs,
)?;
if !repoids.insert(repo_config.repoid) {
return Err(ConfigurationError::DuplicatedRepoId(repo_config.repoid).into());
@ -92,6 +100,7 @@ fn parse_with_repo_definition(
repo_definition: RawRepoDefinition,
named_repo_configs: &HashMap<String, RawRepoConfig>,
named_storage_configs: &HashMap<String, RawStorageConfig>,
named_acl_region_configs: &HashMap<String, RawAclRegionConfig>,
) -> Result<RepoConfig> {
let RawRepoDefinition {
repo_id: repoid,
@ -104,6 +113,7 @@ fn parse_with_repo_definition(
readonly,
needs_backup: _,
external_repo_id: _,
acl_region_config,
} = repo_definition;
let named_repo_config_name = repo_config
@ -266,6 +276,17 @@ fn parse_with_repo_definition(
let repo_client_knobs = repo_client_knobs.convert()?.unwrap_or_default();
let acl_region_config = acl_region_config
.map(|key| {
named_acl_region_configs.get(&key).cloned().ok_or_else(|| {
ConfigurationError::InvalidConfig(format!(
"ACL region config \"{}\" not defined",
key
))
})
})
.transpose()?
.convert()?;
Ok(RepoConfig {
enabled,
@ -303,6 +324,7 @@ fn parse_with_repo_definition(
repo_client_knobs,
phabricator_callsign,
backup_repo_config,
acl_region_config,
})
}
@ -444,18 +466,19 @@ mod test {
use cached_config::TestSource;
use maplit::{btreemap, hashmap, hashset};
use metaconfig_types::{
BlameVersion, BlobConfig, BlobstoreId, BookmarkParams, Bundle2ReplayParams,
CacheWarmupParams, CommitSyncConfig, CommitSyncConfigVersion, DatabaseConfig,
DefaultSmallToLargeCommitSyncPathAction, DerivedDataConfig, DerivedDataTypesConfig,
EphemeralBlobstoreConfig, FilestoreParams, HookBypass, HookConfig, HookManagerParams,
HookParams, InfinitepushNamespace, InfinitepushParams, LfsParams, LocalDatabaseConfig,
MetadataDatabaseConfig, MultiplexId, MultiplexedStoreType, PushParams, PushrebaseFlags,
PushrebaseParams, RemoteDatabaseConfig, RemoteMetadataDatabaseConfig, RepoClientKnobs,
SegmentedChangelogConfig, ShardableRemoteDatabaseConfig, ShardedRemoteDatabaseConfig,
SmallRepoCommitSyncConfig, SourceControlServiceMonitoring, SourceControlServiceParams,
UnodeVersion,
AclRegion, AclRegionConfig, AclRegionRule, BlameVersion, BlobConfig, BlobstoreId,
BookmarkParams, Bundle2ReplayParams, CacheWarmupParams, CommitSyncConfig,
CommitSyncConfigVersion, DatabaseConfig, DefaultSmallToLargeCommitSyncPathAction,
DerivedDataConfig, DerivedDataTypesConfig, EphemeralBlobstoreConfig, FilestoreParams,
HookBypass, HookConfig, HookManagerParams, HookParams, InfinitepushNamespace,
InfinitepushParams, LfsParams, LocalDatabaseConfig, MetadataDatabaseConfig, MultiplexId,
MultiplexedStoreType, PushParams, PushrebaseFlags, PushrebaseParams, RemoteDatabaseConfig,
RemoteMetadataDatabaseConfig, RepoClientKnobs, SegmentedChangelogConfig,
ShardableRemoteDatabaseConfig, ShardedRemoteDatabaseConfig, SmallRepoCommitSyncConfig,
SourceControlServiceMonitoring, SourceControlServiceParams, UnodeVersion,
};
use mononoke_types::MPath;
use mononoke_types_mocks::changesetid::ONES_CSID;
use nonzero_ext::nonzero;
use pretty_assertions::assert_eq;
use regex::Regex;
@ -797,6 +820,7 @@ mod test {
repo_config="fbsource"
needs_backup=false
backup_source_repo_name="source"
acl_region_config="fbsource"
"#;
let www_content = r#"
scuba_table_hooks="scm_hooks"
@ -861,11 +885,22 @@ mod test {
path = "/tmp/www-ephemeral"
"#;
let acl_region_configs = r#"
[[fbsource.allow_rules]]
name = "name_test"
hipster_acl = "acl_test"
[[fbsource.allow_rules.regions]]
roots = ["1111111111111111111111111111111111111111111111111111111111111111"]
heads = []
path_prefixes = ["test/prefix"]
"#;
let paths = btreemap! {
"common/storage.toml" => storage,
"common/common.toml" => common_content,
"common/commitsyncmap.toml" => "",
"common/acl_regions.toml" => acl_region_configs,
"repos/fbsource/server.toml" => fbsource_content,
"repos/www/server.toml" => www_content,
"repo_definitions/fbsource/server.toml" => fbsource_repo_def,
@ -1087,6 +1122,17 @@ mod test {
backup_repo_config: Some(BackupRepoConfig {
source_repo_name: "source".to_string(),
}),
acl_region_config: Some(AclRegionConfig {
allow_rules: vec![AclRegionRule {
name: "name_test".to_string(),
regions: vec![AclRegion {
roots: vec![ONES_CSID],
heads: vec![],
path_prefixes: vec![MPath::new("test/prefix").unwrap()],
}],
hipster_acl: "acl_test".to_string(),
}],
}),
},
);
@ -1153,6 +1199,7 @@ mod test {
repo_client_knobs: RepoClientKnobs::default(),
phabricator_callsign: Some("WWW".to_string()),
backup_repo_config: None,
acl_region_config: None,
},
);
assert_eq!(

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
use std::str::FromStr;
use anyhow::Result;
use metaconfig_types::{AclRegion, AclRegionConfig, AclRegionRule};
use mononoke_types::{ChangesetId, MPath};
use repos::{RawAclRegion, RawAclRegionConfig, RawAclRegionRule};
use crate::convert::Convert;
impl Convert for RawAclRegion {
type Output = AclRegion;
fn convert(self) -> Result<Self::Output> {
Ok(AclRegion {
roots: self
.roots
.into_iter()
.map(|s| ChangesetId::from_str(&s))
.collect::<Result<Vec<_>>>()?,
heads: self
.heads
.into_iter()
.map(|s| ChangesetId::from_str(&s))
.collect::<Result<Vec<_>>>()?,
path_prefixes: self
.path_prefixes
.into_iter()
.map(|b| MPath::try_from(&*b))
.collect::<Result<Vec<_>>>()?,
})
}
}
impl Convert for RawAclRegionRule {
type Output = AclRegionRule;
fn convert(self) -> Result<Self::Output> {
Ok(AclRegionRule {
name: self.name,
regions: self.regions.convert()?,
hipster_acl: self.hipster_acl,
})
}
}
impl Convert for RawAclRegionConfig {
type Output = AclRegionConfig;
fn convert(self) -> Result<Self::Output> {
Ok(AclRegionConfig {
allow_rules: self.allow_rules.convert()?,
})
}
}

View File

@ -7,6 +7,7 @@
use anyhow::Result;
mod acl_regions;
mod commit_sync;
pub(crate) mod repo;
mod storage;

View File

@ -11,8 +11,8 @@ use std::path::Path;
use anyhow::{anyhow, Result};
use cached_config::ConfigStore;
use repos::{
RawCommitSyncConfig, RawCommonConfig, RawRepoConfig, RawRepoConfigs, RawRepoDefinition,
RawRepoDefinitions, RawStorageConfig,
RawAclRegionConfig, RawCommitSyncConfig, RawCommonConfig, RawRepoConfig, RawRepoConfigs,
RawRepoDefinition, RawRepoDefinitions, RawStorageConfig,
};
use crate::errors::ConfigurationError;
@ -62,6 +62,13 @@ fn read_raw_configs_toml(config_path: &Path) -> Result<RawRepoConfigs> {
config_path.join("common").join("storage.toml").as_path(),
true,
)?;
let acl_region_configs = read_toml_path::<HashMap<String, RawAclRegionConfig>>(
config_path
.join("common")
.join("acl_regions.toml")
.as_path(),
true,
)?;
let mut repo_definitions_map = HashMap::new();
let repo_definitions_dir = config_path.join("repo_definitions");
@ -129,6 +136,7 @@ fn read_raw_configs_toml(config_path: &Path) -> Result<RawRepoConfigs> {
common,
repos,
storage,
acl_region_configs,
repo_definitions,
})
}

View File

@ -207,6 +207,8 @@ pub struct RepoConfig {
/// If it's a backup repo, then this field stores information
/// about the backup configuration
pub backup_repo_config: Option<BackupRepoConfig>,
/// ACL region configuration
pub acl_region_config: Option<AclRegionConfig>,
}
/// Backup repo configuration
@ -1534,3 +1536,50 @@ impl Default for SegmentedChangelogConfig {
}
}
}
/// Define a region of the repository, in terms of commits and path prefixes.
///
/// The commit range is equivalent to the Mercurial revset
/// descendants(roots) - descendants(heads)
///
/// If the roots and heads lists are both empty then this region covers the
/// entire repo.
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct AclRegion {
/// List of roots that begin this region. Any commit that is a descendant of any
/// root, including the root itself, will be included in the region. If this
/// list is empty then all commits are included (provided they are not the
/// descendant of a head).
pub roots: Vec<ChangesetId>,
/// List of heads that end this region. Any commit that is a descendant of
/// any head, includin the head itself, will NOT be included in the region.
/// If this list is empty then all commits that are descendants of the roots
/// are included.
pub heads: Vec<ChangesetId>,
/// List of path prefixes that apply to this region. Prefixes are in terms of
/// path elements, so the prefix a/b applies to a/b/c but not a/bb.
pub path_prefixes: Vec<MPath>,
}
/// ACL region rule consisting of multiple regions and path prefixes
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct AclRegionRule {
/// The name of this region rule. This is used in error messages and diagnostics.
pub name: String,
/// A list of regions that this rule applies to.
pub regions: Vec<AclRegion>,
/// The hipster ACL that defines who is permitted to access the regions of
/// the repo defined by this rule.
pub hipster_acl: String,
}
/// Describe ACL Regions for a repository.
///
/// This is a set of rules which define regions of the repository (commits and paths)
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct AclRegionConfig {
/// List of rules that grant access to regions of the repo.
pub allow_rules: Vec<AclRegionRule>,
}