"""``revoke_account`` must delete the user it was ASKED to delete. `CloudAccountRevokeContext.account_id` is documented as the provider's user handle, with an email accepted as a convenience. Three IAM-mode drivers implemented that convenience as "contains ``@`` → take the local part", unconditionally — which destroys the common case where the handle *is* an address. Prod 2026-08-12, Tencent tenant 100002610019: the offboarding kill-switch was asked to delete `tangpeng@pingcap.com`, looked up CAM user ``tangpeng``, got ``UserNotExist``, and returned ``ok=True, note="user already absent"``. The real sub-user ``tangpeng@pingcap.com`` kept **AdministratorAccess**, and Helix recorded the offboarding as complete. 17 of the 22 live CAM users on that tenant have ``@`` in their name — the kill-switch was a no-op for 77% of the tenant while reporting success every time. The rule these tests pin: try the handle LITERALLY first, fall back to the derived local part, and report already-absent only when NEITHER exists. """ from __future__ import annotations from unittest.mock import patch import pytest from app.integrations.driver_base import CloudAccountRevokeContext from app.integrations.drivers._cloud_shared import account_id_candidates from app.integrations.drivers.tencent_cloud import TencentCloudDriver _CFG = { "secret_id": "AKIDtest", "secret_key": "sk-test", "regions": "ap-guangzhou", } def _driver() -> TencentCloudDriver: return TencentCloudDriver(integration_id="tc-test", config=_CFG) class _Resp: def __init__(self, **kw): for k, v in kw.items(): setattr(self, k, v) class _Client: """Stub CAM client. ``_call`` is patched, so the bound method it is handed is never invoked — it only has to exist.""" def __getattr__(self, name): return lambda *a, **kw: None def test_candidates_try_the_literal_handle_first() -> None: assert account_id_candidates( "tangpeng@pingcap.com", lambda e: e.split("@")[0], ) == ["tangpeng@pingcap.com", "tangpeng"] def test_candidates_of_a_bare_handle_are_just_itself() -> None: assert account_id_candidates("chujie", lambda e: e.split("@")[0]) == [ "chujie", ] def test_candidates_drop_a_derivation_equal_to_the_input() -> None: assert account_id_candidates("svc@x", lambda e: "svc@x") == ["svc@x"] def test_candidates_of_blank_are_empty() -> None: assert account_id_candidates(" ", lambda e: e) == [] @pytest.mark.asyncio async def test_email_named_cam_user_is_deleted_not_reported_absent() -> None: """The prod case. ``tangpeng@pingcap.com`` exists verbatim in CAM; the local-part guess does not.""" driver = _driver() from tencentcloud.common.exception.tencent_cloud_sdk_exception import ( TencentCloudSDKException, ) deleted: list[str] = [] def _call(fn, req, **_kw): cls = req.__class__.__name__ if cls == "GetUserRequest": if req.Name == "tangpeng@pingcap.com": return _Resp(Uin=100040397537, Uid=20602750) raise TencentCloudSDKException( "ResourceNotFound.UserNotExist", "no such user", ) if cls == "ListAttachedUserAllPoliciesRequest": return _Resp(PolicyList=[], TotalNum=0) if cls == "ListGroupsForUserRequest": return _Resp(GroupInfo=[], TotalNum=0) if cls == "ListAccessKeysRequest": return _Resp(AccessKeys=[]) if cls == "DeleteUserRequest": deleted.append(req.Name) return _Resp(RequestId="r") return _Resp() with ( patch.object(driver, "_cam_client", return_value=_Client()), patch.object(driver, "_call", side_effect=_call), ): result = await driver.revoke_account(CloudAccountRevokeContext( provider="tencent", account_id="tangpeng@pingcap.com", )) assert result.ok is True # The whole point: the DELETE hit the address-named user, and the # result is not a fabricated "already absent". assert deleted == ["tangpeng@pingcap.com"] assert (result.raw_response or {}).get("note") != "user already absent" @pytest.mark.asyncio async def test_local_part_fallback_still_works() -> None: """Tenants whose users really are named after the local part (AliCloud RAM: ``li.da``) must keep working — the convenience is preserved, it just stops being the FIRST guess.""" driver = _driver() from tencentcloud.common.exception.tencent_cloud_sdk_exception import ( TencentCloudSDKException, ) deleted: list[str] = [] def _call(fn, req, **_kw): cls = req.__class__.__name__ if cls == "GetUserRequest": if req.Name == "lifu.wu": return _Resp(Uin=1, Uid=2) raise TencentCloudSDKException( "ResourceNotFound.UserNotExist", "no such user", ) if cls == "ListAttachedUserAllPoliciesRequest": return _Resp(PolicyList=[], TotalNum=0) if cls == "ListGroupsForUserRequest": return _Resp(GroupInfo=[], TotalNum=0) if cls == "ListAccessKeysRequest": return _Resp(AccessKeys=[]) if cls == "DeleteUserRequest": deleted.append(req.Name) return _Resp(RequestId="r") return _Resp() with ( patch.object(driver, "_cam_client", return_value=_Client()), patch.object(driver, "_call", side_effect=_call), ): result = await driver.revoke_account(CloudAccountRevokeContext( provider="tencent", account_id="lifu.wu@pingcap.com", )) assert result.ok is True assert deleted == ["lifu.wu"] @pytest.mark.asyncio async def test_already_absent_only_when_no_candidate_exists() -> None: driver = _driver() from tencentcloud.common.exception.tencent_cloud_sdk_exception import ( TencentCloudSDKException, ) tried: list[str] = [] def _call(fn, req, **_kw): if req.__class__.__name__ == "GetUserRequest": tried.append(req.Name) raise TencentCloudSDKException( "ResourceNotFound.UserNotExist", "no such user", ) return _Resp() with ( patch.object(driver, "_cam_client", return_value=_Client()), patch.object(driver, "_call", side_effect=_call), ): result = await driver.revoke_account(CloudAccountRevokeContext( provider="tencent", account_id="ghost@pingcap.com", )) assert result.ok is True assert (result.raw_response or {}).get("note") == "user already absent" # Both candidates were genuinely probed before claiming absence. assert tried == ["ghost@pingcap.com", "ghost"] @pytest.mark.asyncio async def test_a_real_probe_error_is_not_read_as_absence() -> None: """An auth failure or throttle on GetUser must surface as ok=False. Treating any exception as "already gone" is how a broken credential becomes a clean offboarding record.""" driver = _driver() from tencentcloud.common.exception.tencent_cloud_sdk_exception import ( TencentCloudSDKException, ) def _call(fn, req, **_kw): if req.__class__.__name__ == "GetUserRequest": raise TencentCloudSDKException( "AuthFailure.SignatureFailure", "bad signature", ) return _Resp() with ( patch.object(driver, "_cam_client", return_value=_Client()), patch.object(driver, "_call", side_effect=_call), ): result = await driver.revoke_account(CloudAccountRevokeContext( provider="tencent", account_id="someone@pingcap.com", )) assert result.ok is False