@sebastienrousseau/dotfiles 0.2.481 → 0.2.499

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 (317) hide show
  1. package/docs/ARCHITECTURE.md +29 -196
  2. package/docs/COMPLIANCE.md +10 -10
  3. package/docs/COPYRIGHT +3 -4
  4. package/docs/OPERATIONS.md +38 -65
  5. package/docs/PLAN.md +3 -3
  6. package/docs/PR_DESCRIPTION.md +85 -84
  7. package/docs/ROADMAP.md +11 -11
  8. package/docs/ROADMAP_legacy.md +556 -0
  9. package/docs/SECURITY_CHECKLIST.md +1 -1
  10. package/docs/TASK.md +4 -4
  11. package/docs/WALKTHROUGH.md +33 -152
  12. package/package.json +17 -5
  13. package/scripts/backup.sh +142 -0
  14. package/scripts/banner.sh +20 -0
  15. package/scripts/benchmark.sh +20 -0
  16. package/scripts/build.sh +41 -0
  17. package/scripts/clean.sh +31 -0
  18. package/scripts/compile.sh +54 -0
  19. package/scripts/copy.sh +108 -0
  20. package/scripts/{tools/detect-collisions.py → detect-collisions.py} +1 -1
  21. package/scripts/doctor.sh +79 -0
  22. package/scripts/dotfiles.sh +63 -0
  23. package/scripts/download.sh +35 -0
  24. package/scripts/help.sh +57 -0
  25. package/scripts/lock-configs.sh +57 -0
  26. package/scripts/package.sh +46 -0
  27. package/scripts/ssh.sh +55 -0
  28. package/scripts/teleport.sh +23 -0
  29. package/scripts/{tests/test-aliases.sh → test-aliases.sh} +3 -3
  30. package/scripts/test_smoke.sh +88 -0
  31. package/scripts/unpack.sh +28 -0
  32. package/scripts/{diagnostics/verify_state.sh → verify_state.sh} +21 -21
  33. package/templates/projects/go/README.md +0 -4
  34. package/templates/projects/node/README.md +0 -4
  35. package/templates/projects/python/README.md +0 -4
  36. package/templates/projects/python/pyproject.toml +0 -15
  37. package/CHANGELOG.md +0 -285
  38. package/LICENSE +0 -1283
  39. package/README.md +0 -315
  40. package/docs/ALIASES.md +0 -128
  41. package/docs/FEATURES.md +0 -166
  42. package/docs/FONTS.md +0 -147
  43. package/docs/INSTALL.md +0 -119
  44. package/docs/KEYS.md +0 -40
  45. package/docs/KEY_ROTATION.md +0 -219
  46. package/docs/LEGACY_ROADMAP.md +0 -142
  47. package/docs/NEOVIM_IDE_GUIDE.md +0 -52
  48. package/docs/README.md +0 -269
  49. package/docs/REPO_AUDIT.md +0 -23
  50. package/docs/SCREENSHOTS.md +0 -116
  51. package/docs/SECRETS.md +0 -76
  52. package/docs/SECURITY.md +0 -30
  53. package/docs/TESTING.md +0 -190
  54. package/docs/TOOLS.md +0 -146
  55. package/docs/TROUBLESHOOTING.md +0 -112
  56. package/docs/UTILS.md +0 -105
  57. package/docs/WSL2_NIX_TROUBLESHOOTING.md +0 -723
  58. package/docs/adr/ADR-001-ci-cd-pipeline.md +0 -101
  59. package/docs/adr/ADR-002-shell-performance.md +0 -121
  60. package/docs/adr/ADR-003-security-first.md +0 -140
  61. package/docs/adr/ADR-004-cli-architecture.md +0 -157
  62. package/docs/adr/ADR-005-chezmoi-choice.md +0 -89
  63. package/docs/adr/ADR-006-shell-selection.md +0 -115
  64. package/docs/adr/README.md +0 -33
  65. package/docs/themes/README.md +0 -20
  66. package/dot_config/aider/aider.conf.yml +0 -32
  67. package/dot_config/alacritty/alacritty.toml.tmpl +0 -483
  68. package/dot_config/ansible/ansible.cfg.tmpl +0 -11
  69. package/dot_config/atuin/config.toml +0 -23
  70. package/dot_config/bat/config +0 -8
  71. package/dot_config/brave-flags.conf.tmpl +0 -7
  72. package/dot_config/btop/btop.conf +0 -16
  73. package/dot_config/btop/themes/tokyonight.theme +0 -34
  74. package/dot_config/bun/bunfig.toml.tmpl +0 -33
  75. package/dot_config/claude/mcp_servers.json +0 -49
  76. package/dot_config/clippy.toml +0 -55
  77. package/dot_config/containers/containers.conf +0 -14
  78. package/dot_config/curl/dot_curlrc +0 -18
  79. package/dot_config/dlv/config.yml +0 -39
  80. package/dot_config/docker/config.json.tmpl +0 -15
  81. package/dot_config/dotfiles/boot/README.md +0 -11
  82. package/dot_config/dotfiles/grub/README.md +0 -11
  83. package/dot_config/dotfiles/lock/README.md +0 -11
  84. package/dot_config/dotfiles/versions.env.tmpl +0 -19
  85. package/dot_config/duf/duf.conf +0 -6
  86. package/dot_config/duti/defaults.duti +0 -5
  87. package/dot_config/emoji/emoji.txt +0 -34
  88. package/dot_config/fastfetch/config.jsonc +0 -28
  89. package/dot_config/firefox/user.js +0 -8
  90. package/dot_config/flatpak/flatpak.list +0 -4
  91. package/dot_config/fontconfig/fonts.conf.tmpl +0 -44
  92. package/dot_config/gem/gemrc +0 -9
  93. package/dot_config/gh/config.yml +0 -12
  94. package/dot_config/ghostty/config.tmpl +0 -661
  95. package/dot_config/git/attributes +0 -12
  96. package/dot_config/git/config.tmpl +0 -77
  97. package/dot_config/git/ignore +0 -27
  98. package/dot_config/gnupg/gpg-agent.conf.tmpl +0 -11
  99. package/dot_config/go/aliases.sh +0 -61
  100. package/dot_config/go/env.sh +0 -24
  101. package/dot_config/go/golangci.yml +0 -118
  102. package/dot_config/go/gopls.json +0 -30
  103. package/dot_config/goose/config.yaml +0 -29
  104. package/dot_config/gtk-3.0/gtk.css.tmpl +0 -305
  105. package/dot_config/gtk-3.0/settings.ini.tmpl +0 -66
  106. package/dot_config/gtk-4.0/gtk.css.tmpl +0 -309
  107. package/dot_config/gtk-4.0/settings.ini.tmpl +0 -21
  108. package/dot_config/htop/htoprc +0 -20
  109. package/dot_config/ice/README.md +0 -13
  110. package/dot_config/inputrc +0 -2
  111. package/dot_config/ipython/profile_default/ipython_config.py.tmpl +0 -5
  112. package/dot_config/just/justfile +0 -104
  113. package/dot_config/k9s/config.yaml.tmpl +0 -65
  114. package/dot_config/k9s/skins/catppuccin-mocha.yaml +0 -116
  115. package/dot_config/karabiner/karabiner.json +0 -14
  116. package/dot_config/kitty/kitty.conf.tmpl +0 -517
  117. package/dot_config/lazydocker/config.yml +0 -186
  118. package/dot_config/lazygit/config.yml +0 -23
  119. package/dot_config/lsd/config.yaml +0 -19
  120. package/dot_config/mas/masapps.txt +0 -5
  121. package/dot_config/minikube/config.json +0 -13
  122. package/dot_config/mise/config.toml +0 -41
  123. package/dot_config/mongosh/mongoshrc.js +0 -67
  124. package/dot_config/mycli/myclirc +0 -67
  125. package/dot_config/nano/nanorc +0 -28
  126. package/dot_config/ncdu/config +0 -12
  127. package/dot_config/nvim/init.lua +0 -4
  128. package/dot_config/nvim/lazy-lock.json +0 -27
  129. package/dot_config/nvim/lua/config/autocmds.lua +0 -63
  130. package/dot_config/nvim/lua/config/keymaps.lua +0 -87
  131. package/dot_config/nvim/lua/config/lazy.lua +0 -34
  132. package/dot_config/nvim/lua/config/options.lua +0 -48
  133. package/dot_config/nvim/lua/plugins/coding.lua +0 -234
  134. package/dot_config/nvim/lua/plugins/dap.lua +0 -201
  135. package/dot_config/nvim/lua/plugins/editor.lua +0 -59
  136. package/dot_config/nvim/lua/plugins/git.lua +0 -9
  137. package/dot_config/nvim/lua/plugins/lsp.lua +0 -221
  138. package/dot_config/nvim/lua/plugins/markdown.lua +0 -17
  139. package/dot_config/nvim/lua/plugins/rust.lua +0 -33
  140. package/dot_config/nvim/lua/plugins/sessions.lua +0 -32
  141. package/dot_config/nvim/lua/plugins/ui.lua +0 -537
  142. package/dot_config/nvim/snippets/all.lua +0 -9
  143. package/dot_config/nvim/snippets/python.lua +0 -16
  144. package/dot_config/pip/pip.conf.tmpl +0 -32
  145. package/dot_config/pypoetry/config.toml.tmpl +0 -6
  146. package/dot_config/pyrightconfig.json.tmpl +0 -5
  147. package/dot_config/raycast/README.md +0 -13
  148. package/dot_config/redis/redisclirc +0 -41
  149. package/dot_config/shell/00-container-detect.sh +0 -53
  150. package/dot_config/shell/00-core-paths.sh.tmpl +0 -95
  151. package/dot_config/shell/05-core-safety.sh.tmpl +0 -13
  152. package/dot_config/shell/40-ls-colors.sh.tmpl +0 -31
  153. package/dot_config/shell/50-logic-functions.sh.tmpl +0 -10
  154. package/dot_config/shell/90-theme-switch.sh +0 -70
  155. package/dot_config/shell/90-ux-aliases.sh.tmpl +0 -35
  156. package/dot_config/shell/91-ux-aliases-lazy.sh.tmpl +0 -23
  157. package/dot_config/shell/Brewfile +0 -207
  158. package/dot_config/shell/Brewfile.cask +0 -92
  159. package/dot_config/shell/Brewfile.cli +0 -119
  160. package/dot_config/shell/README.md +0 -267
  161. package/dot_config/shell/custom/context_suggest.zsh +0 -68
  162. package/dot_config/shell/custom/error_analysis.zsh +0 -45
  163. package/dot_config/sops/dot_sops.yaml +0 -23
  164. package/dot_config/starship.toml.tmpl +0 -124
  165. package/dot_config/task/Taskfile.yml +0 -86
  166. package/dot_config/tflint/tflint.hcl.tmpl +0 -9
  167. package/dot_config/tmux/tmux.conf.tmpl +0 -181
  168. package/dot_config/topgrade/topgrade.toml.tmpl +0 -42
  169. package/dot_config/vscode/extensions.txt +0 -11
  170. package/dot_config/vscode/settings.json.tmpl +0 -123
  171. package/dot_config/waybar/style.css +0 -8
  172. package/dot_config/wezterm/wezterm.lua.tmpl +0 -236
  173. package/dot_config/wget/wgetrc +0 -12
  174. package/dot_config/yarn/yarnrc.yml.tmpl +0 -36
  175. package/dot_config/yazi/yazi.toml +0 -40
  176. package/dot_config/zellij/config.kdl +0 -79
  177. package/dot_config/zsh/dot_zprofile +0 -13
  178. package/dot_config/zsh/dot_zshenv +0 -6
  179. package/dot_config/zsh/dot_zshrc.tmpl +0 -199
  180. package/dot_config/zsh/rc.d/05-ssh-agent.zsh +0 -5
  181. package/dot_config/zsh/rc.d/10-env.zsh.tmpl +0 -28
  182. package/dot_config/zsh/rc.d/20-zinit.zsh.tmpl +0 -22
  183. package/dot_config/zsh/rc.d/30-options.zsh.tmpl +0 -123
  184. package/dot_config/zsh/rc.d/40-bell.zsh.tmpl +0 -20
  185. package/dot_config/zsh/rc.d/50-login-fortune.zsh.tmpl +0 -9
  186. package/dot_local/bin/executable_ai_core +0 -130
  187. package/dot_local/bin/executable_b64 +0 -59
  188. package/dot_local/bin/executable_dot +0 -178
  189. package/dot_local/bin/executable_dot_completion +0 -55
  190. package/dot_local/bin/executable_epoch +0 -62
  191. package/dot_local/bin/executable_extract +0 -108
  192. package/dot_local/bin/executable_git-ai-commit +0 -160
  193. package/dot_local/bin/executable_git-ai-diff +0 -154
  194. package/dot_local/bin/executable_hash +0 -123
  195. package/dot_local/bin/executable_hex +0 -79
  196. package/dot_local/bin/executable_ip +0 -37
  197. package/dot_local/bin/executable_jsonv +0 -54
  198. package/dot_local/bin/executable_jwt +0 -78
  199. package/dot_local/bin/executable_kill-port +0 -59
  200. package/dot_local/bin/executable_lorem +0 -103
  201. package/dot_local/bin/executable_regex +0 -96
  202. package/dot_local/bin/executable_tmux-sessionizer +0 -187
  203. package/dot_local/bin/executable_tour +0 -137
  204. package/dot_local/bin/executable_update +0 -108
  205. package/dot_local/bin/executable_uuid +0 -57
  206. package/dot_local/bin/executable_yamlv +0 -39
  207. package/dot_local/bin/executable_zig-install +0 -89
  208. package/dot_local/bin/voice_ops +0 -7
  209. package/dot_local/share/bash-completion/completions/dot +0 -54
  210. package/dot_local/share/zsh/completions/.keep +0 -0
  211. package/install.sh +0 -255
  212. package/scripts/ci/validate-ci-config.sh +0 -222
  213. package/scripts/demo/record.sh +0 -41
  214. package/scripts/diagnostics/benchmark.sh +0 -201
  215. package/scripts/diagnostics/doctor.sh +0 -115
  216. package/scripts/diagnostics/drift-dashboard.sh +0 -26
  217. package/scripts/diagnostics/health.sh +0 -356
  218. package/scripts/diagnostics/history-analysis.sh +0 -77
  219. package/scripts/diagnostics/security-score.sh +0 -392
  220. package/scripts/dot/commands/appearance.sh +0 -63
  221. package/scripts/dot/commands/core.sh +0 -130
  222. package/scripts/dot/commands/diagnostics.sh +0 -100
  223. package/scripts/dot/commands/meta.sh +0 -117
  224. package/scripts/dot/commands/restore.sh +0 -209
  225. package/scripts/dot/commands/secrets.sh +0 -81
  226. package/scripts/dot/commands/security.sh +0 -73
  227. package/scripts/dot/commands/tools.sh +0 -228
  228. package/scripts/dot/lib/utils.sh +0 -72
  229. package/scripts/fonts/install-nerd-fonts.sh +0 -59
  230. package/scripts/fonts/patch-fonts.sh +0 -34
  231. package/scripts/ops/chezmoi-apply.sh +0 -42
  232. package/scripts/ops/chezmoi-diff.sh +0 -14
  233. package/scripts/ops/chezmoi-remove.sh +0 -43
  234. package/scripts/ops/chezmoi-update.sh +0 -16
  235. package/scripts/ops/heal.sh +0 -466
  236. package/scripts/ops/health-check.sh +0 -380
  237. package/scripts/ops/rollback.sh +0 -531
  238. package/scripts/ops/teleport.sh +0 -32
  239. package/scripts/secrets/age-init.sh +0 -69
  240. package/scripts/secrets/create-secrets-file.sh +0 -44
  241. package/scripts/secrets/encrypt-ssh-key.sh +0 -42
  242. package/scripts/security/backup.sh +0 -17
  243. package/scripts/security/dns-doh.sh +0 -29
  244. package/scripts/security/encryption-check.sh +0 -39
  245. package/scripts/security/enforce-policies.sh +0 -339
  246. package/scripts/security/firewall.sh +0 -34
  247. package/scripts/security/lock-configs.sh +0 -57
  248. package/scripts/security/lock-screen.sh +0 -33
  249. package/scripts/security/manage-secrets.sh +0 -415
  250. package/scripts/security/telemetry-kill.sh +0 -28
  251. package/scripts/security/usb-safety.sh +0 -29
  252. package/scripts/tests/README.md +0 -241
  253. package/scripts/tests/benchmark.sh +0 -91
  254. package/scripts/tests/framework/assertions.sh +0 -283
  255. package/scripts/tests/framework/mocks.sh +0 -201
  256. package/scripts/tests/framework/test_runner.sh +0 -189
  257. package/scripts/tests/integration/test_install.sh +0 -237
  258. package/scripts/tests/performance/benchmark_runner.sh +0 -156
  259. package/scripts/tests/performance/regression_check.sh +0 -73
  260. package/scripts/tests/performance/stress_test.sh +0 -65
  261. package/scripts/tests/test-docker.sh +0 -48
  262. package/scripts/tests/unit/test_ai_aliases.sh +0 -158
  263. package/scripts/tests/unit/test_ai_cli_checks.sh +0 -47
  264. package/scripts/tests/unit/test_backup.sh +0 -227
  265. package/scripts/tests/unit/test_case_functions.sh +0 -238
  266. package/scripts/tests/unit/test_cd_aliases.sh +0 -367
  267. package/scripts/tests/unit/test_dot_cli.sh +0 -217
  268. package/scripts/tests/unit/test_encode64.sh +0 -67
  269. package/scripts/tests/unit/test_environment.sh +0 -78
  270. package/scripts/tests/unit/test_extract.sh +0 -163
  271. package/scripts/tests/unit/test_framework_edge_cases.sh +0 -113
  272. package/scripts/tests/unit/test_genpass.sh +0 -298
  273. package/scripts/tests/unit/test_install_edge_cases.sh +0 -167
  274. package/scripts/tests/unit/test_installers.sh +0 -172
  275. package/scripts/tests/unit/test_keygen.sh +0 -68
  276. package/scripts/tests/unit/test_logging.sh +0 -96
  277. package/scripts/tests/unit/test_os_detection_comprehensive.sh +0 -388
  278. package/scripts/tests/unit/test_package_managers_comprehensive.sh +0 -321
  279. package/scripts/tests/unit/test_prependpath.sh +0 -66
  280. package/scripts/tests/unit/test_prependpath_refactored.sh +0 -89
  281. package/scripts/tests/unit/test_rd.sh +0 -230
  282. package/scripts/tests/unit/test_security_fixes.sh +0 -130
  283. package/scripts/tests/unit/test_security_scripts.sh +0 -87
  284. package/scripts/tests/unit/test_template_validation.sh +0 -238
  285. package/scripts/tests/unit/test_utility_functions.sh +0 -144
  286. package/scripts/tests/unit/test_wave1_alias_split.sh +0 -132
  287. package/scripts/tests/unit/test_wave1_ci_pinning.sh +0 -61
  288. package/scripts/tests/unit/test_wave1_gitleaks_config.sh +0 -52
  289. package/scripts/tests/unit/test_wave1_heal_fixes.sh +0 -97
  290. package/scripts/tests/unit/test_wave1_install_gpg.sh +0 -35
  291. package/scripts/tests/unit/test_wave1_zshenv_path.sh +0 -89
  292. package/scripts/tests/unit/test_wave1_zshrc_lazy_hook.sh +0 -115
  293. package/scripts/tests/unit/test_wave2_dot_new_guard.sh +0 -75
  294. package/scripts/tests/unit/test_zipf.sh +0 -76
  295. package/scripts/theme/apply-gnome-theme.sh +0 -297
  296. package/scripts/theme/install-boot-logo.sh +0 -61
  297. package/scripts/theme/install-catppuccin-themes.sh +0 -346
  298. package/scripts/theme/install-cursors.sh +0 -24
  299. package/scripts/theme/install-file-icons.sh +0 -25
  300. package/scripts/theme/install-grub-theme.sh +0 -51
  301. package/scripts/theme/install-lock-icon.sh +0 -29
  302. package/scripts/theme/switch.sh +0 -250
  303. package/scripts/theme/wallpaper-rotate.sh +0 -82
  304. package/scripts/theme/wallpaper-sync.sh +0 -42
  305. package/scripts/tools/cmatrix.sh +0 -20
  306. package/scripts/tools/emoji-picker.sh +0 -45
  307. package/scripts/tools/figlet-banner.sh +0 -17
  308. package/scripts/tools/log-rotate.sh +0 -29
  309. package/scripts/tools/lolcat-wrap.sh +0 -18
  310. package/scripts/tools/pipes.sh +0 -47
  311. package/scripts/tuning/linux.sh +0 -175
  312. package/scripts/tuning/macos.sh +0 -46
  313. package/templates/projects/molecule/README.md +0 -7
  314. package/templates/projects/molecule/converge.yml +0 -7
  315. package/templates/projects/molecule/molecule.yml +0 -16
  316. package/templates/projects/packer/README.md +0 -15
  317. package/templates/projects/packer/main.pkr.hcl +0 -15
