"""Provider-level cert parsing — locks the field mapping for AWS ACM, Aliyun CAS, Tencent SSL against representative API payloads (no network). """ from __future__ import annotations from datetime import UTC, datetime import pytest from app.domains.cmdb.providers.base import ProviderCapability, ProviderCredentials def _creds(**fields) -> ProviderCredentials: return ProviderCredentials( provider_id="pytest", provider_type="test", account_alias="pytest", fields=fields, ) # ── AWS ACM ───────────────────────────────────────────────────────── class _FakePaginator: def __init__(self, pages): self._pages = pages def paginate(self, **_kw): return iter(self._pages) class _FakeAcm: def get_paginator(self, _name): return _FakePaginator([ {"CertificateSummaryList": [{"CertificateArn": "arn:aws:acm:us-east-1:1:certificate/abc"}]}, ]) def describe_certificate(self, CertificateArn): # noqa: N803 return {"Certificate": { "CertificateArn": CertificateArn, "DomainName": "api.example.com", "SubjectAlternativeNames": ["api.example.com", "www.example.com"], "Issuer": "Amazon", "NotBefore": datetime(2026, 1, 1, tzinfo=UTC), "NotAfter": datetime(2026, 12, 31, tzinfo=UTC), "Serial": "00:ab:cd", "Status": "ISSUED", }} @pytest.mark.asyncio async def test_aws_acm_parse(monkeypatch): from app.domains.cmdb.providers import aws p = aws.AWSProvider(_creds(access_key_id="x", secret_access_key="y")) monkeypatch.setattr(p, "_ec2_regions_sync", lambda: ["us-east-1"]) monkeypatch.setattr(p._session, "client", lambda *a, **k: _FakeAcm()) assert ProviderCapability.CERTIFICATES in aws.AWSProvider.supported_capabilities() certs = await p.list_certificates() assert len(certs) == 1 c = certs[0] assert c.cloud_cert_id == "arn:aws:acm:us-east-1:1:certificate/abc" assert c.common_name == "api.example.com" assert set(c.sans) == {"api.example.com", "www.example.com"} assert c.not_after == datetime(2026, 12, 31, tzinfo=UTC) assert c.status == "ISSUED" # ── Aliyun CAS ────────────────────────────────────────────────────── @pytest.mark.asyncio async def test_aliyun_cas_parse(monkeypatch): from app.domains.cmdb.providers import aliyun p = aliyun.AliyunProvider(_creds(access_key_id="x", access_key_secret="y")) async def _fake_call(endpoint, params): from urllib.parse import urlsplit assert urlsplit(endpoint).hostname == "cas.aliyuncs.com" assert params["Action"] == "DescribeUserCertificateList" return { "TotalCount": 1, "CertificateList": [{ "Id": 12345, "Name": "prod-wildcard", "Common": "*.example.com", "Sans": "*.example.com,example.com", "Issuer": "DigiCert", "StartDate": "2026-01-01", "EndDate": "2026-12-31", "Expired": False, "Fingerprint": "AA:BB", }], } monkeypatch.setattr(p, "_call", _fake_call) certs = await p.list_certificates() assert len(certs) == 1 c = certs[0] assert c.cloud_cert_id == "12345" assert c.common_name == "*.example.com" assert set(c.sans) == {"*.example.com", "example.com"} assert c.issuer == "DigiCert" assert c.not_after == datetime(2026, 12, 31, tzinfo=UTC) assert c.status == "issued" # ── Tencent SSL ───────────────────────────────────────────────────── class _FakeTcCert: CertificateId = "tc-cert-1" Domain = "svc.example.com" SubjectAltName = ["svc.example.com", "alt.example.com"] Issuer = "TrustAsia" CertBeginTime = "2026-01-01 00:00:00" CertEndTime = "2026-12-31 23:59:59" Status = 1 Alias = "svc" ProductZhName = "TrustAsia DV" class _FakeTcResp: Certificates = [_FakeTcCert()] TotalCount = 1 @pytest.mark.asyncio async def test_tencent_ssl_parse(monkeypatch): from app.domains.cmdb.providers import tencent p = tencent.TencentProvider(_creds(secret_id="x", secret_key="y")) class _FakeClient: def DescribeCertificates(self, _req): # noqa: N802 return _FakeTcResp() monkeypatch.setattr(tencent, "_make_tc_client", lambda *a, **k: _FakeClient()) # Bypass the throttle/_call → invoke the SDK fn directly with our resp. monkeypatch.setattr(p, "_call", lambda fn, req, **kw: fn(req)) certs = await p.list_certificates() assert len(certs) == 1 c = certs[0] assert c.cloud_cert_id == "tc-cert-1" assert c.common_name == "svc.example.com" assert set(c.sans) == {"svc.example.com", "alt.example.com"} # Beijing 23:59:59 → UTC 15:59:59 same day assert c.not_after == datetime(2026, 12, 31, 15, 59, 59, tzinfo=UTC) assert c.status == "1"