"""Cloud cert-manager sync → cmdb_certificates (source='cloud').""" from __future__ import annotations import uuid from datetime import UTC, datetime, timedelta import pytest import pytest_asyncio from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.domains.cmdb.models import ( CERT_SOURCE_CLOUD, CERT_SOURCE_PROBED, CmdbCertificate, ) from app.domains.cmdb.providers.base import CloudCertificate from app.domains.cmdb.sync import _sync_certificates from app.integrations.models import Integration class _FakeProvider: def __init__(self, certs): self._certs = certs async def list_certificates(self): return self._certs @pytest_asyncio.fixture async def integ(db_session: AsyncSession) -> Integration: row = Integration( id=uuid.uuid4(), kind="cloud", provider="aws", name="pytest-cert-aws", slug=f"pytest-cert-aws-{uuid.uuid4().hex[:8]}", enabled=True, is_primary=False, capabilities=["certificates"], ) db_session.add(row) await db_session.commit() return row def _cc(cert_id, cn, days): return CloudCertificate( cloud_cert_id=cert_id, common_name=cn, sans=[cn], issuer="Amazon", not_before=datetime.now(UTC) - timedelta(days=1), not_after=datetime.now(UTC) + timedelta(days=days), status="ISSUED", serial_number="00ab", raw={"x": 1}, ) @pytest.mark.asyncio async def test_sync_upserts_cloud_certs(db_session: AsyncSession, integ: Integration): provider = _FakeProvider([_cc("arn:cert/1", "a.example.com", 60), _cc("arn:cert/2", "b.example.com", 5)]) upserted, _deleted = await _sync_certificates( db_session, integ, str(uuid.uuid4()), provider, ) assert upserted == 2 rows = (await db_session.execute( select(CmdbCertificate).where(CmdbCertificate.source == CERT_SOURCE_CLOUD) )).scalars().all() assert len(rows) == 2 by_cn = {r.common_name: r for r in rows} assert by_cn["a.example.com"].status == "valid" assert by_cn["b.example.com"].status == "expiring" # within 30d assert by_cn["a.example.com"].dedup_key == f"cloud:{integ.id}:arn:cert/1" assert by_cn["a.example.com"].integration_id == str(integ.id) @pytest.mark.asyncio async def test_resync_updates_in_place(db_session: AsyncSession, integ: Integration): await _sync_certificates( db_session, integ, str(uuid.uuid4()), _FakeProvider([_cc("arn:cert/1", "a.example.com", 60)]), ) # renewal: same cert_id, later expiry await _sync_certificates( db_session, integ, str(uuid.uuid4()), _FakeProvider([_cc("arn:cert/1", "a.example.com", 200)]), ) rows = (await db_session.execute( select(CmdbCertificate).where( CmdbCertificate.dedup_key == f"cloud:{integ.id}:arn:cert/1" ) )).scalars().all() assert len(rows) == 1 # updated in place, not duplicated assert rows[0].status == "valid" @pytest.mark.asyncio async def test_resync_does_not_revive_admin_soft_deleted_cert( db_session: AsyncSession, integ: Integration, ): """An admin who retires a cloud cert via DELETE /certificates/{id} (sets deleted_at) must NOT have it silently revived on the next sync while the cloud provider still returns it. Mirrors the server (PR #559) and DNS resurrection guards. Before the fix the cert upsert wrote ``deleted_at=None`` in ON DUPLICATE KEY UPDATE and resurrected the row. """ provider = _FakeProvider([_cc("arn:cert/1", "a.example.com", 60)]) await _sync_certificates(db_session, integ, str(uuid.uuid4()), provider) dedup = f"cloud:{integ.id}:arn:cert/1" row = (await db_session.execute( select(CmdbCertificate).where(CmdbCertificate.dedup_key == dedup) )).scalar_one() # Admin retires it. row.deleted_at = datetime.now(UTC) await db_session.commit() # Cloud STILL returns the cert (eventual consistency) — re-sync. await _sync_certificates(db_session, integ, str(uuid.uuid4()), provider) refreshed = (await db_session.execute( select(CmdbCertificate).where(CmdbCertificate.dedup_key == dedup) )).scalar_one() assert refreshed.deleted_at is not None, ( "cloud re-sync must not revive an admin-soft-deleted cert" ) @pytest.mark.asyncio async def test_sweep_skips_probed_manual_rows(db_session: AsyncSession, integ: Integration): # A probed row with NULL integration_id must survive a cloud sync sweep. probed = CmdbCertificate( id=uuid.uuid4(), dedup_key=f"{CERT_SOURCE_PROBED}:p.example.com:443", source=CERT_SOURCE_PROBED, probe_host="p.example.com", common_name="p.example.com", status="valid", not_after=datetime.now(UTC) + timedelta(days=40), ) db_session.add(probed) await db_session.commit() await _sync_certificates( db_session, integ, str(uuid.uuid4()), _FakeProvider([_cc("arn:cert/1", "a.example.com", 60)]), ) # probed row still alive refreshed = await db_session.get(CmdbCertificate, probed.id) assert refreshed.deleted_at is None