Merge remote-tracking branch 'entropy-xu/codex/user-groups-default-permissions' into aether-rust-pioneer

This commit is contained in:
fawney19
2026-05-10 11:26:29 +08:00
49 changed files with 6373 additions and 250 deletions

View File

@@ -575,6 +575,95 @@ pub(super) fn classify_admin_operations_family_route(
"admin:wallets",
false,
))
} else if method == http::Method::GET
&& matches!(
normalized_path,
"/api/admin/user-groups" | "/api/admin/user-groups/"
)
{
Some(classified(
"admin_proxy",
"users_manage",
"list_user_groups",
"admin:users",
false,
))
} else if method == http::Method::POST
&& matches!(
normalized_path,
"/api/admin/user-groups" | "/api/admin/user-groups/"
)
{
Some(classified(
"admin_proxy",
"users_manage",
"create_user_group",
"admin:users",
false,
))
} else if method == http::Method::PUT
&& matches!(
normalized_path,
"/api/admin/user-groups/default" | "/api/admin/user-groups/default/"
)
{
Some(classified(
"admin_proxy",
"users_manage",
"set_default_user_group",
"admin:users",
false,
))
} else if method == http::Method::GET
&& normalized_path.starts_with("/api/admin/user-groups/")
&& normalized_path.ends_with("/members")
&& normalized_path.matches('/').count() == 5
{
Some(classified(
"admin_proxy",
"users_manage",
"list_user_group_members",
"admin:users",
false,
))
} else if method == http::Method::PUT
&& normalized_path.starts_with("/api/admin/user-groups/")
&& normalized_path.ends_with("/members")
&& normalized_path.matches('/').count() == 5
{
Some(classified(
"admin_proxy",
"users_manage",
"replace_user_group_members",
"admin:users",
false,
))
} else if method == http::Method::PUT
&& normalized_path.starts_with("/api/admin/user-groups/")
&& normalized_path.matches('/').count() == 4
&& !normalized_path.ends_with("/default")
&& !normalized_path.ends_with("/members")
{
Some(classified(
"admin_proxy",
"users_manage",
"update_user_group",
"admin:users",
false,
))
} else if method == http::Method::DELETE
&& normalized_path.starts_with("/api/admin/user-groups/")
&& normalized_path.matches('/').count() == 4
&& !normalized_path.ends_with("/default")
&& !normalized_path.ends_with("/members")
{
Some(classified(
"admin_proxy",
"users_manage",
"delete_user_group",
"admin:users",
false,
))
} else if method == http::Method::GET
&& matches!(normalized_path, "/api/admin/users" | "/api/admin/users/")
{

View File

@@ -1,6 +1,8 @@
use http::Uri;
use super::{classify_control_route, headers};
use crate::handlers::shared::local_proxy_route_requires_buffered_body;
use super::{classify_control_route, headers, GatewayPublicRequestContext};
#[test]
fn classifies_admin_users_list_as_admin_proxy_route() {
@@ -68,6 +70,86 @@ fn classifies_admin_user_batch_routes_as_admin_proxy_route() {
);
}
#[test]
fn classifies_admin_user_group_routes_as_admin_proxy_route() {
let headers = headers(&[]);
let list_uri: Uri = "/api/admin/user-groups".parse().expect("uri should parse");
let list = classify_control_route(&http::Method::GET, &list_uri, &headers)
.expect("route should classify");
assert_eq!(list.route_family.as_deref(), Some("users_manage"));
assert_eq!(list.route_kind.as_deref(), Some("list_user_groups"));
let create_uri: Uri = "/api/admin/user-groups".parse().expect("uri should parse");
let create = classify_control_route(&http::Method::POST, &create_uri, &headers)
.expect("route should classify");
assert_eq!(create.route_family.as_deref(), Some("users_manage"));
assert_eq!(create.route_kind.as_deref(), Some("create_user_group"));
let update_uri: Uri = "/api/admin/user-groups/group-1"
.parse()
.expect("uri should parse");
let update = classify_control_route(&http::Method::PUT, &update_uri, &headers)
.expect("route should classify");
assert_eq!(update.route_family.as_deref(), Some("users_manage"));
assert_eq!(update.route_kind.as_deref(), Some("update_user_group"));
let members_uri: Uri = "/api/admin/user-groups/group-1/members"
.parse()
.expect("uri should parse");
let members = classify_control_route(&http::Method::PUT, &members_uri, &headers)
.expect("route should classify");
assert_eq!(members.route_family.as_deref(), Some("users_manage"));
assert_eq!(
members.route_kind.as_deref(),
Some("replace_user_group_members")
);
let default_uri: Uri = "/api/admin/user-groups/default"
.parse()
.expect("uri should parse");
let default = classify_control_route(&http::Method::PUT, &default_uri, &headers)
.expect("route should classify");
assert_eq!(default.route_family.as_deref(), Some("users_manage"));
assert_eq!(
default.route_kind.as_deref(),
Some("set_default_user_group")
);
assert_eq!(
default.auth_endpoint_signature.as_deref(),
Some("admin:users")
);
}
#[test]
fn admin_user_group_write_routes_buffer_request_body() {
let headers = headers(&[]);
let routes = [
(http::Method::POST, "/api/admin/user-groups"),
(http::Method::PUT, "/api/admin/user-groups/group-1"),
(http::Method::PUT, "/api/admin/user-groups/group-1/members"),
(http::Method::PUT, "/api/admin/user-groups/default"),
];
for (method, path) in routes {
let uri: Uri = path.parse().expect("uri should parse");
let decision =
classify_control_route(&method, &uri, &headers).expect("route should classify");
let context = GatewayPublicRequestContext::from_request_parts(
"trace-user-group-write",
&method,
&uri,
&headers,
Some(decision),
);
assert!(
local_proxy_route_requires_buffered_body(&context),
"{method} {path} should buffer request body"
);
}
}
#[test]
fn classifies_admin_user_detail_routes_as_admin_proxy_route() {
let headers = headers(&[]);