refactor(authz): route users_service through the shared authz-verdict mapper

`users_service::require` open-coded the `AuthzDenied → {Forbidden, Backend}`
match that `authz::script_gate` centralizes for every other stateful service —
the one straggler. Extract the mapping into `authz::require_mapped` (used now by
both `script_gate` variants and `users_service::require`), so the verdict→error
mapping lives in exactly one place. Also refresh the stale `to_app_user` comment
(it referenced an unshipped "commit 8" stub; roles are resolved via
`fetch_roles` and passed in). No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-13 19:46:22 +02:00
parent 5e6bb762f4
commit 486cc44a06
2 changed files with 37 additions and 20 deletions

View File

@@ -46,7 +46,7 @@ use crate::app_user_verification_repo::{AppUserVerificationRepo, AppUserVerifica
use crate::auth::{
generate_session_token, hash_password, hash_token, verify_password, TIMING_FLAT_DUMMY_HASH,
};
use crate::authz::{self, AuthzDenied, AuthzRepo, Capability};
use crate::authz::{self, AuthzRepo, Capability};
/// Runtime configuration. Defaults match the v1.1.8 brief — overridable
/// via env vars wired in the picloud binary.
@@ -268,17 +268,18 @@ impl UsersServiceImpl {
// Public HTTP execution — script-as-gate; not denied here.
return Ok(());
};
match authz::require(&*self.authz, p, cap).await {
Ok(()) => Ok(()),
Err(AuthzDenied::Denied) => Err(UsersError::Forbidden),
Err(AuthzDenied::Repo(e)) => Err(UsersError::Backend(e.to_string())),
}
authz::require_mapped(
&*self.authz,
p,
cap,
|| UsersError::Forbidden,
UsersError::Backend,
)
.await
}
/// Compose the public `AppUser` shape from a `AppUserRow`. Roles
/// are always empty in commit 4 of v1.1.8; commit 8 (per-app
/// roles) replaces this stub with an actual `app_user_roles`
/// query.
/// Compose the public `AppUser` shape from an `AppUserRow`, with the caller's
/// already-resolved per-app `roles` (see [`Self::fetch_roles`]).
fn to_app_user(row: AppUserRow, roles: Vec<String>) -> AppUser {
AppUser {
id: row.id,