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