@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.
- package/docs/ARCHITECTURE.md +29 -196
- package/docs/COMPLIANCE.md +10 -10
- package/docs/COPYRIGHT +3 -4
- package/docs/OPERATIONS.md +38 -65
- package/docs/PLAN.md +3 -3
- package/docs/PR_DESCRIPTION.md +85 -84
- package/docs/ROADMAP.md +11 -11
- package/docs/ROADMAP_legacy.md +556 -0
- package/docs/SECURITY_CHECKLIST.md +1 -1
- package/docs/TASK.md +4 -4
- package/docs/WALKTHROUGH.md +33 -152
- package/package.json +17 -5
- package/scripts/backup.sh +142 -0
- package/scripts/banner.sh +20 -0
- package/scripts/benchmark.sh +20 -0
- package/scripts/build.sh +41 -0
- package/scripts/clean.sh +31 -0
- package/scripts/compile.sh +54 -0
- package/scripts/copy.sh +108 -0
- package/scripts/{tools/detect-collisions.py → detect-collisions.py} +1 -1
- package/scripts/doctor.sh +79 -0
- package/scripts/dotfiles.sh +63 -0
- package/scripts/download.sh +35 -0
- package/scripts/help.sh +57 -0
- package/scripts/lock-configs.sh +57 -0
- package/scripts/package.sh +46 -0
- package/scripts/ssh.sh +55 -0
- package/scripts/teleport.sh +23 -0
- package/scripts/{tests/test-aliases.sh → test-aliases.sh} +3 -3
- package/scripts/test_smoke.sh +88 -0
- package/scripts/unpack.sh +28 -0
- package/scripts/{diagnostics/verify_state.sh → verify_state.sh} +21 -21
- package/templates/projects/go/README.md +0 -4
- package/templates/projects/node/README.md +0 -4
- package/templates/projects/python/README.md +0 -4
- package/templates/projects/python/pyproject.toml +0 -15
- package/CHANGELOG.md +0 -285
- package/LICENSE +0 -1283
- package/README.md +0 -315
- package/docs/ALIASES.md +0 -128
- package/docs/FEATURES.md +0 -166
- package/docs/FONTS.md +0 -147
- package/docs/INSTALL.md +0 -119
- package/docs/KEYS.md +0 -40
- package/docs/KEY_ROTATION.md +0 -219
- package/docs/LEGACY_ROADMAP.md +0 -142
- package/docs/NEOVIM_IDE_GUIDE.md +0 -52
- package/docs/README.md +0 -269
- package/docs/REPO_AUDIT.md +0 -23
- package/docs/SCREENSHOTS.md +0 -116
- package/docs/SECRETS.md +0 -76
- package/docs/SECURITY.md +0 -30
- package/docs/TESTING.md +0 -190
- package/docs/TOOLS.md +0 -146
- package/docs/TROUBLESHOOTING.md +0 -112
- package/docs/UTILS.md +0 -105
- package/docs/WSL2_NIX_TROUBLESHOOTING.md +0 -723
- package/docs/adr/ADR-001-ci-cd-pipeline.md +0 -101
- package/docs/adr/ADR-002-shell-performance.md +0 -121
- package/docs/adr/ADR-003-security-first.md +0 -140
- package/docs/adr/ADR-004-cli-architecture.md +0 -157
- package/docs/adr/ADR-005-chezmoi-choice.md +0 -89
- package/docs/adr/ADR-006-shell-selection.md +0 -115
- package/docs/adr/README.md +0 -33
- package/docs/themes/README.md +0 -20
- package/dot_config/aider/aider.conf.yml +0 -32
- package/dot_config/alacritty/alacritty.toml.tmpl +0 -483
- package/dot_config/ansible/ansible.cfg.tmpl +0 -11
- package/dot_config/atuin/config.toml +0 -23
- package/dot_config/bat/config +0 -8
- package/dot_config/brave-flags.conf.tmpl +0 -7
- package/dot_config/btop/btop.conf +0 -16
- package/dot_config/btop/themes/tokyonight.theme +0 -34
- package/dot_config/bun/bunfig.toml.tmpl +0 -33
- package/dot_config/claude/mcp_servers.json +0 -49
- package/dot_config/clippy.toml +0 -55
- package/dot_config/containers/containers.conf +0 -14
- package/dot_config/curl/dot_curlrc +0 -18
- package/dot_config/dlv/config.yml +0 -39
- package/dot_config/docker/config.json.tmpl +0 -15
- package/dot_config/dotfiles/boot/README.md +0 -11
- package/dot_config/dotfiles/grub/README.md +0 -11
- package/dot_config/dotfiles/lock/README.md +0 -11
- package/dot_config/dotfiles/versions.env.tmpl +0 -19
- package/dot_config/duf/duf.conf +0 -6
- package/dot_config/duti/defaults.duti +0 -5
- package/dot_config/emoji/emoji.txt +0 -34
- package/dot_config/fastfetch/config.jsonc +0 -28
- package/dot_config/firefox/user.js +0 -8
- package/dot_config/flatpak/flatpak.list +0 -4
- package/dot_config/fontconfig/fonts.conf.tmpl +0 -44
- package/dot_config/gem/gemrc +0 -9
- package/dot_config/gh/config.yml +0 -12
- package/dot_config/ghostty/config.tmpl +0 -661
- package/dot_config/git/attributes +0 -12
- package/dot_config/git/config.tmpl +0 -77
- package/dot_config/git/ignore +0 -27
- package/dot_config/gnupg/gpg-agent.conf.tmpl +0 -11
- package/dot_config/go/aliases.sh +0 -61
- package/dot_config/go/env.sh +0 -24
- package/dot_config/go/golangci.yml +0 -118
- package/dot_config/go/gopls.json +0 -30
- package/dot_config/goose/config.yaml +0 -29
- package/dot_config/gtk-3.0/gtk.css.tmpl +0 -305
- package/dot_config/gtk-3.0/settings.ini.tmpl +0 -66
- package/dot_config/gtk-4.0/gtk.css.tmpl +0 -309
- package/dot_config/gtk-4.0/settings.ini.tmpl +0 -21
- package/dot_config/htop/htoprc +0 -20
- package/dot_config/ice/README.md +0 -13
- package/dot_config/inputrc +0 -2
- package/dot_config/ipython/profile_default/ipython_config.py.tmpl +0 -5
- package/dot_config/just/justfile +0 -104
- package/dot_config/k9s/config.yaml.tmpl +0 -65
- package/dot_config/k9s/skins/catppuccin-mocha.yaml +0 -116
- package/dot_config/karabiner/karabiner.json +0 -14
- package/dot_config/kitty/kitty.conf.tmpl +0 -517
- package/dot_config/lazydocker/config.yml +0 -186
- package/dot_config/lazygit/config.yml +0 -23
- package/dot_config/lsd/config.yaml +0 -19
- package/dot_config/mas/masapps.txt +0 -5
- package/dot_config/minikube/config.json +0 -13
- package/dot_config/mise/config.toml +0 -41
- package/dot_config/mongosh/mongoshrc.js +0 -67
- package/dot_config/mycli/myclirc +0 -67
- package/dot_config/nano/nanorc +0 -28
- package/dot_config/ncdu/config +0 -12
- package/dot_config/nvim/init.lua +0 -4
- package/dot_config/nvim/lazy-lock.json +0 -27
- package/dot_config/nvim/lua/config/autocmds.lua +0 -63
- package/dot_config/nvim/lua/config/keymaps.lua +0 -87
- package/dot_config/nvim/lua/config/lazy.lua +0 -34
- package/dot_config/nvim/lua/config/options.lua +0 -48
- package/dot_config/nvim/lua/plugins/coding.lua +0 -234
- package/dot_config/nvim/lua/plugins/dap.lua +0 -201
- package/dot_config/nvim/lua/plugins/editor.lua +0 -59
- package/dot_config/nvim/lua/plugins/git.lua +0 -9
- package/dot_config/nvim/lua/plugins/lsp.lua +0 -221
- package/dot_config/nvim/lua/plugins/markdown.lua +0 -17
- package/dot_config/nvim/lua/plugins/rust.lua +0 -33
- package/dot_config/nvim/lua/plugins/sessions.lua +0 -32
- package/dot_config/nvim/lua/plugins/ui.lua +0 -537
- package/dot_config/nvim/snippets/all.lua +0 -9
- package/dot_config/nvim/snippets/python.lua +0 -16
- package/dot_config/pip/pip.conf.tmpl +0 -32
- package/dot_config/pypoetry/config.toml.tmpl +0 -6
- package/dot_config/pyrightconfig.json.tmpl +0 -5
- package/dot_config/raycast/README.md +0 -13
- package/dot_config/redis/redisclirc +0 -41
- package/dot_config/shell/00-container-detect.sh +0 -53
- package/dot_config/shell/00-core-paths.sh.tmpl +0 -95
- package/dot_config/shell/05-core-safety.sh.tmpl +0 -13
- package/dot_config/shell/40-ls-colors.sh.tmpl +0 -31
- package/dot_config/shell/50-logic-functions.sh.tmpl +0 -10
- package/dot_config/shell/90-theme-switch.sh +0 -70
- package/dot_config/shell/90-ux-aliases.sh.tmpl +0 -35
- package/dot_config/shell/91-ux-aliases-lazy.sh.tmpl +0 -23
- package/dot_config/shell/Brewfile +0 -207
- package/dot_config/shell/Brewfile.cask +0 -92
- package/dot_config/shell/Brewfile.cli +0 -119
- package/dot_config/shell/README.md +0 -267
- package/dot_config/shell/custom/context_suggest.zsh +0 -68
- package/dot_config/shell/custom/error_analysis.zsh +0 -45
- package/dot_config/sops/dot_sops.yaml +0 -23
- package/dot_config/starship.toml.tmpl +0 -124
- package/dot_config/task/Taskfile.yml +0 -86
- package/dot_config/tflint/tflint.hcl.tmpl +0 -9
- package/dot_config/tmux/tmux.conf.tmpl +0 -181
- package/dot_config/topgrade/topgrade.toml.tmpl +0 -42
- package/dot_config/vscode/extensions.txt +0 -11
- package/dot_config/vscode/settings.json.tmpl +0 -123
- package/dot_config/waybar/style.css +0 -8
- package/dot_config/wezterm/wezterm.lua.tmpl +0 -236
- package/dot_config/wget/wgetrc +0 -12
- package/dot_config/yarn/yarnrc.yml.tmpl +0 -36
- package/dot_config/yazi/yazi.toml +0 -40
- package/dot_config/zellij/config.kdl +0 -79
- package/dot_config/zsh/dot_zprofile +0 -13
- package/dot_config/zsh/dot_zshenv +0 -6
- package/dot_config/zsh/dot_zshrc.tmpl +0 -199
- package/dot_config/zsh/rc.d/05-ssh-agent.zsh +0 -5
- package/dot_config/zsh/rc.d/10-env.zsh.tmpl +0 -28
- package/dot_config/zsh/rc.d/20-zinit.zsh.tmpl +0 -22
- package/dot_config/zsh/rc.d/30-options.zsh.tmpl +0 -123
- package/dot_config/zsh/rc.d/40-bell.zsh.tmpl +0 -20
- package/dot_config/zsh/rc.d/50-login-fortune.zsh.tmpl +0 -9
- package/dot_local/bin/executable_ai_core +0 -130
- package/dot_local/bin/executable_b64 +0 -59
- package/dot_local/bin/executable_dot +0 -178
- package/dot_local/bin/executable_dot_completion +0 -55
- package/dot_local/bin/executable_epoch +0 -62
- package/dot_local/bin/executable_extract +0 -108
- package/dot_local/bin/executable_git-ai-commit +0 -160
- package/dot_local/bin/executable_git-ai-diff +0 -154
- package/dot_local/bin/executable_hash +0 -123
- package/dot_local/bin/executable_hex +0 -79
- package/dot_local/bin/executable_ip +0 -37
- package/dot_local/bin/executable_jsonv +0 -54
- package/dot_local/bin/executable_jwt +0 -78
- package/dot_local/bin/executable_kill-port +0 -59
- package/dot_local/bin/executable_lorem +0 -103
- package/dot_local/bin/executable_regex +0 -96
- package/dot_local/bin/executable_tmux-sessionizer +0 -187
- package/dot_local/bin/executable_tour +0 -137
- package/dot_local/bin/executable_update +0 -108
- package/dot_local/bin/executable_uuid +0 -57
- package/dot_local/bin/executable_yamlv +0 -39
- package/dot_local/bin/executable_zig-install +0 -89
- package/dot_local/bin/voice_ops +0 -7
- package/dot_local/share/bash-completion/completions/dot +0 -54
- package/dot_local/share/zsh/completions/.keep +0 -0
- package/install.sh +0 -255
- package/scripts/ci/validate-ci-config.sh +0 -222
- package/scripts/demo/record.sh +0 -41
- package/scripts/diagnostics/benchmark.sh +0 -201
- package/scripts/diagnostics/doctor.sh +0 -115
- package/scripts/diagnostics/drift-dashboard.sh +0 -26
- package/scripts/diagnostics/health.sh +0 -356
- package/scripts/diagnostics/history-analysis.sh +0 -77
- package/scripts/diagnostics/security-score.sh +0 -392
- package/scripts/dot/commands/appearance.sh +0 -63
- package/scripts/dot/commands/core.sh +0 -130
- package/scripts/dot/commands/diagnostics.sh +0 -100
- package/scripts/dot/commands/meta.sh +0 -117
- package/scripts/dot/commands/restore.sh +0 -209
- package/scripts/dot/commands/secrets.sh +0 -81
- package/scripts/dot/commands/security.sh +0 -73
- package/scripts/dot/commands/tools.sh +0 -228
- package/scripts/dot/lib/utils.sh +0 -72
- package/scripts/fonts/install-nerd-fonts.sh +0 -59
- package/scripts/fonts/patch-fonts.sh +0 -34
- package/scripts/ops/chezmoi-apply.sh +0 -42
- package/scripts/ops/chezmoi-diff.sh +0 -14
- package/scripts/ops/chezmoi-remove.sh +0 -43
- package/scripts/ops/chezmoi-update.sh +0 -16
- package/scripts/ops/heal.sh +0 -466
- package/scripts/ops/health-check.sh +0 -380
- package/scripts/ops/rollback.sh +0 -531
- package/scripts/ops/teleport.sh +0 -32
- package/scripts/secrets/age-init.sh +0 -69
- package/scripts/secrets/create-secrets-file.sh +0 -44
- package/scripts/secrets/encrypt-ssh-key.sh +0 -42
- package/scripts/security/backup.sh +0 -17
- package/scripts/security/dns-doh.sh +0 -29
- package/scripts/security/encryption-check.sh +0 -39
- package/scripts/security/enforce-policies.sh +0 -339
- package/scripts/security/firewall.sh +0 -34
- package/scripts/security/lock-configs.sh +0 -57
- package/scripts/security/lock-screen.sh +0 -33
- package/scripts/security/manage-secrets.sh +0 -415
- package/scripts/security/telemetry-kill.sh +0 -28
- package/scripts/security/usb-safety.sh +0 -29
- package/scripts/tests/README.md +0 -241
- package/scripts/tests/benchmark.sh +0 -91
- package/scripts/tests/framework/assertions.sh +0 -283
- package/scripts/tests/framework/mocks.sh +0 -201
- package/scripts/tests/framework/test_runner.sh +0 -189
- package/scripts/tests/integration/test_install.sh +0 -237
- package/scripts/tests/performance/benchmark_runner.sh +0 -156
- package/scripts/tests/performance/regression_check.sh +0 -73
- package/scripts/tests/performance/stress_test.sh +0 -65
- package/scripts/tests/test-docker.sh +0 -48
- package/scripts/tests/unit/test_ai_aliases.sh +0 -158
- package/scripts/tests/unit/test_ai_cli_checks.sh +0 -47
- package/scripts/tests/unit/test_backup.sh +0 -227
- package/scripts/tests/unit/test_case_functions.sh +0 -238
- package/scripts/tests/unit/test_cd_aliases.sh +0 -367
- package/scripts/tests/unit/test_dot_cli.sh +0 -217
- package/scripts/tests/unit/test_encode64.sh +0 -67
- package/scripts/tests/unit/test_environment.sh +0 -78
- package/scripts/tests/unit/test_extract.sh +0 -163
- package/scripts/tests/unit/test_framework_edge_cases.sh +0 -113
- package/scripts/tests/unit/test_genpass.sh +0 -298
- package/scripts/tests/unit/test_install_edge_cases.sh +0 -167
- package/scripts/tests/unit/test_installers.sh +0 -172
- package/scripts/tests/unit/test_keygen.sh +0 -68
- package/scripts/tests/unit/test_logging.sh +0 -96
- package/scripts/tests/unit/test_os_detection_comprehensive.sh +0 -388
- package/scripts/tests/unit/test_package_managers_comprehensive.sh +0 -321
- package/scripts/tests/unit/test_prependpath.sh +0 -66
- package/scripts/tests/unit/test_prependpath_refactored.sh +0 -89
- package/scripts/tests/unit/test_rd.sh +0 -230
- package/scripts/tests/unit/test_security_fixes.sh +0 -130
- package/scripts/tests/unit/test_security_scripts.sh +0 -87
- package/scripts/tests/unit/test_template_validation.sh +0 -238
- package/scripts/tests/unit/test_utility_functions.sh +0 -144
- package/scripts/tests/unit/test_wave1_alias_split.sh +0 -132
- package/scripts/tests/unit/test_wave1_ci_pinning.sh +0 -61
- package/scripts/tests/unit/test_wave1_gitleaks_config.sh +0 -52
- package/scripts/tests/unit/test_wave1_heal_fixes.sh +0 -97
- package/scripts/tests/unit/test_wave1_install_gpg.sh +0 -35
- package/scripts/tests/unit/test_wave1_zshenv_path.sh +0 -89
- package/scripts/tests/unit/test_wave1_zshrc_lazy_hook.sh +0 -115
- package/scripts/tests/unit/test_wave2_dot_new_guard.sh +0 -75
- package/scripts/tests/unit/test_zipf.sh +0 -76
- package/scripts/theme/apply-gnome-theme.sh +0 -297
- package/scripts/theme/install-boot-logo.sh +0 -61
- package/scripts/theme/install-catppuccin-themes.sh +0 -346
- package/scripts/theme/install-cursors.sh +0 -24
- package/scripts/theme/install-file-icons.sh +0 -25
- package/scripts/theme/install-grub-theme.sh +0 -51
- package/scripts/theme/install-lock-icon.sh +0 -29
- package/scripts/theme/switch.sh +0 -250
- package/scripts/theme/wallpaper-rotate.sh +0 -82
- package/scripts/theme/wallpaper-sync.sh +0 -42
- package/scripts/tools/cmatrix.sh +0 -20
- package/scripts/tools/emoji-picker.sh +0 -45
- package/scripts/tools/figlet-banner.sh +0 -17
- package/scripts/tools/log-rotate.sh +0 -29
- package/scripts/tools/lolcat-wrap.sh +0 -18
- package/scripts/tools/pipes.sh +0 -47
- package/scripts/tuning/linux.sh +0 -175
- package/scripts/tuning/macos.sh +0 -46
- package/templates/projects/molecule/README.md +0 -7
- package/templates/projects/molecule/converge.yml +0 -7
- package/templates/projects/molecule/molecule.yml +0 -16
- package/templates/projects/packer/README.md +0 -15
- package/templates/projects/packer/main.pkr.hcl +0 -15
package/scripts/ops/rollback.sh
DELETED
|
@@ -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 "$@"
|
package/scripts/ops/teleport.sh
DELETED
|
@@ -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
|