"""Add SSH host key columns to devices table. Adds columns for SSH config backup support: - ssh_port: SSH port override (default 22) - ssh_host_key_fingerprint: TOFU host key fingerprint (SHA256:base64) - ssh_host_key_first_seen: when the host key was first observed - ssh_host_key_last_verified: when the host key was last verified Grants UPDATE on SSH columns to poller_user for TOFU persistence. Revision ID: 028 Revises: 027 Create Date: 2026-03-13 """ revision = "028" down_revision = "027" branch_labels = None depends_on = None from alembic import op import sqlalchemy as sa def upgrade() -> None: conn = op.get_bind() conn.execute(sa.text( "ALTER TABLE devices ADD COLUMN ssh_port INTEGER DEFAULT 22" )) conn.execute(sa.text( "ALTER TABLE devices ADD COLUMN ssh_host_key_fingerprint TEXT" )) conn.execute(sa.text( "ALTER TABLE devices ADD COLUMN ssh_host_key_first_seen TIMESTAMPTZ" )) conn.execute(sa.text( "ALTER TABLE devices ADD COLUMN ssh_host_key_last_verified TIMESTAMPTZ" )) # Grant poller_user UPDATE on SSH columns for TOFU host key persistence conn.execute(sa.text( "GRANT UPDATE (ssh_host_key_fingerprint, ssh_host_key_first_seen, ssh_host_key_last_verified) ON devices TO poller_user" )) def downgrade() -> None: conn = op.get_bind() conn.execute(sa.text( "REVOKE UPDATE (ssh_host_key_fingerprint, ssh_host_key_first_seen, ssh_host_key_last_verified) ON devices FROM poller_user" )) conn.execute(sa.text( "ALTER TABLE devices DROP COLUMN ssh_host_key_last_verified" )) conn.execute(sa.text( "ALTER TABLE devices DROP COLUMN ssh_host_key_first_seen" )) conn.execute(sa.text( "ALTER TABLE devices DROP COLUMN ssh_host_key_fingerprint" )) conn.execute(sa.text( "ALTER TABLE devices DROP COLUMN ssh_port" ))