@sebastienrousseau/dotfiles 0.2.508 → 0.2.510
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 +30 -0
- package/README.md +5 -5
- package/docs/COPYRIGHT +1 -1
- package/docs/GOVERNANCE.md +2 -2
- package/docs/adr/ADR-011-nushell-tier3-keep.md +2 -2
- package/docs/guides/INSTALL.md +3 -3
- package/docs/index.md +116 -27
- package/docs/interop/A2A.md +2 -2
- package/docs/interop/POWERSHELL.md +4 -4
- package/docs/manual/00-introduction.md +3 -3
- package/docs/manual/01-concepts/02-trust-model.md +3 -3
- package/docs/manual/01-concepts/04-fleet.md +1 -1
- package/docs/manual/02-tutorials/01-first-install.md +1 -1
- package/docs/manual/02-tutorials/05-deploy-fleet.md +2 -2
- package/docs/manual/03-reference/02-config-files.md +1 -1
- package/docs/manual/03-reference/04-templates.md +1 -1
- package/docs/manual/04-cookbook/01-recipes.md +1 -1
- package/docs/manual/04-cookbook/02-troubleshooting.md +1 -1
- package/docs/manual/05-appendices/B-security-checklist.md +1 -1
- package/docs/manual/command-index.md +76 -1
- package/docs/manual/index.md +1 -1
- package/docs/operations/ARCHITECTURE_ROADMAP.md +145 -0
- package/docs/operations/CI_CADENCE.md +2 -2
- package/docs/operations/COMPLETIONS.md +2 -2
- package/docs/operations/COVERAGE.md +4 -4
- package/docs/operations/DRIFT.md +1 -1
- package/docs/operations/MAINTENANCE.md +6 -6
- package/docs/operations/PERFORMANCE.md +6 -6
- package/docs/operations/RELIABILITY.md +1 -1
- package/docs/operations/ROADMAP_V0_2_503.md +1 -1
- package/docs/operations/TRACEABILITY.md +2 -0
- package/docs/operations/TRUSTED_AGENT_WORKSTATION.md +6 -6
- package/docs/operations/VERSION_SYNC.md +3 -3
- package/docs/reference/UTILS.md +82 -0
- package/docs/security/AUDIT_BYPASS.md +3 -3
- package/docs/security/AUTOMATION_SECRETS.md +1 -1
- package/docs/security/CI_PINNING.md +10 -10
- package/docs/security/COMMIT_SIGNING.md +10 -10
- package/docs/security/DEPS_DEV_EXCEPTIONS.md +4 -4
- package/docs/security/DISCLOSURE.md +3 -3
- package/docs/security/INCIDENT_RESPONSE.md +1 -1
- package/docs/security/INSTALL_VERIFICATION.md +2 -2
- package/docs/security/MCP_POLICY.md +4 -4
- package/docs/security/SCORECARD.md +7 -7
- package/docs/security/SECURITY_CHECKLIST.md +1 -1
- package/docs/security/SHELL_EXEMPTIONS.md +2 -2
- package/docs/security/SOUP_REGISTER.md +4 -4
- package/docs/stylesheets/extra.css +444 -0
- package/docs/themes/hero-shot.svg +1 -1
- package/install.sh +17 -6
- package/package.json +1 -1
- package/scripts/ci/check-copyright-headers.sh +1 -1
- package/scripts/ci/check-shell-preamble.sh +1 -1
- package/scripts/ci/guard-gitleaks-checkout.sh +1 -1
- package/scripts/dot/commands/agent.sh +7 -6
- package/scripts/dot/commands/ai.sh +8 -5
- package/scripts/dot/commands/appearance.sh +14 -1
- package/scripts/dot/commands/completion.sh +134 -0
- package/scripts/dot/commands/core.sh +8 -0
- package/scripts/dot/commands/diagnostics.sh +16 -0
- package/scripts/dot/commands/fleet.sh +7 -3
- package/scripts/dot/commands/lint.sh +55 -30
- package/scripts/dot/commands/secrets.sh +61 -7
- package/scripts/dot/commands/security.sh +8 -0
- package/scripts/dot/powershell/Dot.psm1 +1 -1
- package/scripts/git-hooks/pre-commit-audit.sh +1 -1
- package/scripts/ops/heal-tools.sh +28 -0
- package/scripts/ops/teleport.sh +2 -2
- package/scripts/qa/examples-coverage.sh +94 -0
- package/scripts/version-sync.sh +29 -2
- package/docs/_config.yml +0 -59
package/install.sh
CHANGED
|
@@ -2,9 +2,20 @@
|
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
# Copyright (c) 2015-2026 Sebastien Rousseau
|
|
4
4
|
# Universal Dotfiles Installer (Zero-Dependency)
|
|
5
|
-
# Usage: bash -c "$(curl -fsSL https://raw.githubusercontent.com/sebastienrousseau/dotfiles/
|
|
5
|
+
# Usage: bash -c "$(curl -fsSL https://raw.githubusercontent.com/sebastienrousseau/dotfiles/main/install.sh)"
|
|
6
6
|
# (or ./install.sh locally)
|
|
7
7
|
|
|
8
|
+
# This installer uses bash features (set -o pipefail, arrays, [[ ]]). If it is
|
|
9
|
+
# run under a POSIX/other shell — e.g. `sh install.sh` or piped to `sh` where
|
|
10
|
+
# /bin/sh is dash — fail fast with a clear message instead of the cryptic
|
|
11
|
+
# "set: Illegal option -o pipefail" from the next line. Kept strictly POSIX so
|
|
12
|
+
# it parses in any shell before bash takes over.
|
|
13
|
+
if [ -z "${BASH_VERSION:-}" ]; then
|
|
14
|
+
echo "install.sh requires bash. Run: bash install.sh" >&2
|
|
15
|
+
echo " or: bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/sebastienrousseau/dotfiles/main/install.sh)\"" >&2
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
8
19
|
set -euo pipefail
|
|
9
20
|
|
|
10
21
|
# Restrict the permissions of any file/dir we create during bootstrap.
|
|
@@ -60,7 +71,7 @@ show_help() {
|
|
|
60
71
|
Usage: install.sh [version] [options]
|
|
61
72
|
|
|
62
73
|
Arguments:
|
|
63
|
-
version The version (tag or branch) to install (default: v0.2.
|
|
74
|
+
version The version (tag or branch) to install (default: v0.2.510)
|
|
64
75
|
|
|
65
76
|
Options:
|
|
66
77
|
--help Show this help message
|
|
@@ -76,7 +87,7 @@ EOF
|
|
|
76
87
|
}
|
|
77
88
|
|
|
78
89
|
main() {
|
|
79
|
-
local version="v0.2.
|
|
90
|
+
local version="v0.2.510"
|
|
80
91
|
local version_set=0
|
|
81
92
|
local minimal=0
|
|
82
93
|
local provision="${DOTFILES_PROVISION:-0}"
|
|
@@ -106,7 +117,7 @@ main() {
|
|
|
106
117
|
# like `foobar` doesn't trigger a 30s+ network download attempt.
|
|
107
118
|
# Caught by the install.sh fuzz harness (#881).
|
|
108
119
|
if [[ ! "$arg" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+([-+][a-zA-Z0-9.-]+)?$ ]]; then
|
|
109
|
-
error "Unrecognized positional argument '$arg' — expected a semver version (e.g. v0.2.
|
|
120
|
+
error "Unrecognized positional argument '$arg' — expected a semver version (e.g. v0.2.510)."
|
|
110
121
|
fi
|
|
111
122
|
version="$arg"
|
|
112
123
|
version_set=1
|
|
@@ -351,7 +362,7 @@ main() {
|
|
|
351
362
|
# 6. Initialize & Apply
|
|
352
363
|
step "Applying Configuration..."
|
|
353
364
|
|
|
354
|
-
# ── Auto-migration for v0.2.
|
|
365
|
+
# ── Auto-migration for v0.2.510 reorg ─────────────────────────────────
|
|
355
366
|
# If the user is upgrading from a pre-0.2.503 install, run the
|
|
356
367
|
# migration script BEFORE `chezmoi apply` so the reorg's source-
|
|
357
368
|
# path moves don't cause chezmoi to delete deployed files.
|
|
@@ -360,7 +371,7 @@ main() {
|
|
|
360
371
|
for migrate_src in "$SOURCE_DIR" "$LEGACY_SOURCE_DIR"; do
|
|
361
372
|
migrate_script="$migrate_src/install/migrate/migrate-v0_2-to-v0_2_503.sh"
|
|
362
373
|
if [[ -x "$migrate_script" ]]; then
|
|
363
|
-
echo " Running v0.2.
|
|
374
|
+
echo " Running v0.2.510 migration (idempotent; safe on fresh installs)..."
|
|
364
375
|
"$migrate_script" || echo " migration exited non-zero — continuing apply"
|
|
365
376
|
break
|
|
366
377
|
fi
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sebastienrousseau/dotfiles",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.510",
|
|
4
4
|
"description": "The Trusted Shell Platform — Universal dotfiles managed by Chezmoi. Features Bash & Zsh for macOS, Linux & WSL. Rust modern tooling & enterprise-grade security.",
|
|
5
5
|
"main": "install.sh",
|
|
6
6
|
"bin": {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
# Copyright (c) 2015-2026 Sebastien Rousseau
|
|
4
4
|
# Compat shim: the canonical script moved to tools/ci/ during the repo reorg.
|
|
5
|
-
# Pinned reusable workflows on
|
|
5
|
+
# Pinned reusable workflows on main still reference the old path;
|
|
6
6
|
# this delegates so they keep working until the next pin bump.
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
exec bash "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/tools/ci/check-copyright-headers.sh" "$@"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
# Copyright (c) 2015-2026 Sebastien Rousseau
|
|
4
4
|
# Compat shim: the canonical script moved to tools/ci/ during the repo reorg.
|
|
5
|
-
# Pinned reusable workflows on
|
|
5
|
+
# Pinned reusable workflows on main still reference the old path;
|
|
6
6
|
# this delegates so they keep working until the next pin bump.
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
exec bash "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/tools/ci/check-shell-preamble.sh" "$@"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
# Copyright (c) 2015-2026 Sebastien Rousseau
|
|
4
4
|
# Compat shim: the canonical script moved to tools/ci/ during the repo reorg.
|
|
5
|
-
# Pinned reusable workflows on
|
|
5
|
+
# Pinned reusable workflows on main still reference the old path;
|
|
6
6
|
# this delegates so they keep working until the next pin bump.
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
exec bash "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/tools/ci/guard-gitleaks-checkout.sh" "$@"
|
|
@@ -88,12 +88,13 @@ _agent_apply_profile_env() {
|
|
|
88
88
|
# Split declare-and-assign to avoid masking the field-getter's exit
|
|
89
89
|
# code (SC2155). If the profile JSON is malformed, the assignment
|
|
90
90
|
# now fails the function instead of silently exporting an empty value.
|
|
91
|
-
local approval filesystem network mcp_profile max_steps
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
91
|
+
local approval filesystem network mcp_profile max_steps tuple
|
|
92
|
+
# One jq read of all five policy fields (was five separate jq processes on
|
|
93
|
+
# every profile application). `|| return 1` preserves fail-on-malformed.
|
|
94
|
+
tuple="$(jq -r --arg name "$name" \
|
|
95
|
+
'.profiles[$name] | [.approval, .filesystem, .network, .mcpProfile, .maxSteps] | @tsv' \
|
|
96
|
+
"$(_agent_profiles_file)")" || return 1
|
|
97
|
+
IFS=$'\t' read -r approval filesystem network mcp_profile max_steps <<<"$tuple"
|
|
97
98
|
export DOT_AGENT_APPROVAL="$approval"
|
|
98
99
|
export DOT_AGENT_FILESYSTEM="$filesystem"
|
|
99
100
|
export DOT_AGENT_NETWORK="$network"
|
|
@@ -147,9 +147,7 @@ _ai_get_cached_status() {
|
|
|
147
147
|
|
|
148
148
|
# Look up field $2 (2=present 0/1, 3=version) for binary $1 from the
|
|
149
149
|
# cached TSV. Replaces a bash-4 associative array for macOS bash 3.2.
|
|
150
|
-
_ai_status_field
|
|
151
|
-
awk -F'\t' -v b="$1" -v f="$2" '$1==b{print $f;exit}' "$AI_STATUS_CACHE_FILE" 2>/dev/null
|
|
152
|
-
}
|
|
150
|
+
# (Removed _ai_status_field — cmd_ai_status now reads both fields in one awk.)
|
|
153
151
|
|
|
154
152
|
# _ai_mise_pkg (binary -> mise package map) is defined in lib/dot/ai-install.sh.
|
|
155
153
|
|
|
@@ -193,8 +191,13 @@ cmd_ai_status() {
|
|
|
193
191
|
ui_section "$category"
|
|
194
192
|
current_category="$category"
|
|
195
193
|
fi
|
|
196
|
-
|
|
197
|
-
|
|
194
|
+
# One awk over the cache line for this tool (was two: field 2 and field 3).
|
|
195
|
+
local _st_installed _st_ver
|
|
196
|
+
IFS=$'\t' read -r _st_installed _st_ver < <(
|
|
197
|
+
awk -F'\t' -v b="$bin" '$1==b{print $2"\t"$3;exit}' "$AI_STATUS_CACHE_FILE" 2>/dev/null
|
|
198
|
+
)
|
|
199
|
+
if [[ "$_st_installed" == "1" ]]; then
|
|
200
|
+
ver="$_st_ver"
|
|
198
201
|
[[ -z "$ver" ]] && ver="installed"
|
|
199
202
|
[[ "$bin" == "claude" ]] && ver="${ver%% *}"
|
|
200
203
|
ui_ok "$name" "$ver — $desc"
|
|
@@ -33,7 +33,20 @@ cmd_wallpaper() {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
cmd_fonts() {
|
|
36
|
-
|
|
36
|
+
local sub="${1:-install}"
|
|
37
|
+
case "$sub" in
|
|
38
|
+
patch)
|
|
39
|
+
shift
|
|
40
|
+
run_script "scripts/fonts/patch-fonts.sh" "Font patch helper" "$@"
|
|
41
|
+
;;
|
|
42
|
+
install | "")
|
|
43
|
+
[[ "$sub" == install ]] && shift || true
|
|
44
|
+
run_script "scripts/fonts/install-nerd-fonts.sh" "Font install script" "$@"
|
|
45
|
+
;;
|
|
46
|
+
*)
|
|
47
|
+
run_script "scripts/fonts/install-nerd-fonts.sh" "Font install script" "$@"
|
|
48
|
+
;;
|
|
49
|
+
esac
|
|
37
50
|
}
|
|
38
51
|
|
|
39
52
|
cmd_tune() {
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
# Copyright (c) 2015-2026 Sebastien Rousseau
|
|
4
|
+
## `dot completion <bash|zsh|fish|nu>` — emit shell completion for `dot`,
|
|
5
|
+
## generated from the canonical _dot_help_specs registry in bin/dot. Using one
|
|
6
|
+
## source of truth keeps all four shells in sync (the previously hand-maintained
|
|
7
|
+
## fish/nushell lists drifted and referenced non-existent commands).
|
|
8
|
+
##
|
|
9
|
+
## Usage:
|
|
10
|
+
## dot completion bash >> ~/.bashrc.d/dot.bash
|
|
11
|
+
## dot completion zsh > "${fpath[1]}/_dot"
|
|
12
|
+
## dot completion fish > ~/.config/fish/completions/dot.fish
|
|
13
|
+
## dot completion nu >> ~/.config/nushell/completions.nu
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
# shellcheck source=../../../lib/dot/utils.sh
|
|
19
|
+
source "$SCRIPT_DIR/../../../lib/dot/utils.sh"
|
|
20
|
+
|
|
21
|
+
_completion_dot_cli() {
|
|
22
|
+
local src
|
|
23
|
+
src="$(resolve_source_dir)"
|
|
24
|
+
printf '%s/bin/dot\n' "$src"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# Emit "name<TAB>description" for every top-level command (a _dot_help_specs
|
|
28
|
+
# field-2 entry with no space; entries containing a space are subcommands).
|
|
29
|
+
# Strip ": ' from descriptions so they can't break any shell's quoting.
|
|
30
|
+
_completion_commands() {
|
|
31
|
+
local cli
|
|
32
|
+
cli="$(_completion_dot_cli)"
|
|
33
|
+
awk -F'|' '
|
|
34
|
+
/_dot_help_specs\(\)/ { in_func = 1; next }
|
|
35
|
+
in_func && /cat <<'\''EOF'\''/ { in_block = 1; next }
|
|
36
|
+
in_block && /^EOF$/ { exit }
|
|
37
|
+
in_block && NF >= 3 && $2 !~ / / {
|
|
38
|
+
name = $2; desc = $3
|
|
39
|
+
gsub(/^[ \t]+|[ \t]+$/, "", name)
|
|
40
|
+
gsub(/^[ \t]+|[ \t]+$/, "", desc)
|
|
41
|
+
gsub(/[":\047]/, "", desc)
|
|
42
|
+
if (name != "") print name "\t" desc
|
|
43
|
+
}
|
|
44
|
+
' "$cli"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Emit "parent<TAB>child<TAB>description" for every subcommand (a field-2
|
|
48
|
+
# entry that contains a space, e.g. "theme list" -> parent=theme child=list).
|
|
49
|
+
_completion_subcommands() {
|
|
50
|
+
local cli
|
|
51
|
+
cli="$(_completion_dot_cli)"
|
|
52
|
+
awk -F'|' '
|
|
53
|
+
/_dot_help_specs\(\)/ { in_func = 1; next }
|
|
54
|
+
in_func && /cat <<'\''EOF'\''/ { in_block = 1; next }
|
|
55
|
+
in_block && /^EOF$/ { exit }
|
|
56
|
+
in_block && NF >= 3 && $2 ~ / / {
|
|
57
|
+
full = $2; desc = $3
|
|
58
|
+
gsub(/^[ \t]+|[ \t]+$/, "", full)
|
|
59
|
+
gsub(/^[ \t]+|[ \t]+$/, "", desc)
|
|
60
|
+
gsub(/[":\047]/, "", desc)
|
|
61
|
+
parent = full; sub(/ .*/, "", parent)
|
|
62
|
+
child = full; sub(/^[^ ]+ /, "", child)
|
|
63
|
+
if (parent != "" && child != "") print parent "\t" child "\t" desc
|
|
64
|
+
}
|
|
65
|
+
' "$cli"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
gen_bash() {
|
|
69
|
+
local names
|
|
70
|
+
names="$(_completion_commands | cut -f1 | tr '\n' ' ')"
|
|
71
|
+
printf '# dot bash completion — generated by: dot completion bash\n'
|
|
72
|
+
printf "complete -W '%s' dot\n" "${names% }"
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
gen_zsh() {
|
|
76
|
+
local name desc
|
|
77
|
+
printf '#compdef dot\n# generated by: dot completion zsh\n'
|
|
78
|
+
printf '_dot() {\n local -a commands\n commands=(\n'
|
|
79
|
+
while IFS=$'\t' read -r name desc; do
|
|
80
|
+
printf " '%s:%s'\n" "$name" "$desc"
|
|
81
|
+
done < <(_completion_commands)
|
|
82
|
+
printf ' )\n _describe '\''command'\'' commands\n}\n_dot "$@"\n'
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
gen_fish() {
|
|
86
|
+
local name desc
|
|
87
|
+
printf '# dot fish completion — generated by: dot completion fish\n'
|
|
88
|
+
printf 'complete -c dot -f\n'
|
|
89
|
+
while IFS=$'\t' read -r name desc; do
|
|
90
|
+
printf 'complete -c dot -n "__fish_use_subcommand" -a %s -d "%s"\n' "$name" "$desc"
|
|
91
|
+
done < <(_completion_commands)
|
|
92
|
+
local parent child
|
|
93
|
+
while IFS=$'\t' read -r parent child desc; do
|
|
94
|
+
printf 'complete -c dot -n "__fish_seen_subcommand_from %s" -a %s -d "%s"\n' \
|
|
95
|
+
"$parent" "$child" "$desc"
|
|
96
|
+
done < <(_completion_subcommands)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
gen_nu() {
|
|
100
|
+
local name desc
|
|
101
|
+
printf '# dot nushell completion — generated by: dot completion nu\n'
|
|
102
|
+
printf 'export extern dot [\n command?: string@dot_commands\n ...args: string\n]\n'
|
|
103
|
+
printf 'def dot_commands [] {\n [\n'
|
|
104
|
+
while IFS=$'\t' read -r name desc; do
|
|
105
|
+
printf ' { value: "%s", description: "%s" }\n' "$name" "$desc"
|
|
106
|
+
done < <(_completion_commands)
|
|
107
|
+
printf ' ]\n}\n'
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
usage() {
|
|
111
|
+
cat <<'USAGE'
|
|
112
|
+
Usage: dot completion <bash|zsh|fish|nu>
|
|
113
|
+
|
|
114
|
+
Generate shell completion for `dot` from the canonical command registry.
|
|
115
|
+
|
|
116
|
+
dot completion bash >> ~/.bashrc.d/dot.bash
|
|
117
|
+
dot completion zsh > "${fpath[1]}/_dot"
|
|
118
|
+
dot completion fish > ~/.config/fish/completions/dot.fish
|
|
119
|
+
dot completion nu >> ~/.config/nushell/completions.nu
|
|
120
|
+
USAGE
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# Dispatch: $1 is the command name ("completion"); $2 is the target shell.
|
|
124
|
+
case "${2:-}" in
|
|
125
|
+
bash) gen_bash ;;
|
|
126
|
+
zsh) gen_zsh ;;
|
|
127
|
+
fish) gen_fish ;;
|
|
128
|
+
nu | nushell) gen_nu ;;
|
|
129
|
+
"" | -h | --help | help) usage ;;
|
|
130
|
+
*)
|
|
131
|
+
echo "dot completion: unknown shell '${2}' (want: bash|zsh|fish|nu)" >&2
|
|
132
|
+
exit 1
|
|
133
|
+
;;
|
|
134
|
+
esac
|
|
@@ -129,6 +129,10 @@ cmd_commit() {
|
|
|
129
129
|
run_script "dot_local/bin/executable_git-ai-commit" "Git AI commit script" "$@"
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
cmd_uninstall() {
|
|
133
|
+
run_script "scripts/uninstall.sh" "Uninstall script" "$@"
|
|
134
|
+
}
|
|
135
|
+
|
|
132
136
|
cmd_clean_cache() {
|
|
133
137
|
ui_info "Cache" "Clearing shell initialization caches"
|
|
134
138
|
local cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}"
|
|
@@ -185,6 +189,10 @@ case "${1:-}" in
|
|
|
185
189
|
shift
|
|
186
190
|
cmd_clean_cache "$@"
|
|
187
191
|
;;
|
|
192
|
+
uninstall)
|
|
193
|
+
shift
|
|
194
|
+
cmd_uninstall "$@"
|
|
195
|
+
;;
|
|
188
196
|
*)
|
|
189
197
|
echo "Unknown core command: ${1:-}" >&2
|
|
190
198
|
exit 1
|
|
@@ -110,6 +110,14 @@ cmd_chaos() {
|
|
|
110
110
|
run_script "scripts/ops/chaos.sh" "Chaos engineering script" "$@"
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
cmd_teleport() {
|
|
114
|
+
run_script "scripts/ops/teleport.sh" "Teleport script" "$@"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
cmd_secret_audit() {
|
|
118
|
+
run_script "scripts/diagnostics/secret-governance.sh" "Secret governance script" "$@"
|
|
119
|
+
}
|
|
120
|
+
|
|
113
121
|
cmd_bundle() {
|
|
114
122
|
run_script "scripts/ops/bundle.sh" "Offline bundle script" "$@"
|
|
115
123
|
}
|
|
@@ -207,6 +215,14 @@ case "${1:-}" in
|
|
|
207
215
|
shift
|
|
208
216
|
cmd_chaos "$@"
|
|
209
217
|
;;
|
|
218
|
+
teleport)
|
|
219
|
+
shift
|
|
220
|
+
cmd_teleport "$@"
|
|
221
|
+
;;
|
|
222
|
+
secret-audit)
|
|
223
|
+
shift
|
|
224
|
+
cmd_secret_audit "$@"
|
|
225
|
+
;;
|
|
210
226
|
bundle)
|
|
211
227
|
shift
|
|
212
228
|
cmd_bundle "$@"
|
|
@@ -202,9 +202,13 @@ cmd_fleet_drift() {
|
|
|
202
202
|
local count="${1:-20}"
|
|
203
203
|
tail -n "$count" "$_DRIFT_HISTORY_FILE" | while IFS= read -r line; do
|
|
204
204
|
local time status file_count
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
# One jq per line (was three: .time, .status, .files|length).
|
|
206
|
+
IFS=$'\t' read -r time status file_count < <(
|
|
207
|
+
printf '%s' "$line" | jq -r '[.time, .status, (.files | length)] | @tsv' 2>/dev/null
|
|
208
|
+
)
|
|
209
|
+
[[ -n "$time" ]] || time="?"
|
|
210
|
+
[[ -n "$status" ]] || status="?"
|
|
211
|
+
[[ -n "$file_count" ]] || file_count=0
|
|
208
212
|
if [[ "$status" == "clean" ]]; then
|
|
209
213
|
ui_ok "$time" "clean"
|
|
210
214
|
else
|
|
@@ -19,6 +19,33 @@ dot_ui_command_banner "Lint" "${1:-}"
|
|
|
19
19
|
SHELLCHECK_ARGS=(--severity=error -e SC1091 -e SC2030 -e SC2031)
|
|
20
20
|
SHFMT_ARGS=(-i 2 -ci)
|
|
21
21
|
|
|
22
|
+
# True only if the file's shebang names a shell that both shellcheck and shfmt
|
|
23
|
+
# can process. The old `grep -qiE 'shell|bash|sh'` matched loosely — "sh" hit
|
|
24
|
+
# "fish", and `file` output pulled in python3 scripts — so non-shell files
|
|
25
|
+
# landed in the lint set and produced spurious SC1071 / shfmt parse "errors".
|
|
26
|
+
_lint_is_shell() {
|
|
27
|
+
local first interp
|
|
28
|
+
first="$(head -1 "$1" 2>/dev/null)"
|
|
29
|
+
case "$first" in '#!'*) ;; *) return 1 ;; esac
|
|
30
|
+
interp="${first#\#!}"
|
|
31
|
+
interp="${interp#"${interp%%[![:space:]]*}"}" # ltrim
|
|
32
|
+
case "$interp" in
|
|
33
|
+
*/env[[:space:]]*)
|
|
34
|
+
interp="${interp#*/env}"
|
|
35
|
+
interp="${interp#"${interp%%[![:space:]]*}"}"
|
|
36
|
+
interp="${interp%%[[:space:]]*}"
|
|
37
|
+
;;
|
|
38
|
+
*)
|
|
39
|
+
interp="${interp%%[[:space:]]*}"
|
|
40
|
+
interp="${interp##*/}"
|
|
41
|
+
;;
|
|
42
|
+
esac
|
|
43
|
+
case "$interp" in
|
|
44
|
+
sh | bash | dash | ksh | mksh | ash) return 0 ;;
|
|
45
|
+
*) return 1 ;;
|
|
46
|
+
esac
|
|
47
|
+
}
|
|
48
|
+
|
|
22
49
|
cmd_lint() {
|
|
23
50
|
local mode="${1:-all}"
|
|
24
51
|
local src_dir
|
|
@@ -40,11 +67,10 @@ cmd_lint() {
|
|
|
40
67
|
chezmoi_src="$(resolve_chezmoi_source_dir)"
|
|
41
68
|
[[ -z "$chezmoi_src" ]] && chezmoi_src="$src_dir"
|
|
42
69
|
|
|
43
|
-
# dot_local/bin/executable_* scripts
|
|
70
|
+
# dot_local/bin/executable_* scripts — shell scripts only (skip python/zsh/etc
|
|
71
|
+
# by inspecting the shebang, so shellcheck/shfmt never see files they can't parse).
|
|
44
72
|
while IFS= read -r -d '' f; do
|
|
45
|
-
if
|
|
46
|
-
files+=("$f")
|
|
47
|
-
elif head -1 "$f" 2>/dev/null | grep -qE '^#!.*(bash|sh)'; then
|
|
73
|
+
if _lint_is_shell "$f"; then
|
|
48
74
|
files+=("$f")
|
|
49
75
|
fi
|
|
50
76
|
done < <(find "$chezmoi_src/dot_local/bin" -name 'executable_*' -type f -print0 2>/dev/null)
|
|
@@ -69,17 +95,16 @@ cmd_lint() {
|
|
|
69
95
|
if has_command shellcheck; then
|
|
70
96
|
ui_section "ShellCheck"
|
|
71
97
|
echo ""
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
done
|
|
78
|
-
if [[ "$sc_fail" -eq 0 ]]; then
|
|
98
|
+
# One shellcheck invocation over all files (was one fork per file).
|
|
99
|
+
# gcc format is one line per issue, so failing files = unique paths.
|
|
100
|
+
local sc_out
|
|
101
|
+
sc_out="$(shellcheck -f gcc "${SHELLCHECK_ARGS[@]}" "${files[@]}" 2>/dev/null || true)"
|
|
102
|
+
if [[ -z "$sc_out" ]]; then
|
|
79
103
|
ui_ok "shellcheck" "$total files clean"
|
|
80
104
|
else
|
|
81
|
-
|
|
82
|
-
|
|
105
|
+
printf '%s\n' "$sc_out"
|
|
106
|
+
sc_errors=$(printf '%s\n' "$sc_out" | cut -d: -f1 | sort -u | grep -c .)
|
|
107
|
+
ui_err "shellcheck" "$sc_errors file(s) with errors"
|
|
83
108
|
fi
|
|
84
109
|
echo ""
|
|
85
110
|
else
|
|
@@ -91,17 +116,15 @@ cmd_lint() {
|
|
|
91
116
|
if has_command shfmt; then
|
|
92
117
|
ui_section "shfmt"
|
|
93
118
|
echo ""
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
done
|
|
100
|
-
if [[ "$fmt_fail" -eq 0 ]]; then
|
|
119
|
+
# `shfmt -l` lists files needing formatting in one invocation
|
|
120
|
+
# (was `shfmt -d` per file).
|
|
121
|
+
local fmt_list
|
|
122
|
+
fmt_list="$(shfmt "${SHFMT_ARGS[@]}" -l "${files[@]}" 2>/dev/null || true)"
|
|
123
|
+
if [[ -z "$fmt_list" ]]; then
|
|
101
124
|
ui_ok "shfmt" "$total files formatted correctly"
|
|
102
125
|
else
|
|
103
|
-
fmt_errors=$
|
|
104
|
-
ui_err "shfmt" "$
|
|
126
|
+
fmt_errors=$(printf '%s\n' "$fmt_list" | grep -c .)
|
|
127
|
+
ui_err "shfmt" "$fmt_errors file(s) need formatting"
|
|
105
128
|
fi
|
|
106
129
|
echo ""
|
|
107
130
|
else
|
|
@@ -118,17 +141,19 @@ cmd_lint() {
|
|
|
118
141
|
fi
|
|
119
142
|
ui_section "Auto-fixing with shfmt"
|
|
120
143
|
echo ""
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
144
|
+
# Find files needing formatting in one `shfmt -l` pass, then only
|
|
145
|
+
# rewrite that (usually small) set — was `shfmt -d` per file.
|
|
146
|
+
local fmt_list fixed=0
|
|
147
|
+
fmt_list="$(shfmt "${SHFMT_ARGS[@]}" -l "${files[@]}" 2>/dev/null || true)"
|
|
148
|
+
if [[ -z "$fmt_list" ]]; then
|
|
149
|
+
ui_ok "shfmt" "All files already formatted"
|
|
150
|
+
else
|
|
151
|
+
while IFS= read -r f; do
|
|
152
|
+
[[ -n "$f" ]] || continue
|
|
124
153
|
shfmt "${SHFMT_ARGS[@]}" -w "$f"
|
|
125
154
|
ui_ok "fixed" "${f#"$src_dir/"}"
|
|
126
155
|
fixed=$((fixed + 1))
|
|
127
|
-
|
|
128
|
-
done
|
|
129
|
-
if [[ "$fixed" -eq 0 ]]; then
|
|
130
|
-
ui_ok "shfmt" "All files already formatted"
|
|
131
|
-
else
|
|
156
|
+
done <<<"$fmt_list"
|
|
132
157
|
ui_ok "shfmt" "$fixed file(s) reformatted"
|
|
133
158
|
fi
|
|
134
159
|
echo ""
|
|
@@ -152,26 +152,80 @@ cmd_secrets_list() {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
cmd_env_load() {
|
|
155
|
-
|
|
155
|
+
# Usage: dot secrets load [<bucket>] [--shell posix|fish|nu]
|
|
156
|
+
# Emits shell code to set the bucket's secrets as env vars, in the target
|
|
157
|
+
# shell's dialect so it works beyond POSIX:
|
|
158
|
+
# posix (default): eval "$(dot secrets load ai)"
|
|
159
|
+
# fish: dot secrets load ai --shell fish | source
|
|
160
|
+
# nu: load-env (dot secrets load ai --shell nu | from nuon)
|
|
161
|
+
local bucket="ai" dialect="posix" data_file key value count=0
|
|
162
|
+
local -a keys=() values=()
|
|
163
|
+
while [[ $# -gt 0 ]]; do
|
|
164
|
+
case "$1" in
|
|
165
|
+
--shell)
|
|
166
|
+
dialect="${2:-posix}"
|
|
167
|
+
shift 2
|
|
168
|
+
;;
|
|
169
|
+
--shell=*)
|
|
170
|
+
dialect="${1#*=}"
|
|
171
|
+
shift
|
|
172
|
+
;;
|
|
173
|
+
-*) die "Unknown flag: $1 (usage: dot secrets load [<bucket>] [--shell posix|fish|nu])" ;;
|
|
174
|
+
*)
|
|
175
|
+
bucket="$1"
|
|
176
|
+
shift
|
|
177
|
+
;;
|
|
178
|
+
esac
|
|
179
|
+
done
|
|
180
|
+
|
|
156
181
|
data_file="$(dot_data_file)"
|
|
157
182
|
[[ -f "$data_file" ]] || die "Missing data file: $data_file"
|
|
158
183
|
|
|
159
184
|
while IFS= read -r key; do
|
|
160
185
|
value="$(dot_secrets_get "$key" || true)"
|
|
161
186
|
if [[ -n "$value" ]]; then
|
|
162
|
-
|
|
163
|
-
|
|
187
|
+
keys+=("$key")
|
|
188
|
+
values+=("$value")
|
|
164
189
|
count=$((count + 1))
|
|
165
190
|
fi
|
|
166
191
|
done < <(dot_secrets_bucket_keys "$data_file" "$bucket")
|
|
167
192
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
193
|
+
[[ "$count" -gt 0 ]] || die "No secrets loaded for bucket: $bucket"
|
|
194
|
+
|
|
195
|
+
local i k v esc
|
|
196
|
+
case "$dialect" in
|
|
197
|
+
posix | sh | bash | zsh)
|
|
198
|
+
for i in "${!keys[@]}"; do
|
|
199
|
+
printf 'export %s=%q\n' "${keys[$i]}" "${values[$i]}"
|
|
200
|
+
done
|
|
201
|
+
;;
|
|
202
|
+
fish)
|
|
203
|
+
for i in "${!keys[@]}"; do
|
|
204
|
+
v="${values[$i]}"
|
|
205
|
+
esc="${v//\\/\\\\}"
|
|
206
|
+
esc="${esc//\'/\\\'}" # fish single-quote escaping
|
|
207
|
+
printf "set -gx %s '%s'\n" "${keys[$i]}" "$esc"
|
|
208
|
+
done
|
|
209
|
+
;;
|
|
210
|
+
nu | nushell)
|
|
211
|
+
# Emit a NUON record for: load-env (dot secrets load <bucket> --shell nu | from nuon)
|
|
212
|
+
printf '{\n'
|
|
213
|
+
for i in "${!keys[@]}"; do
|
|
214
|
+
v="${values[$i]}"
|
|
215
|
+
esc="${v//\\/\\\\}"
|
|
216
|
+
esc="${esc//\"/\\\"}" # double-quote escaping
|
|
217
|
+
printf ' "%s": "%s"\n' "${keys[$i]}" "$esc"
|
|
218
|
+
done
|
|
219
|
+
printf '}\n'
|
|
220
|
+
;;
|
|
221
|
+
*)
|
|
222
|
+
die "Unknown shell dialect: $dialect (want: posix|fish|nu)"
|
|
223
|
+
;;
|
|
224
|
+
esac
|
|
171
225
|
}
|
|
172
226
|
|
|
173
227
|
cmd_secrets_load() {
|
|
174
|
-
cmd_env_load "
|
|
228
|
+
cmd_env_load "$@"
|
|
175
229
|
}
|
|
176
230
|
|
|
177
231
|
# Dispatch
|
|
@@ -40,6 +40,10 @@ cmd_usb_safety() {
|
|
|
40
40
|
run_script "scripts/security/usb-safety.sh" "USB safety script" "$@"
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
cmd_policy() {
|
|
44
|
+
run_script "scripts/security/enforce-policies.sh" "Policy enforcement script" "$@"
|
|
45
|
+
}
|
|
46
|
+
|
|
43
47
|
# Dispatch
|
|
44
48
|
case "${1:-}" in
|
|
45
49
|
backup)
|
|
@@ -70,6 +74,10 @@ case "${1:-}" in
|
|
|
70
74
|
shift
|
|
71
75
|
cmd_usb_safety "$@"
|
|
72
76
|
;;
|
|
77
|
+
policy)
|
|
78
|
+
shift
|
|
79
|
+
cmd_policy "$@"
|
|
80
|
+
;;
|
|
73
81
|
*)
|
|
74
82
|
echo "Unknown security command: ${1:-}" >&2
|
|
75
83
|
exit 1
|
|
@@ -126,7 +126,7 @@ function Invoke-DotHelp {
|
|
|
126
126
|
Write-Host ''
|
|
127
127
|
Write-Host " Version v$version"
|
|
128
128
|
Write-Host " Repo https://github.com/sebastienrousseau/dotfiles"
|
|
129
|
-
Write-Host " Docs https://github.com/sebastienrousseau/dotfiles/blob/
|
|
129
|
+
Write-Host " Docs https://github.com/sebastienrousseau/dotfiles/blob/main/docs/manual/"
|
|
130
130
|
Write-Host ''
|
|
131
131
|
Write-Host 'Native PowerShell commands (no bash required):'
|
|
132
132
|
Write-Host ''
|
|
@@ -141,6 +141,6 @@ if [[ $FAILED -eq 1 ]]; then
|
|
|
141
141
|
printf '%b\\n' " (Use --no-verify to bypass if absolutely necessary)"
|
|
142
142
|
exit 1
|
|
143
143
|
else
|
|
144
|
-
printf '%b\n' "${GREEN}${BOLD}✅ Audit passed.${NC} v0.2.
|
|
144
|
+
printf '%b\n' "${GREEN}${BOLD}✅ Audit passed.${NC} v0.2.510 standards maintained."
|
|
145
145
|
exit 0
|
|
146
146
|
fi
|