Commit Graph
2796 Commits
Author SHA1 Message Date
Ryan Yin 7dc4e7a39f feat(security): harden homelab SSH, services and audit trail
The homelab hosts accept root SSH with long-lived file keys, run several
exposed services with almost no systemd sandboxing, and keep no audit trail of
privileged actions. Close those three gaps, weighing each measure against its
cost instead of adopting a policy wholesale.

SSH
- Turn off KbdInteractiveAuthentication: nixpkgs defaults it to true and PAM
  then still accepts the Unix password despite PasswordAuthentication = false.
- authorizedKeysInHomedir = false: only keys declared in Nix take effect;
  youko keeps Gitea's forced-command file through `Match User gitea`.
- Pin aquamarine's passphrase-free remote-builder keys to
  `restrict,command="nix-daemon --stdio --store daemon"`, so builds run in the
  system daemon instead of an audited root login session.

systemd sandboxing
- Add the mylib.systemdHardening preset and apply it to the exposed, weakly
  sandboxed services: caddy 7.8 -> 1.5, vmalert 8.2 -> 1.4, rustfs 6.6 -> 1.4,
  whisper-asr 7.7 -> 1.6. An eval test pins the key restrictions.
- Rejected: a global all-keys policy (<=0.2 score gains on services nixpkgs
  already sandboxes) and per-service confinement (bind paths to maintain).

auditd on all four hosts, reusing nixpkgs' loader and unit
- Audit login sessions only: a first `-a never,task -F auid=unset` rule keeps
  services out of the per-syscall audit path. A compromised service is
  therefore unrecorded until it opens a session.
- Record root commands, credential and host-key access, writes to SSH, account,
  PAM, Nix-trust and audit configuration, module loads and session denials.
- Rejected: global denial logging, service-UID watches and
  --loginuid-immutable (the kernel already records loginuid changes).

Verified on all four hosts after deployment: zero failed units, k3s 6/6 Ready,
and the exposed services healthy.

Assisted-by: Claude Code (claude-opus-5-5)
2026-10-31 01:09:15 +08:00
Ryan Yin 0376697cef docs(agents): record why rules omit principle names 2026-10-30 18:59:09 +08:00
Ryan Yin def7d8f754 feat(niri): enable on-demand VRR for games
Turn on adaptive sync at the output only when a game window opts in, keeping desktop compositing fixed-rate to avoid idle/low-load VRR flicker. The Steam/Proton game rule enables VRR alongside the fullscreen rule.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-30 00:47:51 +08:00
Ryan Yin 005627d883 fix(niri): let untitled Proton windows go fullscreen
XWayland/Proton windows can commit before they set a title. Excluding empty titles made Phantom Blade Zero miss the fullscreen rule and stay composited. Keep excluding the launcher announcement popup by title.

