aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--.github/copilot-instructions.md4
-rw-r--r--etc/.ignore35
-rw-r--r--justfile42
-rwxr-xr-xrun_onchange_after_deploy-etc.sh.tmpl26
4 files changed, 86 insertions, 21 deletions
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index 44239ac..1e1b733 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -21,7 +21,7 @@ The repo root is a chezmoi source directory. Files targeting `$HOME` use chezmoi
- `bootstrap.sh` at the repo root is a POSIX shell script that takes a fresh minimal Arch install (only `base`) to a fully deployed state. It installs prerequisites, enables `%wheel` sudoers, bootstraps `paru-bin` from the AUR, clones the repo, runs `just init`, and optionally invokes `create-efi`. Designed to be curlable: `curl -fsSL .../bootstrap.sh | sh`.
- `.chezmoiignore` excludes non-home files (`etc/`, `meta/`, `systemd-units/`, `firefox/`, docs) from deployment to `$HOME`.
- `.githooks/` contains git hooks (notably `post-commit` which runs `chezmoi apply`). Activated by `just init`.
-- `justfile` provides recipes: `init` (first-time setup), `sync` (apply + fix), `apply`, `fix`, `status`, `pkg-drift`, `dotfile-drift`, `undeclared`, `diff`, `merge`, `groups`, `install`, `install-all`, `add`, `remove`, `services`, `services-enable`, `services-drift`. Run `just` or `just --list` to see them.
+- `justfile` provides recipes: `init` (first-time setup), `sync` (apply + fix), `apply`, `fix`, `status`, `pkg-drift`, `dotfile-drift`, `undeclared`, `diff`, `merge`, `groups`, `install`, `install-all`, `add`, `remove`, `services`, `services-enable`, `services-drift`, `etc-drift`. Run `just` or `just --list` to see them.
## Window manager
@@ -53,7 +53,7 @@ Additionally, `dot_config/sh/inputrc` provides readline config for non-zsh tools
When modifying configs, use chezmoi naming conventions: `dot_` prefix for dotfiles, `private_` for restricted-permission dirs/files, `executable_` for scripts. To add a new config file, use `chezmoi add <target-path>`.
-The `run_onchange_after_*` scripts are chezmoi templates (`.tmpl`) that embed `sha256sum` hashes of the files they deploy. Chezmoi only re-runs them when file content changes. When adding a new file to `etc/` or `firefox/`, you must add its hash comment and file path to the corresponding run script.
+The `run_onchange_after_*` scripts are chezmoi templates (`.tmpl`) that embed `sha256sum` hashes of the files they deploy. Chezmoi only re-runs them when file content changes. The `etc` deploy script auto-enumerates every file under `etc/` (single combined hash via chezmoi's `output` function + `find`); just drop new files into `etc/` and they'll be deployed on next `chezmoi apply`. The `firefox` deploy script still lists its files explicitly.
When editing shell config, all zsh configuration goes in `dot_config/zsh/` — do not create files in `dot_config/sh/` (only `inputrc` remains there).
diff --git a/etc/.ignore b/etc/.ignore
new file mode 100644
index 0000000..c15fb70
--- /dev/null
+++ b/etc/.ignore
@@ -0,0 +1,35 @@
+# Paths excluded from `just etc-drift` output.
+# Shell-glob patterns (case $path in $pat) work here: *, ?, [].
+
+# Per-host state / auto-generated
+/etc/machine-id
+/etc/adjtime
+/etc/.updated
+/etc/.pwd.lock
+/etc/mtab
+/etc/ld.so.cache
+
+# Per-host identity / secrets
+/etc/ssh/ssh_host_*
+/etc/shadow
+/etc/shadow-
+/etc/gshadow
+/etc/gshadow-
+/etc/passwd-
+/etc/group-
+
+# Regenerated by tools (not worth versioning)
+/etc/resolv.conf
+/etc/ssl/certs/*
+/etc/ca-certificates/extracted/*
+/etc/pacman.d/gnupg/*
+/etc/pacman.d/mirrorlist
+
+# Managed by useradd (podman uses them)
+/etc/subuid
+/etc/subgid
+/etc/subuid-
+/etc/subgid-
+
+# sbctl signed-boot state (keys live here; never commit)
+/etc/secureboot/*
diff --git a/justfile b/justfile
index 26058db..f73d4e5 100644
--- a/justfile
+++ b/justfile
@@ -179,6 +179,48 @@ services-drift:
# ═══════════════════════════════════════════════════════════════════
+# System config (/etc)
+# ═══════════════════════════════════════════════════════════════════
+
+# Show /etc drift: package configs modified from defaults, plus user-created files
+etc-drift:
+ #!/usr/bin/env bash
+ set -eo pipefail
+ tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT
+
+ find etc -type f ! -name .ignore 2>/dev/null \
+ | sed 's|^etc/|/etc/|' | sort -u > "$tmp/managed"
+
+ patterns=()
+ if [ -f etc/.ignore ]; then
+ while IFS= read -r line; do
+ [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
+ patterns+=("$line")
+ done < etc/.ignore
+ fi
+
+ keep() {
+ local path=$1
+ grep -qxF "$path" "$tmp/managed" && return 1
+ for pat in ${patterns[@]+"${patterns[@]}"}; do
+ [[ "$path" == $pat ]] && return 1
+ done
+ return 0
+ }
+
+ echo "=== /etc drift ==="
+ echo "--- modified package configs ---"
+ pacman -Qii 2>/dev/null | grep -oP 'MODIFIED\t\K/\S+' | sort -u \
+ | while IFS= read -r p; do keep "$p" && echo " modified: $p"; done
+
+ echo "--- user-created (no owning package) ---"
+ find /etc -xdev -type f -print0 2>/dev/null \
+ | xargs -0 pacman -Qo 2>&1 >/dev/null \
+ | sed -n 's/^error: No package owns //p' | sort -u \
+ | while IFS= read -r p; do keep "$p" && echo " unowned: $p"; done
+
+
+# ═══════════════════════════════════════════════════════════════════
# Package management
# ═══════════════════════════════════════════════════════════════════
diff --git a/run_onchange_after_deploy-etc.sh.tmpl b/run_onchange_after_deploy-etc.sh.tmpl
index 225ceac..04f72c1 100755
--- a/run_onchange_after_deploy-etc.sh.tmpl
+++ b/run_onchange_after_deploy-etc.sh.tmpl
@@ -1,26 +1,14 @@
#!/bin/sh
-# Deploy system-level configs from etc/ to /etc/
-# chezmoi re-runs this script when any hash below changes.
-# {{ include "etc/doas.conf" | sha256sum }}
-# {{ include "etc/modules-load.d/tcp_bbr.conf" | sha256sum }}
-# {{ include "etc/pacman.d/hooks/orphans.hook" | sha256sum }}
-# {{ include "etc/sysctl.d/99-sysctl.conf" | sha256sum }}
-# {{ include "etc/systemd/system.conf.d/timeout.conf" | sha256sum }}
-# {{ include "etc/xdg/reflector/reflector.conf" | sha256sum }}
+# Deploy system-level configs from etc/ to /etc/.
+# chezmoi re-runs this script whenever any file under etc/ changes.
+# etc/ content hash: {{ output "sh" "-c" (printf "cd %q && find etc -type f ! -name .ignore -exec sha256sum {} + | LC_ALL=C sort" .chezmoi.sourceDir) | sha256sum }}
set -eu
-for f in \
- doas.conf \
- modules-load.d/tcp_bbr.conf \
- pacman.d/hooks/orphans.hook \
- sysctl.d/99-sysctl.conf \
- systemd/system.conf.d/timeout.conf \
- xdg/reflector/reflector.conf
-do
- doas mkdir -p "/etc/$(dirname "$f")"
- doas cp --remove-destination "$CHEZMOI_SOURCE_DIR/etc/$f" "/etc/$f"
+cd "$CHEZMOI_SOURCE_DIR"
+find etc -type f ! -name .ignore | while IFS= read -r src; do
+ dest="/${src}"
+ doas install -D -m 0644 -o root -g root "$src" "$dest"
done
# doas refuses to parse /etc/doas.conf unless it's 0400 root:root
-doas chown root:root /etc/doas.conf
doas chmod 0400 /etc/doas.conf