diff --git a/.agents/skills/nix-config-desktop/SKILL.md b/.agents/skills/nix-config-desktop/SKILL.md index 2c9e4e40..7a59ce64 100644 --- a/.agents/skills/nix-config-desktop/SKILL.md +++ b/.agents/skills/nix-config-desktop/SKILL.md @@ -49,7 +49,7 @@ Store (needs the user to run `just niri`): - Noctalia per-host override: `home/hosts/linux//noctalia.toml` (`host-.toml`) - fcitx5 profile and addons: `home/linux/gui/base/fcitx5/` - vinput (voice input): `home/linux/gui/base/vinput/` (tag-pinned: the `fcitx5-vinput` row in - WORKAROUNDS.md §Pins) + docs/WORKAROUNDS.md §Pins) - Interface a net-speed widget reads: `home/hosts/linux//noctalia.toml` (`[widget.net_rx]`/`[widget.net_tx]` `interface`) - `$HOME` state that must survive: `hosts//preservation.nix` (tmpfs root; `12kingdoms-shoukei` diff --git a/.agents/skills/nix-config-new-host/SKILL.md b/.agents/skills/nix-config-new-host/SKILL.md index b3048207..baf68259 100644 --- a/.agents/skills/nix-config-new-host/SKILL.md +++ b/.agents/skills/nix-config-new-host/SKILL.md @@ -38,9 +38,9 @@ in [hosts/README.md](../../../hosts/README.md). `outputs/x86_64-linux/src/k3s-test-1-worker-1.nix` A MicroVM guest is also registered in its VM host's `microvm.nix`; deploy it with the procedure in -WA-026 of [WORKAROUNDS.md](../../../WORKAROUNDS.md), not `just microvm-deploy`. On a VM host with -the `br0` bridge it also needs a `systemd.network.networks` unit that attaches the guest's tap to -`br0`; the tap name comes from the guest IP (`192.168.5.116` to `vm116`). Some guest outputs also +WA-026 of [WORKAROUNDS.md](../../../docs/WORKAROUNDS.md), not `just microvm-deploy`. On a VM host +with the `br0` bridge it also needs a `systemd.network.networks` unit that attaches the guest's tap +to `br0`; the tap name comes from the guest IP (`192.168.5.116` to `vm116`). Some guest outputs also expose a Colmena node for evaluation or other workflows; do not assume the physical-host deployment is done through Colmena. diff --git a/.agents/skills/nix-config-update/SKILL.md b/.agents/skills/nix-config-update/SKILL.md index a25ea2a1..0d6a1201 100644 --- a/.agents/skills/nix-config-update/SKILL.md +++ b/.agents/skills/nix-config-update/SKILL.md @@ -36,8 +36,8 @@ deploying the result to any host. - `just test` is green _before_ the update, so you have a baseline to compare against. It and every eval fetch the private `mysecrets` input over SSH; without that access they hang instead of failing. -- Check [WORKAROUNDS.md](../../../WORKAROUNDS.md) for the inputs and recipes you are about to use; - an active row that names one of them replaces its command here. +- Check [WORKAROUNDS.md](../../../docs/WORKAROUNDS.md) for the inputs and recipes you are about to + use; an active row that names one of them replaces its command here. - Enough disk for the new closures: `df -h /nix/store`. Broad nixpkgs bumps pull a lot. - Know what will move and choose the narrowest recipe that does the job. diff --git a/.agents/skills/nixpkgs-patched/SKILL.md b/.agents/skills/nixpkgs-patched/SKILL.md index 4e3d2ea2..1e2e54dc 100644 --- a/.agents/skills/nixpkgs-patched/SKILL.md +++ b/.agents/skills/nixpkgs-patched/SKILL.md @@ -3,7 +3,7 @@ name: nixpkgs-patched description: Use when temporarily carrying an unmerged nixpkgs pull request or commit in the personal ryan4yin/nixpkgs fork, updating the nixos-unstable-patched branch, or consuming that branch from - this nix-config flake, including a WORKAROUNDS.md row whose removal condition is carrying the + this nix-config flake, including a docs/WORKAROUNDS.md row whose removal condition is carrying the patch. --- diff --git a/AGENTS.md b/AGENTS.md index d0e71ce6..1a34010f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -81,13 +81,14 @@ for disclosure of AI-assisted contributions: ## Security Security architecture, control limitations, rollout checks, and prioritized work are documented in -[SECURITY.md](./SECURITY.md). Keep it consistent with changes to security boundaries or defaults. +[SECURITY.md](./docs/SECURITY.md). Keep it consistent with changes to security boundaries or +defaults. ## Workarounds Temporary workarounds, version pins, carried patches, and known gaps are recorded in -[WORKAROUNDS.md](./WORKAROUNDS.md), each with a removal condition. Add a row in the same change that -introduces one, and re-evaluate entries when their `Revisit` trigger comes up. +[WORKAROUNDS.md](./docs/WORKAROUNDS.md), each with a removal condition. Add a row in the same change +that introduces one, and re-evaluate entries when their `Revisit` trigger comes up. ## Command Hazards @@ -107,8 +108,8 @@ introduces one, and re-evaluate entries when their `Revisit` trigger comes up. narrower recipe that matches the intended host scope. - `just microvm-deploy ` installs one MicroVM guest's runner on the physical host and restarts its unit there. A later host activation re-points the guest at the runner baked - into the host's system; see WA-026 in [WORKAROUNDS.md](./WORKAROUNDS.md) before deploying. Deploy - guests serially and check the guest Node and host services after each activation. + into the host's system; see WA-026 in [WORKAROUNDS.md](./docs/WORKAROUNDS.md) before deploying. + Deploy guests serially and check the guest Node and host services after each activation. - VM hosts (`shoryu`, `shushou`, `youko`) carry the `br0` bridge for their guests. Use the `boot`-based host deployment procedure for network stack or broad nixpkgs changes; see [hosts/README.md](./hosts/README.md#deploying-vm-hosts). @@ -145,11 +146,12 @@ repository, and cross-link them — no need to be told. ## Further Context +- [Documentation index](./docs/README.md) - [Repository overview](./README.md) -- [Workarounds & known gaps](./WORKAROUNDS.md) +- [Workarounds & known gaps](./docs/WORKAROUNDS.md) - [Outputs and tests](./outputs/README.md) - [Hosts](./hosts/README.md), [system modules](./modules/README.md), and [Home Manager](./home/README.md) -- [Secrets](./secrets/README.md), [backups](./BACKUP.md), and +- [Secrets](./secrets/README.md), [backups](./docs/BACKUP.md), and [hardened app wrappers](./hardening/README.md) - [Installing NixOS from the ISO](./nixos-installer/README.md) diff --git a/Justfile b/Justfile index 4149e3a4..62d003a9 100644 --- a/Justfile +++ b/Justfile @@ -212,7 +212,7 @@ col tag mode="switch": # Deploy one microVM guest: copy its runner to the physical host, then restart the # guest unit there. microvm.nix's sshSwitch step is not used: it switches the guest over -# SSH and dies on the read-only virtiofs /nix/store (WA-026 in WORKAROUNDS.md). +# SSH and dies on the read-only virtiofs /nix/store (WA-026 in docs/WORKAROUNDS.md). # The host is the physical machine running the guest. [linux] [group('homelab')] diff --git a/README.md b/README.md index 219b7b99..bf9dfcd9 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,10 @@ This repository is home to the Nix code that builds all of my systems: 3. **NixOS servers** — three physical mini PCs running the VMs (libvirt and microVMs), the K3s test cluster and the self-hosted services. -See [./hosts](./hosts) for the host inventory, [./outputs](./outputs) for how the flake outputs are -composed, [./docs](./docs) for the BIOS and Wake-on-LAN runbooks, [./BACKUP.md](./BACKUP.md) for the -backup design, and [./AGENTS.md](./AGENTS.md) for the repository conventions. +See [./docs](./docs/README.md) for the documentation index, [./hosts](./hosts) for the host +inventory, [./outputs](./outputs) for how the flake outputs are composed, +[BACKUP.md](./docs/BACKUP.md) for the backup design, and [./AGENTS.md](./AGENTS.md) for the +repository conventions. ## Why NixOS & Flakes? @@ -98,9 +99,9 @@ See [./secrets](./secrets) for details. ## Security & Hardening -See [./SECURITY.md](./SECURITY.md) for the threat model, security architecture, controls and audit -status, [./hardening/README.md](./hardening/README.md) for application sandboxing and Linux -hardening, and [./WORKAROUNDS.md](./WORKAROUNDS.md) for temporary exceptions and known gaps. +See [SECURITY.md](./docs/SECURITY.md) for the threat model, security architecture, controls and +audit status, [./hardening/README.md](./hardening/README.md) for application sandboxing and Linux +hardening, and [WORKAROUNDS.md](./docs/WORKAROUNDS.md) for temporary exceptions and known gaps. ## How to Deploy this Flake? diff --git a/agents/README.md b/agents/README.md index 7e67fcc4..1abee5b2 100644 --- a/agents/README.md +++ b/agents/README.md @@ -120,8 +120,8 @@ recorded in [#428](https://github.com/ryan4yin/nix-config/pull/428). - **Adapt `wayfinder` in the fork** so its map and tickets default to local Markdown and research stays local, instead of GitHub issues and pushed `research/` branches. - **Adapt `domain-modeling` in the fork** to record decisions in the repository's existing documents - (here `AGENTS.md`, `WORKAROUNDS.md`, `SECURITY.md`, READMEs) and create `GLOSSARY.md` or ADRs only - where none exist. + (here `AGENTS.md`, `docs/WORKAROUNDS.md`, `docs/SECURITY.md`, READMEs) and create `GLOSSARY.md` or + ADRs only where none exist. - **Borrow small gstack ideas into the rules**: completion statuses (done, done with concerns, blocked, needs context); never call a failure pre-existing without running the same check on the base branch; a subagent with no one to ask takes the recommended option but never a destructive or diff --git a/BACKUP.md b/docs/BACKUP.md similarity index 90% rename from BACKUP.md rename to docs/BACKUP.md index 9f2a5de3..c0aec487 100644 --- a/BACKUP.md +++ b/docs/BACKUP.md @@ -13,11 +13,11 @@ How this fleet is backed up, where the data lives, and how to restore it. ## Layers -1. **btrbk — local snapshots** ([`modules/nixos/base/btrbk.nix`](./modules/nixos/base/btrbk.nix)). +1. **btrbk — local snapshots** ([`modules/nixos/base/btrbk.nix`](../modules/nixos/base/btrbk.nix)). Same-filesystem btrfs snapshots of `@persistent`, run on Tue/Sat 03:45:20, kept for 7 days (minimum 2). Cheap rollback for mistakes; it does **not** survive disk loss. 2. **restic — encrypted copies on youko** - ([`modules/nixos/base/restic-backup.nix`](./modules/nixos/base/restic-backup.nix)). Encryption + ([`modules/nixos/base/restic-backup.nix`](../modules/nixos/base/restic-backup.nix)). Encryption happens on the client, so the server only ever stores ciphertext. youko runs `restic-rest-server` with `--private-repos`, authenticated by htpasswd, published behind caddy as `restic.writefor.fun`. Deliberately not append-only: a desktop holds both the plaintext and the @@ -152,12 +152,12 @@ Restoring a btrbk snapshot (offline; stop writers first): ## Components -| Path | Role | -| -------------------------------------------------------------------------------- | ---------------------------------------------------- | -| [`modules/nixos/base/restic-backup.nix`](./modules/nixos/base/restic-backup.nix) | client module: repository, paths, excludes, schedule | -| [`modules/nixos/base/btrbk.nix`](./modules/nixos/base/btrbk.nix) | local btrfs snapshots | -| `hosts/12kingdoms-youko/default.nix` | the REST server and youko's own backup | -| `hosts/12kingdoms-youko/homelab-services/restic-server-snapshots.nix` | hourly read-only snapshots of the REST store | -| `hosts/12kingdoms-youko/homelab-services/caddy.nix` | the `restic.writefor.fun` vhost | -| `secrets/nixos.nix` | which secret is defined on which host | -| `hosts/idols-ai/restic.nix`, `hosts/12kingdoms-youko/default.nix` | per-host backup configuration | +| Path | Role | +| --------------------------------------------------------------------------------- | ---------------------------------------------------- | +| [`modules/nixos/base/restic-backup.nix`](../modules/nixos/base/restic-backup.nix) | client module: repository, paths, excludes, schedule | +| [`modules/nixos/base/btrbk.nix`](../modules/nixos/base/btrbk.nix) | local btrfs snapshots | +| `hosts/12kingdoms-youko/default.nix` | the REST server and youko's own backup | +| `hosts/12kingdoms-youko/homelab-services/restic-server-snapshots.nix` | hourly read-only snapshots of the REST store | +| `hosts/12kingdoms-youko/homelab-services/caddy.nix` | the `restic.writefor.fun` vhost | +| `secrets/nixos.nix` | which secret is defined on which host | +| `hosts/idols-ai/restic.nix`, `hosts/12kingdoms-youko/default.nix` | per-host backup configuration | diff --git a/docs/README.md b/docs/README.md index ff56d29a..6ec32076 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,89 @@ # Documentation -- [BIOS settings](./bios.md) -- [Wake-on-LAN](./wake-on-lan.md) -- [NixOS modernization options](./nixos-modernization-options.md) +Canonical index for this repository. Standalone reference material lives in this directory. +Component runbooks stay next to the code they describe so they remain visible during maintenance; +every human-facing document is linked here. + +`README.md` and `AGENTS.md` remain at the repository root because GitHub and coding agents require +those entry points. + +## Repository + +- [Repository overview](../README.md) — systems, components, deployment and validation quick start. +- [Agent guide](../AGENTS.md) — repository conventions, command hazards and validation rules. +- [NixOS modernization options](nixos-modernization-options.md) — design options and decisions. + +## Operations and policy + +- [Security](SECURITY.md) — threat model, trust boundaries, implemented controls and audits. +- [Backups](BACKUP.md) — backup layers, password model, retention and restore procedure. +- [Workarounds and known gaps](WORKAROUNDS.md) — pins, temporary workarounds and removal conditions. +- [BIOS settings](bios.md) — firmware settings for the physical hosts. +- [Wake-on-LAN](wake-on-lan.md) — firmware prerequisites, NixOS setup and wake commands. +- [Runtime hardening validation](../hardening/tests/runtime-validation.md). + +## Hosts and services + +- [Host inventory and deployment notes](../hosts/README.md). +- AI desktop: [host runbook](../hosts/idols-ai/README.md) and [VR notes](../hosts/idols-ai/VR.md). +- Akane: [host runbook](../hosts/idols-akane/README.md). +- Aquamarine: [host runbook](../hosts/idols-aquamarine/README.md), + [iGPU notes](../hosts/idols-aquamarine/IGPU.md) and + [ROCm notes](../hosts/idols-aquamarine/ROCM.md). +- Kana: [host runbook](../hosts/idols-kana/README.md). +- Ruby: [host runbook](../hosts/idols-ruby/README.md). +- Shoukei: [host runbook](../hosts/12kingdoms-shoukei/README.md). +- Youko homelab: [services overview](../hosts/12kingdoms-youko/homelab-services/README.md), + [Immich](../hosts/12kingdoms-youko/homelab-services/immich/README.md), + [monitoring](../hosts/12kingdoms-youko/homelab-services/monitoring/README.md), + [alert rules](../hosts/12kingdoms-youko/homelab-services/monitoring/alert_rules/README.md), + [recording rules](../hosts/12kingdoms-youko/homelab-services/monitoring/recording_rules/README.md) + and [Grafana dashboards](../hosts/12kingdoms-youko/homelab-services/grafana/dashboards/README.md). +- Kubernetes cluster: [k8s host notes](../hosts/k8s/README.md) and + [disko configuration](../hosts/k8s/disko-config/README.md). +- Infrastructure: [infra overview](../infra/README.md), [RustFS](../infra/rustfs/README.md), + [Loki storage](../infra/rustfs/loki/README.md) and + [Terraform S3 backend](../infra/rustfs/tf-s3-backend/README.md). +- NixOS installation: [installer guide](../nixos-installer/README.md) and + [Shoukei notes](../nixos-installer/README.shoukei.md). +- Certificates: [certificate setup](../certs/README.md). + +## Configuration structure + +- [NixOS and nix-darwin modules](../modules/README.md), including + [Darwin modules](../modules/darwin/README.md), + [Mihomo networking](../modules/nixos/desktop/networking/mihomo/README.md) and + [Sunshine](../modules/nixos/desktop/networking/sunshine/README.md). +- [Home Manager modules](../home/README.md). +- [Flake outputs and tests](../outputs/README.md). +- [Secrets management](../secrets/README.md). +- [Overlays](../overlays/README.md), [shared library helpers](../lib/README.md) and + [shared variables](../vars/README.md). +- [Hardening wrappers and policy](../hardening/README.md). + +## Desktop and Home Manager details + +- [Darwin](../home/darwin/README.md), [per-host Home Manager profiles](../home/hosts/README.md) and + [Linux](../home/linux/README.md). +- [Linux desktop stack](../home/linux/gui/README.md): [base GUI](../home/linux/gui/base/README.md), + [Fcitx5](../home/linux/gui/base/fcitx5/README.md), + [hypridle](../home/linux/gui/base/hypridle/README.md), + [vinput](../home/linux/gui/base/vinput/README.md) and [i3](../home/linux/gui/i3/README.md). +- [Base Home Manager profile](../home/base/README.md): + [editors](../home/base/core/editors/README.md), + [editor glossary](../home/base/core/editors/Glossary.md), + [Helix](../home/base/core/editors/helix/README.md), + [Neovim](../home/base/core/editors/neovim/README.md), [Rime](../home/base/gui/rime/README.md) and + [terminal](../home/base/gui/terminal/README.md). +- Terminal tools: [agents](../home/base/tui/agents/README.md) and + [dsh notes](../home/base/tui/agents/dsh.md), [editors](../home/base/tui/editors/README.md), + [encryption](../home/base/tui/encryption/README.md), [GPG](../home/base/tui/gpg/README.md) and + [password store](../home/base/tui/password-store/README.md). + +## Agent resources + +- [Global rules, skills and evaluations](../agents/README.md). +- [Skill catalog](../agents/skills/README.md). +- [Global agent rules](../agents/global-rules.md), + [evaluation guide](../agents/evals/global-rules.md) and + [tooling installation notes](../agents/install-tooling.md). diff --git a/SECURITY.md b/docs/SECURITY.md similarity index 95% rename from SECURITY.md rename to docs/SECURITY.md index b08d49b1..683bd5fc 100644 --- a/SECURITY.md +++ b/docs/SECURITY.md @@ -4,8 +4,8 @@ This is a personal infrastructure repository, not a supported security product. describes the intended architecture, controls present in source, their limitations, and remaining work. A configured control is not evidence that it is active on a running machine. -Related documents: [application hardening](hardening/README.md) for sandbox wrappers and Linux -hardening notes, and [WORKAROUNDS.md](WORKAROUNDS.md) for temporary exceptions and known gaps. +Related documents: [application hardening](../hardening/README.md) for sandbox wrappers and Linux +hardening notes, and [WORKAROUNDS.md](./WORKAROUNDS.md) for temporary exceptions and known gaps. ## Reporting problems @@ -46,12 +46,12 @@ small, reversible controls and narrow exceptions; benchmark before adopting expe | Supply chain | Locked flake inputs; explicit binary-cache trust keys on NixOS; normal user is not a Nix trusted-user | A trusted cache or imported Nix module can supply code executed as root; a lock file is not a security audit | | Recovery | NixOS generations, btrbk/restic, hourly read-only snapshots of the REST store, and documented backup procedures | A rollback does not undo compromised data or secrets; backup configuration alone does not prove restore works; the offsite immutable copy is still planned | -Sources: [host layout](hosts/README.md), [k3s deployment](hosts/k8s/README.md), -[firewall](modules/nixos/base/networking/firewall.nix), [SSH](modules/nixos/base/ssh.nix), -[Nix trust](modules/base/nix.nix), [secrets](secrets/README.md), and [backup](BACKUP.md). Cluster -resources are maintained in the separate k8s-gitops repository. +Sources: [host layout](../hosts/README.md), [k3s deployment](../hosts/k8s/README.md), +[firewall](../modules/nixos/base/networking/firewall.nix), [SSH](../modules/nixos/base/ssh.nix), +[Nix trust](../modules/base/nix.nix), [secrets](../secrets/README.md), and [backup](./BACKUP.md). +Cluster resources are maintained in the separate k8s-gitops repository. -The Macs set `nix.enable = false` ([nix-core.nix](modules/darwin/nix-core.nix)), so nix-darwin +The Macs set `nix.enable = false` ([nix-core.nix](../modules/darwin/nix-core.nix)), so nix-darwin writes no `/etc/nix/nix.conf`: the substituters, trusted keys and access-token include declared here do not reach them. Their Nix settings come from the Determinate installation, which this repository does not manage; those settings were not verified on the Macs. @@ -59,7 +59,7 @@ does not manage; those settings were not verified on the Macs. ## Kernel and process baseline The following explicit, overridable baseline is implemented in -[kernel-hardening.nix](hardening/kernel-hardening.nix), which holds the values; the table below +[kernel-hardening.nix](../hardening/kernel-hardening.nix), which holds the values; the table below summarizes them. It has Linux eval coverage and explicit ARM/RISC-V server imports. Source implementation is not runtime verification. Some values are already kernel/systemd/NixOS defaults; Darwin does not receive Linux sysctls. @@ -97,8 +97,8 @@ an advisory and affected kernel versions before adding CVE claims; search snippe ### Boot integrity and mandatory access control -- ai configures Lanzaboote in [secureboot.nix](hosts/idols-ai/secureboot.nix). Confirm firmware key - enrollment and actual Secure Boot state with `sbctl status`; do not assume all hosts have it. +- ai configures Lanzaboote in [secureboot.nix](../hosts/idols-ai/secureboot.nix). Confirm firmware + key enrollment and actual Secure Boot state with `sbctl status`; do not assume all hosts have it. - Secure Boot, signed boot images, kernel lockdown and module signature enforcement are distinct controls. Test custom kernels and NVIDIA/out-of-tree modules before extending enforcement. - AppArmor is enabled, but the only explicit policy, sudo's, is in complain mode. Complain mode logs @@ -106,17 +106,18 @@ an advisory and affected kernel versions before adding CVE claims; search snippe broad enforced application confinement. - Systemd service sandboxing is per-service, not a global policy. The exposed services nixpkgs leaves weakly sandboxed (caddy, rustfs, vmalert, whisper-asr) use the preset in - [systemdHardening.nix](lib/systemdHardening.nix). Review capabilities, writable paths, network + [systemdHardening.nix](../lib/systemdHardening.nix). Review capabilities, writable paths, network access and syscall requirements before tightening an individual service. -See [application hardening](hardening/README.md) for wrapper details. +See [application hardening](../hardening/README.md) for wrapper details. ### Audit trail -`modules.security.audit` ([auditd.nix](modules/nixos/base/auditd.nix)) runs auditd on youko, shoryu, -shushou and aquamarine. It records, for login sessions only (SSH, and sudo or su from one): every -root command (`root-session`), access to decrypted secrets and SSH host keys (`credential-access`), -writes to SSH, account/PAM, Nix trust and audit configuration, module loads, and denials. +`modules.security.audit` ([auditd.nix](../modules/nixos/base/auditd.nix)) runs auditd on youko, +shoryu, shushou and aquamarine. It records, for login sessions only (SSH, and sudo or su from one): +every root command (`root-session`), access to decrypted secrets and SSH host keys +(`credential-access`), writes to SSH, account/PAM, Nix trust and audit configuration, module loads, +and denials. - Services are not audited: a `never,task` rule gives tasks without a login uid no audit context, so virtiofsd, hypervisors, NFS, PostgreSQL and Nix builds skip the per-syscall audit path. A @@ -228,7 +229,7 @@ checks remain necessary after deployment. reaching the export, but a root user on an allowed client still has server-root write access. `root_squash` is deferred: the existing PVC subdirectories are root-owned (observed `drwxr-xr-x root root` and `drwxrwsr-x root 107`), so enabling it needs a one-time ownership - migration and a maintenance window. See WORKAROUNDS.md. + migration and a maintenance window. See docs/WORKAROUNDS.md. - **Remote consoles:** the libvirt VNC consoles listen on `127.0.0.1` only, and the k3s firewall drops 5900-5903 from pod sources. Reach a console through an SSH tunnel. - **Pod-to-host firewall:** two independent layers deny pod access to the credential-bearing host @@ -324,7 +325,7 @@ isolation. Source review and socket metadata—not reads of private credentials alias or GitHub destination. Do not treat forwarding as enabled for every LAN alias, or remove it without checking deployment/build workflows. - All nine desktop wrappers use shared nixpak policies: cleared environment, filtered session D-Bus - and selected mounts. The [permission inventory](hardening/README.md#app-permissions) lists each + and selected mounts. The [permission inventory](../hardening/README.md#app-permissions) lists each app's file, network, credential and media grants. - Only Firefox/Chromium share host networking. Chromium is an intentional local-development exception; all other apps isolate loopback with pasta but can still reach the LAN/Internet. @@ -348,7 +349,7 @@ isolation. Source review and socket metadata—not reads of private credentials Chromium, Brave Origin, Edge, QQ, Telegram and Zoom; the Chromium smoke test also validates renderer sandboxing, environment clearing, bind scope and profile persistence. WeChat's interactive Wayland check remains pending. See the - [runtime validation](hardening/tests/runtime-validation.md). + [runtime validation](../hardening/tests/runtime-validation.md). #### Agent-first diagnostics by host role @@ -414,7 +415,7 @@ separate verification. | P2 | Validate narrower sandbox/agent boundaries where needed | Source and selected SSH/journal metadata audited; use disposable data/socket probes and preserve core-desktop diagnosis, browserpass and Homelab root workflows | | P3 | Improve security-event alerts and configuration drift checks | Actionable redacted alerts and periodic runtime control readback | -Record temporary exceptions in [WORKAROUNDS.md](WORKAROUNDS.md) with a removal condition. Revisit +Record temporary exceptions in [WORKAROUNDS.md](./WORKAROUNDS.md) with a removal condition. Revisit this architecture after a new exposed service, network/storage change, host addition or significant kernel/nixpkgs update. No control here guarantees containment after host root compromise. diff --git a/WORKAROUNDS.md b/docs/WORKAROUNDS.md similarity index 99% rename from WORKAROUNDS.md rename to docs/WORKAROUNDS.md index 3e6bd54d..0203468d 100644 --- a/WORKAROUNDS.md +++ b/docs/WORKAROUNDS.md @@ -86,7 +86,7 @@ An unfinished feature or gap. - Security architecture, threat model and audit status: [SECURITY.md](./SECURITY.md). - Unmerged **nixpkgs** PRs are carried via the `nixpkgs-patched` input and the - [`.agents/skills/nixpkgs-patched`](./.agents/skills/nixpkgs-patched/SKILL.md) workflow (currently + [`.agents/skills/nixpkgs-patched`](../.agents/skills/nixpkgs-patched/SKILL.md) workflow (currently none). - Routine version pins (colmena, agenix, disko, lanzaboote, haumea, home-manager, `nixpkgs-stable`, `nixpkgs-darwin`, …) are the versions in use, not workarounds, so they are not listed here. diff --git a/docs/nixos-modernization-options.md b/docs/nixos-modernization-options.md index 88c353c8..e465f94e 100644 --- a/docs/nixos-modernization-options.md +++ b/docs/nixos-modernization-options.md @@ -39,7 +39,7 @@ fallback, and a root-readable Cloudflare token in agenix. **Pros:** certificates become automatic and every tailnet device trusts them (today a phone without `ecc-ca` gets a certificate error); removes the Cloudflare token and the DNS-01 propagation workaround from those services; access control moves from "IP trust zone" to tailnet identity/ACL, -which is exactly the limitation `SECURITY.md` records; `--tcp=` can also expose raw TCP. +which is exactly the limitation `docs/SECURITY.md` records; `--tcp=` can also expose raw TCP. **Cons:** Serve routes by mount path on one name, or (via the nixpkgs module) as Tailscale Services with `tcp:` endpoints only — there is no Host/SNI vhost equivalent, so path-sensitive apps @@ -285,10 +285,10 @@ flake input is maintained separately for Secure Boot. the lanzaboote flake input; checksum validation of kernel and initrd; nicer menu. **Cons:** different trust model — it signs **limine itself** and validates artifacts by checksum, -rather than shipping a firmware-verified UKI, so `SECURITY.md` and the threat model must be updated; -key enrollment is a manual firmware dance (Setup Mode + `sbctl enroll-keys`) and is the one change -in this repository that can leave a machine unbootable; the existing lzpt bundle may or may not be -reusable; less NixOS mileage than systemd-boot. +rather than shipping a firmware-verified UKI, so `docs/SECURITY.md` and the threat model must be +updated; key enrollment is a manual firmware dance (Setup Mode + `sbctl enroll-keys`) and is the one +change in this repository that can leave a machine unbootable; the existing lzpt bundle may or may +not be reusable; less NixOS mileage than systemd-boot. **Reversibility:** low on the physical desktop (firmware + ESP state), high on a VM. @@ -466,7 +466,7 @@ prevent boot or login. **Recommendation for the group: evaluate in a disposable | D4 | `system.nixos-init.enable` | `activationScripts` | bashless init | makes `activationScripts` a silent no-op — youko's `data-ro-backing`, `installCaddyWallpapers` and `installHomepageDashboardConfig` would stop running without an error | lab only | | D5 | `security.pam.services..rules` | per-service booleans | freeform PAM config | upstream marks it subject to breaking changes; a mistake locks you out | lab only | | D6 | `security.shadow.enable = false` + greetd | shadow suite provides login/su | fewer setuid programs | assertion couples the two; changes VT login semantics | lab only | -| D7 | `security.apparmor.policies` | `policies.sudo` already in use (`hardening/apparmor/default.nix`); the old `profiles` option is removed upstream | policy set is now data | writing profiles is real work and breakage-prone; `SECURITY.md` explicitly warns against untested profiles | lab only | +| D7 | `security.apparmor.policies` | `policies.sudo` already in use (`hardening/apparmor/default.nix`); the old `profiles` option is removed upstream | policy set is now data | writing profiles is real work and breakage-prone; `docs/SECURITY.md` explicitly warns against untested profiles | lab only | --- @@ -520,7 +520,7 @@ header) should then be trimmed to **adopt** items only. `services/system/{userborn,nix-daemon,zram-generator}.nix`, `services/monitoring/prometheus/exporters.nix`. - NixOS 26.05 release notes; Nix manual, Experimental Features. -- Repo context: `SECURITY.md` (trust zones and control limits), `WORKAROUNDS.md` (WA-001, WA-008, - WA-009, WA-023), `modules/nixos/base/networking/mdns.nix`, +- Repo context: `docs/SECURITY.md` (trust zones and control limits), `docs/WORKAROUNDS.md` (WA-001, + WA-008, WA-009, WA-023), `modules/nixos/base/networking/mdns.nix`, `hosts/12kingdoms-youko/homelab-services/caddy.nix`, `hosts/12kingdoms-youko/homelab-services/README.md`. diff --git a/flake.nix b/flake.nix index 40d195fa..d643a91a 100644 --- a/flake.nix +++ b/flake.nix @@ -145,7 +145,7 @@ # x86/x86_64 emulation on 16K-page ARM64 (Apple Silicon). FEX cannot run # natively with 16K pages, so this wraps FEX in a 4K-page muvm microVM and # exposes an `x86pkgs` set plus Steam/Wine launchers. Used by shoukei; see - # hosts/12kingdoms-shoukei and WORKAROUNDS.md (WA-021). + # hosts/12kingdoms-shoukei and docs/WORKAROUNDS.md (WA-021). # # Pinned to our fork of rowanG077/nix-x86-on-aarch64 at the reviewed commit # 5d69793a. To update, fetch upstream into the fork, review the new commits, diff --git a/hardening/README.md b/hardening/README.md index ea4cd376..fa409b03 100644 --- a/hardening/README.md +++ b/hardening/README.md @@ -1,7 +1,7 @@ # Linux Hardening Deployed and interactively validated on the Linux desktop host (2026-10-31). Policy and limits: -[SECURITY.md](../SECURITY.md). +[SECURITY.md](../docs/SECURITY.md). ## Why these apps are sandboxed diff --git a/hardening/kernel-hardening.nix b/hardening/kernel-hardening.nix index 269d4453..13b14e44 100644 --- a/hardening/kernel-hardening.nix +++ b/hardening/kernel-hardening.nix @@ -2,7 +2,7 @@ { # Keep this baseline independent of a particular kernel CVE. User namespaces # remain available for Nix builds, rootless containers and application sandboxes. - # See SECURITY.md for compatibility constraints and post-deployment checks. + # See docs/SECURITY.md for compatibility constraints and post-deployment checks. boot.kernel.sysctl = { "kernel.dmesg_restrict" = lib.mkDefault 1; # NixOS already sets mkDefault 1; use a stronger default, still overridable diff --git a/hosts/12kingdoms-shoukei/README.md b/hosts/12kingdoms-shoukei/README.md index 1dd7ed0e..d426e2eb 100644 --- a/hosts/12kingdoms-shoukei/README.md +++ b/hosts/12kingdoms-shoukei/README.md @@ -20,11 +20,11 @@ inside a 4 KiB `muvm` microVM and registers both ELF handlers: - `steam` and `x86-arm-wine` for games and Windows programs. The microVM is capped at 6 GiB (`memoryMiB`) on this 16 GiB machine, and needs `/dev/kvm` plus a -running systemd user session. See [WORKAROUNDS.md](../../WORKAROUNDS.md) WA-021. +running systemd user session. See [WORKAROUNDS.md](../../docs/WORKAROUNDS.md) WA-021. Because the host no longer registers qemu-user binfmt, `podman run --platform=linux/amd64`, x86 chroots, and local builds of uncached x86 derivations need a remote x86_64 builder (see -[WORKAROUNDS.md](../../WORKAROUNDS.md) WA-022). +[WORKAROUNDS.md](../../docs/WORKAROUNDS.md) WA-022). Related: diff --git a/hosts/12kingdoms-shoukei/apple-silicon.nix b/hosts/12kingdoms-shoukei/apple-silicon.nix index f4eecae4..4b9770a3 100644 --- a/hosts/12kingdoms-shoukei/apple-silicon.nix +++ b/hosts/12kingdoms-shoukei/apple-silicon.nix @@ -31,7 +31,7 @@ # BCM4378/brcmfmac: disable Wi-Fi power saving. Powersave is a common source # of intermittent association failures / authentication timeouts, which NM # mistakes for a bad key, re-prompts, and lets the client (Noctalia, nmtui, - # nmcli) save as a duplicate " 1" profile. See WORKAROUNDS.md WA-024/025. + # nmcli) save as a duplicate " 1" profile. See docs/WORKAROUNDS.md WA-024/025. networking.networkmanager.wifi.powersave = false; # Specify path to peripheral firmware files. diff --git a/hosts/12kingdoms-shoukei/game/default.nix b/hosts/12kingdoms-shoukei/game/default.nix index ab0111d6..9863f2b0 100644 --- a/hosts/12kingdoms-shoukei/game/default.nix +++ b/hosts/12kingdoms-shoukei/game/default.nix @@ -2,7 +2,7 @@ # # FEX cannot run on the 16K pages this machine boots with, so # nix-x86-on-aarch64 runs FEX inside a 4K-page muvm microVM and owns the -# x86_64/i686 ELF handlers. Pinned to our fork; see WORKAROUNDS.md WA-021. +# x86_64/i686 ELF handlers. Pinned to our fork; see docs/WORKAROUNDS.md WA-021. { nix-x86-on-aarch64, ... }: { imports = [ nix-x86-on-aarch64.nixosModules.default ]; diff --git a/hosts/12kingdoms-youko/homelab-services/grafana/datasources.nix b/hosts/12kingdoms-youko/homelab-services/grafana/datasources.nix index 3db60a1c..717f57c9 100644 --- a/hosts/12kingdoms-youko/homelab-services/grafana/datasources.nix +++ b/hosts/12kingdoms-youko/homelab-services/grafana/datasources.nix @@ -91,7 +91,7 @@ # Disabled: the `playground` role has no password and remote logins # require scram-sha-256, so this datasource could never authenticate. # Re-enable once a `playground` DB password is provisioned (the PostgreSQL - # per-role password follow-up in SECURITY.md). + # per-role password follow-up in docs/SECURITY.md). /* { # https://grafana.com/docs/grafana/latest/datasources/postgres/configure/ diff --git a/hosts/12kingdoms-youko/homelab-services/transmission.nix b/hosts/12kingdoms-youko/homelab-services/transmission.nix index b3aebc06..374a6404 100644 --- a/hosts/12kingdoms-youko/homelab-services/transmission.nix +++ b/hosts/12kingdoms-youko/homelab-services/transmission.nix @@ -59,7 +59,7 @@ in { # transmission 4.1.4 takes an fcntl lock on its config-dir lock file, but the # AppArmor profile shipped by nixpkgs grants rw without k (lock), so the - # daemon exits with "Another process is already using". See WORKAROUNDS.md. + # daemon exits with "Another process is already using". See docs/WORKAROUNDS.md. security.apparmor.includes."local/bin.transmission-daemon" = '' /var/lib/transmission/.config/transmission-daemon/lock rwk, ''; diff --git a/hosts/12kingdoms-youko/nfs-golden.nix b/hosts/12kingdoms-youko/nfs-golden.nix index e5ed2e81..b36acaf8 100644 --- a/hosts/12kingdoms-youko/nfs-golden.nix +++ b/hosts/12kingdoms-youko/nfs-golden.nix @@ -39,5 +39,5 @@ in # NFSv4 only needs 2049/tcp (no rpcbind/mountd/statd). The export is limited # to the hosts above, not the whole LAN. `no_root_squash` stays until the # existing root-owned PVC subdirectories are migrated for `root_squash`; see - # SECURITY.md. + # docs/SECURITY.md. } diff --git a/hosts/idols-aquamarine/asr.nix b/hosts/idols-aquamarine/asr.nix index 89ed94c4..f91ec26a 100644 --- a/hosts/idols-aquamarine/asr.nix +++ b/hosts/idols-aquamarine/asr.nix @@ -13,7 +13,7 @@ let # OpenVINO publishes static IRs for Whisper only, and the NPU compiler accepts # nothing less: any other ASR family keeps a dynamic time axis and aborts it - # (WORKAROUNDS.md WA-037). Pinned by content because the NPU caches the + # (docs/WORKAROUNDS.md WA-037). Pinned by content because the NPU caches the # compiled graph; a version bump should be deliberate. modelFiles = { "added_tokens.json" = "sha256-PFH2bEwh+eEmlwB48RrnenjHSu6N9gbunauobkZxCOA="; diff --git a/hosts/idols-aquamarine/asr/server.py b/hosts/idols-aquamarine/asr/server.py index c94a1f24..e21ef493 100644 --- a/hosts/idols-aquamarine/asr/server.py +++ b/hosts/idols-aquamarine/asr/server.py @@ -4,7 +4,7 @@ vinput records raw PCM (S16_LE, mono, 16 kHz), wraps it in a WAV container and POSTs it to /v1/audio/transcriptions; this service is that endpoint. Whisper is the only ASR family OpenVINO publishes fully static IRs for, and a static graph is what the NPU compiler accepts -- every other family keeps a dynamic time axis -and aborts the compiler, see WORKAROUNDS.md WA-037. +and aborts the compiler, see docs/WORKAROUNDS.md WA-037. """ import io diff --git a/hosts/k8s/README.md b/hosts/k8s/README.md index 90b0f950..526ffda8 100644 --- a/hosts/k8s/README.md +++ b/hosts/k8s/README.md @@ -37,9 +37,9 @@ just microvm-deploy For example, `just microvm-deploy k3s-test-1-master-3 shushou`. The recipe copies the runner to the physical host, then restarts `microvm@` there; microvm.nix's SSH switch is not used because it cannot write the guest's read-only `/nix/store` (WA-026 in -[WORKAROUNDS.md](../../WORKAROUNDS.md)). A later activation of the physical host re-points the guest -at the runner baked into the host's system, so switch the host after installing a guest from a newer -tree. +[WORKAROUNDS.md](../../docs/WORKAROUNDS.md)). A later activation of the physical host re-points the +guest at the runner baked into the host's system, so switch the host after installing a guest from a +newer tree. Use `just build-microvm ` to build a runner without deploying it. Preserve the guest's `etc.img`, `var.img`, and `home.img` when updating it; they contain its identity and K3s state. diff --git a/modules/README.md b/modules/README.md index ab9b3cbd..e3f15993 100644 --- a/modules/README.md +++ b/modules/README.md @@ -38,7 +38,7 @@ modules/ │ ├── networking/ # Network configuration │ ├── nix.nix # Nix settings │ ├── packages.nix # System packages - │ ├── restic-backup.nix # Encrypted off-host backups (see ../BACKUP.md) + │ ├── restic-backup.nix # Encrypted off-host backups (see ../docs/BACKUP.md) │ ├── ssh.nix # SSH daemon configuration │ ├── trash.nix # Trash retention cleanup │ ├── user-group.nix # User and group management diff --git a/modules/nixos/base/auditd.nix b/modules/nixos/base/auditd.nix index 45ce14e5..699d6617 100644 --- a/modules/nixos/base/auditd.nix +++ b/modules/nixos/base/auditd.nix @@ -10,7 +10,7 @@ let inherit (config.services) openssh; # Audit trail for login sessions, so that a stolen deployment key leaves a - # record of what each session did; see SECURITY.md ("Audit trail"). + # record of what each session did; see docs/SECURITY.md ("Audit trail"). # `auditctl -R` aborts at the first watch whose path is missing, leaving # auditing off, so every watched path must exist when the rules load. diff --git a/outputs/README.md b/outputs/README.md index fada8371..eae00642 100644 --- a/outputs/README.md +++ b/outputs/README.md @@ -72,7 +72,7 @@ Problems: agenix secrets. - [ ] Maybe it's better to test every service separately, not the whole host? -Full-host tests are tracked as WA-013 in [WORKAROUNDS.md](../WORKAROUNDS.md). +Full-host tests are tracked as WA-013 in [WORKAROUNDS.md](../docs/WORKAROUNDS.md). `outputs/x86_64-linux/nixos-tests/idols-ruby.nix` is exported as `packages.x86_64-linux.ruby-nixos-tests`, but it is not a `checks` entry, so CI never builds it and nothing else runs it. What runs today is the eval set above with `just test`, plus one NixOS-driver @@ -122,5 +122,5 @@ All the outputs of this flake are defined here. The tree lists the per-host sources and tests. The flake also exposes a `checks` output: every system has `eval-tests` and `pre-commit-check`, and `x86_64-linux` adds `security-exporters`, which -imports the top-level `tests/security-exporters.nix`. See [`../SECURITY.md`](../SECURITY.md) for -when to run it. +imports the top-level `tests/security-exporters.nix`. See +[`../docs/SECURITY.md`](../docs/SECURITY.md) for when to run it. diff --git a/outputs/default.nix b/outputs/default.nix index 2af9b60f..e5b7d5b6 100644 --- a/outputs/default.nix +++ b/outputs/default.nix @@ -136,7 +136,7 @@ let deployment # Colmena evaluates with nixpkgs' plain lib, which lacks the version the # flake's lib reports; without this the toplevel differs (`26.11pre-git`). - # Recorded as WA-042 in WORKAROUNDS.md. + # Recorded as WA-042 in docs/WORKAROUNDS.md. { system.nixos.versionSuffix = lib.trivial.versionSuffix; system.nixos.revision = lib.trivial.revisionWithDefault null; diff --git a/scripts/shoukei-home-wifi-static.nu b/scripts/shoukei-home-wifi-static.nu index bcf5a63d..3e821f2a 100644 --- a/scripts/shoukei-home-wifi-static.nu +++ b/scripts/shoukei-home-wifi-static.nu @@ -11,7 +11,7 @@ # # just shoukei-home-wifi # -# See hosts/12kingdoms-shoukei/README.md and WORKAROUNDS.md WA-024/025. +# See hosts/12kingdoms-shoukei/README.md and docs/WORKAROUNDS.md WA-024/025. # --------------------------------------------------------------------------- # Configuration