security: enforce actor-aware Mail profile access
This commit is contained in:
@@ -4,6 +4,8 @@ import unittest
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import patch
|
||||
|
||||
from fastapi import HTTPException
|
||||
|
||||
from govoplan_mail.backend.router import create_profile, deactivate_profile, update_profile
|
||||
from govoplan_mail.backend.schemas import MailServerProfileCreateRequest, MailServerProfileUpdateRequest
|
||||
|
||||
@@ -48,6 +50,7 @@ class MailProfileDeletionRouteTests(unittest.TestCase):
|
||||
patch("govoplan_mail.backend.router._require_profile_write_scope"),
|
||||
patch("govoplan_mail.backend.router._require_profile_credentials_scope"),
|
||||
patch("govoplan_mail.backend.router.delete_mail_profile_credentials", return_value=()),
|
||||
patch("govoplan_mail.backend.router.clear_mailbox_index") as clear_index,
|
||||
patch("govoplan_mail.backend.router._record_mail_change") as record_change,
|
||||
patch("govoplan_mail.backend.router._profile_response", return_value=self.profile),
|
||||
):
|
||||
@@ -56,6 +59,7 @@ class MailProfileDeletionRouteTests(unittest.TestCase):
|
||||
self.assertIs(result, self.profile)
|
||||
self.assertEqual(session.commits, 1)
|
||||
self.assertEqual(session.rollbacks, 0)
|
||||
clear_index.assert_called_once_with(session, profile_id="profile-1")
|
||||
record_change.assert_not_called()
|
||||
|
||||
def test_change_feed_reports_whether_credentials_were_deleted(self) -> None:
|
||||
@@ -66,6 +70,7 @@ class MailProfileDeletionRouteTests(unittest.TestCase):
|
||||
patch("govoplan_mail.backend.router._require_profile_write_scope"),
|
||||
patch("govoplan_mail.backend.router._require_profile_credentials_scope"),
|
||||
patch("govoplan_mail.backend.router.delete_mail_profile_credentials", return_value=()),
|
||||
patch("govoplan_mail.backend.router.clear_mailbox_index") as clear_index,
|
||||
patch("govoplan_mail.backend.router._record_mail_change") as record_change,
|
||||
patch("govoplan_mail.backend.router._profile_response", return_value=self.profile),
|
||||
):
|
||||
@@ -73,6 +78,7 @@ class MailProfileDeletionRouteTests(unittest.TestCase):
|
||||
|
||||
self.assertFalse(record_change.call_args.kwargs["payload"]["credentials_deleted"])
|
||||
self.assertEqual(record_change.call_args.kwargs["payload"]["deleted_credential_protocols"], [])
|
||||
clear_index.assert_called_once_with(session, profile_id="profile-1")
|
||||
|
||||
def test_generic_secret_deletion_failure_rolls_back(self) -> None:
|
||||
self.profile.is_active = True
|
||||
@@ -89,6 +95,29 @@ class MailProfileDeletionRouteTests(unittest.TestCase):
|
||||
self.assertEqual(session.commits, 0)
|
||||
self.assertEqual(session.rollbacks, 1)
|
||||
|
||||
def test_patch_deactivation_is_rejected_in_favor_of_audited_delete(self) -> None:
|
||||
self.profile.is_active = True
|
||||
self.profile.smtp_password_encrypted = "existing-ciphertext"
|
||||
session = _Session()
|
||||
payload = MailServerProfileUpdateRequest(is_active=False)
|
||||
with (
|
||||
patch("govoplan_mail.backend.router.get_mail_server_profile", return_value=self.profile),
|
||||
patch("govoplan_mail.backend.router._require_profile_write_scope"),
|
||||
self.assertRaises(HTTPException) as captured,
|
||||
):
|
||||
update_profile(
|
||||
self.profile.id,
|
||||
payload,
|
||||
principal=self.principal,
|
||||
session=session,
|
||||
)
|
||||
|
||||
self.assertEqual(captured.exception.status_code, 422)
|
||||
self.assertTrue(self.profile.is_active)
|
||||
self.assertEqual(self.profile.smtp_password_encrypted, "existing-ciphertext")
|
||||
self.assertEqual(session.commits, 0)
|
||||
self.assertEqual(session.rollbacks, 1)
|
||||
|
||||
def test_system_profile_changes_are_instance_wide_in_the_change_feed(self) -> None:
|
||||
system_profile = SimpleNamespace(
|
||||
id="profile-system",
|
||||
@@ -132,6 +161,7 @@ class MailProfileDeletionRouteTests(unittest.TestCase):
|
||||
patch("govoplan_mail.backend.router._require_profile_write_scope"),
|
||||
patch("govoplan_mail.backend.router._require_profile_credentials_scope"),
|
||||
patch("govoplan_mail.backend.router.delete_mail_profile_credentials", return_value=()),
|
||||
patch("govoplan_mail.backend.router.clear_mailbox_index"),
|
||||
patch("govoplan_mail.backend.router._record_mail_change") as delete_change,
|
||||
patch("govoplan_mail.backend.router._profile_response", return_value=system_profile),
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user