fix(secrets): audit connector credential deletion

This commit is contained in:
2026-07-21 15:45:39 +02:00
parent 5dc9392290
commit 613fb15a80
2 changed files with 128 additions and 0 deletions

View File

@@ -1051,6 +1051,72 @@ END:VCARD
self.assertFalse(book.read_only)
self.assertEqual([item.id for item in list_contacts(self.session, self.principal, address_book_id=book.id)], [contact.id])
def test_delete_sync_source_deletes_and_audits_encrypted_credential_atomically(self) -> None:
book = create_address_book(
self.session,
self.principal,
AddressBookCreateRequest(scope_type="user", name="Audited remote"),
)
self.session.commit()
self.session.refresh(book)
source = create_carddav_sync_source(
self.session,
self.principal,
book.id,
AddressCardDavSourceCreateRequest(
collection_url="https://carddav.example.local/addressbooks/audited/",
auth_type="basic",
username="ada",
password="do-not-audit-this",
),
)
self.session.commit()
source_id = source.id
with patch("govoplan_addresses.backend.service.audit_event") as audit:
delete_sync_source(self.session, self.principal, source_id)
self.session.commit()
self.assertIsNone(self.session.get(AddressSyncSource, source_id))
audit.assert_called_once()
audit_call = audit.call_args.kwargs
self.assertEqual(audit_call["action"], "addresses.sync_credential_deleted")
self.assertEqual(audit_call["object_id"], source_id)
self.assertEqual(audit_call["details"]["storage_backend"], "encrypted_database")
self.assertNotIn("credential_ref", audit_call["details"])
self.assertNotIn("secret_encrypted", audit_call["details"])
self.assertNotIn("do-not-audit-this", repr(audit_call))
def test_delete_sync_source_is_not_staged_when_credential_audit_fails(self) -> None:
book = create_address_book(
self.session,
self.principal,
AddressBookCreateRequest(scope_type="user", name="Audit failure"),
)
self.session.commit()
self.session.refresh(book)
source = create_carddav_sync_source(
self.session,
self.principal,
book.id,
AddressCardDavSourceCreateRequest(
collection_url="https://carddav.example.local/addressbooks/audit-failure/",
auth_type="bearer",
bearer_token="do-not-audit-this",
),
)
self.session.commit()
with patch(
"govoplan_addresses.backend.service.audit_event",
side_effect=RuntimeError("audit unavailable"),
), self.assertRaisesRegex(RuntimeError, "audit unavailable"):
delete_sync_source(self.session, self.principal, source.id)
self.session.rollback()
persisted = self.session.get(AddressSyncSource, source.id)
self.assertIsNotNone(persisted)
self.assertIn("secret_encrypted", (persisted.metadata_ or {})["carddav"])
if __name__ == "__main__":
unittest.main()