@@ -1,531 +0,0 @@
1
- #!/usr/bin/env bash
2
- # shellcheck disable=SC2034
3
- # =============================================================================
4
- # Dotfiles Rollback Script - Self-Healing Configuration Recovery
5
- # Safely reverts failed dotfile applications with automatic backup
6
- # Usage: ./scripts/ops/rollback.sh [OPTIONS]
7
- # =============================================================================
8
-
9
- set -euo pipefail
10
-
11
- # Configuration
12
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
- REPO_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
14
- DOTFILES_SOURCE="${HOME}/.dotfiles"
15
- BACKUP_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/dotfiles/backups"
16
- STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/dotfiles"
17
- ROLLBACK_LOG="$STATE_DIR/rollback.log"
18
- MAX_BACKUPS=10
19
-
20
- # Colors (respect NO_COLOR: https://no-color.org)
21
- if [[ -z "${NO_COLOR:-}" ]] && [[ -t 1 ]]; then
22
- RED='\033[0;31m'
23
- GREEN='\033[0;32m'
24
- YELLOW='\033[0;33m'
25
- BLUE='\033[0;34m'
26
- BOLD='\033[1m'
27
- NC='\033[0m'
28
- else
29
- RED='' GREEN='' YELLOW='' BLUE='' BOLD='' NC=''
30
- fi
31
-
32
- # Logging
33
- log() { echo -e "$*"; }
34
- log_info() { log "${BLUE}[INFO]${NC} $*"; }
35
- log_success() { log "${GREEN}[OK]${NC} $*"; }
36
- log_warn() { log "${YELLOW}[WARN]${NC} $*"; }
37
- log_error() { log "${RED}[ERROR]${NC} $*"; }
38
- log_step() { log "\n${BOLD}==> $*${NC}"; }
39
-
40
- # Persistent logging
41
- persist_log() {
42
- mkdir -p "$STATE_DIR"
43
- echo "[$(date -Iseconds)] $*" >>"$ROLLBACK_LOG"
44
- }
45
-
46
- usage() {
47
- cat <<EOF
48
- Dotfiles Rollback & Recovery Tool
49
-
50
- Usage: $(basename "$0") [COMMAND] [OPTIONS]
51
-
52
- Commands:
53
- status Show current state and available backups
54
- backup Create a manual backup of current dotfiles
55
- rollback Rollback to the previous backup
56
- rollback-to N Rollback to specific backup number (from status list)
57
- git-reset Reset to last known good git commit
58
- restore FILE Restore a specific file from backup
59
- clean Remove old backups (keeps last $MAX_BACKUPS)
60
-
61
- Options:
62
- -f, --force Skip confirmation prompts
63
- -n, --dry-run Show what would be done without making changes
64
- -v, --verbose Show detailed output
65
- -h, --help Show this help message
66
-
67
- Examples:
68
- $(basename "$0") status # List available backups
69
- $(basename "$0") backup # Create manual backup
70
- $(basename "$0") rollback # Rollback to previous state
71
- $(basename "$0") rollback-to 3 # Rollback to backup #3
72
- $(basename "$0") git-reset # Reset to last good commit
73
- $(basename "$0") restore .bashrc # Restore specific file
74
-
75
- EOF
76
- }
77
-
78
- # Ensure directories exist
79
- ensure_dirs() {
80
- mkdir -p "$BACKUP_DIR" "$STATE_DIR"
81
- }
82
-
83
- # List available backups
84
- list_backups() {
85
- local backups=()
86
- local i=1
87
-
88
- if [[ ! -d "$BACKUP_DIR" ]]; then
89
- log_warn "No backup directory found"
90
- return 1
91
- fi
92
-
93
- log_step "Available Backups"
94
- echo ""
95
-
96
- while IFS= read -r backup; do
97
- if [[ -d "$backup" ]]; then
98
- local name timestamp size
99
- name=$(basename "$backup")
100
- timestamp=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M:%S" "$backup" 2>/dev/null || stat -c "%y" "$backup" 2>/dev/null | cut -d'.' -f1)
101
- size=$(du -sh "$backup" 2>/dev/null | cut -f1)
102
- printf " %2d. %-30s %s %s\n" "$i" "$name" "$timestamp" "$size"
103
- ((i++))
104
- fi
105
- done < <(find "$BACKUP_DIR" -maxdepth 1 -type d -name "backup_*" | sort -r)
106
-
107
- if [[ $i -eq 1 ]]; then
108
- log_warn "No backups found"
109
- return 1
110
- fi
111
- echo ""
112
- }
113
-
114
- # Create a backup
115
- create_backup() {
116
- local reason="${1:-manual}"
117
- local timestamp
118
- timestamp=$(date +"%Y%m%d_%H%M%S")
119
- local backup_name="backup_${timestamp}_${reason}"
120
- local backup_path="$BACKUP_DIR/$backup_name"
121
-
122
- log_step "Creating Backup: $backup_name"
123
- ensure_dirs
124
-
125
- mkdir -p "$backup_path"
126
-
127
- # List of files/directories to backup
128
- local targets=(
129
- "$HOME/.bashrc"
130
- "$HOME/.zshrc"
131
- "$HOME/.zshenv"
132
- "$HOME/.profile"
133
- "$HOME/.inputrc"
134
- "$HOME/.vimrc"
135
- "$HOME/.gitconfig"
136
- "$HOME/.config/shell"
137
- "$HOME/.config/nvim"
138
- "$HOME/.config/git"
139
- "$HOME/.config/tmux"
140
- "$HOME/.config/chezmoi"
141
- )
142
-
143
- local backed_up=0
144
- for target in "${targets[@]}"; do
145
- if [[ -e "$target" ]]; then
146
- local rel_path="${target#"$HOME"/}"
147
- local dest_dir
148
- dest_dir=$(dirname "$backup_path/$rel_path")
149
- mkdir -p "$dest_dir"
150
- cp -a "$target" "$backup_path/$rel_path" 2>/dev/null || true
151
- ((backed_up++))
152
- [[ "$VERBOSE" == "1" ]] && log_info "Backed up: $rel_path"
153
- fi
154
- done
155
-
156
- # Record metadata
157
- cat >"$backup_path/.backup_meta" <<EOF
158
- timestamp=$timestamp
159
- reason=$reason
160
- chezmoi_version=$(chezmoi --version 2>/dev/null || echo "unknown")
161
- git_commit=$(cd "$DOTFILES_SOURCE" 2>/dev/null && git rev-parse --short HEAD 2>/dev/null || echo "unknown")
162
- files_backed_up=$backed_up
163
- EOF
164
-
165
- log_success "Backup created: $backup_path ($backed_up items)"
166
- persist_log "BACKUP_CREATED: $backup_name ($backed_up items)"
167
-
168
- # Cleanup old backups
169
- cleanup_old_backups
170
- }
171
-
172
- # Cleanup old backups, keeping only MAX_BACKUPS
173
- cleanup_old_backups() {
174
- local count
175
- count=$(find "$BACKUP_DIR" -maxdepth 1 -type d -name "backup_*" 2>/dev/null | wc -l | tr -d ' ')
176
-
177
- if [[ $count -gt $MAX_BACKUPS ]]; then
178
- local to_delete=$((count - MAX_BACKUPS))
179
- log_info "Cleaning up $to_delete old backup(s)..."
180
-
181
- find "$BACKUP_DIR" -maxdepth 1 -type d -name "backup_*" | sort | head -n "$to_delete" | while read -r old; do
182
- rm -rf "$old"
183
- [[ "$VERBOSE" == "1" ]] && log_info "Removed: $(basename "$old")"
184
- done
185
- fi
186
- }
187
-
188
- # Get the most recent backup
189
- get_latest_backup() {
190
- find "$BACKUP_DIR" -maxdepth 1 -type d -name "backup_*" 2>/dev/null | sort -r | head -1
191
- }
192
-
193
- # Get backup by index (1-based)
194
- get_backup_by_index() {
195
- local index="$1"
196
- find "$BACKUP_DIR" -maxdepth 1 -type d -name "backup_*" | sort -r | sed -n "${index}p"
197
- }
198
-
199
- # Rollback to a specific backup
200
- perform_rollback() {
201
- local backup_path="$1"
202
- local dry_run="${2:-0}"
203
-
204
- if [[ ! -d "$backup_path" ]]; then
205
- log_error "Backup not found: $backup_path"
206
- return 1
207
- fi
208
-
209
- log_step "Rollback from: $(basename "$backup_path")"
210
-
211
- # First, create a safety backup of current state
212
- if [[ "$dry_run" != "1" ]]; then
213
- create_backup "pre_rollback"
214
- fi
215
-
216
- # Restore files
217
- local restored=0
218
- while IFS= read -r -d '' file; do
219
- local rel_path="${file#"$backup_path"/}"
220
- local dest="$HOME/$rel_path"
221
-
222
- # Skip metadata file
223
- [[ "$rel_path" == ".backup_meta" ]] && continue
224
-
225
- if [[ "$dry_run" == "1" ]]; then
226
- log_info "[DRY-RUN] Would restore: $rel_path"
227
- else
228
- local dest_dir
229
- dest_dir=$(dirname "$dest")
230
- mkdir -p "$dest_dir"
231
- cp -a "$file" "$dest"
232
- ((restored++))
233
- [[ "$VERBOSE" == "1" ]] && log_info "Restored: $rel_path"
234
- fi
235
- done < <(find "$backup_path" -type f -print0)
236
-
237
- if [[ "$dry_run" != "1" ]]; then
238
- log_success "Rollback complete: $restored file(s) restored"
239
- persist_log "ROLLBACK: from $(basename "$backup_path"), $restored files restored"
240
- fi
241
- }
242
-
243
- # Git-based rollback
244
- git_reset() {
245
- local dry_run="${1:-0}"
246
-
247
- if [[ ! -d "$DOTFILES_SOURCE/.git" ]]; then
248
- log_error "Not a git repository: $DOTFILES_SOURCE"
249
- return 1
250
- fi
251
-
252
- log_step "Git Reset Recovery"
253
-
254
- cd "$DOTFILES_SOURCE"
255
-
256
- # Show recent commits
257
- log_info "Recent commits:"
258
- git log --oneline -5
259
- echo ""
260
-
261
- # Check for uncommitted changes
262
- if [[ -n "$(git status --porcelain)" ]]; then
263
- log_warn "Uncommitted changes detected"
264
- if [[ "$FORCE" == "1" ]]; then
265
- git stash push -m "Auto-stash before rollback $(date +%Y%m%d_%H%M%S)"
266
- log_success "Changes auto-stashed (use 'git stash pop' to recover)"
267
- else
268
- read -rp "Stash changes? [y/N] " response
269
- if [[ "$response" =~ ^[Yy]$ ]]; then
270
- git stash push -m "Auto-stash before rollback $(date +%Y%m%d_%H%M%S)"
271
- log_success "Changes stashed"
272
- fi
273
- fi
274
- fi
275
-
276
- # Find last good commit (last tag or HEAD~1)
277
- local target_commit
278
- target_commit=$(git describe --tags --abbrev=0 2>/dev/null || echo "HEAD~1")
279
-
280
- log_info "Reset target: $target_commit"
281
-
282
- if [[ "$dry_run" == "1" ]]; then
283
- log_info "[DRY-RUN] Would reset to: $target_commit"
284
- git diff --stat HEAD "$target_commit"
285
- else
286
- # Create backup first
287
- create_backup "pre_git_reset"
288
-
289
- git reset --hard "$target_commit"
290
- log_success "Git reset to: $target_commit"
291
-
292
- # Re-apply chezmoi
293
- if command -v chezmoi >/dev/null 2>&1; then
294
- log_info "Re-applying chezmoi..."
295
- chezmoi apply --force --exclude=scripts
296
- log_success "Chezmoi re-applied"
297
- fi
298
-
299
- persist_log "GIT_RESET: to $target_commit"
300
- fi
301
- }
302
-
303
- # Restore a specific file from the latest backup
304
- restore_file() {
305
- local file_path="$1"
306
- local dry_run="${2:-0}"
307
-
308
- # Normalize path
309
- file_path="${file_path#"$HOME"/}"
310
- file_path="${file_path#./}"
311
- file_path="${file_path#~/}"
312
-
313
- # Validate against path traversal (e.g., "../../etc/passwd")
314
- # Reject paths containing ".." components
315
- if [[ "$file_path" == *".."* ]]; then
316
- log_error "Path traversal detected in file path: $file_path"
317
- return 1
318
- fi
319
-
320
- local backup
321
- backup=$(get_latest_backup)
322
-
323
- if [[ -z "$backup" ]]; then
324
- log_error "No backups available"
325
- return 1
326
- fi
327
-
328
- local source_file="$backup/$file_path"
329
-
330
- # Verify resolved source path stays within the backup directory
331
- local resolved_source
332
- resolved_source="$(cd "$(dirname "$source_file")" 2>/dev/null && pwd)/$(basename "$source_file")" || {
333
- log_error "Cannot resolve source path: $source_file"
334
- return 1
335
- }
336
- if [[ "$resolved_source" != "$backup/"* ]]; then
337
- log_error "Path traversal detected: resolved path escapes backup directory"
338
- return 1
339
- fi
340
-
341
- # Verify resolved destination stays within HOME
342
- local resolved_dest_dir
343
- resolved_dest_dir="$(cd "$(dirname "$HOME/$file_path")" 2>/dev/null && pwd)" || {
344
- log_error "Cannot resolve destination directory for: $file_path"
345
- return 1
346
- }
347
- if [[ "$resolved_dest_dir" != "$HOME"* ]]; then
348
- log_error "Path traversal detected: destination escapes HOME directory"
349
- return 1
350
- fi
351
-
352
- if [[ ! -f "$source_file" ]]; then
353
- log_error "File not found in backup: $file_path"
354
- log_info "Available files in backup:"
355
- find "$backup" -type f -name "*.backup_meta" -prune -o -type f -print | sed "s|$backup/||" | head -20
356
- return 1
357
- fi
358
-
359
- local dest="$HOME/$file_path"
360
-
361
- if [[ "$dry_run" == "1" ]]; then
362
- log_info "[DRY-RUN] Would restore: $file_path"
363
- log_info "From: $source_file"
364
- log_info "To: $dest"
365
- else
366
- # Backup current version
367
- if [[ -f "$dest" ]]; then
368
- cp "$dest" "${dest}.rollback.$(date +%Y%m%d_%H%M%S)"
369
- fi
370
-
371
- local dest_dir
372
- dest_dir=$(dirname "$dest")
373
- mkdir -p "$dest_dir"
374
- cp -a "$source_file" "$dest"
375
- log_success "Restored: $file_path"
376
- persist_log "RESTORE_FILE: $file_path"
377
- fi
378
- }
379
-
380
- # Show current status
381
- show_status() {
382
- log_step "Dotfiles Rollback Status"
383
- echo ""
384
-
385
- # Chezmoi status
386
- if command -v chezmoi >/dev/null 2>&1; then
387
- log_info "Chezmoi version: $(chezmoi --version | head -1)"
388
- local status
389
- status=$(chezmoi status 2>/dev/null || echo "")
390
- if [[ -z "$status" ]]; then
391
- log_success "Chezmoi: All files in sync"
392
- else
393
- log_warn "Chezmoi: $(echo "$status" | wc -l | tr -d ' ') file(s) out of sync"
394
- fi
395
- fi
396
-
397
- # Git status
398
- if [[ -d "$DOTFILES_SOURCE/.git" ]]; then
399
- cd "$DOTFILES_SOURCE"
400
- log_info "Git commit: $(git rev-parse --short HEAD)"
401
- log_info "Git branch: $(git branch --show-current)"
402
- local changes
403
- changes=$(git status --porcelain | wc -l | tr -d ' ')
404
- if [[ "$changes" -eq 0 ]]; then
405
- log_success "Git: Working tree clean"
406
- else
407
- log_warn "Git: $changes uncommitted change(s)"
408
- fi
409
- fi
410
-
411
- # List backups
412
- echo ""
413
- list_backups || true
414
-
415
- # Recent rollback log
416
- if [[ -f "$ROLLBACK_LOG" ]]; then
417
- echo ""
418
- log_info "Recent rollback activity:"
419
- tail -5 "$ROLLBACK_LOG" | while read -r line; do
420
- echo " $line"
421
- done
422
- fi
423
- }
424
-
425
- # =============================================================================
426
- # Main
427
- # =============================================================================
428
-
429
- FORCE=0
430
- DRY_RUN=0
431
- VERBOSE=0
432
-
433
- main() {
434
- local command="${1:-status}"
435
- shift || true
436
-
437
- # Parse global options
438
- while [[ $# -gt 0 ]]; do
439
- case "$1" in
440
- -f | --force)
441
- FORCE=1
442
- shift
443
- ;;
444
- -n | --dry-run)
445
- DRY_RUN=1
446
- shift
447
- ;;
448
- -v | --verbose)
449
- VERBOSE=1
450
- shift
451
- ;;
452
- -h | --help)
453
- usage
454
- exit 0
455
- ;;
456
- *) break ;;
457
- esac
458
- done
459
-
460
- ensure_dirs
461
-
462
- case "$command" in
463
- status)
464
- show_status
465
- ;;
466
- backup)
467
- create_backup "manual"
468
- ;;
469
- rollback)
470
- local latest
471
- latest=$(get_latest_backup)
472
- if [[ -z "$latest" ]]; then
473
- log_error "No backups available for rollback"
474
- exit 1
475
- fi
476
- if [[ "$FORCE" != "1" ]] && [[ "$DRY_RUN" != "1" ]]; then
477
- read -rp "Rollback to $(basename "$latest")? [y/N] " response
478
- [[ ! "$response" =~ ^[Yy]$ ]] && exit 0
479
- fi
480
- perform_rollback "$latest" "$DRY_RUN"
481
- ;;
482
- rollback-to)
483
- local index="${1:-}"
484
- if [[ -z "$index" ]] || ! [[ "$index" =~ ^[0-9]+$ ]]; then
485
- log_error "Please specify a backup number (see 'status' command)"
486
- exit 1
487
- fi
488
- local backup
489
- backup=$(get_backup_by_index "$index")
490
- if [[ -z "$backup" ]]; then
491
- log_error "Backup #$index not found"
492
- exit 1
493
- fi
494
- if [[ "$FORCE" != "1" ]] && [[ "$DRY_RUN" != "1" ]]; then
495
- read -rp "Rollback to $(basename "$backup")? [y/N] " response
496
- [[ ! "$response" =~ ^[Yy]$ ]] && exit 0
497
- fi
498
- perform_rollback "$backup" "$DRY_RUN"
499
- ;;
500
- git-reset)
501
- if [[ "$FORCE" != "1" ]] && [[ "$DRY_RUN" != "1" ]]; then
502
- read -rp "Reset to last known good commit? [y/N] " response
503
- [[ ! "$response" =~ ^[Yy]$ ]] && exit 0
504
- fi
505
- git_reset "$DRY_RUN"
506
- ;;
507
- restore)
508
- local file="${1:-}"
509
- if [[ -z "$file" ]]; then
510
- log_error "Please specify a file to restore"
511
- exit 1
512
- fi
513
- restore_file "$file" "$DRY_RUN"
514
- ;;
515
- clean)
516
- log_info "Cleaning old backups (keeping last $MAX_BACKUPS)..."
517
- cleanup_old_backups
518
- log_success "Cleanup complete"
519
- ;;
520
- -h | --help | help)
521
- usage
522
- ;;
523
- *)
524
- log_error "Unknown command: $command"
525
- usage
526
- exit 1
527
- ;;
528
- esac
529
- }
530
-
531
- main "$@"
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Script: teleport.sh
3
- # Description: Deploys dotfiles to a remote host ephemerally.
4
- # Usage: ./teleport.sh user@hostname
5
-
6
- set -e
7
-
8
- TARGET="$1"
9
-
10
- if [[ -z "$TARGET" ]]; then
11
- echo "Usage: $0 user@host"
12
- exit 1
13
- fi
14
-
15
- # Validate SSH target: must be user@host format, no shell metacharacters
16
- if [[ ! "$TARGET" =~ ^[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+$ ]]; then
17
- echo "Invalid SSH target: $TARGET" >&2
18
- echo "Expected format: user@hostname (alphanumeric, dots, hyphens, underscores only)" >&2
19
- exit 1
20
- fi
21
-
22
- echo " Teleporting dotfiles to ${TARGET}..."
23
-
24
- # 1. Archive the current state
25
- # 2. Pipe to SSH
26
- # 3. Extract in remote home directory with safety flags
27
- # --no-same-owner: don't try to preserve owner (non-root)
28
- # --strip-components=0: don't strip path components
29
- chezmoi archive | ssh "$TARGET" 'tar xz -C "$HOME" --no-same-owner'
30
-
31
- echo " Teleport successful!"
32
- echo " Note: Changes are applied to files, but shell may need restart or sourcing."
@@ -1,69 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- SECRETS_DIR="$HOME/.config/chezmoi"
5
- KEY_FILE="$SECRETS_DIR/key.txt"
6
- CONFIG_FILE="$SECRETS_DIR/chezmoi.toml"
7
-
8
- mkdir -p "$SECRETS_DIR"
9
-
10
- if ! command -v age-keygen >/dev/null; then
11
- echo "age-keygen not found. Install 'age' first." >&2
12
- exit 1
13
- fi
14
-
15
- if [[ ! -f "$KEY_FILE" ]]; then
16
- age-keygen -o "$KEY_FILE"
17
- chmod 600 "$KEY_FILE"
18
- echo "Age key created at $KEY_FILE"
19
- else
20
- echo "Age key already exists: $KEY_FILE"
21
- fi
22
-
23
- recipient=$(age-keygen -y "$KEY_FILE")
24
-
25
- python3 - "$CONFIG_FILE" "$KEY_FILE" "$recipient" <<'PY'
26
- import sys
27
- import json
28
- from pathlib import Path
29
-
30
- config_path = Path(sys.argv[1])
31
- key_file = sys.argv[2]
32
- recipient = sys.argv[3]
33
-
34
- content = ""
35
- if config_path.exists():
36
- content = config_path.read_text(encoding="utf-8")
37
-
38
- lines = content.splitlines()
39
-
40
- # Remove existing encryption/age block
41
- out = []
42
- in_age = False
43
- for line in lines:
44
- if line.strip().startswith("[age]"):
45
- in_age = True
46
- continue
47
- if in_age:
48
- if line.strip().startswith("["):
49
- in_age = False
50
- out.append(line)
51
- else:
52
- continue
53
- else:
54
- if line.strip().startswith("encryption ="):
55
- continue
56
- out.append(line)
57
-
58
- # Append updated config (use json.dumps for safe string escaping)
59
- out.append("")
60
- out.append("encryption = \"age\"")
61
- out.append("")
62
- out.append("[age]")
63
- out.append(f"identity = {json.dumps(key_file)}")
64
- out.append(f"recipient = {json.dumps(recipient)}")
65
-
66
- config_path.write_text("\n".join(out).rstrip() + "\n", encoding="utf-8")
67
- PY
68
-
69
- echo "Updated $CONFIG_FILE with age encryption settings."
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- OUT_FILE="${1:-$HOME/.config/chezmoi/encrypted_secrets.env.age}"
5
- KEYRING_DIR="$HOME/.config/chezmoi"
6
- AGE_KEY="$KEYRING_DIR/key.txt"
7
-
8
- if [ ! -f "$AGE_KEY" ]; then
9
- echo "Age identity not found: $AGE_KEY"
10
- echo "Run: dot secrets-init"
11
- exit 1
12
- fi
13
-
14
- if ! command -v age >/dev/null; then
15
- echo "age not found. Install it first."
16
- exit 1
17
- fi
18
-
19
- if [ -f "$OUT_FILE" ]; then
20
- echo "Secrets file already exists: $OUT_FILE"
21
- exit 0
22
- fi
23
-
24
- recipient="$(age-keygen -y "$AGE_KEY")"
25
- mkdir -p "$(dirname "$OUT_FILE")"
26
-
27
- tmp_secrets="$(umask 077 && mktemp)" || exit 1
28
- tmp_recipient="$(umask 077 && mktemp)" || exit 1
29
- trap 'rm -f "$tmp_secrets" "$tmp_recipient"' EXIT
30
-
31
- printf "%s\n" "# Add secrets as KEY=VALUE" "EXAMPLE_TOKEN=change_me" >"$tmp_secrets"
32
- printf "%s" "$recipient" >"$tmp_recipient"
33
-
34
- age -R "$tmp_recipient" -o "$OUT_FILE" "$tmp_secrets"
35
-
36
- chmod 600 "$OUT_FILE"
37
-
38
- cat <<MSG
39
- Created encrypted secrets file:
40
- $OUT_FILE
41
-
42
- Edit it with:
43
- dot secrets
44
- MSG