"""baseline schema Revision ID: 4a914b1d62a0 Revises: Create Date: 2026-06-16 16:24:28.972499 """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa import sqlmodel # SQLModel column types (AutoString, …) referenced by autogenerate from sqlalchemy.dialects import mysql # revision identifiers, used by Alembic. revision: str = '4a914b1d62a0' down_revision: Union[str, Sequence[str], None] = None branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: """Upgrade schema.""" # ### commands auto generated by Alembic - please adjust! ### op.create_table('bounty', sa.Column('id', sa.Integer(), nullable=False), sa.Column('timestamp', sa.DateTime(), nullable=False), sa.Column('decky', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('service', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('attacker_ip', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('bounty_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('payload', sa.Text(), nullable=False), sa.PrimaryKeyConstraint('id') ) with op.batch_alter_table('bounty', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_bounty_attacker_ip'), ['attacker_ip'], unique=False) batch_op.create_index(batch_op.f('ix_bounty_bounty_type'), ['bounty_type'], unique=False) batch_op.create_index(batch_op.f('ix_bounty_decky'), ['decky'], unique=False) batch_op.create_index(batch_op.f('ix_bounty_service'), ['service'], unique=False) batch_op.create_index(batch_op.f('ix_bounty_timestamp'), ['timestamp'], unique=False) op.create_table('campaigns', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('schema_version', sa.Integer(), nullable=False), sa.Column('first_seen_at', sa.DateTime(), nullable=True), sa.Column('last_seen_at', sa.DateTime(), nullable=True), sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.Column('confidence', sa.Float(), nullable=True), sa.Column('identity_count', sa.Integer(), nullable=False), sa.Column('ja3_hashes', sa.Text(), nullable=True), sa.Column('hassh_hashes', sa.Text(), nullable=True), sa.Column('tls_cert_sha256', sa.Text(), nullable=True), sa.Column('payload_simhashes', sa.Text(), nullable=True), sa.Column('c2_endpoints', sa.Text(), nullable=True), sa.Column('merged_into_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('notes', sa.Text(), nullable=True), sa.ForeignKeyConstraint(['merged_into_uuid'], ['campaigns.uuid'], ), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('campaigns', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_campaigns_created_at'), ['created_at'], unique=False) batch_op.create_index(batch_op.f('ix_campaigns_first_seen_at'), ['first_seen_at'], unique=False) batch_op.create_index(batch_op.f('ix_campaigns_last_seen_at'), ['last_seen_at'], unique=False) batch_op.create_index(batch_op.f('ix_campaigns_merged_into_uuid'), ['merged_into_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_campaigns_updated_at'), ['updated_at'], unique=False) op.create_table('canary_blobs', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('sha256', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('filename', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('content_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('size_bytes', sa.Integer(), nullable=False), sa.Column('uploaded_by', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('uploaded_at', sa.DateTime(), nullable=False), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('canary_blobs', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_canary_blobs_sha256'), ['sha256'], unique=True) batch_op.create_index(batch_op.f('ix_canary_blobs_uploaded_by'), ['uploaded_by'], unique=False) op.create_table('credential_reuse', sa.Column('id', sqlmodel.sql.sqltypes.AutoString(length=36), nullable=False), sa.Column('secret_sha256', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('secret_kind', sqlmodel.sql.sqltypes.AutoString(length=32), nullable=False), sa.Column('principal', sqlmodel.sql.sqltypes.AutoString(length=256), nullable=True), sa.Column('principal_key', sqlmodel.sql.sqltypes.AutoString(length=256), nullable=False), sa.Column('attacker_uuids', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('attacker_ips', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('deckies', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('services', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('target_count', sa.Integer(), nullable=False), sa.Column('attempt_count', sa.Integer(), nullable=False), sa.Column('confidence', sa.Float(), nullable=False), sa.Column('first_seen', sa.DateTime(), nullable=False), sa.Column('last_seen', sa.DateTime(), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('secret_sha256', 'secret_kind', 'principal_key', name='uq_credential_reuse_secret_principal') ) with op.batch_alter_table('credential_reuse', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_credential_reuse_first_seen'), ['first_seen'], unique=False) batch_op.create_index(batch_op.f('ix_credential_reuse_last_seen'), ['last_seen'], unique=False) batch_op.create_index(batch_op.f('ix_credential_reuse_secret_kind'), ['secret_kind'], unique=False) batch_op.create_index(batch_op.f('ix_credential_reuse_secret_sha256'), ['secret_sha256'], unique=False) batch_op.create_index(batch_op.f('ix_credential_reuse_target_count'), ['target_count'], unique=False) batch_op.create_index(batch_op.f('ix_credential_reuse_updated_at'), ['updated_at'], unique=False) op.create_table('decky_lifecycle', sa.Column('id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('decky_name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('host_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('operation', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('error', sa.Text(), nullable=True), sa.Column('started_at', sa.DateTime(), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.Column('completed_at', sa.DateTime(), nullable=True), sa.PrimaryKeyConstraint('id') ) with op.batch_alter_table('decky_lifecycle', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_decky_lifecycle_decky_name'), ['decky_name'], unique=False) batch_op.create_index(batch_op.f('ix_decky_lifecycle_host_uuid'), ['host_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_decky_lifecycle_operation'), ['operation'], unique=False) batch_op.create_index(batch_op.f('ix_decky_lifecycle_status'), ['status'], unique=False) op.create_table('fleet_deckies', sa.Column('host_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('services', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('decky_config', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=True), sa.Column('decky_ip', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('state', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('last_error', sa.Text(), nullable=True), sa.Column('compose_hash', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('last_seen', sa.DateTime(), nullable=True), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.PrimaryKeyConstraint('host_uuid', 'name') ) with op.batch_alter_table('fleet_deckies', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_fleet_deckies_host_uuid'), ['host_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_fleet_deckies_state'), ['state'], unique=False) op.create_table('logs', sa.Column('id', sa.Integer(), nullable=False), sa.Column('timestamp', sa.DateTime(), nullable=False), sa.Column('decky', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('service', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('event_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('attacker_ip', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('raw_line', sa.Text(), nullable=False), sa.Column('fields', sa.Text(), nullable=False), sa.Column('msg', sa.Text(), nullable=True), sa.Column('trace_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('span_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.PrimaryKeyConstraint('id') ) with op.batch_alter_table('logs', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_logs_attacker_ip'), ['attacker_ip'], unique=False) batch_op.create_index(batch_op.f('ix_logs_decky'), ['decky'], unique=False) batch_op.create_index(batch_op.f('ix_logs_event_type'), ['event_type'], unique=False) batch_op.create_index(batch_op.f('ix_logs_service'), ['service'], unique=False) batch_op.create_index(batch_op.f('ix_logs_timestamp'), ['timestamp'], unique=False) op.create_table('observed_attachments', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('sha256', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('first_seen', sa.DateTime(), nullable=False), sa.Column('last_seen', sa.DateTime(), nullable=False), sa.Column('observation_count', sa.Integer(), nullable=False), sa.Column('first_seen_decky_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('first_seen_attacker_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('last_seen_attacker_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('extensions', sa.JSON(), nullable=False), sa.Column('first_subject', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('mal_hash_match', sa.Boolean(), nullable=True), sa.Column('mal_hash_match_provider', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=True), sa.Column('mal_hash_match_at', sa.DateTime(), nullable=True), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('observed_attachments', schema=None) as batch_op: batch_op.create_index('ix_observed_attachments_first_seen', ['first_seen'], unique=False) batch_op.create_index(batch_op.f('ix_observed_attachments_first_seen_attacker_uuid'), ['first_seen_attacker_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_observed_attachments_first_seen_decky_uuid'), ['first_seen_decky_uuid'], unique=False) batch_op.create_index('ix_observed_attachments_last_seen', ['last_seen'], unique=False) batch_op.create_index(batch_op.f('ix_observed_attachments_last_seen_attacker_uuid'), ['last_seen_attacker_uuid'], unique=False) batch_op.create_index('ix_observed_attachments_mal_hash_match', ['mal_hash_match'], unique=False) batch_op.create_index(batch_op.f('ix_observed_attachments_sha256'), ['sha256'], unique=True) op.create_table('orchestrator_emails', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('ts', sa.DateTime(), nullable=False), sa.Column('mail_decky_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('thread_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('message_id', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), sa.Column('in_reply_to', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), sa.Column('sender_email', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), sa.Column('recipient_email', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), sa.Column('subject', sqlmodel.sql.sqltypes.AutoString(length=512), nullable=False), sa.Column('language', sqlmodel.sql.sqltypes.AutoString(length=8), nullable=False), sa.Column('eml_path', sqlmodel.sql.sqltypes.AutoString(length=1024), nullable=False), sa.Column('success', sa.Boolean(), nullable=False), sa.Column('payload', sa.Text(), nullable=False), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('orchestrator_emails', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_orchestrator_emails_mail_decky_uuid'), ['mail_decky_uuid'], unique=False) batch_op.create_index('ix_orchestrator_emails_mail_ts', ['mail_decky_uuid', 'ts'], unique=False) batch_op.create_index(batch_op.f('ix_orchestrator_emails_recipient_email'), ['recipient_email'], unique=False) batch_op.create_index(batch_op.f('ix_orchestrator_emails_sender_email'), ['sender_email'], unique=False) batch_op.create_index(batch_op.f('ix_orchestrator_emails_success'), ['success'], unique=False) batch_op.create_index('ix_orchestrator_emails_thread', ['thread_id'], unique=False) batch_op.create_index(batch_op.f('ix_orchestrator_emails_thread_id'), ['thread_id'], unique=False) batch_op.create_index(batch_op.f('ix_orchestrator_emails_ts'), ['ts'], unique=False) op.create_table('orchestrator_events', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('ts', sa.DateTime(), nullable=False), sa.Column('kind', sqlmodel.sql.sqltypes.AutoString(length=16), nullable=False), sa.Column('protocol', sqlmodel.sql.sqltypes.AutoString(length=16), nullable=False), sa.Column('action', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('src_decky_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('dst_decky_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('success', sa.Boolean(), nullable=False), sa.Column('payload', sa.Text(), nullable=False), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('orchestrator_events', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_orchestrator_events_dst_decky_uuid'), ['dst_decky_uuid'], unique=False) batch_op.create_index('ix_orchestrator_events_dst_ts', ['dst_decky_uuid', 'ts'], unique=False) batch_op.create_index(batch_op.f('ix_orchestrator_events_kind'), ['kind'], unique=False) batch_op.create_index(batch_op.f('ix_orchestrator_events_protocol'), ['protocol'], unique=False) batch_op.create_index(batch_op.f('ix_orchestrator_events_src_decky_uuid'), ['src_decky_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_orchestrator_events_success'), ['success'], unique=False) batch_op.create_index(batch_op.f('ix_orchestrator_events_ts'), ['ts'], unique=False) op.create_table('realism_config', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('key', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('value', sa.Text(), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('realism_config', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_realism_config_key'), ['key'], unique=True) op.create_table('revoked_tokens', sa.Column('jti', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('user_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('expires_at', sa.DateTime(), nullable=False), sa.Column('revoked_at', sa.DateTime(), nullable=False), sa.PrimaryKeyConstraint('jti') ) with op.batch_alter_table('revoked_tokens', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_revoked_tokens_expires_at'), ['expires_at'], unique=False) batch_op.create_index(batch_op.f('ix_revoked_tokens_user_uuid'), ['user_uuid'], unique=False) op.create_table('state', sa.Column('key', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('value', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.PrimaryKeyConstraint('key') ) op.create_table('swarm_hosts', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('address', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('agent_port', sa.Integer(), nullable=False), sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('last_heartbeat', sa.DateTime(), nullable=True), sa.Column('client_cert_fingerprint', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('updater_cert_fingerprint', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('cert_bundle_path', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('enrolled_at', sa.DateTime(), nullable=False), sa.Column('notes', sa.Text(), nullable=True), sa.Column('use_ipvlan', sa.Boolean(), nullable=False), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('swarm_hosts', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_swarm_hosts_name'), ['name'], unique=True) batch_op.create_index(batch_op.f('ix_swarm_hosts_status'), ['status'], unique=False) op.create_table('synthetic_files', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('decky_uuid', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('path', sqlmodel.sql.sqltypes.AutoString(length=512), nullable=False), sa.Column('persona', sqlmodel.sql.sqltypes.AutoString(length=128), nullable=False), sa.Column('content_class', sqlmodel.sql.sqltypes.AutoString(length=32), nullable=False), sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column('last_modified', sa.DateTime(), nullable=False), sa.Column('edit_count', sa.Integer(), nullable=False), sa.Column('content_hash', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('last_body', sa.Text(), nullable=False), sa.PrimaryKeyConstraint('uuid'), sa.UniqueConstraint('decky_uuid', 'path', name='uq_synthetic_files_decky_path') ) with op.batch_alter_table('synthetic_files', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_synthetic_files_content_class'), ['content_class'], unique=False) batch_op.create_index(batch_op.f('ix_synthetic_files_created_at'), ['created_at'], unique=False) batch_op.create_index('ix_synthetic_files_decky_modified', ['decky_uuid', 'last_modified'], unique=False) batch_op.create_index(batch_op.f('ix_synthetic_files_decky_uuid'), ['decky_uuid'], unique=False) op.create_table('tarpit_rules', sa.Column('id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('decky_name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('ports', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('delay_ms', sa.Integer(), nullable=False), sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column('created_by', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.PrimaryKeyConstraint('id') ) with op.batch_alter_table('tarpit_rules', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_tarpit_rules_decky_name'), ['decky_name'], unique=True) op.create_table('ttp_rule', sa.Column('rule_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('rule_version', sa.Integer(), nullable=False), sa.Column('source_path', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('yaml_content', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.Column('updated_by', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.PrimaryKeyConstraint('rule_id') ) op.create_table('ttp_rule_state', sa.Column('rule_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('state', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('confidence_max', sa.Float(), nullable=True), sa.Column('expires_at', sa.DateTime(), nullable=True), sa.Column('reason', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('set_by', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('set_at', sa.DateTime(), nullable=False), sa.PrimaryKeyConstraint('rule_id') ) op.create_table('users', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('username', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('password_hash', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('role', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('must_change_password', sa.Boolean(), nullable=False), sa.Column('tokens_valid_from', sa.DateTime(), nullable=True), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('users', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_users_username'), ['username'], unique=True) op.create_table('webhook_subscriptions', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('url', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('secret', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('topic_patterns', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('enabled', sa.Boolean(), nullable=False), sa.Column('consecutive_failures', sa.Integer(), nullable=False), sa.Column('last_success_at', sa.DateTime(), nullable=True), sa.Column('last_failure_at', sa.DateTime(), nullable=True), sa.Column('last_error', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('auto_disabled_at', sa.DateTime(), nullable=True), sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('webhook_subscriptions', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_webhook_subscriptions_enabled'), ['enabled'], unique=False) batch_op.create_index(batch_op.f('ix_webhook_subscriptions_name'), ['name'], unique=True) op.create_table('attacker_identities', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('schema_version', sa.Integer(), nullable=False), sa.Column('campaign_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('first_seen_at', sa.DateTime(), nullable=True), sa.Column('last_seen_at', sa.DateTime(), nullable=True), sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.Column('confidence', sa.Float(), nullable=True), sa.Column('observation_count', sa.Integer(), nullable=False), sa.Column('ja3_hashes', sa.Text(), nullable=True), sa.Column('hassh_hashes', sa.Text(), nullable=True), sa.Column('ja4h_hashes', sa.Text(), nullable=True), sa.Column('ja4_quic_hashes', sa.Text(), nullable=True), sa.Column('http_versions_seen', sa.Text(), nullable=True), sa.Column('tls_cert_sha256', sa.Text(), nullable=True), sa.Column('ipv6_link_local_iids', sa.Text(), nullable=True), sa.Column('payload_simhashes', sa.Text(), nullable=True), sa.Column('c2_endpoints', sa.Text(), nullable=True), sa.Column('kd_digraph_simhash', sa.BINARY(length=8).with_variant(sa.LargeBinary(), 'sqlite'), nullable=True), sa.Column('merged_into_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('notes', sa.Text(), nullable=True), sa.ForeignKeyConstraint(['campaign_id'], ['campaigns.uuid'], ), sa.ForeignKeyConstraint(['merged_into_uuid'], ['attacker_identities.uuid'], ), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('attacker_identities', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_attacker_identities_campaign_id'), ['campaign_id'], unique=False) batch_op.create_index(batch_op.f('ix_attacker_identities_created_at'), ['created_at'], unique=False) batch_op.create_index(batch_op.f('ix_attacker_identities_first_seen_at'), ['first_seen_at'], unique=False) batch_op.create_index(batch_op.f('ix_attacker_identities_kd_digraph_simhash'), ['kd_digraph_simhash'], unique=False) batch_op.create_index(batch_op.f('ix_attacker_identities_last_seen_at'), ['last_seen_at'], unique=False) batch_op.create_index(batch_op.f('ix_attacker_identities_merged_into_uuid'), ['merged_into_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_attacker_identities_updated_at'), ['updated_at'], unique=False) op.create_table('canary_tokens', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('kind', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('decky_name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('topology_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('blob_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('instrumenter', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('generator', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('placement_path', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('callback_token', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('secret_seed', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('placed_at', sa.DateTime(), nullable=False), sa.Column('last_triggered_at', sa.DateTime(), nullable=True), sa.Column('trigger_count', sa.Integer(), nullable=False), sa.Column('created_by', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('state', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('last_error', sa.Text(), nullable=True), sa.Column('fingerprint_nonce', sqlmodel.sql.sqltypes.AutoString(length=16), nullable=True), sa.ForeignKeyConstraint(['blob_uuid'], ['canary_blobs.uuid'], ), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('canary_tokens', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_canary_tokens_blob_uuid'), ['blob_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_canary_tokens_callback_token'), ['callback_token'], unique=True) batch_op.create_index(batch_op.f('ix_canary_tokens_created_by'), ['created_by'], unique=False) batch_op.create_index('ix_canary_tokens_decky', ['decky_name', 'state'], unique=False) batch_op.create_index(batch_op.f('ix_canary_tokens_decky_name'), ['decky_name'], unique=False) batch_op.create_index(batch_op.f('ix_canary_tokens_kind'), ['kind'], unique=False) batch_op.create_index(batch_op.f('ix_canary_tokens_last_triggered_at'), ['last_triggered_at'], unique=False) batch_op.create_index(batch_op.f('ix_canary_tokens_state'), ['state'], unique=False) batch_op.create_index(batch_op.f('ix_canary_tokens_topology_id'), ['topology_id'], unique=False) op.create_table('decky_shards', sa.Column('decky_name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('host_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('services', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('decky_config', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=True), sa.Column('decky_ip', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('state', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('last_error', sa.Text(), nullable=True), sa.Column('compose_hash', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('last_seen', sa.DateTime(), nullable=True), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.ForeignKeyConstraint(['host_uuid'], ['swarm_hosts.uuid'], ), sa.PrimaryKeyConstraint('decky_name') ) with op.batch_alter_table('decky_shards', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_decky_shards_host_uuid'), ['host_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_decky_shards_state'), ['state'], unique=False) op.create_table('topologies', sa.Column('id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('mode', sa.String(length=16), nullable=False), sa.Column('target_host_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('config_snapshot', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('status', sa.String(length=32), nullable=False), sa.Column('status_changed_at', sa.DateTime(), nullable=False), sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column('version', sa.Integer(), nullable=False), sa.Column('needs_resync', sa.Boolean(), nullable=False), sa.Column('email_personas', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('language_default', sqlmodel.sql.sqltypes.AutoString(length=8), nullable=False), sa.ForeignKeyConstraint(['target_host_uuid'], ['swarm_hosts.uuid'], ), sa.PrimaryKeyConstraint('id') ) with op.batch_alter_table('topologies', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_topologies_created_at'), ['created_at'], unique=False) batch_op.create_index(batch_op.f('ix_topologies_name'), ['name'], unique=True) batch_op.create_index(batch_op.f('ix_topologies_status'), ['status'], unique=False) batch_op.create_index(batch_op.f('ix_topologies_target_host_uuid'), ['target_host_uuid'], unique=False) op.create_table('attackers', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('ip', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('identity_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('first_seen', sa.DateTime(), nullable=False), sa.Column('last_seen', sa.DateTime(), nullable=False), sa.Column('event_count', sa.Integer(), nullable=False), sa.Column('service_count', sa.Integer(), nullable=False), sa.Column('decky_count', sa.Integer(), nullable=False), sa.Column('services', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('deckies', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('traversal_path', sa.Text(), nullable=True), sa.Column('is_traversal', sa.Boolean(), nullable=False), sa.Column('bounty_count', sa.Integer(), nullable=False), sa.Column('credential_count', sa.Integer(), nullable=False), sa.Column('fingerprints', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('commands', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('country_code', sqlmodel.sql.sqltypes.AutoString(length=2), nullable=True), sa.Column('country_source', sqlmodel.sql.sqltypes.AutoString(length=16), nullable=True), sa.Column('asn', sa.Integer(), nullable=True), sa.Column('as_name', sqlmodel.sql.sqltypes.AutoString(length=128), nullable=True), sa.Column('bgp_prefix', sqlmodel.sql.sqltypes.AutoString(length=43), nullable=True), sa.Column('asn_source', sqlmodel.sql.sqltypes.AutoString(length=16), nullable=True), sa.Column('rpki_status', sqlmodel.sql.sqltypes.AutoString(length=16), nullable=True), sa.Column('rpki_source', sqlmodel.sql.sqltypes.AutoString(length=16), nullable=True), sa.Column('ptr_record', sqlmodel.sql.sqltypes.AutoString(length=256), nullable=True), sa.Column('rotation_count', sa.Integer(), nullable=False), sa.Column('last_rotation_at', sa.DateTime(), nullable=True), sa.Column('ipv6_leak_count', sa.Integer(), nullable=False), sa.Column('last_ipv6_leak_at', sa.DateTime(), nullable=True), sa.Column('last_ipv6_link_local', sqlmodel.sql.sqltypes.AutoString(length=45), nullable=True), sa.Column('last_ipv6_iid_kind', sqlmodel.sql.sqltypes.AutoString(length=16), nullable=True), sa.Column('last_ipv6_mac_oui', sqlmodel.sql.sqltypes.AutoString(length=8), nullable=True), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.ForeignKeyConstraint(['identity_id'], ['attacker_identities.uuid'], ), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('attackers', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_attackers_asn'), ['asn'], unique=False) batch_op.create_index(batch_op.f('ix_attackers_bgp_prefix'), ['bgp_prefix'], unique=False) batch_op.create_index(batch_op.f('ix_attackers_country_code'), ['country_code'], unique=False) batch_op.create_index(batch_op.f('ix_attackers_first_seen'), ['first_seen'], unique=False) batch_op.create_index(batch_op.f('ix_attackers_identity_id'), ['identity_id'], unique=False) batch_op.create_index(batch_op.f('ix_attackers_ip'), ['ip'], unique=False) batch_op.create_index(batch_op.f('ix_attackers_last_ipv6_leak_at'), ['last_ipv6_leak_at'], unique=False) batch_op.create_index(batch_op.f('ix_attackers_last_rotation_at'), ['last_rotation_at'], unique=False) batch_op.create_index(batch_op.f('ix_attackers_last_seen'), ['last_seen'], unique=False) batch_op.create_index(batch_op.f('ix_attackers_updated_at'), ['updated_at'], unique=False) op.create_table('attribution_state', sa.Column('identity_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('primitive', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('current_value', sa.JSON(), nullable=False), sa.Column('state', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('confidence', sa.Float(), nullable=False), sa.Column('observation_count', sa.Integer(), nullable=False), sa.Column('last_change_ts', sa.Float(), nullable=False), sa.Column('last_observation_ts', sa.Float(), nullable=False), sa.Column('schema_version', sa.Integer(), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.ForeignKeyConstraint(['identity_uuid'], ['attacker_identities.uuid'], ), sa.PrimaryKeyConstraint('identity_uuid', 'primitive') ) with op.batch_alter_table('attribution_state', schema=None) as batch_op: batch_op.create_index('ix_attribution_state_identity_state', ['identity_uuid', 'state'], unique=False) batch_op.create_index('ix_attribution_state_last_change', ['last_change_ts'], unique=False) batch_op.create_index('ix_attribution_state_state', ['state'], unique=False) op.create_table('canary_triggers', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('token_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('occurred_at', sa.DateTime(), nullable=False), sa.Column('src_ip', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('user_agent', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('request_path', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('dns_qname', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('raw_headers', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('attacker_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.ForeignKeyConstraint(['token_uuid'], ['canary_tokens.uuid'], ), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('canary_triggers', schema=None) as batch_op: batch_op.create_index('ix_canary_triggers_attacker', ['attacker_id'], unique=False) batch_op.create_index(batch_op.f('ix_canary_triggers_attacker_id'), ['attacker_id'], unique=False) batch_op.create_index(batch_op.f('ix_canary_triggers_src_ip'), ['src_ip'], unique=False) batch_op.create_index('ix_canary_triggers_token_ts', ['token_uuid', 'occurred_at'], unique=False) batch_op.create_index(batch_op.f('ix_canary_triggers_token_uuid'), ['token_uuid'], unique=False) op.create_table('lans', sa.Column('id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('topology_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('docker_network_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('subnet', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('is_dmz', sa.Boolean(), nullable=False), sa.Column('x', sa.Float(), nullable=True), sa.Column('y', sa.Float(), nullable=True), sa.ForeignKeyConstraint(['topology_id'], ['topologies.id'], ), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('topology_id', 'name', name='uq_lan_topology_name') ) with op.batch_alter_table('lans', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_lans_topology_id'), ['topology_id'], unique=False) op.create_table('topology_deckies', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('topology_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('services', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('decky_config', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=True), sa.Column('ip', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('state', sa.String(length=32), nullable=False), sa.Column('last_error', sa.Text(), nullable=True), sa.Column('compose_hash', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('last_seen', sa.DateTime(), nullable=True), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.Column('x', sa.Float(), nullable=True), sa.Column('y', sa.Float(), nullable=True), sa.ForeignKeyConstraint(['topology_id'], ['topologies.id'], ), sa.PrimaryKeyConstraint('uuid'), sa.UniqueConstraint('topology_id', 'name', name='uq_topology_decky_name') ) with op.batch_alter_table('topology_deckies', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_topology_deckies_state'), ['state'], unique=False) batch_op.create_index(batch_op.f('ix_topology_deckies_topology_id'), ['topology_id'], unique=False) op.create_table('topology_mutations', sa.Column('id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('topology_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('op', sa.String(length=32), nullable=False), sa.Column('payload', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('state', sa.String(length=32), nullable=False), sa.Column('requested_at', sa.DateTime(), nullable=False), sa.Column('applied_at', sa.DateTime(), nullable=True), sa.Column('reason', sa.Text(), nullable=True), sa.ForeignKeyConstraint(['topology_id'], ['topologies.id'], ), sa.PrimaryKeyConstraint('id') ) with op.batch_alter_table('topology_mutations', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_topology_mutations_op'), ['op'], unique=False) batch_op.create_index(batch_op.f('ix_topology_mutations_requested_at'), ['requested_at'], unique=False) batch_op.create_index(batch_op.f('ix_topology_mutations_state'), ['state'], unique=False) batch_op.create_index('ix_topology_mutations_state_topology', ['state', 'topology_id'], unique=False) batch_op.create_index(batch_op.f('ix_topology_mutations_topology_id'), ['topology_id'], unique=False) op.create_table('topology_status_events', sa.Column('id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('topology_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('from_status', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('to_status', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('at', sa.DateTime(), nullable=False), sa.Column('reason', sa.Text(), nullable=True), sa.ForeignKeyConstraint(['topology_id'], ['topologies.id'], ), sa.PrimaryKeyConstraint('id') ) with op.batch_alter_table('topology_status_events', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_topology_status_events_at'), ['at'], unique=False) batch_op.create_index(batch_op.f('ix_topology_status_events_topology_id'), ['topology_id'], unique=False) op.create_table('attacker_behavior', sa.Column('attacker_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('os_guess', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('hop_distance', sa.Integer(), nullable=True), sa.Column('tcp_fingerprint', sa.Text(), nullable=False), sa.Column('kex_order_raw', sa.Text(), nullable=True), sa.Column('ssh_client_banners', sa.Text(), nullable=True), sa.Column('retransmit_count', sa.Integer(), nullable=False), sa.Column('behavior_class', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('beacon_interval_s', sa.Float(), nullable=True), sa.Column('beacon_jitter_pct', sa.Float(), nullable=True), sa.Column('tool_guesses', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('timing_stats', sa.Text(), nullable=False), sa.Column('phase_sequence', sa.Text(), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.ForeignKeyConstraint(['attacker_uuid'], ['attackers.uuid'], ), sa.PrimaryKeyConstraint('attacker_uuid') ) with op.batch_alter_table('attacker_behavior', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_attacker_behavior_updated_at'), ['updated_at'], unique=False) op.create_table('attacker_fingerprint_state', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('attacker_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('port', sa.Integer(), nullable=False), sa.Column('probe_type', sqlmodel.sql.sqltypes.AutoString(length=16), nullable=False), sa.Column('last_hash', sqlmodel.sql.sqltypes.AutoString(length=128), nullable=False), sa.Column('last_seen', sa.DateTime(), nullable=False), sa.Column('rotation_count', sa.Integer(), nullable=False), sa.ForeignKeyConstraint(['attacker_uuid'], ['attackers.uuid'], ), sa.PrimaryKeyConstraint('uuid'), sa.UniqueConstraint('attacker_uuid', 'port', 'probe_type', name='uq_attacker_fingerprint_state_natural') ) with op.batch_alter_table('attacker_fingerprint_state', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_attacker_fingerprint_state_attacker_uuid'), ['attacker_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_attacker_fingerprint_state_last_seen'), ['last_seen'], unique=False) op.create_table('attacker_intel', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('attacker_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('attacker_ip', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('schema_version', sa.Integer(), nullable=False), sa.Column('greynoise_classification', sqlmodel.sql.sqltypes.AutoString(length=32), nullable=True), sa.Column('greynoise_name', sqlmodel.sql.sqltypes.AutoString(length=128), nullable=True), sa.Column('greynoise_tags', sa.JSON(), nullable=False), sa.Column('greynoise_raw', sa.JSON(), nullable=False), sa.Column('greynoise_queried_at', sa.DateTime(), nullable=True), sa.Column('abuseipdb_score', sa.Integer(), nullable=True), sa.Column('abuseipdb_categories', sa.JSON(), nullable=False), sa.Column('abuseipdb_raw', sa.JSON(), nullable=False), sa.Column('abuseipdb_queried_at', sa.DateTime(), nullable=True), sa.Column('feodo_listed', sa.Boolean(), nullable=True), sa.Column('feodo_malware_family', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=True), sa.Column('feodo_raw', sa.JSON(), nullable=False), sa.Column('feodo_queried_at', sa.DateTime(), nullable=True), sa.Column('threatfox_listed', sa.Boolean(), nullable=True), sa.Column('threatfox_threat_types', sa.JSON(), nullable=False), sa.Column('threatfox_ioc_types', sa.JSON(), nullable=False), sa.Column('threatfox_malware_families', sa.JSON(), nullable=False), sa.Column('threatfox_raw', sa.JSON(), nullable=False), sa.Column('threatfox_queried_at', sa.DateTime(), nullable=True), sa.Column('aggregate_verdict', sqlmodel.sql.sqltypes.AutoString(length=32), nullable=True), sa.Column('cached_at', sa.DateTime(), nullable=False), sa.Column('expires_at', sa.DateTime(), nullable=False), sa.ForeignKeyConstraint(['attacker_uuid'], ['attackers.uuid'], ), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('attacker_intel', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_attacker_intel_aggregate_verdict'), ['aggregate_verdict'], unique=False) batch_op.create_index(batch_op.f('ix_attacker_intel_attacker_ip'), ['attacker_ip'], unique=False) batch_op.create_index(batch_op.f('ix_attacker_intel_attacker_uuid'), ['attacker_uuid'], unique=True) batch_op.create_index(batch_op.f('ix_attacker_intel_cached_at'), ['cached_at'], unique=False) batch_op.create_index(batch_op.f('ix_attacker_intel_expires_at'), ['expires_at'], unique=False) op.create_table('credentials', sa.Column('id', sa.Integer(), nullable=False), sa.Column('attacker_ip', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('attacker_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('decky_name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('service', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('principal', sqlmodel.sql.sqltypes.AutoString(length=256), nullable=True), sa.Column('principal_key', sqlmodel.sql.sqltypes.AutoString(length=256), nullable=False), sa.Column('secret_kind', sqlmodel.sql.sqltypes.AutoString(length=32), nullable=False), sa.Column('secret_sha256', sqlmodel.sql.sqltypes.AutoString(length=64), nullable=False), sa.Column('secret_b64', sqlmodel.sql.sqltypes.AutoString(length=2048), nullable=True), sa.Column('secret_printable', sqlmodel.sql.sqltypes.AutoString(length=512), nullable=True), sa.Column('outcome', sqlmodel.sql.sqltypes.AutoString(length=16), nullable=True), sa.Column('fields', sa.Text().with_variant(mysql.MEDIUMTEXT(), 'mysql'), nullable=False), sa.Column('first_seen', sa.DateTime(), nullable=False), sa.Column('last_seen', sa.DateTime(), nullable=False), sa.Column('attempt_count', sa.Integer(), nullable=False), sa.ForeignKeyConstraint(['attacker_uuid'], ['attackers.uuid'], ), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('attacker_ip', 'decky_name', 'service', 'secret_kind', 'secret_sha256', 'principal_key', name='uq_credentials_dedup') ) with op.batch_alter_table('credentials', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_credentials_attacker_ip'), ['attacker_ip'], unique=False) batch_op.create_index(batch_op.f('ix_credentials_attacker_uuid'), ['attacker_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_credentials_decky_name'), ['decky_name'], unique=False) batch_op.create_index(batch_op.f('ix_credentials_first_seen'), ['first_seen'], unique=False) batch_op.create_index(batch_op.f('ix_credentials_last_seen'), ['last_seen'], unique=False) batch_op.create_index(batch_op.f('ix_credentials_principal'), ['principal'], unique=False) batch_op.create_index('ix_credentials_principal_service', ['principal', 'service'], unique=False) batch_op.create_index(batch_op.f('ix_credentials_secret_kind'), ['secret_kind'], unique=False) batch_op.create_index('ix_credentials_secret_service', ['secret_sha256', 'service'], unique=False) batch_op.create_index(batch_op.f('ix_credentials_secret_sha256'), ['secret_sha256'], unique=False) batch_op.create_index(batch_op.f('ix_credentials_service'), ['service'], unique=False) op.create_table('observations', sa.Column('id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('identity_ref', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('primitive', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('value', sa.JSON(), nullable=False), sa.Column('confidence', sa.Float(), nullable=False), sa.Column('window_start_ts', sa.Float(), nullable=False), sa.Column('window_end_ts', sa.Float(), nullable=False), sa.Column('source', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('evidence_ref', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('envelope_v', sa.Integer(), nullable=False), sa.Column('ts', sa.Float(), nullable=False), sa.Column('attacker_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.ForeignKeyConstraint(['attacker_uuid'], ['attackers.uuid'], ), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('evidence_ref', 'primitive', name='uq_observations_evidence_primitive') ) with op.batch_alter_table('observations', schema=None) as batch_op: batch_op.create_index('ix_observations_attacker_primitive_ts', ['attacker_uuid', 'primitive', 'ts'], unique=False) batch_op.create_index(batch_op.f('ix_observations_attacker_uuid'), ['attacker_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_observations_primitive'), ['primitive'], unique=False) batch_op.create_index('ix_observations_primitive_ts', ['primitive', 'ts'], unique=False) batch_op.create_index(batch_op.f('ix_observations_ts'), ['ts'], unique=False) op.create_table('smtp_targets', sa.Column('id', sa.Integer(), nullable=False), sa.Column('attacker_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('domain', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('first_seen', sa.DateTime(), nullable=False), sa.Column('last_seen', sa.DateTime(), nullable=False), sa.Column('count', sa.Integer(), nullable=False), sa.ForeignKeyConstraint(['attacker_uuid'], ['attackers.uuid'], ), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('attacker_uuid', 'domain', name='uq_smtp_targets_attacker_domain') ) with op.batch_alter_table('smtp_targets', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_smtp_targets_attacker_uuid'), ['attacker_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_smtp_targets_domain'), ['domain'], unique=False) batch_op.create_index(batch_op.f('ix_smtp_targets_last_seen'), ['last_seen'], unique=False) op.create_table('topology_edges', sa.Column('id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('topology_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('decky_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('lan_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('is_bridge', sa.Boolean(), nullable=False), sa.Column('forwards_l3', sa.Boolean(), nullable=False), sa.ForeignKeyConstraint(['decky_uuid'], ['topology_deckies.uuid'], ), sa.ForeignKeyConstraint(['lan_id'], ['lans.id'], ), sa.ForeignKeyConstraint(['topology_id'], ['topologies.id'], ), sa.PrimaryKeyConstraint('id') ) with op.batch_alter_table('topology_edges', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_topology_edges_decky_uuid'), ['decky_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_topology_edges_lan_id'), ['lan_id'], unique=False) batch_op.create_index(batch_op.f('ix_topology_edges_topology_id'), ['topology_id'], unique=False) op.create_table('ttp_tag', sa.Column('uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('source_kind', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('source_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('attacker_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('identity_uuid', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('session_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('decky_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('tactic', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('technique_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('sub_technique_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('confidence', sa.Float(), nullable=False), sa.Column('rule_id', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('rule_version', sa.Integer(), nullable=False), sa.Column('evidence', sa.JSON(), nullable=False), sa.Column('attack_release', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column('mitre_url', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column('created_at', sa.DateTime(), nullable=False), sa.CheckConstraint('attacker_uuid IS NOT NULL OR identity_uuid IS NOT NULL', name='ttp_tag_has_anchor'), sa.CheckConstraint('confidence >= 0.0 AND confidence <= 1.0', name='ttp_tag_confidence_range'), sa.ForeignKeyConstraint(['attacker_uuid'], ['attackers.uuid'], ondelete='CASCADE'), sa.ForeignKeyConstraint(['identity_uuid'], ['attacker_identities.uuid'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('uuid') ) with op.batch_alter_table('ttp_tag', schema=None) as batch_op: batch_op.create_index(batch_op.f('ix_ttp_tag_attack_release'), ['attack_release'], unique=False) batch_op.create_index('ix_ttp_tag_attacker_technique', ['attacker_uuid', 'technique_id'], unique=False) batch_op.create_index(batch_op.f('ix_ttp_tag_attacker_uuid'), ['attacker_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_ttp_tag_created_at'), ['created_at'], unique=False) batch_op.create_index(batch_op.f('ix_ttp_tag_decky_id'), ['decky_id'], unique=False) batch_op.create_index('ix_ttp_tag_identity_technique', ['identity_uuid', 'technique_id'], unique=False) batch_op.create_index(batch_op.f('ix_ttp_tag_identity_uuid'), ['identity_uuid'], unique=False) batch_op.create_index(batch_op.f('ix_ttp_tag_rule_id'), ['rule_id'], unique=False) batch_op.create_index(batch_op.f('ix_ttp_tag_session_id'), ['session_id'], unique=False) batch_op.create_index(batch_op.f('ix_ttp_tag_sub_technique_id'), ['sub_technique_id'], unique=False) batch_op.create_index(batch_op.f('ix_ttp_tag_tactic'), ['tactic'], unique=False) batch_op.create_index('ix_ttp_tag_technique_created', ['technique_id', 'created_at'], unique=False) batch_op.create_index(batch_op.f('ix_ttp_tag_technique_id'), ['technique_id'], unique=False) # ### end Alembic commands ### def downgrade() -> None: """Downgrade schema.""" # ### commands auto generated by Alembic - please adjust! ### with op.batch_alter_table('ttp_tag', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_ttp_tag_technique_id')) batch_op.drop_index('ix_ttp_tag_technique_created') batch_op.drop_index(batch_op.f('ix_ttp_tag_tactic')) batch_op.drop_index(batch_op.f('ix_ttp_tag_sub_technique_id')) batch_op.drop_index(batch_op.f('ix_ttp_tag_session_id')) batch_op.drop_index(batch_op.f('ix_ttp_tag_rule_id')) batch_op.drop_index(batch_op.f('ix_ttp_tag_identity_uuid')) batch_op.drop_index('ix_ttp_tag_identity_technique') batch_op.drop_index(batch_op.f('ix_ttp_tag_decky_id')) batch_op.drop_index(batch_op.f('ix_ttp_tag_created_at')) batch_op.drop_index(batch_op.f('ix_ttp_tag_attacker_uuid')) batch_op.drop_index('ix_ttp_tag_attacker_technique') batch_op.drop_index(batch_op.f('ix_ttp_tag_attack_release')) op.drop_table('ttp_tag') with op.batch_alter_table('topology_edges', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_topology_edges_topology_id')) batch_op.drop_index(batch_op.f('ix_topology_edges_lan_id')) batch_op.drop_index(batch_op.f('ix_topology_edges_decky_uuid')) op.drop_table('topology_edges') with op.batch_alter_table('smtp_targets', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_smtp_targets_last_seen')) batch_op.drop_index(batch_op.f('ix_smtp_targets_domain')) batch_op.drop_index(batch_op.f('ix_smtp_targets_attacker_uuid')) op.drop_table('smtp_targets') with op.batch_alter_table('observations', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_observations_ts')) batch_op.drop_index('ix_observations_primitive_ts') batch_op.drop_index(batch_op.f('ix_observations_primitive')) batch_op.drop_index(batch_op.f('ix_observations_attacker_uuid')) batch_op.drop_index('ix_observations_attacker_primitive_ts') op.drop_table('observations') with op.batch_alter_table('credentials', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_credentials_service')) batch_op.drop_index(batch_op.f('ix_credentials_secret_sha256')) batch_op.drop_index('ix_credentials_secret_service') batch_op.drop_index(batch_op.f('ix_credentials_secret_kind')) batch_op.drop_index('ix_credentials_principal_service') batch_op.drop_index(batch_op.f('ix_credentials_principal')) batch_op.drop_index(batch_op.f('ix_credentials_last_seen')) batch_op.drop_index(batch_op.f('ix_credentials_first_seen')) batch_op.drop_index(batch_op.f('ix_credentials_decky_name')) batch_op.drop_index(batch_op.f('ix_credentials_attacker_uuid')) batch_op.drop_index(batch_op.f('ix_credentials_attacker_ip')) op.drop_table('credentials') with op.batch_alter_table('attacker_intel', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_attacker_intel_expires_at')) batch_op.drop_index(batch_op.f('ix_attacker_intel_cached_at')) batch_op.drop_index(batch_op.f('ix_attacker_intel_attacker_uuid')) batch_op.drop_index(batch_op.f('ix_attacker_intel_attacker_ip')) batch_op.drop_index(batch_op.f('ix_attacker_intel_aggregate_verdict')) op.drop_table('attacker_intel') with op.batch_alter_table('attacker_fingerprint_state', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_attacker_fingerprint_state_last_seen')) batch_op.drop_index(batch_op.f('ix_attacker_fingerprint_state_attacker_uuid')) op.drop_table('attacker_fingerprint_state') with op.batch_alter_table('attacker_behavior', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_attacker_behavior_updated_at')) op.drop_table('attacker_behavior') with op.batch_alter_table('topology_status_events', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_topology_status_events_topology_id')) batch_op.drop_index(batch_op.f('ix_topology_status_events_at')) op.drop_table('topology_status_events') with op.batch_alter_table('topology_mutations', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_topology_mutations_topology_id')) batch_op.drop_index('ix_topology_mutations_state_topology') batch_op.drop_index(batch_op.f('ix_topology_mutations_state')) batch_op.drop_index(batch_op.f('ix_topology_mutations_requested_at')) batch_op.drop_index(batch_op.f('ix_topology_mutations_op')) op.drop_table('topology_mutations') with op.batch_alter_table('topology_deckies', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_topology_deckies_topology_id')) batch_op.drop_index(batch_op.f('ix_topology_deckies_state')) op.drop_table('topology_deckies') with op.batch_alter_table('lans', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_lans_topology_id')) op.drop_table('lans') with op.batch_alter_table('canary_triggers', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_canary_triggers_token_uuid')) batch_op.drop_index('ix_canary_triggers_token_ts') batch_op.drop_index(batch_op.f('ix_canary_triggers_src_ip')) batch_op.drop_index(batch_op.f('ix_canary_triggers_attacker_id')) batch_op.drop_index('ix_canary_triggers_attacker') op.drop_table('canary_triggers') with op.batch_alter_table('attribution_state', schema=None) as batch_op: batch_op.drop_index('ix_attribution_state_state') batch_op.drop_index('ix_attribution_state_last_change') batch_op.drop_index('ix_attribution_state_identity_state') op.drop_table('attribution_state') with op.batch_alter_table('attackers', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_attackers_updated_at')) batch_op.drop_index(batch_op.f('ix_attackers_last_seen')) batch_op.drop_index(batch_op.f('ix_attackers_last_rotation_at')) batch_op.drop_index(batch_op.f('ix_attackers_last_ipv6_leak_at')) batch_op.drop_index(batch_op.f('ix_attackers_ip')) batch_op.drop_index(batch_op.f('ix_attackers_identity_id')) batch_op.drop_index(batch_op.f('ix_attackers_first_seen')) batch_op.drop_index(batch_op.f('ix_attackers_country_code')) batch_op.drop_index(batch_op.f('ix_attackers_bgp_prefix')) batch_op.drop_index(batch_op.f('ix_attackers_asn')) op.drop_table('attackers') with op.batch_alter_table('topologies', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_topologies_target_host_uuid')) batch_op.drop_index(batch_op.f('ix_topologies_status')) batch_op.drop_index(batch_op.f('ix_topologies_name')) batch_op.drop_index(batch_op.f('ix_topologies_created_at')) op.drop_table('topologies') with op.batch_alter_table('decky_shards', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_decky_shards_state')) batch_op.drop_index(batch_op.f('ix_decky_shards_host_uuid')) op.drop_table('decky_shards') with op.batch_alter_table('canary_tokens', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_canary_tokens_topology_id')) batch_op.drop_index(batch_op.f('ix_canary_tokens_state')) batch_op.drop_index(batch_op.f('ix_canary_tokens_last_triggered_at')) batch_op.drop_index(batch_op.f('ix_canary_tokens_kind')) batch_op.drop_index(batch_op.f('ix_canary_tokens_decky_name')) batch_op.drop_index('ix_canary_tokens_decky') batch_op.drop_index(batch_op.f('ix_canary_tokens_created_by')) batch_op.drop_index(batch_op.f('ix_canary_tokens_callback_token')) batch_op.drop_index(batch_op.f('ix_canary_tokens_blob_uuid')) op.drop_table('canary_tokens') with op.batch_alter_table('attacker_identities', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_attacker_identities_updated_at')) batch_op.drop_index(batch_op.f('ix_attacker_identities_merged_into_uuid')) batch_op.drop_index(batch_op.f('ix_attacker_identities_last_seen_at')) batch_op.drop_index(batch_op.f('ix_attacker_identities_kd_digraph_simhash')) batch_op.drop_index(batch_op.f('ix_attacker_identities_first_seen_at')) batch_op.drop_index(batch_op.f('ix_attacker_identities_created_at')) batch_op.drop_index(batch_op.f('ix_attacker_identities_campaign_id')) op.drop_table('attacker_identities') with op.batch_alter_table('webhook_subscriptions', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_webhook_subscriptions_name')) batch_op.drop_index(batch_op.f('ix_webhook_subscriptions_enabled')) op.drop_table('webhook_subscriptions') with op.batch_alter_table('users', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_users_username')) op.drop_table('users') op.drop_table('ttp_rule_state') op.drop_table('ttp_rule') with op.batch_alter_table('tarpit_rules', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_tarpit_rules_decky_name')) op.drop_table('tarpit_rules') with op.batch_alter_table('synthetic_files', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_synthetic_files_decky_uuid')) batch_op.drop_index('ix_synthetic_files_decky_modified') batch_op.drop_index(batch_op.f('ix_synthetic_files_created_at')) batch_op.drop_index(batch_op.f('ix_synthetic_files_content_class')) op.drop_table('synthetic_files') with op.batch_alter_table('swarm_hosts', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_swarm_hosts_status')) batch_op.drop_index(batch_op.f('ix_swarm_hosts_name')) op.drop_table('swarm_hosts') op.drop_table('state') with op.batch_alter_table('revoked_tokens', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_revoked_tokens_user_uuid')) batch_op.drop_index(batch_op.f('ix_revoked_tokens_expires_at')) op.drop_table('revoked_tokens') with op.batch_alter_table('realism_config', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_realism_config_key')) op.drop_table('realism_config') with op.batch_alter_table('orchestrator_events', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_orchestrator_events_ts')) batch_op.drop_index(batch_op.f('ix_orchestrator_events_success')) batch_op.drop_index(batch_op.f('ix_orchestrator_events_src_decky_uuid')) batch_op.drop_index(batch_op.f('ix_orchestrator_events_protocol')) batch_op.drop_index(batch_op.f('ix_orchestrator_events_kind')) batch_op.drop_index('ix_orchestrator_events_dst_ts') batch_op.drop_index(batch_op.f('ix_orchestrator_events_dst_decky_uuid')) op.drop_table('orchestrator_events') with op.batch_alter_table('orchestrator_emails', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_orchestrator_emails_ts')) batch_op.drop_index(batch_op.f('ix_orchestrator_emails_thread_id')) batch_op.drop_index('ix_orchestrator_emails_thread') batch_op.drop_index(batch_op.f('ix_orchestrator_emails_success')) batch_op.drop_index(batch_op.f('ix_orchestrator_emails_sender_email')) batch_op.drop_index(batch_op.f('ix_orchestrator_emails_recipient_email')) batch_op.drop_index('ix_orchestrator_emails_mail_ts') batch_op.drop_index(batch_op.f('ix_orchestrator_emails_mail_decky_uuid')) op.drop_table('orchestrator_emails') with op.batch_alter_table('observed_attachments', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_observed_attachments_sha256')) batch_op.drop_index('ix_observed_attachments_mal_hash_match') batch_op.drop_index(batch_op.f('ix_observed_attachments_last_seen_attacker_uuid')) batch_op.drop_index('ix_observed_attachments_last_seen') batch_op.drop_index(batch_op.f('ix_observed_attachments_first_seen_decky_uuid')) batch_op.drop_index(batch_op.f('ix_observed_attachments_first_seen_attacker_uuid')) batch_op.drop_index('ix_observed_attachments_first_seen') op.drop_table('observed_attachments') with op.batch_alter_table('logs', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_logs_timestamp')) batch_op.drop_index(batch_op.f('ix_logs_service')) batch_op.drop_index(batch_op.f('ix_logs_event_type')) batch_op.drop_index(batch_op.f('ix_logs_decky')) batch_op.drop_index(batch_op.f('ix_logs_attacker_ip')) op.drop_table('logs') with op.batch_alter_table('fleet_deckies', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_fleet_deckies_state')) batch_op.drop_index(batch_op.f('ix_fleet_deckies_host_uuid')) op.drop_table('fleet_deckies') with op.batch_alter_table('decky_lifecycle', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_decky_lifecycle_status')) batch_op.drop_index(batch_op.f('ix_decky_lifecycle_operation')) batch_op.drop_index(batch_op.f('ix_decky_lifecycle_host_uuid')) batch_op.drop_index(batch_op.f('ix_decky_lifecycle_decky_name')) op.drop_table('decky_lifecycle') with op.batch_alter_table('credential_reuse', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_credential_reuse_updated_at')) batch_op.drop_index(batch_op.f('ix_credential_reuse_target_count')) batch_op.drop_index(batch_op.f('ix_credential_reuse_secret_sha256')) batch_op.drop_index(batch_op.f('ix_credential_reuse_secret_kind')) batch_op.drop_index(batch_op.f('ix_credential_reuse_last_seen')) batch_op.drop_index(batch_op.f('ix_credential_reuse_first_seen')) op.drop_table('credential_reuse') with op.batch_alter_table('canary_blobs', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_canary_blobs_uploaded_by')) batch_op.drop_index(batch_op.f('ix_canary_blobs_sha256')) op.drop_table('canary_blobs') with op.batch_alter_table('campaigns', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_campaigns_updated_at')) batch_op.drop_index(batch_op.f('ix_campaigns_merged_into_uuid')) batch_op.drop_index(batch_op.f('ix_campaigns_last_seen_at')) batch_op.drop_index(batch_op.f('ix_campaigns_first_seen_at')) batch_op.drop_index(batch_op.f('ix_campaigns_created_at')) op.drop_table('campaigns') with op.batch_alter_table('bounty', schema=None) as batch_op: batch_op.drop_index(batch_op.f('ix_bounty_timestamp')) batch_op.drop_index(batch_op.f('ix_bounty_service')) batch_op.drop_index(batch_op.f('ix_bounty_decky')) batch_op.drop_index(batch_op.f('ix_bounty_bounty_type')) batch_op.drop_index(batch_op.f('ix_bounty_attacker_ip')) op.drop_table('bounty') # ### end Alembic commands ###