| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The previous fix sidestepped sudo-rs's env scrubbing by setting
DIFFPROG inside a nested root shell. That works but it's the wrong
shape — every command that wants to honour a user UX env var would
have to do the same dance. Configure the policy once instead.
etc/sudoers-rs:
Defaults env_keep += "DIFFPROG"
Defaults env_keep += "EDITOR VISUAL SUDO_EDITOR GIT_EDITOR"
Defaults env_keep += "PAGER MANPAGER GIT_PAGER SYSTEMD_PAGER"
Defaults env_keep += "LESS LESSOPEN SYSTEMD_LESS"
env_keep is the unconditional pass-through list, so no '-E' is needed
on the call site — `DIFFPROG='nvim -d' sudo pacdiff` Just Works, same
as it does for `EDITOR=nvim sudo systemctl edit foo`,
`PAGER=less sudo journalctl …`, etc. None of these vars influence
privilege boundaries; they only configure user-facing program
behaviour, so widening env_keep to cover them carries no security
trade-off worth accounting for. The existing per-visudo env_keep
lines are kept for documentation value (they're now subsumed by the
global rule but make the intent explicit at the visudo call sites).
The waybar pacdiff click handler reverts to the canonical form
`DIFFPROG='nvim -d' sudo pacdiff`, matching the recipe pacman.git
ships in /usr/share/doc/pacman/.
Will take effect after the next `chezmoi apply` redeploys
/etc/sudoers-rs (the run_onchange_after_deploy-etc.sh.tmpl script
re-installs it with mode 0440 whenever its hash changes).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Wiring (mirrors arch-audit, with weekly cadence and Nice=19/idle I/O):
lostfiles.timer (weekly, Persistent=true, RandomizedDelaySec=1h)
→ lostfiles.service
→ /run/lostfiles.txt (default mode — strict produces too many
false positives for a passive reminder)
→ custom/lostfiles waybar module (interval 600s)
→ mako 'normal' once/7d while count > 0
→ on-click: `ghostty -e nvim -R /run/lostfiles.txt`
Default mode (no `strict` argument) is intentional: it already filters
the package's curated false-positive list at /etc/lostfiles.conf, which
is what we want for a low-noise weekly nudge. Switching to `strict` is
a one-line change in lostfiles.service if signal-vs-noise tilts later.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Wiring:
arch-audit.timer (daily, RandomizedDelaySec=1h, Persistent=true)
→ arch-audit.service (After=network-online.target)
→ /run/arch-audit.txt ('--upgradable' output, atomic via .tmp+mv)
→ custom/arch-audit waybar module (interval 300s)
→ mako 'critical' once/24h while count > 0
→ on-click: `ghostty -e nvim -R /run/arch-audit.txt`
The bar entry stays hidden when there are no fixable CVEs, fades in as
red 'CVE N' the moment arch-audit finds at least one, and the throttled
mako means you'll see exactly one notification per day instead of one
per waybar poll. No -Sy refresh and no auto-update — this only reports
the gap between what's installed and what's already in the repos.
Why /run and not the user's runtime dir: the producer is a system unit
(needs the system's pacman db on the network-online path), the consumer
is a user-scope waybar that just reads it; /run is the canonical 'fast,
volatile, world-readable' system-tmpfs and survives the reboot cycle in
exactly the way we want — fresh empty file on every boot, repopulated
on the next timer fire.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Template service+timer that runs `btrfs balance start -dusage=50
-musage=50 %f` once a month on the instance's mount path. Mirrors the
shape of the stock btrfs-scrub@.{service,timer} so the operational
model is identical: enable btrfs-balance@-.timer for /, btrfs-balance@\
x2dhome.timer for /home, etc.
Why a partial balance and not a full one: full `btrfs balance start`
rewrites every block group, which on a multi-TB volume takes hours and
can chew through enormous amounts of CSUM/free-space-tree work.
`-dusage=50 -musage=50` only consolidates block groups that are less
than half full, which is exactly the operation that reclaims space
'lost' to fragmentation after lots of small writes — the only practical
reason a healthy single-disk btrfs needs balancing at all.
`Nice=19 IOSchedulingClass=idle` keeps it out of the way of foreground
work; `KillSignal=SIGINT` (same as btrfs-scrub) lets a graceful Ctrl-C
checkpoint the operation cleanly. Persistent=true catches the run on
next boot if the machine was off when the timer fired.
Enabled in systemd-units/system.txt as btrfs-balance@-.timer (root
volume only — /home isn't a separate subvolume on this machine).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
waybar:
- cpu / custom/memory: on-click opens floating ghostty with htop
- new custom/vpn module between custom/memory and network#bond:
shows 'VPN' coloured by interface UP flag (green up, dim down);
on-click toggles networkctl up/down hodor; SIGRTMIN+8 used for
instant refresh after toggle
sway:
- Super+Shift+Return -> ghostty -e yazi
- Super+Shift+b -> librewolf
vpn-toggle.sh runs networkctl (no sudo) thanks to a new polkit rule
allowing wheel-group members to invoke org.freedesktop.network1.*
without a password prompt. systemd-networkd's polkit gate is a
separate path from sudoers, so this is the idiomatic fix.
KEYBINDS.md updated for both new sway bindings.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The Shokz dongle emits KEY_POWER press without a matching release on
USB disconnect; logind classified that as a long-press after 5s and
fired HandlePowerKeyLongPress=poweroff (confirmed in journal: 'Power
key pressed long. Powering off...').
There is no policy that distinguishes 'real 5s hold of power button'
from 'misbehaving device that never sends release'. Ignore both.
Clean shutdowns now require systemctl poweroff or GUI menus; a very
long hold of the physical power button still force-offs via firmware.
|
| |
|
|
|
|
| |
The drop-in is generic policy, not tied to one device. Reword the
comment to reflect that any USB device emitting spurious KEY_POWER
(headsets, KVM switches, cheap keyboards) is covered.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Shokz OpenMeet dongle (3511:2EF2) emits KEY_POWER on USB
enumeration and on headset power transitions, which logind handles
with HandlePowerKey=poweroff and immediately shuts the host down.
The previous attempt — an hwdb scancode remap of c0030 to reserved —
sets the udev property correctly but the kernel does not honor
EVIOCSKEYCODE for this device's HID consumer-page mapping (verified:
KEY_POWER 116 still appears in the evdev keymap after udevadm trigger
and libinput still reports it). Drop the hwdb file and the
systemd-hwdb hooks from the etc deploy script.
Replace with a logind drop-in that sets HandlePowerKey=ignore and
HandlePowerKeyLongPress=poweroff. Single-tap power events from any
source become no-ops; a 5s hold still shuts the machine down, so the
real hardware-power-button safety net is preserved. Add a HUP to
systemd-logind in the deploy script so the change takes effect
without restarting the daemon.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The previous /etc/udev/rules.d/80-shokz-blacklist.rules deauthorized the
entire usbhid interface for the Shokz OpenMeet dongle (3511:2EF2) to stop
the host from powering off when the headset is turned off. That also
killed mic-mute, volume, and media keys on the same HID Consumer Control
node.
Replace it with a narrow hwdb override that remaps just the offending
scancode (Consumer page Power, c0030 -> KEY_POWER) to reserved on that
specific vendor/product. KEY_MUTE / volume / media keys keep working.
Add 'systemd-hwdb update' + an input-subsystem udevadm trigger to the
etc deploy hook so new hwdb files take effect immediately.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
AssumeInstalled is only a CLI flag (--assume-installed), not a
pacman.conf directive. The line I added was emitting a warning at
every pacman run and didn't actually keep base-devel from pulling
sudo.
Live with sudo installed: /usr/local/bin/sudo (-> sudo-rs) shadows
it via PATH precedence, so the /usr/bin/sudo binary is dead code
on disk. The alternative — maintaining a dummy 'provides=sudo'
package — is more cost than the ~1.5 MB it would save.
Update bootstrap.sh comment to reflect that sudo stays installed.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
base-devel hard-depends on the sudo package, so without help, pacman
refuses to remove it. The Arch-native fix is pacman.conf's
AssumeInstalled directive: tell pacman to pretend a virtual
sudo=99.0 is installed and base-devel's dep is satisfied without
actually pulling sudo in.
- etc/pacman.conf: AssumeInstalled = sudo=99.0
- bootstrap.sh: after 'just init' (which writes the AssumeInstalled
line and installs sudo-rs), Rns the leftover sudo package so a
fresh install ends up with sudo-rs only.
Also reformat bootstrap.sh and the etc deploy script with the
project's shfmt style (-i 2 -ci -s).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
doas's one-shot password and absent 'sudo -v' kept wasting hour-long
paru AUR builds. sudo-rs is a memory-safe Rust rewrite (ISRG/Ferrous
Systems), drop-in CLI compatible, and the same one Ubuntu 25.10 ships
as default. We follow the Arch wiki 'Using sudo-rs without the sudo
package' recipe verbatim — no custom shims.
- meta/base.txt: -doas-sudo-shim +sudo-rs
- etc/sudoers-rs (mode 0440): wiki minimal config + NOPASSWD reboot/poweroff
- etc/pam.d/sudo: 4-line copy of upstream sudo's PAM file
- run_onchange_after_deploy-etc.sh.tmpl: use real sudo, deploy sudoers-rs
at 0440, create /etc/pam.d/sudo-i and /usr/local/bin/{sudo,sudoedit,
su,visudo} → sudo-rs symlinks idempotently
- delete etc/doas.conf, dot_local/bin/{doasedit,sudo}
- zshrc: drop sudo=doas/sudoedit=doasedit aliases; rewrite ss/gimme/
pacdiff/ssys to call sudo
- justfile: s/doas/sudo/g (status/diff/restore helpers)
- nvim: rename :DoasWrite → :SudoWrite (uses sudo -S)
- sway config: reboot/poweroff buttons call sudo
- bootstrap.sh: update step-5 comment
- README/KEYBINDS/copilot-instructions: flip the privesc convention
No Defaults overrides: sudo's defaults (passwd_tries=3,
timestamp_timeout=5) already fix the doas pain, and paru SudoLoop
(kept) refreshes the 5-min window via real sudo -v.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Install Nix (multi-user daemon) on Arch and wire up direnv so any project
can declare its toolchain in a flake.nix and get a hermetic dev shell on
cd. No NixOS, no home-manager, no migration off paru/chezmoi — just one
new package manager scoped to project dev shells.
- meta/nix.txt: nix from extra repo
- meta/dev.txt: direnv (general-purpose, not nix-specific)
- systemd-units/system/nix.txt: nix-daemon.socket (socket-activated)
- etc/nix/nix.conf: enable flakes + nix-command, trusted-users=@wheel,
auto-optimise-store, keep-outputs/derivations so direnv envs survive GC
- dot_config/direnv/direnvrc: load nix-direnv 3.1.1 via source_url with
pinned sha256 (not packaged for Arch; refusing -git AUR)
- dot_config/nix/templates/{flake.nix,dev/}: flake template usable via
'nix flake init -t ~/.config/nix/templates'
- dot_config/zsh/dot_zshrc: 'eval "$(direnv hook zsh)"'
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Default-deny inbound, allow outbound. Scoped to 'inet filter' with
'destroy table' on reload so podman/netavark tables are preserved.
- meta/base.txt: add nftables
- systemd-units/system/base.txt: enable nftables.service
- etc/nftables.conf: laptop ruleset (loopback, ct state, ICMP/ICMPv6
essentials, DHCPv6 client, default-drop input/forward, accept output)
- etc/sysctl.d/99-sysctl.conf: rp_filter=2, no redirects, no source-route,
log_martians
- README.md: firewall section with reload caveat
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The old etc-status scanned all of /etc (pacman -Qkk for modified
backup configs, then 'find /etc | xargs pacman -Qo' for unowned
files), producing a discovery report of things we might want to
track. That was useful when seeding the repo but is slow and
misaligned with dotfiles-status, which only reports drift on files
chezmoi already manages.
Rewrite etc-status to mirror that model: iterate etc/, render .tmpl
sources, and cmp against the live /etc file. Report 'modified' or
'missing' per tracked path. Runs in under a second and matches the
semantics of 'just status'.
Drop the now-unused etc/.ignore and update README.
|
| |
|
|
|
|
|
| |
lsblk without -d lists the partition AND its children, so on a LUKS
setup the second line (the mapper's UUID) was leaking into the
rendered cmdline and deploy script. Add -d so only the partition's
own UUID is emitted.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Prompt once at 'chezmoi init' time for the LUKS root partition (e.g.
nvme0n1p2) and store it under [data].luksRootPartition in the per-machine
chezmoi config. etc/kernel/cmdline.tmpl resolves the UUID at apply time
via lsblk, so reinstalls only require re-entering the partition name.
The etc deploy script now renders *.tmpl sources through
'chezmoi execute-template' and installs them without the suffix. The
resolved UUID is folded into the onchange hash so the script re-runs
when the UUID changes even if etc/ content is unchanged.
just etc-status/diff transparently handle .tmpl sources (strip suffix
for the live-path mapping, render before diffing). etc-re-add skips
.tmpl files since template sources can't be reverse-rendered from the
live file.
|
| |
|
|
|
| |
setterm only affects the Linux console (TERM=linux); sway's KMS/DRM
session is unaffected. Wakes on any keypress.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
- New dot_config/systemd/user/swayidle.service, pulled in by
sway-session.target alongside mako/display-watcher/poweralertd. Same
lifetime as the rest of the session: starts after graphical-session,
restarts on failure, stops on logout.
- Drop the swayidle exec from sway config (was unmanaged background
process with no restart, no logging hookup).
- Revert etc/systemd/logind.conf overrides: swayidle handles idle-lock
directly via Wayland ext-idle-notifier, so the logind IdleAction
belt-and-suspenders is redundant. Run just etc-reset
/etc/systemd/logind.conf on the host to restore pristine.
|
| |
|
|
|
|
|
|
|
|
|
| |
- logind: IdleAction=lock, IdleActionSec=5min. systemd emits a lock
signal at 5min idle (session becomes locked from logind PoV; swayidle
listens and invokes swaylock).
- swayidle: lock at 5min, blank display at 6min, lock before sleep.
Closes the gap where lid-close or manual suspend would wake to an
unlocked session.
- swaylock: add -i (--ignore-empty-password) to ignore accidental Enter.
- meta/wayland: add swayidle.
|
| |
|
|
|
|
| |
Arch already ships systemd-based HOOKS as default; only add sd-encrypt.
keymap is redundant with sd-vconsole but harmless, and keeping it
minimizes diff from upstream (one word changed).
|
| |
|
|
|
|
|
|
|
| |
Prerequisite for TPM2 LUKS unlock. systemd-cryptenroll stores TPM hints
in LUKS2 token metadata, so no cmdline options are needed beyond
rd.luks.name (sd-encrypt auto-discovers enrolled tokens).
After chezmoi apply: sudo mkinitcpio -P && sudo sbctl verify, then
reboot. Passphrase still works; TPM enrollment is a separate step.
|
| |
|
|
|
|
| |
Only CriticalPowerAction=PowerOff is a behaviorally meaningful change
vs pristine. Percentage tweaks (15/7/3 vs 20/5/2) are not worth the
drift.
|
| |
|
|
|
|
|
| |
- Drop ES/PT from country list (always-on VPN exits in Zurich; Iberian
mirrors are slow through that path).
- Replace --latest 5 + --sort age with --age 12 + --fastest 10 +
--threads 5 (real throughput benchmark over 5 parallel probes).
|
| |
|
|
|
| |
No behavior change; only the four overrides (PercentageLow/Critical/
Action, CriticalPowerAction=PowerOff) differ from upstream defaults.
|
| |
|
|
|
|
| |
Single-user laptop behind FDE with key-only SSH means local brute
force is not a realistic threat. Tight defaults (3 attempts, 10min
lock) mainly punish typos.
|
| |
|
|
|
|
| |
User scopes (e.g. ghostty surface containing zellij) inherit timeouts
from the user manager, not /etc/systemd/system.conf.d. Without this,
zellij sessions stall reboot for 90s before SIGKILL.
|
| |
|
|
|
|
|
| |
Replace sway exec launches with a sway-session.target that BindsTo
graphical-session.target and Wants mako, poweralertd, and a new
display-watcher.service. Services now get restart-on-failure, journal
integration, and clean shutdown when sway exits.
|
| |
|
|
|
|
|
| |
Track /etc/kernel/cmdline and enable default_uki/fallback_uki in
linux.preset. Remove create-efi helper (UKI is self-contained; only
needed once at install time). Update bootstrap to print the one-off
efibootmgr command instead of launching create-efi.
|
| |
|
|
|
| |
Cap at 8 GiB, zstd compression. Tune VM for RAM-backed swap:
high swappiness, no read-ahead clustering.
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
| |
All 44 lines are comments/section headers — zero active settings.
Tracking was useless: no real state to preserve, and 'just etc'
would surface any future drift anyway.
The live /etc/systemd/resolved.conf on the host is unaffected;
chezmoi's deploy-etc script only installs files, never removes.
|
| |
|
|
|
|
|
| |
Type=ether and Type=wlan match every interface of that class.
Add comments pointing out that future USB/Thunderbolt dongles
would get auto-enslaved into bond0, and how to narrow the match
if that becomes undesirable.
|
| |
|
|
|
|
|
| |
Having only the 'default' preset means no safety net if the main
initramfs ever fails to boot (broken firmware update, microcode
regression, hook misconfig). The fallback image is ~40 MB and
regenerates with every kernel update — cheap insurance.
|
| |
|
|
|
|
|
|
| |
Pristine /etc/xdg/reflector/reflector.conf sets '--protocol https'.
Dropping it reverts to reflector's permissive default (http, https,
rsync, ftp), which could let non-HTTPS mirrors into the mirrorlist.
Also drop '--completion-percent 100' — that's reflector's default.
|
| |
|
|
|
|
|
| |
Adopted via 'just etc-add' after 'just etc-drift' surfaced them:
locale.conf, locale.gen, mkinitcpio.conf, mkinitcpio.d/linux.preset,
pacman.conf, resolved.conf, systemd/network/30-bond*, and the shokz
udev blacklist rule.
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
- etc-diff: diff repo-managed etc/<path> vs live /etc (defaults to all)
- etc-upstream-diff: diff live /etc vs pristine pacman archive
(defaults to pacman -Qkk modified set)
- etc-add: copy /etc/<path> into the repo's etc/ tree
- etc-reset: restore pristine via bsdtar -xpf, or rm if unowned;
refuses managed paths without --force
- ignore /etc/fstab (host-specific UUIDs/layout)
- path-traversal guards on all recipe inputs
- regular-file-only enforcement (no symlinks/dirs)
- fail-fast with clear message if mirror can't supply installed version
|
| |
|
|
|
|
|
|
|
| |
Pacman emits lines like "backup file: <pkg>: <path> (<reason>)", not the
"(Modified backup file)" suffix format. Anchor the path extraction to
/etc/ to avoid catching stderr warnings interleaved into a line.
Also extend etc/.ignore with /etc/{passwd,group,shells} — system-managed
identity files that surfaced in the new drift output.
|
| | |
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
| |
- `just etc-drift` reports /etc files modified from pacman defaults
(via pacman -Qii) and user-created files (via pacman -Qo), subtracting
already-managed paths and patterns listed in etc/.ignore.
- Refactor run_onchange_after_deploy-etc.sh.tmpl to enumerate files under
etc/ automatically via find; single combined hash via chezmoi output +
sha256sum, so new files only need to be dropped into etc/.
- etc/.ignore seeds noise filters: machine-id, ssh host keys, pacman
keyring, mirrorlist, shadow/passwd backups, sbctl keys, ca-certs.
|
| | |
|
| |
|
|
|
| |
Added to the etc/ deploy loop plus a post-copy chown/chmod to 0400
root:root since doas refuses to parse otherwise.
|
| |
|
|
|
|
|
|
| |
- etc2/ only existed because stow used symlinks and reflector refused
them. Chezmoi copies files, so no reason to keep them separate.
- Run scripts are now .tmpl files with sha256sum hashes of deployed
files. chezmoi only re-runs them when file content actually changes,
avoiding unnecessary doas prompts on every apply.
|
| |
|
|
|
| |
- orphans.hook: remove commented-out alternative Exec line
- reflector.conf: strip comment bloat, keep only active settings
|
| | |
|
| |
|