@sebastienrousseau/dotfiles 0.2.500 → 0.2.502
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/CHANGELOG.md +154 -0
- package/README.md +113 -45
- package/docs/.vitepress/reports/localization-readability-audit.md +4 -0
- package/docs/AI.md +8 -2
- package/docs/CNAME +1 -0
- package/docs/COPYRIGHT +1 -1
- package/docs/NAMING_CONVENTIONS.md +7 -0
- package/docs/README.md +4 -0
- package/docs/_config.yml +59 -0
- package/docs/adr/ADR-001-ci-cd-pipeline.md +17 -0
- package/docs/adr/ADR-002-shell-performance.md +9 -0
- package/docs/adr/ADR-003-security-first.md +18 -0
- package/docs/adr/ADR-004-cli-architecture.md +14 -0
- package/docs/adr/ADR-005-chezmoi-choice.md +10 -0
- package/docs/adr/ADR-006-shell-selection.md +9 -0
- package/docs/adr/ADR-007-multi-shell-parity.md +10 -1
- package/docs/adr/ADR-008-alias-system-architecture.md +10 -0
- package/docs/adr/ADR-009-wallpaper-driven-theming.md +131 -0
- package/docs/adr/ADR-010-starship-transient-prompt.md +144 -0
- package/docs/adr/ADR-011-nushell-tier3-keep.md +144 -0
- package/docs/adr/README.md +7 -0
- package/docs/architecture/ARCHITECTURE.md +4 -0
- package/docs/architecture/INTEROP.md +8 -0
- package/docs/architecture/REPO_LAYOUT.md +5 -1
- package/docs/architecture/WALKTHROUGH.md +4 -0
- package/docs/architecture/fleet-deployment.md +4 -0
- package/docs/archive/EUXIS_2026_REVIEW.md +11 -3
- package/docs/archive/LEGACY_ROADMAP.md +45 -27
- package/docs/archive/MILESTONE_v0.2.493.md +4 -0
- package/docs/archive/PLAN.md +46 -8
- package/docs/archive/REPO_AUDIT.md +8 -0
- package/docs/guides/INSTALL.md +4 -0
- package/docs/guides/NEOVIM_IDE_GUIDE.md +9 -0
- package/docs/guides/THEMING.md +8 -0
- package/docs/guides/TROUBLESHOOTING.md +28 -0
- package/docs/guides/WSL2_NIX_TROUBLESHOOTING.md +70 -1
- package/docs/index.md +6 -2
- package/docs/interop/A2A.md +7 -0
- package/docs/interop/POWERSHELL.md +102 -0
- package/docs/manual/00-introduction.md +5 -1
- package/docs/manual/01-concepts/01-architecture.md +4 -0
- package/docs/manual/01-concepts/02-trust-model.md +6 -2
- package/docs/manual/01-concepts/03-theme-engine.md +4 -0
- package/docs/manual/01-concepts/04-fleet.md +7 -1
- package/docs/manual/01-concepts/05-self-healing.md +8 -1
- package/docs/manual/02-tutorials/01-first-install.md +5 -0
- package/docs/manual/02-tutorials/02-add-wallpaper.md +5 -0
- package/docs/manual/02-tutorials/03-create-profile.md +6 -0
- package/docs/manual/02-tutorials/04-encrypt-secret.md +6 -0
- package/docs/manual/02-tutorials/05-deploy-fleet.md +5 -1
- package/docs/manual/03-reference/01-dot-cli.md +67 -45
- package/docs/manual/03-reference/02-config-files.md +8 -2
- package/docs/manual/03-reference/03-environment.md +4 -0
- package/docs/manual/03-reference/04-templates.md +7 -1
- package/docs/manual/03-reference/05-feature-flags.md +72 -3
- package/docs/manual/04-cookbook/01-recipes.md +4 -0
- package/docs/manual/04-cookbook/02-troubleshooting.md +32 -0
- package/docs/manual/04-cookbook/03-faq.md +8 -0
- package/docs/manual/05-appendices/A-platform-matrix.md +4 -0
- package/docs/manual/05-appendices/B-security-checklist.md +6 -0
- package/docs/manual/05-appendices/C-glossary.md +4 -0
- package/docs/manual/05-appendices/D-bibliography.md +5 -1
- package/docs/manual/05-appendices/E-license.md +4 -0
- package/docs/manual/_toc.yml +1 -1
- package/docs/manual/command-index.md +16 -8
- package/docs/manual/concept-index.md +4 -0
- package/docs/manual/index.md +66 -0
- package/docs/operations/ATTESTATION.md +5 -0
- package/docs/operations/CI_CADENCE.md +107 -0
- package/docs/operations/CI_COMPOSITES.md +156 -0
- package/docs/operations/COMPLETIONS.md +123 -0
- package/docs/operations/COVERAGE.md +182 -0
- package/docs/operations/DRIFT.md +107 -0
- package/docs/operations/HARD_AUDIT_2026.md +631 -0
- package/docs/operations/MAINTENANCE.md +5 -1
- package/docs/operations/MIGRATION.md +14 -6
- package/docs/operations/OPERATIONS.md +24 -0
- package/docs/operations/PERFORMANCE.md +133 -0
- package/docs/operations/REGISTRY.md +89 -0
- package/docs/operations/RELIABILITY.md +6 -0
- package/docs/operations/ROADMAP.md +36 -18
- package/docs/operations/ROADMAP_2026.md +665 -0
- package/docs/operations/TESTING.md +4 -0
- package/docs/operations/TRACEABILITY.md +7 -0
- package/docs/operations/TRUSTED_AGENT_WORKSTATION.md +4 -0
- package/docs/operations/VERSION_SYNC.md +54 -5
- package/docs/reference/ALIASES.md +7 -0
- package/docs/reference/ALIASES_CHEATSHEET.md +5 -1
- package/docs/reference/ALIASES_DEPRECATIONS.md +5 -1
- package/docs/reference/FEATURES.md +4 -0
- package/docs/reference/FONTS.md +4 -0
- package/docs/reference/POWERSHELL_PARITY.md +80 -0
- package/docs/reference/PROFILES.md +4 -0
- package/docs/reference/SCREENSHOTS.md +4 -0
- package/docs/reference/SCRIPTS.md +4 -0
- package/docs/reference/SUPPORT_MATRIX.md +10 -4
- package/docs/reference/THEMES.md +4 -0
- package/docs/reference/TOOLS.md +4 -0
- package/docs/reference/UTILS.md +16 -12
- package/docs/registry.json +6 -0
- package/docs/security/AI_ACT_COMPLIANCE.md +4 -0
- package/docs/security/AUDIT_BYPASS.md +103 -0
- package/docs/security/AUTOMATION_SECRETS.md +4 -0
- package/docs/security/CI_EGRESS_ALLOWLIST.md +127 -0
- package/docs/security/CI_PINNING.md +113 -0
- package/docs/security/COMMIT_SIGNING.md +138 -0
- package/docs/security/COMPLIANCE.md +5 -0
- package/docs/security/DEPS_DEV_EXCEPTIONS.md +86 -0
- package/docs/security/DISCLOSURE.md +130 -0
- package/docs/security/ENCRYPTION.md +5 -0
- package/docs/security/FMEA.md +4 -0
- package/docs/security/HISTORY_FILTERING.md +132 -0
- package/docs/security/INCIDENT_RESPONSE.md +4 -0
- package/docs/security/INSTALL_VERIFICATION.md +122 -0
- package/docs/security/KEYS.md +4 -0
- package/docs/security/KEY_ROTATION.md +85 -1
- package/docs/security/MCP_POLICY.md +9 -0
- package/docs/security/POLICY_RELEASES.md +4 -0
- package/docs/security/README.md +4 -0
- package/docs/security/SCORECARD.md +140 -0
- package/docs/security/SECRETS.md +12 -0
- package/docs/security/SECURITY.md +4 -0
- package/docs/security/SECURITY_CHECKLIST.md +11 -0
- package/docs/security/SHELL_EXEMPTIONS.md +145 -0
- package/docs/security/SOUP_REGISTER.md +4 -0
- package/docs/security/THREAT_MODEL.md +10 -0
- package/docs/security/VERIFICATION_VALIDATION.md +5 -1
- package/docs/security/security-pubkey.asc +15 -0
- package/docs/themes/README.md +4 -0
- package/docs/themes/VISUAL_INTEGRITY_REPORT.md +4 -0
- package/dot_config/ai/identity.md +3 -0
- package/dot_config/ai/patterns/architect.md +2 -0
- package/dot_config/ai/patterns/hardener.md +2 -0
- package/dot_config/ai/patterns/refactor.md +2 -0
- package/dot_config/alacritty/alacritty.toml.tmpl +3 -3
- package/dot_config/atuin/config.toml.tmpl +47 -0
- package/dot_config/dotfiles/agent-card.json +1 -1
- package/dot_config/dotfiles/boot/README.md +2 -0
- package/dot_config/dotfiles/grub/README.md +2 -0
- package/dot_config/dotfiles/lock/README.md +2 -0
- package/dot_config/fish/conf.d/direnv.fish +4 -0
- package/dot_config/fish/conf.d/init.fish.tmpl +21 -0
- package/dot_config/fish/conf.d/mise-activate.fish +5 -0
- package/dot_config/fish/functions/_cached_eval.fish +84 -11
- package/dot_config/fish/functions/_cached_eval_clear.fish +17 -0
- package/dot_config/foot/foot.ini.tmpl +3 -3
- package/dot_config/fuzzel/fuzzel.ini.tmpl +2 -2
- package/dot_config/ghostty/config.tmpl +3 -3
- package/dot_config/git/hooks/executable_commit-msg +146 -0
- package/dot_config/goose/config.yaml +2 -2
- package/dot_config/gtk-3.0/gtk.css.tmpl +2 -2
- package/dot_config/gtk-3.0/settings.ini.tmpl +2 -2
- package/dot_config/gtk-4.0/gtk.css.tmpl +2 -2
- package/dot_config/gtk-4.0/settings.ini.tmpl +2 -2
- package/dot_config/kitty/kitty.conf.tmpl +3 -3
- package/dot_config/mise/config.toml +1 -1
- package/dot_config/niri/config.kdl.tmpl +2 -2
- package/dot_config/nushell/cached_eval.nu +80 -0
- package/dot_config/nushell/env.nu.tmpl +21 -13
- package/dot_config/shell/00-core-paths.sh.tmpl +9 -1
- package/dot_config/shell/05-core-safety.sh +1 -0
- package/dot_config/shell/10-secrets.sh +1 -0
- package/dot_config/shell/40-fzf-defaults.sh.tmpl +1 -0
- package/dot_config/shell/40-ls-colors.sh +1 -0
- package/dot_config/shell/50-logic-functions-core.sh.tmpl +1 -0
- package/dot_config/shell/50-logic-functions.sh.tmpl +1 -0
- package/dot_config/shell/51-logic-functions-extra.sh.tmpl +1 -0
- package/dot_config/shell/90-ux-aliases.sh.tmpl +1 -0
- package/dot_config/shell/91-ux-aliases-lazy.sh.tmpl +1 -0
- package/dot_config/shell/README.md +25 -8
- package/dot_config/starship.toml.tmpl +2 -2
- package/dot_config/tmux/tmux.conf.tmpl +3 -3
- package/dot_config/user-dirs.dirs +1 -0
- package/dot_config/vscode/settings.json.tmpl +2 -2
- package/dot_config/waybar/config.jsonc.tmpl +2 -2
- package/dot_config/waybar/style.css.tmpl +2 -2
- package/dot_config/wezterm/wezterm.lua.tmpl +3 -3
- package/dot_config/zsh/dot_zshrc.tmpl +207 -17
- package/dot_config/zsh/rc.d/00-alias-shims.zsh +28 -6
- package/dot_config/zsh/rc.d/30-options.zsh.tmpl +27 -7
- package/dot_local/bin/executable_bm +2 -0
- package/dot_local/bin/executable_dot +56 -9
- package/dot_local/bin/executable_dot-bootstrap +0 -1
- package/dot_local/bin/executable_dot-load-benchmark +1 -1
- package/dot_local/bin/executable_dot-theme-sync +8 -8
- package/dot_local/bin/executable_notify +2 -0
- package/dot_local/bin/executable_open +2 -0
- package/dot_local/bin/executable_tour +4 -2
- package/dot_local/bin/executable_up +3 -1
- package/dot_local/share/man/man1/dot.1 +1 -1
- package/dot_local/share/zsh/completions/_dot +4 -0
- package/install.sh +53 -38
- package/package.json +1 -1
- package/scripts/ci/check-dangerous-chmod.sh +19 -0
- package/scripts/ci/check-deps-dev.sh +236 -0
- package/scripts/ci/check-insecure-tls.sh +61 -0
- package/scripts/ci/check-regression-traceability.sh +67 -0
- package/scripts/ci/check-shell-preamble.sh +106 -0
- package/scripts/ci/dot-cli-startup-bench.sh +126 -0
- package/scripts/ci/install-chezmoi-verified.sh +4 -1
- package/scripts/ci/lint-reusable-pins.sh +78 -0
- package/scripts/ci/run-coverage.sh +451 -0
- package/scripts/ci/validate-chezmoidata.sh +25 -0
- package/scripts/ci/windows-smoke-test.ps1 +136 -0
- package/scripts/diagnostics/doctor.sh +203 -5
- package/scripts/diagnostics/drift-dashboard.sh +177 -13
- package/scripts/diagnostics/health.sh +21 -4
- package/scripts/diagnostics/perf.sh +304 -77
- package/scripts/diagnostics/workstation-attestation.sh +6 -1
- package/scripts/dot/commands/agent.sh +33 -27
- package/scripts/dot/commands/agents.sh +325 -0
- package/scripts/dot/commands/ai.sh +75 -10
- package/scripts/dot/commands/aliases.sh +10 -8
- package/scripts/dot/commands/core.sh +10 -4
- package/scripts/dot/commands/fleet.sh +278 -3
- package/scripts/dot/commands/init.sh +184 -0
- package/scripts/dot/commands/meta.sh +7 -4
- package/scripts/dot/commands/registry.sh +263 -0
- package/scripts/dot/commands/tools.sh +49 -1
- package/scripts/dot/lib/bento.sh +2 -1
- package/scripts/dot/lib/log.sh +6 -0
- package/scripts/dot/lib/platform.sh +22 -8
- package/scripts/dot/lib/ui.sh +145 -2
- package/scripts/dot/lib/utils.sh +6 -1
- package/scripts/git-hooks/pre-commit-audit.sh +1 -1
- package/scripts/git-hooks/pre-push +66 -3
- package/scripts/lib/secrets_provider.sh +32 -6
- package/scripts/ops/heal-chezmoi.sh +41 -6
- package/scripts/ops/rollback.sh +14 -0
- package/scripts/qa/powershell-contract.ps1 +95 -0
- package/scripts/security/check-disclosure-key-expiry.sh +110 -0
- package/scripts/security/lock-configs.sh +11 -2
- package/scripts/theme/merge-wallpaper.sh +4 -0
- package/scripts/theme/switch.sh +20 -10
- package/scripts/version-sync.sh +3 -0
- package/dot_config/atuin/config.toml +0 -40
- package/dot_local/bin/__pycache__/executable_dot-load-benchmark-ptycpython-312.pyc +0 -0
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# Copyright (c) 2015-2026 Dotfiles. All rights reserved.
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# pre-push hook
|
|
5
|
+
#
|
|
6
|
+
# 1. Refuses to push any commit that is not GPG/SSH-signed.
|
|
7
|
+
# 2. Runs `scripts/qa/reliability-audit.sh --quick`. The audit is mandatory
|
|
8
|
+
# by default; explicit per-push bypass requires `DOTFILES_ALLOW_UNSKIPPED_PUSH=1`,
|
|
9
|
+
# and every bypass is logged to `~/.local/share/dotfiles/audit-bypass.log`.
|
|
10
|
+
#
|
|
11
|
+
# The legacy `DOTFILES_SKIP_PRE_PUSH_AUDIT=1` env var (opt-out) is rejected
|
|
12
|
+
# with a migration message. The new variable is intentionally awkwardly
|
|
13
|
+
# named so that setting it requires deliberate intent. See
|
|
14
|
+
# `docs/security/AUDIT_BYPASS.md`.
|
|
15
|
+
# =============================================================================
|
|
16
|
+
|
|
2
17
|
set -euo pipefail
|
|
3
18
|
|
|
4
19
|
repo_root="$(git rev-parse --show-toplevel)"
|
|
5
20
|
|
|
21
|
+
# -----------------------------------------------------------------------------
|
|
22
|
+
# Step 1 — signed-commit enforcement (unchanged)
|
|
23
|
+
# -----------------------------------------------------------------------------
|
|
6
24
|
while read -r local_ref local_sha remote_ref remote_sha; do
|
|
7
25
|
[ "$local_sha" = "0000000000000000000000000000000000000000" ] && continue
|
|
8
26
|
|
|
@@ -18,12 +36,57 @@ while read -r local_ref local_sha remote_ref remote_sha; do
|
|
|
18
36
|
|
|
19
37
|
for c in $(git rev-list "$range"); do
|
|
20
38
|
if ! git verify-commit "$c" >/dev/null 2>&1; then
|
|
21
|
-
echo "Blocked: unsigned commit $c"
|
|
39
|
+
echo "Blocked: unsigned commit $c" >&2
|
|
22
40
|
exit 1
|
|
23
41
|
fi
|
|
24
42
|
done
|
|
25
43
|
done
|
|
26
44
|
|
|
27
|
-
|
|
28
|
-
|
|
45
|
+
# -----------------------------------------------------------------------------
|
|
46
|
+
# Step 2 — reject the legacy opt-out variable
|
|
47
|
+
# -----------------------------------------------------------------------------
|
|
48
|
+
if [ "${DOTFILES_SKIP_PRE_PUSH_AUDIT:-}" = "1" ]; then
|
|
49
|
+
cat >&2 <<'EOF'
|
|
50
|
+
ERROR: DOTFILES_SKIP_PRE_PUSH_AUDIT is no longer honored.
|
|
51
|
+
|
|
52
|
+
The pre-push audit was previously opt-out — setting one env var was enough
|
|
53
|
+
to skip it. That made bypass invisible and routine. Effective with #871,
|
|
54
|
+
the policy is fail-closed: the audit always runs unless you explicitly
|
|
55
|
+
authorize a bypass for this single push.
|
|
56
|
+
|
|
57
|
+
To bypass for one push:
|
|
58
|
+
DOTFILES_ALLOW_UNSKIPPED_PUSH=1 git push
|
|
59
|
+
|
|
60
|
+
Every bypass is recorded to ~/.local/share/dotfiles/audit-bypass.log
|
|
61
|
+
and surfaced by `dot doctor` if any are recent.
|
|
62
|
+
|
|
63
|
+
See: docs/security/AUDIT_BYPASS.md
|
|
64
|
+
EOF
|
|
65
|
+
exit 1
|
|
29
66
|
fi
|
|
67
|
+
|
|
68
|
+
# -----------------------------------------------------------------------------
|
|
69
|
+
# Step 3 — run the audit (or log + skip if explicitly bypassed)
|
|
70
|
+
# -----------------------------------------------------------------------------
|
|
71
|
+
if [ "${DOTFILES_ALLOW_UNSKIPPED_PUSH:-}" = "1" ]; then
|
|
72
|
+
bypass_log_dir="${XDG_STATE_HOME:-$HOME/.local/state}/dotfiles"
|
|
73
|
+
# The audit-bypass log lives under XDG_STATE_HOME (user state — never
|
|
74
|
+
# checked in, never deployed by chezmoi to other locations).
|
|
75
|
+
mkdir -p "$bypass_log_dir"
|
|
76
|
+
bypass_log="$bypass_log_dir/audit-bypass.log"
|
|
77
|
+
|
|
78
|
+
ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
79
|
+
branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)"
|
|
80
|
+
remote="$(git remote get-url --push @{upstream} 2>/dev/null ||
|
|
81
|
+
git config --get remote.origin.url 2>/dev/null ||
|
|
82
|
+
echo unknown)"
|
|
83
|
+
reason="${DOTFILES_BYPASS_REASON:-no reason given}"
|
|
84
|
+
|
|
85
|
+
printf '%s\tbranch=%s\tremote=%s\treason=%s\n' \
|
|
86
|
+
"$ts" "$branch" "$remote" "$reason" >>"$bypass_log"
|
|
87
|
+
|
|
88
|
+
echo "WARN: pre-push audit bypassed (logged to $bypass_log)" >&2
|
|
89
|
+
exit 0
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
bash "$repo_root/scripts/qa/reliability-audit.sh" --quick
|
|
@@ -126,15 +126,41 @@ dot_secrets_set() {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
dot_secrets_get() {
|
|
129
|
-
local key="${1:-}" provider
|
|
130
|
-
[[ -n "$key" ]] ||
|
|
129
|
+
local key="${1:-}" provider value rc=0
|
|
130
|
+
[[ -n "$key" ]] || {
|
|
131
|
+
printf 'dot_secrets_get: empty key\n' >&2
|
|
132
|
+
return 1
|
|
133
|
+
}
|
|
131
134
|
provider="$(dot_secrets_provider)"
|
|
132
135
|
case "$provider" in
|
|
133
|
-
macos-keychain) dot_secrets_get_macos "$key" ;;
|
|
134
|
-
pass) dot_secrets_get_pass "$key" ;;
|
|
135
|
-
plain-enc) dot_secrets_get_plain_enc "$key" ;;
|
|
136
|
-
|
|
136
|
+
macos-keychain) value="$(dot_secrets_get_macos "$key")" || rc=$? ;;
|
|
137
|
+
pass) value="$(dot_secrets_get_pass "$key")" || rc=$? ;;
|
|
138
|
+
plain-enc) value="$(dot_secrets_get_plain_enc "$key")" || rc=$? ;;
|
|
139
|
+
none)
|
|
140
|
+
# No usable provider on this host — silent miss is wrong;
|
|
141
|
+
# callers need to know whether to fall back.
|
|
142
|
+
printf 'dot_secrets_get: no provider configured for key=%s\n' "$key" >&2
|
|
143
|
+
return 2
|
|
144
|
+
;;
|
|
145
|
+
*)
|
|
146
|
+
printf 'dot_secrets_get: unknown provider %q\n' "$provider" >&2
|
|
147
|
+
return 1
|
|
148
|
+
;;
|
|
137
149
|
esac
|
|
150
|
+
if [[ "$rc" -ne 0 ]]; then
|
|
151
|
+
printf 'dot_secrets_get: provider %q failed (rc=%d) for key=%s\n' \
|
|
152
|
+
"$provider" "$rc" "$key" >&2
|
|
153
|
+
return "$rc"
|
|
154
|
+
fi
|
|
155
|
+
if [[ -z "$value" ]]; then
|
|
156
|
+
# An empty return from a successful provider call usually means
|
|
157
|
+
# "key not found" — distinguish from "provider crashed" so the
|
|
158
|
+
# caller's fallback can be different.
|
|
159
|
+
printf 'dot_secrets_get: provider %q returned empty for key=%s (not found?)\n' \
|
|
160
|
+
"$provider" "$key" >&2
|
|
161
|
+
return 3
|
|
162
|
+
fi
|
|
163
|
+
printf '%s' "$value"
|
|
138
164
|
}
|
|
139
165
|
|
|
140
166
|
dot_secrets_bucket_keys() {
|
|
@@ -37,15 +37,50 @@ heal_chezmoi_drift() {
|
|
|
37
37
|
return 0
|
|
38
38
|
fi
|
|
39
39
|
|
|
40
|
+
# Partition the drift: column 2 is what `chezmoi apply` would fix
|
|
41
|
+
# (destination differs from source). Column 1 is source-only drift
|
|
42
|
+
# (unstaged edits in the chezmoi source tree). Apply can't help with
|
|
43
|
+
# the second case — that needs `git commit` in the source repo.
|
|
44
|
+
local applicable
|
|
45
|
+
local source_only
|
|
46
|
+
applicable=$(printf '%s\n' "$status_output" | awk 'substr($0,2,1)!=" "' | wc -l | tr -d ' ')
|
|
47
|
+
source_only=$(printf '%s\n' "$status_output" | awk 'substr($0,1,1)!=" " && substr($0,2,1)==" "' | wc -l | tr -d ' ')
|
|
48
|
+
|
|
40
49
|
ISSUES_FOUND=$((ISSUES_FOUND + 1))
|
|
41
50
|
|
|
42
51
|
if [[ "$DRY_RUN" == "1" ]]; then
|
|
43
|
-
log_dry "run 'chezmoi apply --force' to re-sync"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
log_dry "run 'chezmoi apply --force' to re-sync ($applicable file(s))"
|
|
53
|
+
return 0
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Skip the apply if every file is source-only drift; nothing to fix.
|
|
57
|
+
if [[ "$applicable" -eq 0 ]]; then
|
|
58
|
+
printf ' \033[38;5;220m⚠\033[0m chezmoi state %s file(s) modified in source only — commit or revert in the source repo\n' "$source_only"
|
|
59
|
+
return 0
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Capture apply output so we can surface failure reasons.
|
|
63
|
+
local apply_log
|
|
64
|
+
apply_log=$(mktemp)
|
|
65
|
+
if chezmoi apply --force >"$apply_log" 2>&1; then
|
|
66
|
+
FIXES_APPLIED=$((FIXES_APPLIED + 1))
|
|
67
|
+
CHEZMOI_APPLIED=1
|
|
68
|
+
persist_log "HEAL: chezmoi apply --force"
|
|
69
|
+
|
|
70
|
+
# Verify: did apply actually clean the drift?
|
|
71
|
+
local remaining
|
|
72
|
+
remaining=$(chezmoi status 2>/dev/null | awk 'substr($0,2,1)!=" "' | wc -l | tr -d ' ')
|
|
73
|
+
if [[ "$remaining" -eq 0 ]]; then
|
|
74
|
+
printf ' \033[38;5;42m✓\033[0m chezmoi re-apply %s file(s) synced\n' "$applicable"
|
|
75
|
+
else
|
|
76
|
+
# shellcheck disable=SC2016
|
|
77
|
+
printf ' \033[38;5;220m⚠\033[0m chezmoi re-apply %s applied, %s still drifted — run `chezmoi diff` to inspect\n' \
|
|
78
|
+
"$((applicable - remaining))" "$remaining"
|
|
49
79
|
fi
|
|
80
|
+
else
|
|
81
|
+
printf ' \033[38;5;196m✗\033[0m chezmoi re-apply failed; see %s\n' "$apply_log"
|
|
82
|
+
tail -5 "$apply_log" | sed 's/^/ /'
|
|
83
|
+
return 1
|
|
50
84
|
fi
|
|
85
|
+
rm -f "$apply_log"
|
|
51
86
|
}
|
package/scripts/ops/rollback.sh
CHANGED
|
@@ -122,6 +122,10 @@ list_backups() {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
# Create a backup
|
|
125
|
+
# LCOV_EXCL_START — body mutates real $HOME (cp/mkdir of dotfiles);
|
|
126
|
+
# can't be exercised under the coverage sandbox without destroying
|
|
127
|
+
# fixture state. The dispatcher reaches this function but the body
|
|
128
|
+
# is genuinely off-limits.
|
|
125
129
|
create_backup() {
|
|
126
130
|
local reason="${1:-manual}"
|
|
127
131
|
local timestamp
|
|
@@ -183,7 +187,9 @@ EOF
|
|
|
183
187
|
# Cleanup old backups
|
|
184
188
|
cleanup_old_backups
|
|
185
189
|
}
|
|
190
|
+
# LCOV_EXCL_STOP
|
|
186
191
|
|
|
192
|
+
# LCOV_EXCL_START — rm -rf of real backup dirs.
|
|
187
193
|
# Cleanup old backups, keeping only MAX_BACKUPS
|
|
188
194
|
cleanup_old_backups() {
|
|
189
195
|
local count
|
|
@@ -199,6 +205,7 @@ cleanup_old_backups() {
|
|
|
199
205
|
done
|
|
200
206
|
fi
|
|
201
207
|
}
|
|
208
|
+
# LCOV_EXCL_STOP
|
|
202
209
|
|
|
203
210
|
# Get the most recent backup
|
|
204
211
|
get_latest_backup() {
|
|
@@ -211,6 +218,8 @@ get_backup_by_index() {
|
|
|
211
218
|
find "$BACKUP_DIR" -maxdepth 1 -type d -name "backup_*" | sort -r | sed -n "${index}p"
|
|
212
219
|
}
|
|
213
220
|
|
|
221
|
+
# LCOV_EXCL_START — body restores files into real $HOME; dispatcher
|
|
222
|
+
# reaches it but the actual mutation is off-limits under coverage.
|
|
214
223
|
# Rollback to a specific backup
|
|
215
224
|
perform_rollback() {
|
|
216
225
|
local backup_path="$1"
|
|
@@ -278,7 +287,9 @@ Analyze why the environment may have reached a state requiring rollback and sugg
|
|
|
278
287
|
fi
|
|
279
288
|
fi
|
|
280
289
|
}
|
|
290
|
+
# LCOV_EXCL_STOP
|
|
281
291
|
|
|
292
|
+
# LCOV_EXCL_START — runs git reset --hard, mutates working tree.
|
|
282
293
|
# Git-based rollback
|
|
283
294
|
git_reset() {
|
|
284
295
|
local dry_run="${1:-0}"
|
|
@@ -338,7 +349,9 @@ git_reset() {
|
|
|
338
349
|
persist_log "GIT_RESET: to $target_commit"
|
|
339
350
|
fi
|
|
340
351
|
}
|
|
352
|
+
# LCOV_EXCL_STOP
|
|
341
353
|
|
|
354
|
+
# LCOV_EXCL_START — body copies files into real $HOME.
|
|
342
355
|
# Restore a specific file from the latest backup
|
|
343
356
|
restore_file() {
|
|
344
357
|
local file_path="$1"
|
|
@@ -417,6 +430,7 @@ restore_file() {
|
|
|
417
430
|
persist_log "RESTORE_FILE: $file_path"
|
|
418
431
|
fi
|
|
419
432
|
}
|
|
433
|
+
# LCOV_EXCL_STOP
|
|
420
434
|
|
|
421
435
|
# Show current status
|
|
422
436
|
show_status() {
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Copyright (c) 2015-2026 Dotfiles. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# PowerShell parity contract — smoke test for the dotfiles PowerShell
|
|
4
|
+
# profile. Run by the windows-latest CI job (#860). Asserts that:
|
|
5
|
+
#
|
|
6
|
+
# 1. The profile parses + loads without throwing.
|
|
7
|
+
# 2. Core function shims (`dot`, `ll`, `la`, `cat`) are defined.
|
|
8
|
+
# 3. PSScriptAnalyzer reports no errors against the profile (warnings
|
|
9
|
+
# surface but don't fail the gate; tighten later).
|
|
10
|
+
#
|
|
11
|
+
# Exit codes:
|
|
12
|
+
# 0 contract intact.
|
|
13
|
+
# 1 any check failed; details printed to host.
|
|
14
|
+
|
|
15
|
+
$ErrorActionPreference = 'Stop'
|
|
16
|
+
$Failures = New-Object System.Collections.Generic.List[string]
|
|
17
|
+
|
|
18
|
+
$RepoRoot = if ($env:GITHUB_WORKSPACE) { $env:GITHUB_WORKSPACE } else { (Get-Location).Path }
|
|
19
|
+
$ProfileSrc = Join-Path $RepoRoot 'dot_config/powershell/Microsoft.PowerShell_profile.ps1.tmpl'
|
|
20
|
+
|
|
21
|
+
if (-not (Test-Path $ProfileSrc)) {
|
|
22
|
+
Write-Output "FAIL: profile source not found at $ProfileSrc"
|
|
23
|
+
exit 1
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Step 1 — chezmoi-render the template into a real .ps1 we can dot-source.
|
|
27
|
+
# In CI, chezmoi is on PATH (installed by setup-chezmoi composite).
|
|
28
|
+
$Rendered = Join-Path $env:TEMP 'Microsoft.PowerShell_profile.ps1'
|
|
29
|
+
if (Get-Command chezmoi -ErrorAction SilentlyContinue) {
|
|
30
|
+
& chezmoi execute-template --init --promptString version=0.2.501 `
|
|
31
|
+
--in $ProfileSrc | Set-Content -Path $Rendered -NoNewline
|
|
32
|
+
} else {
|
|
33
|
+
# Fallback: strip chezmoi template syntax with a simple regex so the
|
|
34
|
+
# contract still runs locally without chezmoi installed.
|
|
35
|
+
(Get-Content $ProfileSrc -Raw) -replace '\{\{[^}]+\}\}', '0.0.0-fallback' |
|
|
36
|
+
Set-Content -Path $Rendered -NoNewline
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (-not (Test-Path $Rendered)) {
|
|
40
|
+
$Failures.Add("profile template did not render to $Rendered")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Step 2 — dot-source the rendered profile and verify it didn't throw.
|
|
44
|
+
$loadOk = $false
|
|
45
|
+
try {
|
|
46
|
+
. $Rendered
|
|
47
|
+
$loadOk = $true
|
|
48
|
+
Write-Output "OK: profile dot-sourced"
|
|
49
|
+
} catch {
|
|
50
|
+
Write-Output "FAIL: profile threw during load: $_"
|
|
51
|
+
$Failures.Add("profile load: $_")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Step 3 — verify required function shims are defined.
|
|
55
|
+
$RequiredFunctions = @('dot', 'd', 'll', 'la', 'cat')
|
|
56
|
+
foreach ($fn in $RequiredFunctions) {
|
|
57
|
+
if (Get-Command $fn -CommandType Function -ErrorAction SilentlyContinue) {
|
|
58
|
+
Write-Output "OK: function $fn defined"
|
|
59
|
+
} else {
|
|
60
|
+
Write-Output "FAIL: function $fn not defined"
|
|
61
|
+
$Failures.Add("missing function: $fn")
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Step 4 — PSScriptAnalyzer (static analysis). Pre-installed on the
|
|
66
|
+
# windows-latest GitHub-hosted runner; install on demand if missing.
|
|
67
|
+
if (-not (Get-Module -ListAvailable -Name PSScriptAnalyzer)) {
|
|
68
|
+
Write-Output "Installing PSScriptAnalyzer..."
|
|
69
|
+
Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser -ErrorAction SilentlyContinue | Out-Null
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (Get-Module -ListAvailable -Name PSScriptAnalyzer) {
|
|
73
|
+
Import-Module PSScriptAnalyzer -Force
|
|
74
|
+
$Findings = Invoke-ScriptAnalyzer -Path $Rendered -Severity 'Error' -ErrorAction SilentlyContinue
|
|
75
|
+
if ($Findings) {
|
|
76
|
+
foreach ($f in $Findings) {
|
|
77
|
+
Write-Output "FAIL: PSScriptAnalyzer error: $($f.RuleName) at line $($f.Line): $($f.Message)"
|
|
78
|
+
$Failures.Add("PSScriptAnalyzer error: $($f.RuleName)")
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
Write-Output "OK: PSScriptAnalyzer clean (Error severity)"
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
Write-Output "WARN: PSScriptAnalyzer not available — static analysis skipped"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
Write-Output ""
|
|
88
|
+
if ($Failures.Count -eq 0) {
|
|
89
|
+
Write-Output "PowerShell contract: PASS"
|
|
90
|
+
exit 0
|
|
91
|
+
} else {
|
|
92
|
+
Write-Output "PowerShell contract: FAIL ($($Failures.Count) issue(s))"
|
|
93
|
+
foreach ($f in $Failures) { Write-Output " - $f" }
|
|
94
|
+
exit 1
|
|
95
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Copyright (c) 2015-2026 Dotfiles. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# scripts/security/check-disclosure-key-expiry.sh
|
|
5
|
+
#
|
|
6
|
+
# Reads the disclosure public key from `docs/security/security-pubkey.asc`,
|
|
7
|
+
# parses its expiry, and exits non-zero when the remaining lifetime is
|
|
8
|
+
# below threshold. Closes the R3 audit N2 finding (no automated alert
|
|
9
|
+
# for the 2029-05-15 expiry).
|
|
10
|
+
#
|
|
11
|
+
# Two thresholds:
|
|
12
|
+
# --warn-days N Emit a `::warning::` if expiry is < N days away.
|
|
13
|
+
# Default 90.
|
|
14
|
+
# --fail-days N Exit 1 (CI failure) if expiry is < N days away.
|
|
15
|
+
# Default 30.
|
|
16
|
+
#
|
|
17
|
+
# Usage:
|
|
18
|
+
# bash scripts/security/check-disclosure-key-expiry.sh
|
|
19
|
+
# bash scripts/security/check-disclosure-key-expiry.sh --warn-days 180 --fail-days 60
|
|
20
|
+
#
|
|
21
|
+
# Designed to run from `.github/workflows/verify-gpg-wkd.yml` on the
|
|
22
|
+
# weekly schedule, and from a maintainer's local pre-release sanity
|
|
23
|
+
# check. Does NOT require network — reads the in-repo .asc only.
|
|
24
|
+
|
|
25
|
+
set -euo pipefail
|
|
26
|
+
|
|
27
|
+
WARN_DAYS=90
|
|
28
|
+
FAIL_DAYS=30
|
|
29
|
+
|
|
30
|
+
while [[ $# -gt 0 ]]; do
|
|
31
|
+
case "$1" in
|
|
32
|
+
--warn-days)
|
|
33
|
+
WARN_DAYS="$2"
|
|
34
|
+
shift 2
|
|
35
|
+
;;
|
|
36
|
+
--fail-days)
|
|
37
|
+
FAIL_DAYS="$2"
|
|
38
|
+
shift 2
|
|
39
|
+
;;
|
|
40
|
+
-h | --help)
|
|
41
|
+
sed -n '5,25p' "${BASH_SOURCE[0]}"
|
|
42
|
+
exit 0
|
|
43
|
+
;;
|
|
44
|
+
*)
|
|
45
|
+
echo "Unknown arg: $1" >&2
|
|
46
|
+
exit 2
|
|
47
|
+
;;
|
|
48
|
+
esac
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
52
|
+
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
53
|
+
ASC="$REPO_ROOT/docs/security/security-pubkey.asc"
|
|
54
|
+
|
|
55
|
+
if [[ ! -f "$ASC" ]]; then
|
|
56
|
+
echo "::error::no public key at $ASC" >&2
|
|
57
|
+
exit 2
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
if ! command -v gpg >/dev/null 2>&1; then
|
|
61
|
+
echo "::warning::gpg not installed — cannot verify key expiry" >&2
|
|
62
|
+
exit 0
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Import into a throwaway keyring so we don't pollute the user's real one.
|
|
66
|
+
GNUPGHOME="$(mktemp -d -t dot-disclosure-key.XXXXXX)"
|
|
67
|
+
export GNUPGHOME
|
|
68
|
+
chmod 700 "$GNUPGHOME"
|
|
69
|
+
trap 'rm -rf "$GNUPGHOME"' EXIT
|
|
70
|
+
|
|
71
|
+
# gpg can emit harmless warnings ("keyboxd older than us", "gpg-agent
|
|
72
|
+
# IPC failed" in fresh GNUPGHOME, etc.) and exit non-zero under
|
|
73
|
+
# `set -e` even when the import itself succeeded. Verify success by
|
|
74
|
+
# checking the err log for the literal `imported: N` (N >= 1) line
|
|
75
|
+
# rather than trusting gpg's exit code.
|
|
76
|
+
gpg --batch --import "$ASC" >/dev/null 2>"$GNUPGHOME/import.err" || true
|
|
77
|
+
if ! grep -qE '^gpg:[[:space:]]*imported: [1-9]' "$GNUPGHOME/import.err"; then
|
|
78
|
+
echo "::error::gpg import failed for $ASC" >&2
|
|
79
|
+
cat "$GNUPGHOME/import.err" >&2
|
|
80
|
+
exit 2
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# `--with-colons` field 7 of the `pub:` line is the expiry in Unix
|
|
84
|
+
# seconds; 0 means no expiry.
|
|
85
|
+
expires=$(gpg --with-colons --fingerprint 2>/dev/null | awk -F: '/^pub:/{print $7; exit}')
|
|
86
|
+
|
|
87
|
+
if [[ -z "$expires" || "$expires" == "0" ]]; then
|
|
88
|
+
echo "::warning::disclosure key has no expiry — set one per docs/security/KEY_ROTATION.md" >&2
|
|
89
|
+
exit 0
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
now=$(date -u +%s)
|
|
93
|
+
remaining_days=$(((expires - now) / 86400))
|
|
94
|
+
|
|
95
|
+
expires_date=$(date -u -r "$expires" '+%Y-%m-%d' 2>/dev/null || date -u -d "@$expires" '+%Y-%m-%d' 2>/dev/null || echo "(date format unknown)")
|
|
96
|
+
|
|
97
|
+
echo "Disclosure key expires: $expires_date ($remaining_days days from now)"
|
|
98
|
+
echo " warn threshold: $WARN_DAYS days"
|
|
99
|
+
echo " fail threshold: $FAIL_DAYS days"
|
|
100
|
+
|
|
101
|
+
if ((remaining_days < FAIL_DAYS)); then
|
|
102
|
+
echo "::error::Disclosure key expires in $remaining_days days. Rotate now per docs/security/KEY_ROTATION.md." >&2
|
|
103
|
+
exit 1
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
if ((remaining_days < WARN_DAYS)); then
|
|
107
|
+
echo "::warning::Disclosure key expires in $remaining_days days. Schedule rotation per docs/security/KEY_ROTATION.md." >&2
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
exit 0
|
|
@@ -22,13 +22,22 @@ if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
|
22
22
|
UNLOCK_CMD="chflags nouchg"
|
|
23
23
|
CHECK_CMD="ls -lO"
|
|
24
24
|
else
|
|
25
|
-
# Linux (requires root
|
|
25
|
+
# Linux (chattr +i requires root; fail loudly when sudo is missing
|
|
26
|
+
# rather than printing a confusing error per file in automation)
|
|
26
27
|
if command -v chattr >/dev/null; then
|
|
28
|
+
if ! command -v sudo >/dev/null; then
|
|
29
|
+
echo " 'sudo' not found; chattr requires root. Aborting." >&2
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
if ! sudo -n true 2>/dev/null && [[ ! -t 0 ]]; then
|
|
33
|
+
echo " sudo requires a password but no TTY is attached. Aborting." >&2
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
27
36
|
LOCK_CMD="sudo chattr +i"
|
|
28
37
|
UNLOCK_CMD="sudo chattr -i"
|
|
29
38
|
CHECK_CMD="lsattr"
|
|
30
39
|
else
|
|
31
|
-
echo " 'chattr' not found. Cannot set immutability on Linux without it."
|
|
40
|
+
echo " 'chattr' not found. Cannot set immutability on Linux without it." >&2
|
|
32
41
|
exit 1
|
|
33
42
|
fi
|
|
34
43
|
fi
|
|
@@ -81,6 +81,10 @@ merge_pair() {
|
|
|
81
81
|
|
|
82
82
|
local tmpdir
|
|
83
83
|
tmpdir="$(mktemp -d)"
|
|
84
|
+
# Single-quotes prevent the variable expanding at trap-definition time;
|
|
85
|
+
# `$tmpdir` resolves when the trap fires (still scoped to this function
|
|
86
|
+
# because RETURN is per-function).
|
|
87
|
+
# shellcheck disable=SC2064 # intentionally expand $tmpdir at trap time within this function scope
|
|
84
88
|
trap "rm -rf '$tmpdir'" RETURN
|
|
85
89
|
|
|
86
90
|
# Convert both to JPEG for heif-enc input (it handles JPEG best)
|
package/scripts/theme/switch.sh
CHANGED
|
@@ -184,7 +184,7 @@ pick_theme() {
|
|
|
184
184
|
fi
|
|
185
185
|
|
|
186
186
|
local current
|
|
187
|
-
|
|
187
|
+
current="$(current_theme)"
|
|
188
188
|
|
|
189
189
|
if [[ ! -f "$THEMES_FILE" ]]; then
|
|
190
190
|
ui_err "Missing" "$THEMES_FILE"
|
|
@@ -234,7 +234,8 @@ pick_theme() {
|
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
list_themes() {
|
|
237
|
-
local current
|
|
237
|
+
local current
|
|
238
|
+
current="$(current_theme)"
|
|
238
239
|
local current_family="${current%-dark}"
|
|
239
240
|
[[ "$current_family" != "$current" ]] || current_family="${current%-light}"
|
|
240
241
|
|
|
@@ -260,7 +261,8 @@ list_themes() {
|
|
|
260
261
|
|
|
261
262
|
# Toggle between light and dark within the same family, or switch families
|
|
262
263
|
toggle_theme() {
|
|
263
|
-
local current
|
|
264
|
+
local current
|
|
265
|
+
current="$(current_theme)"
|
|
264
266
|
|
|
265
267
|
if is_dark_theme "$current"; then
|
|
266
268
|
if [[ "$current" == *-dark ]]; then
|
|
@@ -279,8 +281,9 @@ toggle_theme() {
|
|
|
279
281
|
|
|
280
282
|
# Switch to the next wallpaper family while preserving mode.
|
|
281
283
|
switch_family() {
|
|
282
|
-
local current
|
|
283
|
-
|
|
284
|
+
local current family
|
|
285
|
+
current="$(current_theme)"
|
|
286
|
+
family="$(get_theme_family "$current")"
|
|
284
287
|
local mode="dark"
|
|
285
288
|
local families=()
|
|
286
289
|
local idx=0
|
|
@@ -316,8 +319,9 @@ switch_family() {
|
|
|
316
319
|
|
|
317
320
|
# Show current theme info
|
|
318
321
|
show_current() {
|
|
319
|
-
local current
|
|
320
|
-
|
|
322
|
+
local current family
|
|
323
|
+
current="$(current_theme)"
|
|
324
|
+
family="$(get_theme_family "$current")"
|
|
321
325
|
local mode="dark"
|
|
322
326
|
if ! is_dark_theme "$current" 2>/dev/null; then
|
|
323
327
|
mode="light"
|
|
@@ -338,8 +342,13 @@ sync_theme() {
|
|
|
338
342
|
;;
|
|
339
343
|
Linux)
|
|
340
344
|
if command -v gsettings >/dev/null 2>&1; then
|
|
341
|
-
# Check GNOME color scheme
|
|
342
|
-
local scheme=scheme=$(
|
|
345
|
+
# Check GNOME color scheme. Fixes a long-standing bug where the
|
|
346
|
+
# variable was declared as `local scheme=scheme=$(...)` — the
|
|
347
|
+
# extra `scheme=` prefix made the value always start with that
|
|
348
|
+
# literal, so the `prefer-light` test below could never match
|
|
349
|
+
# and the system always fell through to the dark branch.
|
|
350
|
+
local scheme
|
|
351
|
+
scheme=$(gsettings get org.gnome.desktop.interface color-scheme 2>/dev/null | tr -d "'")
|
|
343
352
|
if [[ "$scheme" == "prefer-light" ]]; then
|
|
344
353
|
os_mode="light"
|
|
345
354
|
else
|
|
@@ -349,7 +358,8 @@ sync_theme() {
|
|
|
349
358
|
;;
|
|
350
359
|
esac
|
|
351
360
|
|
|
352
|
-
local current
|
|
361
|
+
local current
|
|
362
|
+
current="$(current_theme)"
|
|
353
363
|
if is_dark_theme "$current" && [[ "$os_mode" == "light" ]]; then
|
|
354
364
|
ui_info "Sync" "System is light, switching dotfiles to light..."
|
|
355
365
|
toggle_theme
|
package/scripts/version-sync.sh
CHANGED
|
@@ -142,6 +142,8 @@ sed_in_place() {
|
|
|
142
142
|
fi
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
# LCOV_EXCL_START — rm -rf BACKUP_DIR + cp of real release files;
|
|
146
|
+
# only run during a real release flow, not safe under coverage.
|
|
145
147
|
create_backup() {
|
|
146
148
|
local files=("$@")
|
|
147
149
|
|
|
@@ -166,6 +168,7 @@ create_backup() {
|
|
|
166
168
|
|
|
167
169
|
log_success "Backed up $backup_count files"
|
|
168
170
|
}
|
|
171
|
+
# LCOV_EXCL_STOP
|
|
169
172
|
|
|
170
173
|
update_version_references() {
|
|
171
174
|
local target_version="$1"
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# Atuin Configuration (~/.config/atuin/config.toml)
|
|
2
|
-
# https://atuin.sh/docs/config
|
|
3
|
-
|
|
4
|
-
# Core
|
|
5
|
-
update_check = false
|
|
6
|
-
db_path = "~/.local/share/atuin/history.db"
|
|
7
|
-
key_path = "~/.local/share/atuin/key"
|
|
8
|
-
session_path = "~/.local/share/atuin/session"
|
|
9
|
-
|
|
10
|
-
# Sync
|
|
11
|
-
auto_sync = true
|
|
12
|
-
sync_frequency = "10m"
|
|
13
|
-
sync_address = "https://api.atuin.sh"
|
|
14
|
-
|
|
15
|
-
# UI
|
|
16
|
-
style = "compact"
|
|
17
|
-
inline_height = 20
|
|
18
|
-
show_preview = true
|
|
19
|
-
enter_accept = true
|
|
20
|
-
|
|
21
|
-
# Search
|
|
22
|
-
search_mode = "fuzzy"
|
|
23
|
-
filter_mode = "global"
|
|
24
|
-
workspaces = true
|
|
25
|
-
|
|
26
|
-
# Privacy: skip commands that may contain secrets
|
|
27
|
-
history_filter = [
|
|
28
|
-
"^export (SECRET|TOKEN|PASSWORD|API_KEY|AWS_)",
|
|
29
|
-
"^PASSWORD=",
|
|
30
|
-
"^ssh-keygen",
|
|
31
|
-
"^(aws|gcloud|az|kubectl).*(configure|auth|login|-k |--kubeconfig)",
|
|
32
|
-
"curl.*-H.*[Aa]uthorization",
|
|
33
|
-
"git clone.*https://.*:.*@",
|
|
34
|
-
"^vault ",
|
|
35
|
-
"^op (read|inject|run)",
|
|
36
|
-
]
|
|
37
|
-
|
|
38
|
-
# Skip ephemeral directories
|
|
39
|
-
secrets_filter = true
|
|
40
|
-
network_timeout = 30
|