VRR is intentionally not enabled here: on-demand VRR caused display corruption in this game and is tracked separately.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-30 00:46:22 +08:00
ryan4yin | 二花 e8e9691f2d chore(nix): update nixpkgs to e62746b and refresh flake inputs (#488)
* chore(nix): update nixpkgs to e62746b and fix 26.11 breakage

Bump nixpkgs to e62746b and preservation to 00be7f7, then adapt to the removals and renamed options in the new revision: drop the removed boot.initrd.systemd.enable settings, trim the stale emSign CA blacklist on Linux while keeping it for the older Darwin input, and migrate Avahi publishing to settings.publish. Work around sunshine still setting the legacy Avahi options and keep dsh-nu on its tested Nushell 0.115.1. Patch NUR dsh's pnpm call to pass nodejs = null, and update pyclipsync for the stdenv.hostPlatform.system rename.

* chore(nix): refresh flake inputs for 26.11

- update nixpkgs-darwin to the same e62746b revision as nixpkgs
- make dsh-nu follow main nixpkgs and patch its testedWith manifest for the resolved Nushell
- refresh floating inputs; update lanzaboote, tuios, and ponytail
- drop the nixpkgs-2505 and rust-overlay workarounds
- keep pyclipsync on main and simplify the cross-platform CA blacklist
- adopt home-manager's Nushell loadSessionVariables default

* fix(gitea): use ROOT_URL for nixpkgs 26.11

nixpkgs removed the legacy settings.server.DOMAIN option; the existing ROOT_URL already carries the public URL.

* chore(nix): update dsh-nu to 0.7.0

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-30 00:39:01 +08:00
Ryan Yin 4fcdb79719 docs(agents): answer challenges before continuing work
A user question or challenge is the current task; resolve it before doing unrelated work.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-29 21:40:46 +08:00
Ryan Yin ba1515f094 docs(agents): ask for SSH access instead of falling back
A missing GitHub SSH key is a credential boundary, not a reason to switch transports silently.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-29 21:39:16 +08:00
Ryan Yin 13afe01441 docs(agents): prefer upstream fixes over local workarounds
Clarify that minimality means the smallest best-practice change, not a local patch around an upstream defect.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-29 21:37:41 +08:00
Ryan Yin 7e579d6aca fix(monitoring): order nvidia exporter after network-online
The nvidia exporter binds the host's static LAN IPv4, but unlike the node and smartctl exporters it was not ordered after network-online.target. On boot it lost the race with networkd, hit the systemd start limit, and stayed failed until manually restarted.
2026-10-29 21:28:08 +08:00
Ryan Yin 01d2e76410 chore(secrets): refresh mysecrets and follow agenix-rules rename
Update the mysecrets lock to 7f93490, which renames secrets.nix to agenix-rules.nix, drops the deprecated ./ key prefixes for agenix 0.18, and re-encrypts the access-token secret. Update the docs and agenix skill to the new filename and path convention.
2026-10-29 21:28:08 +08:00
Ryan Yin 38d1d85e85 feat(home): re-add gitleaks
Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-29 17:04:39 +08:00
Ryan Yin 8a6cc86664 docs(agents): stop on credential failure
Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-29 15:55:30 +08:00
Ryan Yin add8ad9796 chore(home): remove VS Code 2026-10-28 13:51:16 +08:00
Ryan Yin bd41cca5c6 fix(grafana): correct alertmanager dashboard description typo 2026-10-28 13:51:16 +08:00
Ryan Yin b334336cd9 feat: idols-ai - persistent ~/models 2026-10-24 17:16:20 +08:00
Ryan Yin c562f47049 docs(workarounds): drop WA-043 now that the bootstrap fix is live
k8s-gitops#54 merged and reconciled, a full cold start of all six guests
brought the VIP back without manual action, and a probe from a pod shows
2379 denied while 2381 stays open. SECURITY.md records the fix and the
probe; the workaround row and its TODO entry are gone.

Assisted-by: DeepSeek Harness (gpt-6-astra)
2026-10-24 14:26:53 +08:00
Ryan Yin 8affae69d6 docs(security): record the 2026-10-22 audit follow-up and WA-043
Baseline sysctls, exporter binds and the #399/#400/#401 rules verified
live on 13 hosts; kiali self-escalation and the list-vs-get probe blind
spot recorded; WA-043 registers the k3s-test-1 Cilium/kube-vip bootstrap
cycle (WA-040 is the Root CA blacklist row); the TODO table gains the
cluster-recovery line. The same section records the manual recovery and
its fix in k8s-gitops, plus the 2026-10-24 full cold start that brought
the VIP back without manual action; WA-043 drops when #54 merges.

Assisted-by: DeepSeek Harness (gpt-6-astra)
2026-10-24 14:16:14 +08:00
Ryan Yin 5088535ac3 fix(ai): bind the nvidia GPU exporter to the static LAN IPv4
The 2026-10-22 audit found the live socket on *:9835: #373 bound
node/smartctl in monitoring.nix, but the nvidia exporter enabled in
hardware-nvidia.nix kept the nixpkgs default, so the socket-level
defence-in-depth layer never existed for 9835.

Extend the security-exporters eval check to every enabled exporter's
listenAddress so a future exporter without a bind fails the test.

Assisted-by: DeepSeek Harness (gpt-6-astra)
2026-10-24 14:16:14 +08:00
Ryan Yin d4aa25d368 fix(k3s): deny pod sources the etcd client port 2379
The etcd client API listens on the masters' static LAN address, and the
pod-source deny lists omitted it. Add 2379 to both nft drop lines and
assert it in the security-k3s-pod-firewall eval test. 2381 (etcd
metrics, scraped by in-cluster monitoring) stays reachable by design.

Pairs with the matching Cilium egressDeny port in k8s-gitops.

Assisted-by: DeepSeek Harness (gpt-6-astra)
2026-10-24 14:16:14 +08:00
Ryan Yin f564807ac5 fix(preservation): persist OpenRGB settings and profiles
Assisted-by: DeepSeek Harness (gpt-6-astra)
2026-10-23 11:29:45 +08:00
Ryan Yin cfafc94666 chore(modules): drop the riscv64 module, which belongs to nixos-config-sbc
Nothing imported it and the riscv64 output was already commented out; riscv64 hosts live in ryan4yin/nixos-config-sbc.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-22 00:54:27 +08:00
Ryan Yin cf34f52af0 flake.lock: Update
Flake lock file updates:

• Updated input 'dsh-nu':
    'github:ryan4yin/dsh-nu/c7c0b2ca8fcd6fd5791823d6ed2a8f37e817b275?narHash=sha256-Ua5VKHzb7iobq%2B6P7Q8t/2U8t%2BheFmdXl5zIQB4hJGI%3D' (2026-10-21)
  → 'github:ryan4yin/dsh-nu/405e24541f8ea1c99bde545689e3d22819efe4ac?narHash=sha256-K95TJliFJrD3ssB9jMEqEQ3R7qJtK5wd6tK9oy5ZZ9E%3D' (2026-10-21)
2026-10-22 00:54:27 +08:00
Ryan Yin 75a98e5f66 docs(agents): say that pushes need authorization
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-22 00:54:27 +08:00
Ryan Yin b5a6a5e81b chore(home): drop a duplicate fzf and a no-op gpg setting
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-22 00:54:27 +08:00
Ryan Yin d421a89bd9 fix(tailscale): drop a duplicate CLI install and a stale comment
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-22 00:54:27 +08:00
Ryan Yin 267ccd9d34 fix(firewall): note the one port that is open to the Internet
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-22 00:54:27 +08:00
Ryan Yin 6dea887202 fix(home): open tg: links with the Telegram desktop entry
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-22 00:54:27 +08:00
Ryan Yin 9b68cfdb8a feat(backup): alert when the last successful backup goes stale
The backup unit publishes `restic_backup_last_success_timestamp_seconds` for the node_exporter textfile collector, and a rejected alert now fails the notify unit instead of exiting 0.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-22 00:54:27 +08:00
Ryan Yin d2b11840d0 flake.lock: Update dsh-nu to 0.6.0
Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-21 22:56:37 +08:00
ryan4yin | 二花 4e78fd964a fix(outputs): keep microvm-guest-parity from forcing guest config (#484)
Reading the host's install script evaluated each guest, which pulls the private secrets input, so
CI could not evaluate the suite at all.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-21 21:49:07 +08:00
ryan4yin | 二花 de6a66ccd4 fix(microvm): run k3s guests from their nixosConfigurations entry (#483)
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (claude-opus-5-5)
2026-10-21 21:32:56 +08:00
ryan4yin | 二花 41f6db32ed docs(workarounds): record the Colmena version override (#482)
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (claude-opus-5-5)
2026-10-21 21:13:52 +08:00
Ryan Yin 1324131c6d docs: correct statements that no longer match the configuration
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (claude-opus-5-5)
2026-10-21 20:59:07 +08:00
Ryan Yin a3c75250c4 fix(restic): catch up backups missed while a host was off
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (claude-opus-5-5)
2026-10-21 20:59:07 +08:00
Ryan Yin 92f59df25a fix(youko): date restic store snapshots by name, not mtime
On its next run the unit deletes every snapshot whose name stamp is older than 14 days, whatever
its mtime.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (claude-opus-5-5)
2026-10-21 20:59:07 +08:00
Ryan Yin 3b3992468b fix(colmena): deploy the systems nixosConfigurations evaluates
Colmena deployments now ship the same toplevel as nixosConfigurations: nodes gain the nixpkgs
registry, nixPath and dated version, and akane no longer gets the x86_64 dsh.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (claude-opus-5-5)
2026-10-21 20:59:07 +08:00
ryan4yin | 二花 9a3cf189cd fix(hypridle): keep displays awake during gamepad use (#480)
Assisted-by: DeepSeek Harness (gpt-6-astra)
2026-10-21 16:17:59 +08:00
Ryan Yin a8d47e30cf fix(ai): pin the 4K monitor at 144 Hz and record the OSD wake workaround
The DPMS wake failure is the monitor no-signal auto power-off (HPD cycling during idle), not the refresh rate: the 120 Hz pin did not fix it. Disabled in the OSD and recorded as WA-041; pin 144.000 explicitly so niri stops silently falling back.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-21 13:56:01 +08:00
Ryan Yin 169a87f3b9 fix(ai): pin the 4K monitor to its real 120 Hz mode
The 4090 reports the panel 120 Hz mode as 119.880, not 120, so niri fell back to 144 Hz; that DSC link stays dark after a DPMS wake.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-21 12:03:40 +08:00
ryan4yin | 二花 0dcf547d1f fix(pki): distrust roots with compromised eMudhra intermediates (#479)
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (gpt-6.1-sol)
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-20 23:49:52 +08:00
ryan4yin | 二花 274590df63 feat(aquamarine): track linuxPackages_latest (#478)
Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-20 23:12:37 +08:00
Ryan Yin 58334d86b3 fix(microvm): pass myNurPkgs into the k3s guests
The guest configurations import modules/base/overlays.nix, whose overlays
require myNurPkgs, so every VM host failed to evaluate its microVM definitions.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-20 00:24:08 +08:00
Ryan Yin 52573278bd feat(base): install python313 on every NixOS host
Hosts without Home Manager (aquamarine, the VM hosts, k3s guests) had no
interpreter. The system profile is separate from the per-user one, so desktops
keep their Home Manager copy in PATH.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-20 00:20:12 +08:00
Ryan Yin 90edf3fe2a chore(agents): update dsh-nu to 0.5.0
The lock bump moves the input from 47c813c to b8e30ec. The guide now says which Nushell the bundle builds against and that its pin warns on divergence, names direct script execution as the replacement for a refused shell handoff, and uses a Nushell stderr redirect in the verification snippet.

Assisted-by: DeepSeek Harness (deepseek-flash)
v0.19.0
2026-10-19 15:35:25 +08:00
Ryan Yin b0cf128e37 flake.lock: Update dsh-nu
dsh-nu 0.3.3 -> 0.4.0; the input now resolves to the merged AST-preflight release.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-19 11:17:37 +08:00
ryan4yin | 二花 d5fac4bcce fix(ai): bound niri's NVIDIA free-buffer pool (#477)
* fix(ai): bound niri's NVIDIA free-buffer pool

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)

* docs(ai): trim the niri VRAM workaround comment

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-19 01:15:54 +08:00
ryan4yin | 二花 b2673908df chore(agents): build dsh-nu from its own flake (#476)
* chore(agents): build dsh-nu from its own flake

NUR now keeps only dsh, so a plugin release needs `nix flake update dsh-nu` instead of a NUR package update.
2026-10-19 01:15:28 +08:00
Ryan Yin 2a792a643f fix(ai): reclaim page cache before the desktop's anon pages
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-18 22:05:03 +08:00
Ryan Yin 11569839fc feat(easyeffects): exclude local media and meeting apps
Loading the output preset replaces the GUI-managed Excluded Apps list, so the
exclusions are declared in the preset. Meeting apps apply their own gain
control, and local media playback is better left unprocessed.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-18 21:42:52 +08:00
Ryan Yin 35ae8732c3 fix(preservation): keep EasyEffects state across reboots
EasyEffects 8 keeps its KConfig settings database plus user presets, autoload
profiles and imported models under $HOME, which the tmpfs root drops on
reboot; bind-mount both directories from /persistent.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-18 21:42:52 +08:00