feat(mail): enforce owned profile self-service

This commit is contained in:
2026-07-21 20:48:46 +02:00
parent 193898b00d
commit 9f49591a98
10 changed files with 826 additions and 39 deletions

View File

@@ -14,7 +14,9 @@ from govoplan_mail.backend.mail_profiles import (
MAIL_POLICY_DOC_SCOPES = ("mail:profile:read", "admin:policies:read", "system:settings:read")
MAIL_PROFILE_READ_SCOPE = "mail:profile:read"
MAIL_PROFILE_WRITE_SCOPE = "mail:profile:write"
MAIL_SECRET_MANAGE_SCOPE = "mail:secret:manage"
MAIL_PROFILE_WRITE_OWN_SCOPE = "mail:profile:write_own"
MAIL_SECRET_MANAGE_SCOPE = "mail:secret:manage" # noqa: S105 -- permission identifier, not a credential
MAIL_SECRET_MANAGE_OWN_SCOPE = "mail:secret:manage_own" # noqa: S105 -- permission identifier, not a credential
MAIL_PROFILE_TEST_SCOPE = "mail:profile:test"
MAIL_PROFILE_USE_SCOPE = "mail:profile:use"
_HOST_POLICY_FIELDS = (("SMTP", "smtp_hosts"), ("IMAP", "imap_hosts"))
@@ -120,7 +122,9 @@ def _custom_mail_profile_topic(context: DocumentationContext) -> DocumentationTo
if context.documentation_type != "user":
return None
principal = context.principal
if not _has_all_scopes(principal, (MAIL_PROFILE_READ_SCOPE, MAIL_PROFILE_WRITE_SCOPE)):
if not _has_any_scope(principal, (MAIL_PROFILE_WRITE_SCOPE, MAIL_PROFILE_WRITE_OWN_SCOPE)):
return None
if not _has_all_scopes(principal, (MAIL_PROFILE_READ_SCOPE,)):
return None
tenant_id = str(getattr(principal, "tenant_id", "") or "")
user_id = str(getattr(getattr(principal, "user", None), "id", "") or "")
@@ -143,7 +147,10 @@ def _custom_mail_profile_topic(context: DocumentationContext) -> DocumentationTo
if not policy.allow_user_profiles:
return None
can_manage_credentials = _has_any_scope(principal, (MAIL_SECRET_MANAGE_SCOPE,))
can_manage_credentials = _has_any_scope(
principal,
(MAIL_SECRET_MANAGE_SCOPE, MAIL_SECRET_MANAGE_OWN_SCOPE),
)
can_test_profile = _has_all_scopes(principal, (MAIL_PROFILE_TEST_SCOPE, MAIL_PROFILE_USE_SCOPE))
can_use_profile = _has_any_scope(principal, (MAIL_PROFILE_USE_SCOPE,))
approval_required = bool(policy.allowed_profile_id_sets)
@@ -175,7 +182,8 @@ def _custom_mail_profile_topic(context: DocumentationContext) -> DocumentationTo
conditions=(
DocumentationCondition(
required_modules=("mail",),
required_scopes=(MAIL_PROFILE_READ_SCOPE, MAIL_PROFILE_WRITE_SCOPE),
required_scopes=(MAIL_PROFILE_READ_SCOPE,),
any_scopes=(MAIL_PROFILE_WRITE_SCOPE, MAIL_PROFILE_WRITE_OWN_SCOPE),
configuration_keys=("mail_profile_policy",),
),
),