feat(server): grant-scope org attachment write paths in pre-receive hook
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
pub enum PathClass {
|
||||
/// `members.json`, `collections.json`, `org.json` — only Owner/Admin may write.
|
||||
Protected,
|
||||
/// `items/<slug>/<id>.enc` — writer must hold a grant for `<slug>`.
|
||||
/// `items/<slug>/<id>.enc` and `attachments/<slug>/<item-id>/<att-id>.enc` —
|
||||
/// writer must hold a grant for `<slug>`.
|
||||
Item { collection: String },
|
||||
/// `keys/<id>.enc`, `manifest.enc`, `.gitignore`, etc. — gated only by the
|
||||
/// per-commit signature check (signer must be a current member).
|
||||
@@ -42,6 +43,23 @@ pub fn classify_path(path: &str) -> PathClass {
|
||||
return PathClass::Item { collection: slug.to_string() };
|
||||
}
|
||||
|
||||
if let Some(rest) = path.strip_prefix("attachments/") {
|
||||
// Expect exactly: <slug>/<item-id>/<att-id>.enc → three segments.
|
||||
let segments: Vec<&str> = rest.split('/').collect();
|
||||
if segments.len() != 3 {
|
||||
return PathClass::Rejected(
|
||||
"attachments path must be attachments/<slug>/<item-id>/<att-id>.enc".to_string());
|
||||
}
|
||||
let slug = segments[0];
|
||||
if slug.is_empty() {
|
||||
return PathClass::Rejected("empty collection slug in attachments path".to_string());
|
||||
}
|
||||
if slug.contains('.') {
|
||||
return PathClass::Rejected(format!("invalid collection slug: {:?}", slug));
|
||||
}
|
||||
return PathClass::Item { collection: slug.to_string() };
|
||||
}
|
||||
|
||||
PathClass::Unrestricted
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user