CREATE TEMP TABLE IF NOT EXISTS ssh_access_profile_explicit_grant_map ( profile_public_id TEXT PRIMARY KEY, grant_public_id TEXT NOT NULL ); DELETE FROM ssh_access_profile_explicit_grant_map; INSERT INTO ssh_access_profile_explicit_grant_map (profile_public_id, grant_public_id) SELECT public_id, lower(hex(randomblob(16))) FROM ssh_access_profiles WHERE auth_method = 'managed_ssh_cert' AND COALESCE(ssh_principal_mode, 'explicit') <> 'grant' AND json_array_length(COALESCE(ssh_principals_json, '[]')) > 0; INSERT INTO ssh_principal_grants ( public_id, principal, principals_json, valid_after, valid_before, max_cert_valid_seconds, max_uses, used_count, disabled, reason, created_by_user_public_id, created_at, updated_at, last_used_at ) SELECT m.grant_public_id, p.name, p.ssh_principals_json, 0, 0, p.max_valid_seconds, 0, 0, 0, 'Migrated from explicit SSH access profile principals', NULLIF(p.created_by_subject_id, ''), p.created_at, p.updated_at, 0 FROM ssh_access_profile_explicit_grant_map m JOIN ssh_access_profiles p ON p.public_id = m.profile_public_id; INSERT OR IGNORE INTO ssh_principal_grant_targets ( grant_public_id, target_type, target_public_id, created_at ) SELECT m.grant_public_id, t.target_type, t.target_public_id, t.created_at FROM ssh_access_profile_explicit_grant_map m JOIN ssh_access_profile_targets t ON t.profile_public_id = m.profile_public_id; INSERT OR IGNORE INTO ssh_principal_grant_targets ( grant_public_id, target_type, target_public_id, created_at ) SELECT m.grant_public_id, 'user', p.owner_user_public_id, p.created_at FROM ssh_access_profile_explicit_grant_map m JOIN ssh_access_profiles p ON p.public_id = m.profile_public_id WHERE p.owner_scope = 'user' AND NULLIF(p.owner_user_public_id, '') IS NOT NULL; UPDATE ssh_access_profiles SET ssh_principal_grant_ids_json = ( SELECT json_array(grant_public_id) FROM ssh_access_profile_explicit_grant_map WHERE profile_public_id = ssh_access_profiles.public_id ) WHERE public_id IN ( SELECT profile_public_id FROM ssh_access_profile_explicit_grant_map ); PRAGMA foreign_keys = OFF; CREATE TABLE ssh_access_profiles_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, public_id TEXT NOT NULL UNIQUE, server_public_id TEXT NOT NULL, name TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', remote_username TEXT NOT NULL, auth_method TEXT NOT NULL, second_factor_mode TEXT NOT NULL DEFAULT 'none', owner_scope TEXT NOT NULL DEFAULT 'user', owner_user_public_id TEXT DEFAULT '', allow_user_edit INTEGER NOT NULL DEFAULT 0, enabled INTEGER NOT NULL DEFAULT 1, secret_public_id TEXT DEFAULT '', auth_public_key TEXT NOT NULL DEFAULT '', auth_public_key_fingerprint TEXT NOT NULL DEFAULT '', ssh_user_ca_public_id TEXT DEFAULT '', ssh_principal_grant_ids_json TEXT NOT NULL DEFAULT '[]', default_valid_seconds INTEGER NOT NULL DEFAULT 3600, max_valid_seconds INTEGER NOT NULL DEFAULT 3600, created_by_kind TEXT NOT NULL DEFAULT 'user', created_by_subject_id TEXT NOT NULL DEFAULT '', created_by_subject_name TEXT NOT NULL DEFAULT '', created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, FOREIGN KEY (server_public_id) REFERENCES ssh_servers(public_id) ON DELETE CASCADE, FOREIGN KEY (secret_public_id) REFERENCES ssh_secrets(public_id) ON DELETE SET NULL, FOREIGN KEY (ssh_user_ca_public_id) REFERENCES ssh_user_cas(public_id) ON DELETE SET NULL ); INSERT INTO ssh_access_profiles_new ( id, public_id, server_public_id, name, description, remote_username, auth_method, second_factor_mode, owner_scope, owner_user_public_id, allow_user_edit, enabled, secret_public_id, auth_public_key, auth_public_key_fingerprint, ssh_user_ca_public_id, ssh_principal_grant_ids_json, default_valid_seconds, max_valid_seconds, created_by_kind, created_by_subject_id, created_by_subject_name, created_at, updated_at ) SELECT id, public_id, server_public_id, name, description, remote_username, auth_method, second_factor_mode, owner_scope, owner_user_public_id, allow_user_edit, enabled, secret_public_id, auth_public_key, auth_public_key_fingerprint, ssh_user_ca_public_id, ssh_principal_grant_ids_json, default_valid_seconds, max_valid_seconds, created_by_kind, created_by_subject_id, created_by_subject_name, created_at, updated_at FROM ssh_access_profiles; DROP TABLE ssh_access_profiles; ALTER TABLE ssh_access_profiles_new RENAME TO ssh_access_profiles; CREATE INDEX IF NOT EXISTS idx_ssh_access_profiles_server ON ssh_access_profiles(server_public_id); CREATE INDEX IF NOT EXISTS idx_ssh_access_profiles_owner_scope ON ssh_access_profiles(owner_scope); CREATE INDEX IF NOT EXISTS idx_ssh_access_profiles_owner_user ON ssh_access_profiles(owner_user_public_id); CREATE INDEX IF NOT EXISTS idx_ssh_access_profiles_enabled ON ssh_access_profiles(enabled); PRAGMA foreign_keys = ON; DROP TABLE ssh_access_profile_explicit_grant_map;