grit_lib/
upload_filter.rs1use crate::config::ConfigSet;
4use crate::rev_list::ObjectFilter;
5use thiserror::Error;
6
7#[derive(Debug, Error)]
9pub enum UploadFilterError {
10 #[error("unable to parse uploadpackfilter.tree.maxdepth")]
12 InvalidTreeMaxDepth,
13 #[error("filter '{0}' not supported")]
15 UnsupportedFilter(String),
16 #[error("tree filter allows max depth {max}, but got {actual}")]
18 TreeDepthTooLarge {
19 max: u64,
21 actual: u64,
23 },
24 #[error("{0}")]
26 InvalidFilterSpec(String),
27}
28
29pub fn validate_upload_filter_config(config: &ConfigSet) -> Result<(), UploadFilterError> {
37 tree_max_depth(config).map(|_| ())
38}
39
40pub fn validate_upload_filter_request(
47 config: &ConfigSet,
48 spec: &str,
49) -> Result<(), UploadFilterError> {
50 let filter = ObjectFilter::parse(spec).map_err(UploadFilterError::InvalidFilterSpec)?;
51 validate_filter(config, &filter)
52}
53
54fn tree_max_depth(config: &ConfigSet) -> Result<Option<u64>, UploadFilterError> {
55 config
56 .get("uploadpackfilter.tree.maxdepth")
57 .map(|value| {
58 value
59 .trim()
60 .parse::<u64>()
61 .map_err(|_| UploadFilterError::InvalidTreeMaxDepth)
62 })
63 .transpose()
64}
65
66fn validate_filter(config: &ConfigSet, filter: &ObjectFilter) -> Result<(), UploadFilterError> {
67 match filter {
68 ObjectFilter::BlobNone => ensure_filter_allowed(config, "blob:none", "blob:none"),
69 ObjectFilter::BlobLimit(_) => ensure_filter_allowed(config, "blob:limit", "blob:limit"),
70 ObjectFilter::TreeDepth(depth) => {
71 ensure_filter_allowed(config, "tree", "tree")?;
72 if let Some(max) = tree_max_depth(config)? {
73 if *depth > max {
74 return Err(UploadFilterError::TreeDepthTooLarge {
75 max,
76 actual: *depth,
77 });
78 }
79 }
80 Ok(())
81 }
82 ObjectFilter::SparseOid(_) => ensure_filter_allowed(config, "sparse:oid", "sparse:oid"),
83 ObjectFilter::ObjectType(_) => ensure_filter_allowed(config, "object:type", "object:type"),
84 ObjectFilter::Combine(filters) => {
85 ensure_filter_allowed(config, "combine", "combine")?;
86 for filter in filters {
87 validate_filter(config, filter)?;
88 }
89 Ok(())
90 }
91 }
92}
93
94fn ensure_filter_allowed(
95 config: &ConfigSet,
96 config_kind: &str,
97 display_kind: &str,
98) -> Result<(), UploadFilterError> {
99 let key = format!("uploadpackfilter.{config_kind}.allow");
100 if let Some(value) = config.get_bool(&key) {
101 if value.unwrap_or(false) {
102 return Ok(());
103 }
104 return Err(UploadFilterError::UnsupportedFilter(
105 display_kind.to_owned(),
106 ));
107 }
108
109 if config
110 .get_bool("uploadpackfilter.allow")
111 .map(|value| value.unwrap_or(false))
112 .unwrap_or(true)
113 {
114 Ok(())
115 } else {
116 Err(UploadFilterError::UnsupportedFilter(
117 display_kind.to_owned(),
118 ))
119 }
120}