Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions crates/gitlawb-node/src/api/visibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,23 @@ fn validate_path_glob(path_glob: &str) -> Result<()> {
"path_glob must not end with '/'".into(),
));
}
if path_glob.contains('*') && !path_glob.ends_with("/**") {
// Reject empty path segments. `glob_prefix` collapses "//**" to "/" (whole
// repo), so without this an operator could bypass the "/**" guard above and
// grant repo-wide read with "//**", or set a dead rule like "//secret/**"
// whose prefix never matches a real single-slash path and silently leaves
// the subtree readable.
if path_glob.contains("//") {
return Err(AppError::BadRequest(
"the only supported wildcard is a trailing '/**'".into(),
"path_glob must not contain empty path segments".into(),
));
}
// Strip the one permitted trailing "/**" before checking for stray
// wildcards, otherwise a "*" elsewhere in the prefix (e.g. "/a*b/**" or
// "/a/**/**") slips through because the string still ends with "/**".
let prefix = path_glob.strip_suffix("/**").unwrap_or(path_glob);
if prefix.contains('*') {
return Err(AppError::BadRequest(
"the only supported wildcard is a single trailing '/**'".into(),
));
}
Ok(())
Expand Down Expand Up @@ -240,9 +254,22 @@ mod tests {

#[test]
fn rejects_malformed_globs() {
// empty, no leading slash, whole-repo via "/**", trailing slash, and
// non-trailing wildcards are all rejected.
for g in ["", "secret/**", "/**", "/secret/", "/a*b", "/*/x"] {
// empty, no leading slash, whole-repo via "/**", trailing slash,
// non-trailing wildcards, double wildcards, and empty path segments
// (which would collapse to whole-repo or a dead rule) are all rejected.
for g in [
"",
"secret/**",
"/**",
"/**/**",
"/secret/",
"/a*b",
"/*/x",
"/a*b/**",
"/a/**/**",
"//**",
"//secret/**",
] {
assert!(validate_path_glob(g).is_err(), "{g} should be rejected");
}
}
Expand Down
Loading