machineconfig 7.98__py3-none-any.whl → 8.51__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- machineconfig/cluster/remote/run_cluster.py +1 -1
- machineconfig/cluster/remote/run_remote.py +1 -1
- machineconfig/cluster/sessions_managers/utils/maker.py +10 -8
- machineconfig/cluster/sessions_managers/wt_local.py +1 -1
- machineconfig/cluster/sessions_managers/wt_local_manager.py +1 -1
- machineconfig/cluster/sessions_managers/zellij_local.py +1 -1
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +1 -1
- machineconfig/jobs/installer/checks/check_installations.py +133 -0
- machineconfig/jobs/installer/checks/install_utils.py +132 -0
- machineconfig/jobs/installer/checks/report_utils.py +39 -0
- machineconfig/jobs/installer/checks/vt_utils.py +89 -0
- machineconfig/jobs/installer/installer_data.json +271 -152
- machineconfig/jobs/installer/linux_scripts/docker.sh +6 -9
- machineconfig/jobs/installer/package_groups.py +11 -9
- machineconfig/jobs/installer/{custom → python_scripts}/boxes.py +1 -2
- machineconfig/jobs/installer/{custom_dev → python_scripts}/brave.py +1 -1
- machineconfig/jobs/installer/{custom_dev → python_scripts}/code.py +10 -8
- machineconfig/jobs/installer/{custom → python_scripts}/hx.py +30 -13
- machineconfig/jobs/installer/{custom_dev → python_scripts}/nerdfont.py +1 -1
- machineconfig/jobs/installer/{custom_dev → python_scripts}/nerfont_windows_helper.py +6 -5
- machineconfig/jobs/installer/{custom_dev → python_scripts}/sysabc.py +26 -20
- machineconfig/jobs/installer/{custom_dev → python_scripts}/wezterm.py +1 -1
- machineconfig/jobs/installer/{custom → python_scripts}/yazi.py +39 -19
- machineconfig/jobs/scripts/powershell_scripts/cmatrix.ps1 +52 -0
- machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +13 -0
- machineconfig/jobs/scripts/powershell_scripts/obs.ps1 +4 -0
- machineconfig/jobs/scripts_dynamic/a.py +428 -0
- machineconfig/logger.py +1 -1
- machineconfig/profile/create_helper.py +21 -10
- machineconfig/profile/create_links.py +77 -20
- machineconfig/profile/create_links_export.py +63 -58
- machineconfig/profile/create_shell_profile.py +14 -0
- machineconfig/profile/mapper_data.toml +45 -0
- machineconfig/profile/mapper_dotfiles.toml +249 -0
- machineconfig/scripts/python/agents.py +76 -171
- machineconfig/scripts/python/ai/initai.py +3 -1
- machineconfig/scripts/python/ai/scripts/__init__.py +1 -0
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +2 -0
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +8 -6
- machineconfig/scripts/python/ai/solutions/claude/claude.py +1 -1
- machineconfig/scripts/python/ai/solutions/cline/cline.py +1 -1
- machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +1 -1
- machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +29 -0
- machineconfig/scripts/python/ai/solutions/crush/crush.py +1 -1
- machineconfig/scripts/python/ai/solutions/cursor/cursors.py +1 -1
- machineconfig/scripts/python/ai/solutions/gemini/gemini.py +1 -1
- machineconfig/scripts/python/ai/solutions/gemini/settings.json +3 -0
- machineconfig/scripts/python/ai/{solutions → utils}/generic.py +2 -15
- machineconfig/scripts/python/ai/utils/vscode_tasks.py +6 -3
- machineconfig/scripts/python/cloud.py +58 -11
- machineconfig/scripts/python/croshell.py +4 -155
- machineconfig/scripts/python/devops.py +57 -38
- machineconfig/scripts/python/devops_navigator.py +17 -3
- machineconfig/scripts/python/fire_jobs.py +10 -193
- machineconfig/scripts/python/ftpx.py +5 -224
- machineconfig/scripts/python/graph/cli_graph.json +8743 -0
- machineconfig/scripts/python/{env_manager → helper_env}/path_manager_tui.py +2 -2
- machineconfig/scripts/python/{env_manager → helpers/helper_env}/env_manager_tui.py +1 -1
- machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +228 -0
- machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.py +1 -1
- machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_cursor_agents.py +1 -1
- machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_gemini.py +1 -1
- machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_qwen.py +1 -1
- machineconfig/scripts/python/helpers/helpers_agents/agents_impl.py +168 -0
- machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_launch.py +10 -7
- machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aichat/config.yaml +5 -0
- machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aider/.aider.conf.yml +2 -0
- machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/copilot/config.yml +1 -0
- machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/crush/crush.json +10 -0
- machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/gemini/settings.json +12 -0
- machineconfig/scripts/python/helpers/helpers_agents/privacy/privacy.py +109 -0
- machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.sh +3 -1
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_copy.py +6 -6
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_mount.py +10 -5
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_sync.py +4 -4
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers2.py +1 -1
- machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +225 -0
- machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/scheduler.py +4 -4
- machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/start_slidev.py +7 -6
- machineconfig/scripts/python/helpers/helpers_devops/backup_config.py +149 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_backup_retrieve.py +262 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +98 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_config_dotfile.py +274 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +67 -0
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_nw.py +69 -82
- machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +274 -0
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_self.py +47 -22
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_file.py +44 -30
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_server.py +26 -43
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_terminal.py +12 -6
- machineconfig/scripts/python/helpers/helpers_devops/cli_ssh.py +167 -0
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_status.py +12 -6
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_update_repos.py +1 -1
- machineconfig/scripts/python/{interactive.py → helpers/helpers_devops/interactive.py} +64 -50
- machineconfig/scripts/python/helpers/helpers_devops/run_script.py +197 -0
- machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.ps1 +41 -0
- machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.sh +48 -0
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_wezterm_theme.py +3 -3
- machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/file_wrangler.py +1 -0
- machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_args_helper.py +1 -0
- machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_impl.py +233 -0
- machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_route_helper.py +3 -3
- machineconfig/scripts/python/helpers/helpers_msearch/msearch_impl.py +248 -0
- machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_linux/fzfg +4 -3
- machineconfig/scripts/python/helpers/helpers_msearch/scripts_linux/search_with_context.sh +48 -0
- machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_windows/fzfg.ps1 +1 -1
- machineconfig/scripts/python/helpers/helpers_navigator/__init__.py +20 -0
- machineconfig/scripts/python/helpers/helpers_navigator/cli_graph_loader.py +234 -0
- machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/command_builder.py +61 -13
- machineconfig/scripts/python/helpers/helpers_navigator/command_detail.py +153 -0
- machineconfig/scripts/python/helpers/helpers_navigator/command_tree.py +45 -0
- machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/data_models.py +18 -11
- machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/main_app.py +5 -5
- machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/address.py +52 -10
- machineconfig/scripts/python/helpers/helpers_network/address_switch.py +78 -0
- machineconfig/scripts/python/helpers/helpers_network/ftpx_impl.py +276 -0
- machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_ssh.py +2 -2
- machineconfig/scripts/python/helpers/helpers_network/ssh_add_identity.py +73 -0
- machineconfig/scripts/python/helpers/helpers_network/ssh_add_ssh_key.py +175 -0
- machineconfig/scripts/python/helpers/helpers_network/ssh_debug_linux.py +319 -0
- machineconfig/scripts/python/helpers/helpers_network/ssh_debug_windows.py +275 -0
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action.py +3 -3
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action_helper.py +3 -3
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/cloud_repo_sync.py +118 -34
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/grource.py +3 -2
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/record.py +33 -13
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_2.py +63 -19
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/update.py +0 -6
- machineconfig/scripts/python/helpers/helpers_search/script_help.py +81 -0
- machineconfig/scripts/python/helpers/helpers_sessions/__init__.py +0 -0
- machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +186 -0
- machineconfig/scripts/python/{helpers_sessions → helpers/helpers_sessions}/sessions_multiprocess.py +1 -2
- machineconfig/scripts/python/helpers/helpers_terminal/__init__.py +0 -0
- machineconfig/scripts/python/helpers/helpers_terminal/terminal_impl.py +96 -0
- machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/download.py +1 -1
- machineconfig/scripts/python/{helpers_devops/cli_utils.py → helpers/helpers_utils/pdf.py} +2 -2
- machineconfig/scripts/python/{helpers_utils/path.py → helpers/helpers_utils/python.py} +65 -40
- machineconfig/scripts/python/helpers/helpers_utils/specs.py +246 -0
- machineconfig/scripts/python/mcfg_entry.py +133 -48
- machineconfig/scripts/python/msearch.py +16 -61
- machineconfig/scripts/python/sessions.py +68 -203
- machineconfig/scripts/python/terminal.py +27 -102
- machineconfig/scripts/python/utils.py +101 -22
- machineconfig/settings/atuin/config.toml +294 -0
- machineconfig/settings/atuin/themes/catppuccin-mocha-mauve.toml +12 -0
- machineconfig/settings/linters/.ruff.toml +2 -1
- machineconfig/settings/mprocs/windows/mprocs.yaml +2 -2
- machineconfig/settings/shells/bash/init.sh +6 -3
- machineconfig/settings/shells/nushell/config.nu +23 -1
- machineconfig/settings/shells/nushell/env.nu +22 -48
- machineconfig/settings/shells/nushell/init.nu +64 -240
- machineconfig/settings/shells/pwsh/init.ps1 +69 -1
- machineconfig/settings/shells/pwsh/search_pwsh_history.ps1 +99 -0
- machineconfig/settings/shells/wezterm/wezterm.lua +4 -1
- machineconfig/settings/shells/wt/settings.json +21 -21
- machineconfig/settings/shells/zsh/init.sh +25 -4
- machineconfig/settings/television/cable_unix/bash-history.toml +1 -1
- machineconfig/settings/television/cable_windows/pwsh-history.toml +1 -1
- machineconfig/settings/tv/config.toml +234 -0
- machineconfig/settings/tv/themes/catppuccin-mocha-sky.toml +22 -0
- machineconfig/settings/wsl/.wslconfig +5 -30
- machineconfig/settings/wt/__init__.py +0 -0
- machineconfig/settings/yazi/yazi_linux.toml +18 -8
- machineconfig/settings/zellij/layouts/st.kdl +40 -9
- machineconfig/settings/zellij/layouts/st2.kdl +1 -1
- machineconfig/setup_linux/__init__.py +0 -1
- machineconfig/setup_linux/apps_desktop.sh +8 -27
- machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
- machineconfig/setup_linux/web_shortcuts/live_from_github.sh +3 -0
- machineconfig/setup_mac/__init__.py +0 -2
- machineconfig/setup_windows/__init__.py +2 -5
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +14 -13
- machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +4 -3
- machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +3 -3
- machineconfig/type_hinting/sql/__init__.py +1 -0
- machineconfig/type_hinting/sql/base.py +216 -0
- machineconfig/type_hinting/sql/core_schema.py +64 -0
- machineconfig/type_hinting/sql/core_schema_typeddict.py +41 -0
- machineconfig/type_hinting/sql/typeddict_codegen.py +222 -0
- machineconfig/type_hinting/typedict/__init__.py +1 -0
- machineconfig/type_hinting/typedict/ast_utils.py +130 -0
- machineconfig/type_hinting/typedict/generator_helpers.py +319 -0
- machineconfig/type_hinting/typedict/generators.py +231 -0
- machineconfig/type_hinting/typedict/polars_schema.py +24 -0
- machineconfig/type_hinting/typedict/polars_schema_typeddict.py +63 -0
- machineconfig/utils/accessories.py +24 -0
- machineconfig/utils/code.py +78 -33
- machineconfig/utils/files/ascii_art.py +10 -14
- machineconfig/utils/files/headers.py +3 -5
- machineconfig/utils/files/read.py +8 -1
- machineconfig/utils/installer_utils/github_release_bulk.py +11 -91
- machineconfig/utils/installer_utils/github_release_scraper.py +99 -0
- machineconfig/utils/installer_utils/install_from_url.py +1 -1
- machineconfig/utils/installer_utils/installer_class.py +12 -4
- machineconfig/utils/installer_utils/installer_cli.py +1 -15
- machineconfig/utils/installer_utils/installer_helper.py +2 -2
- machineconfig/utils/installer_utils/installer_locator_utils.py +13 -13
- machineconfig/utils/installer_utils/installer_runner.py +4 -4
- machineconfig/utils/io.py +25 -8
- machineconfig/utils/meta.py +6 -4
- machineconfig/utils/options.py +49 -19
- machineconfig/utils/options_utils/__init__.py +0 -0
- machineconfig/utils/options_utils/options_tv_linux.py +211 -0
- machineconfig/utils/options_utils/options_tv_windows.py +88 -0
- machineconfig/utils/options_utils/tv_options.py +37 -0
- machineconfig/utils/path_extended.py +8 -7
- machineconfig/utils/scheduler.py +8 -2
- machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
- machineconfig/utils/source_of_truth.py +6 -1
- machineconfig/utils/ssh.py +73 -23
- machineconfig/utils/ssh_utils/abc.py +1 -1
- machineconfig/utils/ssh_utils/copy_from_here.py +19 -14
- machineconfig/utils/ssh_utils/copy_to_here.py +2 -1
- machineconfig/utils/ssh_utils/utils.py +23 -7
- machineconfig/utils/ssh_utils/wsl.py +107 -170
- machineconfig/utils/ssh_utils/wsl_helper.py +217 -0
- machineconfig/utils/upgrade_packages.py +4 -8
- {machineconfig-7.98.dist-info → machineconfig-8.51.dist-info}/METADATA +30 -22
- machineconfig-8.51.dist-info/RECORD +543 -0
- machineconfig/jobs/installer/check_installations.py +0 -248
- machineconfig/profile/backup.toml +0 -49
- machineconfig/profile/mapper.toml +0 -263
- machineconfig/scripts/linux/other/switch_ip +0 -20
- machineconfig/scripts/python/helpers/run_py_script.py +0 -79
- machineconfig/scripts/python/helpers/tmp_py_scripts/a.py +0 -26
- machineconfig/scripts/python/helpers_devops/cli_config.py +0 -105
- machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +0 -89
- machineconfig/scripts/python/helpers_devops/cli_data.py +0 -25
- machineconfig/scripts/python/helpers_devops/cli_repos.py +0 -215
- machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +0 -80
- machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +0 -3
- machineconfig/scripts/python/helpers_navigator/__init__.py +0 -20
- machineconfig/scripts/python/helpers_navigator/command_detail.py +0 -44
- machineconfig/scripts/python/helpers_navigator/command_tree.py +0 -620
- machineconfig/scripts/python/helpers_network/devops_add_identity.py +0 -82
- machineconfig/scripts/python/helpers_network/devops_add_ssh_key.py +0 -153
- machineconfig/scripts/python/helpers_network/ssh_debug_linux.py +0 -391
- machineconfig/scripts/python/helpers_network/ssh_debug_windows.py +0 -338
- machineconfig/scripts/python/helpers_network/wsl_windows_transfer.py +0 -67
- machineconfig/scripts/python/helpers_repos/entrypoint.py +0 -77
- machineconfig/scripts/windows/mounts/mount_ssh.ps1 +0 -13
- machineconfig/setup_linux/others/mint_keyboard_shortcuts.sh +0 -30
- machineconfig/setup_linux/ssh/openssh_all.sh +0 -25
- machineconfig/setup_linux/ssh/openssh_wsl.sh +0 -38
- machineconfig/setup_mac/ssh/openssh_setup.sh +0 -114
- machineconfig/setup_windows/others/obs.ps1 +0 -4
- machineconfig/setup_windows/ssh/add-sshkey.ps1 +0 -29
- machineconfig/setup_windows/ssh/add_identity.ps1 +0 -11
- machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -37
- machineconfig/setup_windows/ssh/openssh-server_add_key.ps1 +0 -7
- machineconfig/setup_windows/ssh/openssh-server_copy-ssh-id.ps1 +0 -14
- machineconfig/utils/options_tv.py +0 -119
- machineconfig/utils/tst.py +0 -20
- machineconfig-7.98.dist-info/RECORD +0 -504
- /machineconfig/jobs/installer/{custom_dev → checks}/__init__.py +0 -0
- /machineconfig/{scripts/python/helpers_agents → jobs/installer/python_scripts}/__init__.py +0 -0
- /machineconfig/jobs/installer/{custom_dev → python_scripts}/alacritty.py +0 -0
- /machineconfig/jobs/installer/{custom_dev → python_scripts}/bypass_paywall.py +0 -0
- /machineconfig/jobs/installer/{custom_dev → python_scripts}/cloudflare_warp_cli.py +0 -0
- /machineconfig/jobs/installer/{custom_dev → python_scripts}/cursor.py +0 -0
- /machineconfig/jobs/installer/{custom_dev → python_scripts}/dubdb_adbc.py +0 -0
- /machineconfig/jobs/installer/{custom_dev → python_scripts}/espanso.py +0 -0
- /machineconfig/jobs/installer/{custom → python_scripts}/gh.py +0 -0
- /machineconfig/jobs/installer/{custom_dev → python_scripts}/goes.py +0 -0
- /machineconfig/jobs/installer/{custom_dev → python_scripts}/lvim.py +0 -0
- /machineconfig/jobs/installer/{custom_dev → python_scripts}/redis.py +0 -0
- /machineconfig/jobs/installer/{custom_dev → python_scripts}/winget.py +0 -0
- /machineconfig/{setup_linux/others → jobs/scripts/bash_scripts}/android.sh +0 -0
- /machineconfig/jobs/{installer/linux_scripts → scripts/bash_scripts}/lid.sh +0 -0
- /machineconfig/{scripts/python/helpers_network → jobs/scripts/bash_scripts}/mount_drive +0 -0
- /machineconfig/{scripts/python/helpers_network → jobs/scripts/bash_scripts}/mount_nfs +0 -0
- /machineconfig/{scripts/python/helpers_network → jobs/scripts/bash_scripts}/mount_nw_drive +0 -0
- /machineconfig/{scripts/python/helpers_network → jobs/scripts/bash_scripts}/mount_smb +0 -0
- /machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_cloud.sh +0 -0
- /machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_nfs +0 -0
- /machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/start_docker +0 -0
- /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/Restore-ThunderbirdProfile.ps1 +0 -0
- /machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/docker.ps1 +0 -0
- /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nfs.ps1 +0 -0
- /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nw.ps1 +0 -0
- /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_smb.ps1 +0 -0
- /machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/power_options.ps1 +0 -0
- /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_cloud.cmd +0 -0
- /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_smb.ps1 +0 -0
- /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/unlock_bitlocker.ps1 +0 -0
- /machineconfig/scripts/python/ai/{solutions/_shared.py → utils/shared.py} +0 -0
- /machineconfig/scripts/python/{helpers_agents/agentic_frameworks → graph}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_cloud → helpers}/__init__.py +0 -0
- /machineconfig/scripts/python/{env_manager → helpers/helper_env}/__init__.py +0 -0
- /machineconfig/scripts/python/{env_manager → helpers/helper_env}/path_manager_backend.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_agents}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_devops → helpers/helpers_agents/agentic_frameworks}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.json +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_search.py +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_helper_types.py +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_load_balancer.py +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/prompt.txt +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.ps1 +0 -0
- /machineconfig/scripts/python/{helpers_devops/themes → helpers/helpers_cloud}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_helpers.py +0 -0
- /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers5.py +0 -0
- /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_croshell}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/crosh.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/pomodoro.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer_template.py +0 -0
- /machineconfig/scripts/python/{helpers_network → helpers/helpers_devops}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_sessions → helpers/helpers_devops/themes}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
- /machineconfig/{setup_windows/wt_and_pwsh → scripts/python/helpers/helpers_fire_command}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/cloud_manager.py +0 -0
- /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/f.py +0 -0
- /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_streamlit_helper.py +0 -0
- /machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/search_bar.py +0 -0
- /machineconfig/scripts/python/{helpers_devops/themes/choose_starship_theme.ps1 → helpers/helpers_network/__init__.py} +0 -0
- /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nfs.py +0 -0
- /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nw_drive.py +0 -0
- /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/onetimeshare.py +0 -0
- /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/wifi_conn.py +0 -0
- /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/clone.py +0 -0
- /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_1.py +0 -0
- /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/sync.py +0 -0
- /machineconfig/scripts/python/helpers/{ast_search.py → helpers_search/ast_search.py} +0 -0
- /machineconfig/scripts/python/helpers/{qr_code.py → helpers_search/qr_code.py} +0 -0
- /machineconfig/scripts/python/helpers/{repo_rag.py → helpers_search/repo_rag.py} +0 -0
- /machineconfig/scripts/python/helpers/{symantic_search.py → helpers_search/symantic_search.py} +0 -0
- /machineconfig/{setup_windows/wt_and_pwsh → settings/wt}/set_wt_settings.py +0 -0
- {machineconfig-7.98.dist-info → machineconfig-8.51.dist-info}/WHEEL +0 -0
- {machineconfig-7.98.dist-info → machineconfig-8.51.dist-info}/entry_points.txt +0 -0
- {machineconfig-7.98.dist-info → machineconfig-8.51.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""SSH"""
|
|
2
|
+
|
|
3
|
+
from platform import system
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.panel import Panel
|
|
7
|
+
from rich import box
|
|
8
|
+
from typing import Optional, Annotated
|
|
9
|
+
import typer
|
|
10
|
+
import subprocess
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
console = Console()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _add_ssh_key_windows(path_to_key: Path) -> None:
|
|
17
|
+
"""Add SSH key on Windows using Python with proper UTF-8 encoding.
|
|
18
|
+
This replaces the PowerShell script that was writing UTF-16LE encoded files which openssh server cannot read.
|
|
19
|
+
"""
|
|
20
|
+
sshd_dir = Path("C:/ProgramData/ssh")
|
|
21
|
+
admin_auth_keys = sshd_dir / "administrators_authorized_keys"
|
|
22
|
+
sshd_config = sshd_dir / "sshd_config"
|
|
23
|
+
key_content = path_to_key.read_text(encoding="utf-8").strip()
|
|
24
|
+
if admin_auth_keys.exists():
|
|
25
|
+
existing = admin_auth_keys.read_text(encoding="utf-8")
|
|
26
|
+
if not existing.endswith("\n"):
|
|
27
|
+
existing += "\n"
|
|
28
|
+
admin_auth_keys.write_text(existing + key_content + "\n", encoding="utf-8")
|
|
29
|
+
else:
|
|
30
|
+
admin_auth_keys.write_text(key_content + "\n", encoding="utf-8")
|
|
31
|
+
icacls_cmd = f'icacls "{admin_auth_keys}" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"'
|
|
32
|
+
subprocess.run(icacls_cmd, shell=True, check=True)
|
|
33
|
+
if sshd_config.exists():
|
|
34
|
+
config_text = sshd_config.read_text(encoding="utf-8")
|
|
35
|
+
config_text = config_text.replace("#PubkeyAuthentication", "PubkeyAuthentication")
|
|
36
|
+
sshd_config.write_text(config_text, encoding="utf-8")
|
|
37
|
+
subprocess.run("Restart-Service sshd -Force", shell=True, check=True)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_add_ssh_key_script(path_to_key: Path, verbose: bool = True) -> tuple[str, str]:
|
|
41
|
+
"""Returns (program_script, status_message) tuple. For Windows, program_script is empty because we handle it in Python."""
|
|
42
|
+
os_name = system()
|
|
43
|
+
if os_name == "Linux" or os_name == "Darwin":
|
|
44
|
+
authorized_keys = Path.home().joinpath(".ssh/authorized_keys")
|
|
45
|
+
os_icon, os_label = "🐧", "Linux/macOS"
|
|
46
|
+
elif os_name == "Windows":
|
|
47
|
+
authorized_keys = Path("C:/ProgramData/ssh/administrators_authorized_keys")
|
|
48
|
+
os_icon, os_label = "🪟", "Windows"
|
|
49
|
+
else:
|
|
50
|
+
raise NotImplementedError("Only Linux, macOS and Windows are supported")
|
|
51
|
+
|
|
52
|
+
status_lines: list[str] = [f"{os_icon} {os_label} │ Auth file: {authorized_keys}"]
|
|
53
|
+
program = ""
|
|
54
|
+
|
|
55
|
+
if authorized_keys.exists():
|
|
56
|
+
keys_text = authorized_keys.read_text(encoding="utf-8").split("\n")
|
|
57
|
+
key_count = len([k for k in keys_text if k.strip()])
|
|
58
|
+
status_lines.append(f"🔑 Existing keys: {key_count}")
|
|
59
|
+
if path_to_key.read_text(encoding="utf-8") in authorized_keys.read_text(encoding="utf-8"):
|
|
60
|
+
status_lines.append(f"⚠️ Key [yellow]{path_to_key.name}[/yellow] already authorized, skipping")
|
|
61
|
+
else:
|
|
62
|
+
status_lines.append(f"➕ Adding: [green]{path_to_key.name}[/green]")
|
|
63
|
+
if os_name == "Linux" or os_name == "Darwin":
|
|
64
|
+
program = f"cat {path_to_key} >> ~/.ssh/authorized_keys"
|
|
65
|
+
elif os_name == "Windows":
|
|
66
|
+
_add_ssh_key_windows(path_to_key)
|
|
67
|
+
else:
|
|
68
|
+
raise NotImplementedError
|
|
69
|
+
else:
|
|
70
|
+
status_lines.append(f"📝 Creating auth file with: [green]{path_to_key.name}[/green]")
|
|
71
|
+
if os_name == "Linux" or os_name == "Darwin":
|
|
72
|
+
program = f"cat {path_to_key} > ~/.ssh/authorized_keys"
|
|
73
|
+
else:
|
|
74
|
+
_add_ssh_key_windows(path_to_key)
|
|
75
|
+
|
|
76
|
+
if os_name == "Linux" or os_name == "Darwin":
|
|
77
|
+
program += """
|
|
78
|
+
sudo chmod 700 ~/.ssh
|
|
79
|
+
sudo chmod 644 ~/.ssh/authorized_keys
|
|
80
|
+
sudo chmod 644 ~/.ssh/*.pub
|
|
81
|
+
sudo service ssh --full-restart
|
|
82
|
+
# from superuser.com/questions/215504/permissions-on-private-key-in-ssh-folder
|
|
83
|
+
"""
|
|
84
|
+
return program, "\n".join(status_lines)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
Common pitfalls:
|
|
89
|
+
🚫 Wrong line endings (LF/CRLF) in config files
|
|
90
|
+
🌐 Network port conflicts (try 2222 -> 2223) between WSL and Windows
|
|
91
|
+
sudo service ssh restart
|
|
92
|
+
sudo service ssh status
|
|
93
|
+
sudo nano /etc/ssh/sshd_config
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def main(pub_path: Annotated[Optional[str], typer.Argument(help="Path to the public key file")] = None,
|
|
98
|
+
pub_choose: Annotated[bool, typer.Option("--choose", "-c", help="Choose from available public keys in ~/.ssh")] = False,
|
|
99
|
+
pub_val: Annotated[bool, typer.Option("--paste", "-p", help="Paste the public key content manually")] = False,
|
|
100
|
+
from_github: Annotated[Optional[str], typer.Option("--from-github", "-g", help="Fetch public keys from a GitHub username")] = None
|
|
101
|
+
) -> None:
|
|
102
|
+
info_lines: list[str] = []
|
|
103
|
+
program = ""
|
|
104
|
+
status_msg = ""
|
|
105
|
+
|
|
106
|
+
if pub_path:
|
|
107
|
+
key_path = Path(pub_path).expanduser().absolute()
|
|
108
|
+
key_path.parent.mkdir(parents=True, exist_ok=True)
|
|
109
|
+
if not key_path.exists():
|
|
110
|
+
console.print(Panel(f"❌ Key path does not exist: {key_path}", title="[bold red]Error[/bold red]", border_style="red"))
|
|
111
|
+
raise typer.Exit(code=1)
|
|
112
|
+
info_lines.append(f"📄 Source: Local file │ {key_path}")
|
|
113
|
+
program, status_msg = get_add_ssh_key_script(key_path)
|
|
114
|
+
|
|
115
|
+
elif pub_choose:
|
|
116
|
+
pub_keys = list(Path.home().joinpath(".ssh").glob("*.pub"))
|
|
117
|
+
if not pub_keys:
|
|
118
|
+
console.print(Panel("⚠️ No public keys found in ~/.ssh", title="[bold yellow]Warning[/bold yellow]", border_style="yellow"))
|
|
119
|
+
return
|
|
120
|
+
info_lines.append(f"📄 Source: Local ~/.ssh │ Found {len(pub_keys)} key(s)")
|
|
121
|
+
programs: list[str] = []
|
|
122
|
+
statuses: list[str] = []
|
|
123
|
+
for key in pub_keys:
|
|
124
|
+
p, s = get_add_ssh_key_script(key)
|
|
125
|
+
programs.append(p)
|
|
126
|
+
statuses.append(s)
|
|
127
|
+
program = "\n\n\n".join(programs)
|
|
128
|
+
status_msg = "\n".join(statuses)
|
|
129
|
+
|
|
130
|
+
elif pub_val:
|
|
131
|
+
key_filename = input("📝 File name (default: my_pasted_key.pub): ") or "my_pasted_key.pub"
|
|
132
|
+
key_path = Path.home().joinpath(f".ssh/{key_filename}")
|
|
133
|
+
key_path.parent.mkdir(parents=True, exist_ok=True)
|
|
134
|
+
key_path.write_text(input("🔑 Paste the public key here: "), encoding="utf-8")
|
|
135
|
+
info_lines.append(f"📄 Source: Pasted │ Saved to {key_path}")
|
|
136
|
+
program, status_msg = get_add_ssh_key_script(key_path)
|
|
137
|
+
|
|
138
|
+
elif from_github:
|
|
139
|
+
import requests
|
|
140
|
+
response = requests.get(f"https://api.github.com/users/{from_github}/keys")
|
|
141
|
+
if response.status_code != 200:
|
|
142
|
+
console.print(Panel(f"❌ GitHub API error for user '{from_github}' │ Status: {response.status_code}", title="[bold red]Error[/bold red]", border_style="red"))
|
|
143
|
+
raise typer.Exit(code=1)
|
|
144
|
+
keys = response.json()
|
|
145
|
+
if not keys:
|
|
146
|
+
console.print(Panel(f"⚠️ No public keys found for GitHub user: {from_github}", title="[bold yellow]Warning[/bold yellow]", border_style="yellow"))
|
|
147
|
+
return
|
|
148
|
+
key_path = Path.home().joinpath(f".ssh/{from_github}_github_keys.pub")
|
|
149
|
+
key_path.parent.mkdir(parents=True, exist_ok=True)
|
|
150
|
+
key_path.write_text("\n".join([key["key"] for key in keys]), encoding="utf-8")
|
|
151
|
+
info_lines.append(f"📄 Source: GitHub @{from_github} │ {len(keys)} key(s) → {key_path}")
|
|
152
|
+
program, status_msg = get_add_ssh_key_script(key_path)
|
|
153
|
+
|
|
154
|
+
else:
|
|
155
|
+
console.print(Panel("❌ No key source specified. Use --help for options.", title="[bold red]Error[/bold red]", border_style="red"))
|
|
156
|
+
raise typer.Exit(code=1)
|
|
157
|
+
|
|
158
|
+
combined_info = "\n".join(info_lines + [""] + status_msg.split("\n"))
|
|
159
|
+
console.print(Panel(combined_info, title="[bold blue]🔑 SSH Key Authorization[/bold blue]", border_style="blue"))
|
|
160
|
+
|
|
161
|
+
if program.strip():
|
|
162
|
+
from machineconfig.utils.code import run_shell_script
|
|
163
|
+
run_shell_script(script=program, display_script=True, clean_env=False)
|
|
164
|
+
|
|
165
|
+
import machineconfig.scripts.python.helpers.helpers_network.address as helper
|
|
166
|
+
res = helper.select_lan_ipv4(prefer_vpn=False)
|
|
167
|
+
if res is None:
|
|
168
|
+
console.print(Panel("❌ Could not determine local LAN IPv4 address", title="[bold red]Error[/bold red]", border_style="red"))
|
|
169
|
+
raise typer.Exit(code=1)
|
|
170
|
+
|
|
171
|
+
console.print(Panel(f"✅ Complete │ This machine accessible at: [green]{res}[/green]", title="[bold green]SSH Key Authorization[/bold green]", border_style="green", box=box.DOUBLE_EDGE))
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
if __name__ == "__main__":
|
|
175
|
+
pass
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from platform import system
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.panel import Panel
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
from rich import box
|
|
9
|
+
import subprocess
|
|
10
|
+
import os
|
|
11
|
+
import re
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
console = Console()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _run(cmd: list[str]) -> tuple[bool, str]:
|
|
18
|
+
try:
|
|
19
|
+
result = subprocess.run(cmd, capture_output=True, text=True, check=False)
|
|
20
|
+
return result.returncode == 0, result.stdout.strip()
|
|
21
|
+
except FileNotFoundError:
|
|
22
|
+
return False, ""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _check_sshd_installed() -> tuple[bool, str]:
|
|
26
|
+
sshd_paths = ["/usr/sbin/sshd", "/usr/bin/sshd", "/sbin/sshd"]
|
|
27
|
+
for path in sshd_paths:
|
|
28
|
+
if Path(path).exists():
|
|
29
|
+
return True, path
|
|
30
|
+
ok, which_out = _run(["which", "sshd"])
|
|
31
|
+
if ok and which_out:
|
|
32
|
+
return True, which_out
|
|
33
|
+
return False, ""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _detect_package_manager() -> tuple[str, str]:
|
|
37
|
+
if Path("/usr/bin/apt").exists() or Path("/usr/bin/apt-get").exists():
|
|
38
|
+
return "apt", "sudo apt update && sudo apt install -y openssh-server"
|
|
39
|
+
if Path("/usr/bin/dnf").exists():
|
|
40
|
+
return "dnf", "sudo dnf install -y openssh-server"
|
|
41
|
+
if Path("/usr/bin/yum").exists():
|
|
42
|
+
return "yum", "sudo yum install -y openssh-server"
|
|
43
|
+
if Path("/usr/bin/pacman").exists():
|
|
44
|
+
return "pacman", "sudo pacman -S --noconfirm openssh"
|
|
45
|
+
if Path("/usr/bin/zypper").exists():
|
|
46
|
+
return "zypper", "sudo zypper install -y openssh"
|
|
47
|
+
return "unknown", "# Install openssh-server using your package manager"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def ssh_debug_linux() -> dict[str, dict[str, str | bool]]:
|
|
51
|
+
if system() != "Linux":
|
|
52
|
+
raise NotImplementedError("ssh_debug_linux is only supported on Linux")
|
|
53
|
+
|
|
54
|
+
results: dict[str, dict[str, str | bool]] = {}
|
|
55
|
+
issues: list[tuple[str, str, str]] = []
|
|
56
|
+
current_user = os.environ.get("USER", os.environ.get("USERNAME", "unknown"))
|
|
57
|
+
ssh_port = "22"
|
|
58
|
+
ip_addresses: list[str] = []
|
|
59
|
+
|
|
60
|
+
ok, hostname = _run(["hostname"])
|
|
61
|
+
hostname = hostname if ok else "unknown"
|
|
62
|
+
|
|
63
|
+
install_info: list[str] = []
|
|
64
|
+
sshd_installed, sshd_path = _check_sshd_installed()
|
|
65
|
+
_pkg_manager, install_cmd = _detect_package_manager()
|
|
66
|
+
if not sshd_installed:
|
|
67
|
+
results["installation"] = {"status": "error", "message": "OpenSSH Server not installed"}
|
|
68
|
+
issues.append(("sshd not installed", "Cannot accept incoming SSH connections", install_cmd))
|
|
69
|
+
install_info.append("❌ OpenSSH Server: [red]NOT INSTALLED[/red]")
|
|
70
|
+
install_info.append(f" [dim]Install with: {install_cmd}[/dim]")
|
|
71
|
+
else:
|
|
72
|
+
results["installation"] = {"status": "ok", "message": f"sshd found at {sshd_path}"}
|
|
73
|
+
install_info.append(f"✅ OpenSSH Server: installed at [cyan]{sshd_path}[/cyan]")
|
|
74
|
+
console.print(Panel("\n".join(install_info), title="[bold]Installation[/bold]", border_style="blue"))
|
|
75
|
+
|
|
76
|
+
ssh_dir = Path.home().joinpath(".ssh")
|
|
77
|
+
authorized_keys = ssh_dir.joinpath("authorized_keys")
|
|
78
|
+
home_dir = Path.home()
|
|
79
|
+
|
|
80
|
+
perm_info: list[str] = []
|
|
81
|
+
home_stat = os.stat(home_dir)
|
|
82
|
+
home_perms = oct(home_stat.st_mode)[-3:]
|
|
83
|
+
if home_perms[2] in ["7", "6", "3", "2"]:
|
|
84
|
+
results["home_directory"] = {"status": "error", "message": f"Home world-writable: {home_perms}"}
|
|
85
|
+
issues.append((f"Home dir perms {home_perms}", "sshd refuses login if home is world-writable", f"chmod 755 {home_dir}"))
|
|
86
|
+
perm_info.append(f"❌ Home directory: [red]{home_perms}[/red] (world-writable)")
|
|
87
|
+
perm_info.append(" [dim]sshd will refuse key auth if home is writable by others[/dim]")
|
|
88
|
+
else:
|
|
89
|
+
perm_info.append(f"✅ Home directory: {home_perms}")
|
|
90
|
+
|
|
91
|
+
if not ssh_dir.exists():
|
|
92
|
+
results["ssh_directory"] = {"status": "error", "message": "~/.ssh missing"}
|
|
93
|
+
issues.append(("~/.ssh missing", "No place for authorized_keys", "mkdir -p ~/.ssh && chmod 700 ~/.ssh"))
|
|
94
|
+
perm_info.append("❌ ~/.ssh: [red]does not exist[/red]")
|
|
95
|
+
else:
|
|
96
|
+
ssh_perms = oct(os.stat(ssh_dir).st_mode)[-3:]
|
|
97
|
+
if ssh_perms != "700":
|
|
98
|
+
results["ssh_directory"] = {"status": "error", "message": f"~/.ssh perms {ssh_perms}"}
|
|
99
|
+
issues.append((f"~/.ssh perms {ssh_perms}", "sshd requires 700 on ~/.ssh", "chmod 700 ~/.ssh"))
|
|
100
|
+
perm_info.append(f"❌ ~/.ssh: [red]{ssh_perms}[/red] (must be 700)")
|
|
101
|
+
else:
|
|
102
|
+
perm_info.append(f"✅ ~/.ssh: {ssh_perms}")
|
|
103
|
+
|
|
104
|
+
if not authorized_keys.exists():
|
|
105
|
+
results["authorized_keys"] = {"status": "error", "message": "authorized_keys missing"}
|
|
106
|
+
issues.append(("authorized_keys missing", "No keys = no login", "Add public key: cat id_rsa.pub >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"))
|
|
107
|
+
perm_info.append("❌ authorized_keys: [red]does not exist[/red]")
|
|
108
|
+
perm_info.append(" [dim]No authorized keys = cannot login with SSH key[/dim]")
|
|
109
|
+
else:
|
|
110
|
+
ak_perms = oct(os.stat(authorized_keys).st_mode)[-3:]
|
|
111
|
+
try:
|
|
112
|
+
keys = [line for line in authorized_keys.read_text(encoding="utf-8").split("\n") if line.strip()]
|
|
113
|
+
key_count = len(keys)
|
|
114
|
+
except Exception:
|
|
115
|
+
key_count = 0
|
|
116
|
+
if ak_perms not in ["600", "644"]:
|
|
117
|
+
results["authorized_keys"] = {"status": "error", "message": f"authorized_keys perms {ak_perms}"}
|
|
118
|
+
issues.append((f"authorized_keys perms {ak_perms}", "sshd requires 600 or 644", "chmod 600 ~/.ssh/authorized_keys"))
|
|
119
|
+
perm_info.append(f"❌ authorized_keys: [red]{ak_perms}[/red] ({key_count} key(s)) - must be 600/644")
|
|
120
|
+
else:
|
|
121
|
+
results["authorized_keys"] = {"status": "ok", "message": f"{key_count} key(s)"}
|
|
122
|
+
perm_info.append(f"✅ authorized_keys: {ak_perms} ([green]{key_count} key(s)[/green])")
|
|
123
|
+
|
|
124
|
+
console.print(Panel("\n".join(perm_info), title="[bold]Permissions[/bold]", border_style="blue"))
|
|
125
|
+
|
|
126
|
+
svc_info: list[str] = []
|
|
127
|
+
ssh_ok, _ = _run(["systemctl", "is-active", "ssh"])
|
|
128
|
+
sshd_ok, _ = _run(["systemctl", "is-active", "sshd"])
|
|
129
|
+
if ssh_ok or sshd_ok:
|
|
130
|
+
svc_name = "ssh" if ssh_ok else "sshd"
|
|
131
|
+
results["ssh_service"] = {"status": "ok", "message": f"{svc_name} running"}
|
|
132
|
+
svc_info.append(f"✅ Service: [green]{svc_name} running[/green]")
|
|
133
|
+
else:
|
|
134
|
+
results["ssh_service"] = {"status": "error", "message": "sshd not running"}
|
|
135
|
+
issues.append(("sshd not running", "No SSH daemon = no connections", "sudo systemctl start ssh && sudo systemctl enable ssh"))
|
|
136
|
+
svc_info.append("❌ Service: [red]not running[/red]")
|
|
137
|
+
|
|
138
|
+
console.print(Panel("\n".join(svc_info), title="[bold]Service[/bold]", border_style="blue"))
|
|
139
|
+
|
|
140
|
+
net_info: list[str] = []
|
|
141
|
+
ok, ip_out = _run(["ip", "addr", "show"])
|
|
142
|
+
if ok:
|
|
143
|
+
ip_addresses = re.findall(r'inet\s+(\d+\.\d+\.\d+\.\d+)/\d+.*scope\s+global', ip_out)
|
|
144
|
+
if ip_addresses:
|
|
145
|
+
net_info.append(f"🌐 IP: [cyan]{', '.join(ip_addresses)}[/cyan]")
|
|
146
|
+
|
|
147
|
+
sshd_config_paths = [Path("/etc/ssh/sshd_config"), Path("/etc/sshd_config")]
|
|
148
|
+
sshd_config: Path | None = None
|
|
149
|
+
for p in sshd_config_paths:
|
|
150
|
+
if p.exists():
|
|
151
|
+
sshd_config = p
|
|
152
|
+
break
|
|
153
|
+
|
|
154
|
+
if sshd_config:
|
|
155
|
+
try:
|
|
156
|
+
config_text = sshd_config.read_text(encoding="utf-8")
|
|
157
|
+
port_lines = [line for line in config_text.split("\n") if line.strip().startswith("Port") and not line.strip().startswith("#")]
|
|
158
|
+
if port_lines:
|
|
159
|
+
ssh_port = port_lines[0].split()[1]
|
|
160
|
+
net_info.append(f"🔌 Port: [cyan]{ssh_port}[/cyan]")
|
|
161
|
+
|
|
162
|
+
pubkey_lines = [line for line in config_text.split("\n") if "PubkeyAuthentication" in line and not line.strip().startswith("#")]
|
|
163
|
+
if pubkey_lines and "no" in pubkey_lines[-1].lower():
|
|
164
|
+
results["pubkey_auth"] = {"status": "error", "message": "PubkeyAuthentication disabled"}
|
|
165
|
+
issues.append(("PubkeyAuthentication disabled", "Key-based login won't work", f"Edit {sshd_config}: set PubkeyAuthentication yes, then sudo systemctl restart ssh"))
|
|
166
|
+
net_info.append("❌ PubkeyAuthentication: [red]disabled[/red]")
|
|
167
|
+
else:
|
|
168
|
+
net_info.append("✅ PubkeyAuthentication: enabled")
|
|
169
|
+
|
|
170
|
+
password_lines = [line for line in config_text.split("\n") if "PasswordAuthentication" in line and not line.strip().startswith("#")]
|
|
171
|
+
if password_lines:
|
|
172
|
+
password_enabled = "yes" in password_lines[-1].lower()
|
|
173
|
+
if password_enabled:
|
|
174
|
+
results["password_auth"] = {"status": "ok", "message": "PasswordAuthentication enabled"}
|
|
175
|
+
net_info.append("✅ PasswordAuthentication: [green]enabled[/green]")
|
|
176
|
+
else:
|
|
177
|
+
results["password_auth"] = {"status": "info", "message": "PasswordAuthentication disabled"}
|
|
178
|
+
net_info.append("ℹ️ PasswordAuthentication: [yellow]disabled[/yellow] (key-only)")
|
|
179
|
+
else:
|
|
180
|
+
results["password_auth"] = {"status": "ok", "message": "PasswordAuthentication enabled (default)"}
|
|
181
|
+
net_info.append("✅ PasswordAuthentication: [green]enabled[/green] (default)")
|
|
182
|
+
|
|
183
|
+
permit_root = [line for line in config_text.split("\n") if "PermitRootLogin" in line and not line.strip().startswith("#")]
|
|
184
|
+
if permit_root:
|
|
185
|
+
val = permit_root[-1].split()[-1].lower()
|
|
186
|
+
net_info.append(f"ℹ️ PermitRootLogin: {val}")
|
|
187
|
+
except Exception:
|
|
188
|
+
pass
|
|
189
|
+
|
|
190
|
+
ok, ss_out = _run(["ss", "-tlnp"])
|
|
191
|
+
if ok:
|
|
192
|
+
listening = [line for line in ss_out.split("\n") if f":{ssh_port}" in line]
|
|
193
|
+
if not listening:
|
|
194
|
+
results["ssh_listening"] = {"status": "error", "message": f"Not listening on {ssh_port}"}
|
|
195
|
+
issues.append((f"Not listening on port {ssh_port}", "No connections possible", "sudo systemctl restart ssh"))
|
|
196
|
+
net_info.append(f"❌ Listening: [red]NOT on port {ssh_port}[/red]")
|
|
197
|
+
elif all("127.0.0.1" in line or "[::1]" in line for line in listening):
|
|
198
|
+
results["ssh_listening"] = {"status": "error", "message": "Localhost only"}
|
|
199
|
+
issues.append(("SSH bound to localhost", "Only local connections", f"Edit {sshd_config}: remove/comment ListenAddress 127.0.0.1"))
|
|
200
|
+
net_info.append("❌ Listening: [red]localhost only[/red]")
|
|
201
|
+
else:
|
|
202
|
+
results["ssh_listening"] = {"status": "ok", "message": f"Listening on {ssh_port}"}
|
|
203
|
+
net_info.append(f"✅ Listening: 0.0.0.0:{ssh_port}")
|
|
204
|
+
|
|
205
|
+
fw_checked = False
|
|
206
|
+
ok, ufw_out = _run(["ufw", "status"])
|
|
207
|
+
if ok and "Status: active" in ufw_out:
|
|
208
|
+
fw_checked = True
|
|
209
|
+
if f"{ssh_port}/tcp" in ufw_out.lower() or "ssh" in ufw_out.lower() or f" {ssh_port} " in ufw_out:
|
|
210
|
+
results["firewall"] = {"status": "ok", "message": "UFW allows SSH"}
|
|
211
|
+
net_info.append("✅ Firewall (UFW): allows SSH")
|
|
212
|
+
else:
|
|
213
|
+
results["firewall"] = {"status": "error", "message": "UFW blocking SSH"}
|
|
214
|
+
issues.append(("UFW blocking SSH", "Incoming connections dropped", f"sudo ufw allow {ssh_port}/tcp"))
|
|
215
|
+
net_info.append("❌ Firewall (UFW): [red]blocking SSH[/red]")
|
|
216
|
+
net_info.append(" [dim]Active firewall without SSH rule = blocked[/dim]")
|
|
217
|
+
|
|
218
|
+
if not fw_checked:
|
|
219
|
+
ok, fwd_out = _run(["firewall-cmd", "--state"])
|
|
220
|
+
if ok and "running" in fwd_out.lower():
|
|
221
|
+
fw_checked = True
|
|
222
|
+
ok2, svc_out = _run(["firewall-cmd", "--list-services"])
|
|
223
|
+
if ok2 and "ssh" in svc_out.lower():
|
|
224
|
+
results["firewall"] = {"status": "ok", "message": "firewalld allows SSH"}
|
|
225
|
+
net_info.append("✅ Firewall (firewalld): allows SSH")
|
|
226
|
+
else:
|
|
227
|
+
results["firewall"] = {"status": "error", "message": "firewalld blocking SSH"}
|
|
228
|
+
issues.append(("firewalld blocking SSH", "Incoming connections dropped", "sudo firewall-cmd --permanent --add-service=ssh && sudo firewall-cmd --reload"))
|
|
229
|
+
net_info.append("❌ Firewall (firewalld): [red]blocking SSH[/red]")
|
|
230
|
+
|
|
231
|
+
if not fw_checked:
|
|
232
|
+
ok, ipt_out = _run(["iptables", "-L", "INPUT", "-n"])
|
|
233
|
+
if ok and ipt_out:
|
|
234
|
+
has_drop_policy = "policy DROP" in ipt_out or "policy REJECT" in ipt_out
|
|
235
|
+
has_ssh_allow = f"dpt:{ssh_port}" in ipt_out or "dpt:ssh" in ipt_out
|
|
236
|
+
if has_drop_policy and not has_ssh_allow:
|
|
237
|
+
results["firewall"] = {"status": "error", "message": "iptables blocking SSH"}
|
|
238
|
+
issues.append(("iptables blocking SSH", "DROP/REJECT policy without SSH allow", f"sudo iptables -I INPUT -p tcp --dport {ssh_port} -j ACCEPT"))
|
|
239
|
+
net_info.append("❌ Firewall (iptables): [red]DROP policy, no SSH rule[/red]")
|
|
240
|
+
fw_checked = True
|
|
241
|
+
elif has_drop_policy and has_ssh_allow:
|
|
242
|
+
results["firewall"] = {"status": "ok", "message": "iptables allows SSH"}
|
|
243
|
+
net_info.append("✅ Firewall (iptables): allows SSH")
|
|
244
|
+
fw_checked = True
|
|
245
|
+
|
|
246
|
+
if not fw_checked:
|
|
247
|
+
net_info.append("ℹ️ Firewall: none detected / not active")
|
|
248
|
+
|
|
249
|
+
console.print(Panel("\n".join(net_info), title="[bold]Network & Firewall[/bold]", border_style="blue"))
|
|
250
|
+
|
|
251
|
+
other_info: list[str] = []
|
|
252
|
+
hosts_deny = Path("/etc/hosts.deny")
|
|
253
|
+
if hosts_deny.exists():
|
|
254
|
+
try:
|
|
255
|
+
content = hosts_deny.read_text(encoding="utf-8")
|
|
256
|
+
active = [line for line in content.splitlines() if line.strip() and not line.strip().startswith("#")]
|
|
257
|
+
joined = " ".join(active).lower()
|
|
258
|
+
if "sshd" in joined or "all" in joined:
|
|
259
|
+
results["hosts_deny"] = {"status": "error", "message": "hosts.deny blocking"}
|
|
260
|
+
issues.append(("hosts.deny blocking SSH", "TCP wrappers deny before firewall", "Edit /etc/hosts.deny to remove sshd/ALL entries"))
|
|
261
|
+
other_info.append("❌ /etc/hosts.deny: [red]may block SSH[/red]")
|
|
262
|
+
else:
|
|
263
|
+
other_info.append("✅ /etc/hosts.deny: OK")
|
|
264
|
+
except Exception:
|
|
265
|
+
pass
|
|
266
|
+
|
|
267
|
+
ok, se_out = _run(["getenforce"])
|
|
268
|
+
if ok and se_out:
|
|
269
|
+
if se_out == "Enforcing":
|
|
270
|
+
other_info.append("ℹ️ SELinux: Enforcing (run [cyan]restorecon -Rv ~/.ssh[/cyan] if issues)")
|
|
271
|
+
else:
|
|
272
|
+
other_info.append(f"ℹ️ SELinux: {se_out}")
|
|
273
|
+
|
|
274
|
+
log_files = [Path("/var/log/auth.log"), Path("/var/log/secure")]
|
|
275
|
+
for lf in log_files:
|
|
276
|
+
if lf.exists():
|
|
277
|
+
ok, tail = _run(["tail", "-n", "20", str(lf)])
|
|
278
|
+
if ok:
|
|
279
|
+
errors = [line for line in tail.split("\n") if any(k in line.lower() for k in ["error", "failed", "refused", "denied"]) and "ssh" in line.lower()]
|
|
280
|
+
if errors:
|
|
281
|
+
other_info.append(f"⚠️ Recent SSH errors in {lf.name}: {len(errors)}")
|
|
282
|
+
else:
|
|
283
|
+
other_info.append(f"✅ {lf.name}: no recent SSH errors")
|
|
284
|
+
break
|
|
285
|
+
|
|
286
|
+
if other_info:
|
|
287
|
+
console.print(Panel("\n".join(other_info), title="[bold]Additional[/bold]", border_style="blue"))
|
|
288
|
+
|
|
289
|
+
if issues:
|
|
290
|
+
fix_table = Table(title="Issues & Fixes", box=box.ROUNDED, show_lines=True, title_style="bold red")
|
|
291
|
+
fix_table.add_column("Issue", style="yellow", width=25)
|
|
292
|
+
fix_table.add_column("Impact", style="white", width=35)
|
|
293
|
+
fix_table.add_column("Fix Command", style="green", width=55)
|
|
294
|
+
for issue, impact, fix in issues:
|
|
295
|
+
fix_table.add_row(issue, impact, fix)
|
|
296
|
+
console.print(fix_table)
|
|
297
|
+
|
|
298
|
+
fix_script_path = Path("/tmp/ssh_fix.sh")
|
|
299
|
+
script_lines = ["#!/bin/bash", "set -e", "", "# SSH Fix Script - Generated by ssh_debug_linux", f"# {len(issues)} issue(s) to fix", ""]
|
|
300
|
+
for issue, _impact, fix in issues:
|
|
301
|
+
script_lines.append(f"# Fix: {issue}")
|
|
302
|
+
script_lines.append(fix)
|
|
303
|
+
script_lines.append("")
|
|
304
|
+
script_lines.append("echo 'All fixes applied. Re-run ssh_debug_linux to verify.'")
|
|
305
|
+
fix_script_path.write_text("\n".join(script_lines), encoding="utf-8")
|
|
306
|
+
fix_script_path.chmod(0o755)
|
|
307
|
+
|
|
308
|
+
console.print(Panel(f"[bold yellow]⚠️ {len(issues)} issue(s) found[/bold yellow]\n\nFix script generated: [cyan]{fix_script_path}[/cyan]\nRun: [green]sudo bash {fix_script_path}[/green]", title="[bold]Summary[/bold]", border_style="yellow"))
|
|
309
|
+
else:
|
|
310
|
+
conn_info = f"👤 {current_user} 🖥️ {hostname} 🔌 :{ssh_port}"
|
|
311
|
+
if ip_addresses:
|
|
312
|
+
conn_info += f"\n\n[bold]Connect:[/bold] ssh {current_user}@{ip_addresses[0]}"
|
|
313
|
+
console.print(Panel(f"[bold green]✅ All checks passed[/bold green]\n\n{conn_info}", title="[bold]Ready[/bold]", border_style="green"))
|
|
314
|
+
|
|
315
|
+
return results
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
if __name__ == "__main__":
|
|
319
|
+
ssh_debug_linux()
|