fix(manager-core): F-Q-005 preserve AuthzDenied::Repo through service-layer authz checks

Every check_read/check_write/check_publish helper across kv, docs,
files, pubsub, queue services used `.map_err(|_| KvError::Forbidden)?`,
collapsing AuthzDenied::Denied AND AuthzDenied::Repo(repo_err) into
a single Forbidden. A transient Postgres blip during the membership
lookup surfaced as 403 to scripts; operators couldn't distinguish
"real forbidden" from "DB flap during permission check".

Replace each call site with the explicit match pattern already used by
users_service::require (users_service.rs:177-181):

  Ok(())                          → continue
  Err(AuthzDenied::Denied)        → Err(ServiceError::Forbidden)
  Err(AuthzDenied::Repo(e))       → Err(ServiceError::Backend(e.to_string()))

7 call sites updated (2 in kv_service, 2 in docs_service, 2 in
files_service, 2 in pubsub_service, 1 in queue_service).

AUDIT.md anchor: F-Q-005. Depends on F-Q-004 (which added Backend
to QueueError/PubsubError).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-07 19:46:37 +02:00
parent b192cf2cc9
commit 655c3ab97e
5 changed files with 52 additions and 22 deletions

View File

@@ -56,18 +56,24 @@ impl DocsServiceImpl {
async fn check_read(&self, cx: &SdkCallCx) -> Result<(), DocsError> {
if let Some(ref principal) = cx.principal {
authz::require(&*self.authz, principal, Capability::AppDocsRead(cx.app_id))
.await
.map_err(|_| DocsError::Forbidden)?;
match authz::require(&*self.authz, principal, Capability::AppDocsRead(cx.app_id)).await
{
Ok(()) => {}
Err(authz::AuthzDenied::Denied) => return Err(DocsError::Forbidden),
Err(authz::AuthzDenied::Repo(e)) => return Err(DocsError::Backend(e.to_string())),
}
}
Ok(())
}
async fn check_write(&self, cx: &SdkCallCx) -> Result<(), DocsError> {
if let Some(ref principal) = cx.principal {
authz::require(&*self.authz, principal, Capability::AppDocsWrite(cx.app_id))
.await
.map_err(|_| DocsError::Forbidden)?;
match authz::require(&*self.authz, principal, Capability::AppDocsWrite(cx.app_id)).await
{
Ok(()) => {}
Err(authz::AuthzDenied::Denied) => return Err(DocsError::Forbidden),
Err(authz::AuthzDenied::Repo(e)) => return Err(DocsError::Backend(e.to_string())),
}
}
Ok(())
}