"""certificate owner becomes a manual-override flag, not a snapshot. Background: ``cmdb_certificates.owner_person_id`` used to be COPIED from the DNS record / domain owner at probe-creation time (a frozen snapshot). That drifts the moment the DNS record / domain owner changes, and a probed cert that re-appears never re-inherits. The certificate ownership model is moving to LIVE resolution (``cert_owner_resolver.CertOwnerResolver``): a cert's responsible owner follows the DNS record / zone domain it serves, computed at read / alert time — the cert no longer holds its own owner. The stored ``owner_person_id`` column survives ONLY as a deliberate admin override (manual-entry certs on unreachable hosts, or an explicit re-assignment). This migration adds ``owner_is_manual`` so the resolver can tell a deliberate override (honour it) from a legacy auto-snapshot (ignore it, live-resolve instead). We do NOT clear the legacy snapshot values: with ``owner_is_manual`` defaulting to FALSE for every existing row, the resolver simply ignores them — non-destructive and reversible. ``source='manual'`` certs were genuinely admin-entered, so they are flipped to ``owner_is_manual=TRUE`` to preserve their owner as an override. Revision ID: 360 Revises: 359 """ from __future__ import annotations import sqlalchemy as sa from alembic import op revision = "360" down_revision = "359" branch_labels = None depends_on = None TABLE = "cmdb_certificates" COLUMN = "owner_is_manual" def _column_exists(bind, table: str, column: str) -> bool: return bind.execute( sa.text( "SELECT 1 FROM information_schema.columns " "WHERE table_schema = DATABASE() AND table_name = :t " "AND column_name = :c" ), {"t": table, "c": column}, ).scalar() is not None def upgrade() -> None: bind = op.get_bind() if not _column_exists(bind, TABLE, COLUMN): op.add_column( TABLE, sa.Column( COLUMN, sa.Boolean(), nullable=False, server_default=sa.text("0"), ), ) # Preserve owner intent for genuinely admin-entered (manual) certs: # those owners were deliberate, so keep them as overrides. Probed / # cloud rows keep owner_is_manual=FALSE so the resolver live-resolves. bind.execute( sa.text( "UPDATE cmdb_certificates " "SET owner_is_manual = 1 " "WHERE source = 'manual' AND owner_person_id IS NOT NULL" ) ) def downgrade() -> None: bind = op.get_bind() if _column_exists(bind, TABLE, COLUMN): op.drop_column(TABLE, COLUMN)