aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--dot_config/git/config4
-rw-r--r--dot_config/zsh/dot_zshrc6
-rw-r--r--remote-dev/README.md109
-rw-r--r--remote-dev/home.nix35
4 files changed, 133 insertions, 21 deletions
diff --git a/dot_config/git/config b/dot_config/git/config
index db562a6..9eae2c0 100644
--- a/dot_config/git/config
+++ b/dot_config/git/config
@@ -148,3 +148,7 @@
assume8bitEncoding = UTF-8
[credential "smtp://127.0.0.1:1025"]
helper = "!f() { test \"$1\" = get && printf 'password=%s\\n' \"$(pass show proton/bridge-smtp)\"; }; f"
+[include]
+ ; Machine-local overrides (e.g. SSH-format signing on the remote-dev VM).
+ ; Git silently skips this if the file is absent.
+ path = ~/.config/git/config.local
diff --git a/dot_config/zsh/dot_zshrc b/dot_config/zsh/dot_zshrc
index 7a9538d..94781ac 100644
--- a/dot_config/zsh/dot_zshrc
+++ b/dot_config/zsh/dot_zshrc
@@ -359,15 +359,15 @@ export GPG_TTY=$TTY
gpg-connect-agent updatestartuptty /bye &>/dev/null
# ── direnv (per-project env via .envrc; nix-direnv loaded from direnvrc) ─────
-eval "$(direnv hook zsh)"
+command -v direnv >/dev/null && eval "$(direnv hook zsh)"
# ── Zoxide (smart directory jumping) ──────────────────────────────────────────
# z foo → jump to frecency-ranked dir matching "foo"
# zi → interactive picker with fzf
-eval "$(zoxide init zsh)"
+command -v zoxide >/dev/null && eval "$(zoxide init zsh)"
# ── FZF ───────────────────────────────────────────────────────────────────────
-source <(fzf --zsh)
+command -v fzf >/dev/null && source <(fzf --zsh)
# Ctrl-X Ctrl-R: search history with fzf and immediately execute
fzf-history-widget-accept() {
diff --git a/remote-dev/README.md b/remote-dev/README.md
index 0377b09..cc3eecc 100644
--- a/remote-dev/README.md
+++ b/remote-dev/README.md
@@ -21,36 +21,115 @@ GitHub on first launch.
2. Clones this repo to `~/.local/share/dotfiles`.
3. Runs `home-manager switch --flake .../remote-dev#vm`, which:
- Installs the CLI tool subset (see `home.nix`).
- - Symlinks `~/.config/{nvim,zellij,zsh,direnv,ghostty}` at the cloned
- working tree via `mkOutOfStoreSymlink`, so `git pull` is enough to
- pick up config edits — no rebuild needed for config-only changes.
+ - Symlinks `~/.config/{nvim,zellij,zsh,direnv,ghostty,git}` and
+ `~/.ssh/config` at the cloned working tree via
+ `mkOutOfStoreSymlink`, so `git pull` is enough to pick up config
+ edits — no rebuild needed for config-only changes.
- Sets `ZDOTDIR=$HOME/.config/zsh` so the shared zshrc/zprofile load.
4. Appends the nix-store zsh to `/etc/shells` and `chsh`'s to it.
-## Updating
+## Updating after a dotfiles change
+
+Two flavours of update:
```sh
-cd ~/.local/share/dotfiles
-git pull
-nix run home-manager/master -- switch --flake ./remote-dev#vm
+# (a) Config-only change (nvim/zellij/zsh/git/ssh): no rebuild needed.
+git -C ~/.local/share/dotfiles pull
+
+# (b) Package set in home.nix changed: rebuild HM.
+cd ~/.local/share/dotfiles/remote-dev
+home-manager switch --impure --flake .#vm -b backup
```
## Adding a tool
Edit `home.nix`, add to `home.packages`, then `home-manager switch`.
+## Single-shell policy (leaf tools only)
+
+Nix on this VM carries **leaf CLI tools** plus **editor/AI-agent
+runtimes**, and nothing else. Specifically forbidden in `home.packages`
+because they would shadow Ubuntu's via `PATH` and silently break builds
+against the system sysroot/libc/CI: `cc`, `c++`, `gcc`, `g++`, `clang`,
+`clang++`, `ld`, `make`, `cmake`, `ninja`, `meson`, `pkg-config`,
+`autoconf`, `automake`, `python`, `python3`, `pip`, `cargo`, `rustc`,
+`go`. The system `python3` (`/usr/bin/python3`) stays the default
+interpreter for project builds.
+
+Explicit carve-outs (used only by Mason/editor/AI agents, never by the
+project build):
+
+- `nodejs` — `node`/`npm`/`npx` for npm-based LSPs.
+- `uv` — `uv`/`uvx` for Python LSPs in isolated venvs. `uv` does NOT
+ install a `python3` in PATH; it manages its own interpreters under
+ `~/.local/share/uv/`. System `python3` is untouched.
+- `clang-tools` — `clang-format`, `clang-tidy`, `clangd` only (no
+ compiler driver).
+
+If a project needs a newer build toolchain, drop a `flake.nix` +
+`.envrc` in that project tree (direnv + nix-direnv is already wired
+up). Don't add it to `home.nix`.
+
+## Commit signing on the VM (SSH-format, no GPG secrets)
+
+GPG private keys never leave the host. Commits on the VM are signed
+with the **forwarded SSH agent** in SSH-signature format, using the
+authentication subkey gpg-agent already exposes via `ssh-add -L`.
+
+One-time setup on the VM:
+
+```sh
+mkdir -p ~/.config/git
+
+# allowed_signers: maps your committer email to the SSH pubkey of the
+# auth subkey. Adjust the grep if you have multiple keys.
+printf '%s %s\n' \
+ "$(git config user.email)" \
+ "$(ssh-add -L | head -n1)" \
+ > ~/.config/git/allowed_signers
+
+# Machine-local git override (NOT tracked in dotfiles).
+cat > ~/.config/git/config.local <<EOF
+[gpg]
+ format = ssh
+[gpg "ssh"]
+ allowedSignersFile = ~/.config/git/allowed_signers
+[user]
+ signingkey = $(ssh-add -L | head -n1 | awk '{print $1" "$2}')
+EOF
+```
+
+The tracked `dot_config/git/config` ends with `[include] path =
+~/.config/git/config.local`, so the override is picked up
+automatically (and silently ignored on machines that don't have it).
+
+Required on the **host's** `~/.ssh/config` for the VM `Host` block:
+
+```
+ForwardAgent yes
+```
+
+Verify on the VM after SSH-ing in:
+
+```sh
+ssh-add -L # should list your auth pubkey(s)
+git commit --allow-empty -m test
+git log --show-signature -1
+```
+
## Caveats
-- **GPG / pass**: HM installs `gnupg` and `pass` but does _not_ import any
- private key. Bring your key separately if you need signed commits or
- `pass`-backed env vars on the VM.
+- **GPG / pass**: HM installs `gnupg` and `pass` but does _not_ import
+ any private key. Don't try; use SSH-format signing via the forwarded
+ agent instead (see above).
- **Disk usage**: Nix store + nvim plugins consumes ~3-5 GB. Check the
VM's root partition size first.
-- **Network for first nvim launch**: `vim.pack.add` fetches plugins from
- GitHub on first start.
-- **Ubuntu apt collisions**: Nix-installed binaries appear first in PATH.
- If you need a specific apt-version of something, install it manually
- and prefix with the full path.
+- **Network for first nvim launch**: `vim.pack.add` fetches plugins
+ from GitHub on first start. Mason will also fetch LSP servers using
+ `nodejs`/`uv` from this profile.
+- **Ubuntu apt collisions**: Nix-installed binaries appear first in
+ PATH. The leaf-tools policy above exists precisely to keep this
+ shadowing contained to harmless tools.
## How it's wired
diff --git a/remote-dev/home.nix b/remote-dev/home.nix
index a2b9392..184de6b 100644
--- a/remote-dev/home.nix
+++ b/remote-dev/home.nix
@@ -15,9 +15,19 @@ in
home.stateVersion = "25.05";
# ── Packages ────────────────────────────────────────────────────────────────
- # Mirrors the dev-tool subset of `meta/base.txt` on the Arch host. Tools that
- # only make sense on a workstation (procs/gdu/duf for sysadmin, lazygit
- # unused, node/yarn only needed for markdown-preview on GUI) are excluded.
+ # Policy: this profile carries leaf CLI tools plus editor/AI-agent
+ # runtimes (node, uv). It must NEVER carry anything the project build
+ # might invoke. Forbidden on PATH (would shadow Ubuntu's and break
+ # builds against the system sysroot/libc): cc, c++, gcc, g++, clang,
+ # clang++, ld, ld.lld, ar, nm, objcopy, make, cmake, ninja, meson,
+ # pkg-config, autoconf, automake, libtool, python, python3, pip,
+ # cargo, rustc, go. If a project needs a newer toolchain, put it in
+ # a project-local flake.nix + direnv `.envrc`, NOT here.
+ #
+ # Allowed runtimes (used only by Mason/editor/AI agents): node, npm,
+ # npx (via `nodejs`), uv, uvx (via `uv` — does NOT install a python3,
+ # manages its own interpreters under XDG). clang-tools is allowed
+ # because it ships only formatters/linters/clangd, no compiler driver.
home.packages = with pkgs; [
# Editor + multiplexer
neovim
@@ -30,6 +40,7 @@ in
fzf
sd
choose
+ zoxide
# Viewers
bat
@@ -66,6 +77,17 @@ in
gnupg
pass
+ # C/C++ source tooling (no compiler driver in PATH)
+ clang-tools
+
+ # Editor/AI agent runtimes — NOT for project builds (see policy above)
+ nodejs # Mason npm LSPs; system python3 stays at /usr/bin/python3
+ uv # Mason python LSPs in isolated venvs; brings `uv`/`uvx` only
+
+ # AI coding agents
+ claude-code
+ github-copilot-cli # NB: pkgs.copilot-cli is AWS Copilot, NOT this
+
# Zsh and plugins (sourced from $HOME/.nix-profile/share/... by the shared zshrc)
zsh
zsh-syntax-highlighting
@@ -90,8 +112,15 @@ in
"zsh/.zprofile".source = link "dot_config/zsh/dot_zprofile";
"ghostty".source = link "dot_config/ghostty"; # for terminfo refs only
"direnv/direnvrc".source = link "dot_config/direnv/direnvrc";
+ "git/config".source = link "dot_config/git/config";
+ "git/attributes".source = link "dot_config/git/attributes";
+ "git/ignore".source = link "dot_config/git/ignore";
};
+ # ~/.ssh/config from the dotfiles tree (read-only); keys + known_hosts
+ # stay machine-local on the VM.
+ home.file.".ssh/config".source = link "private_dot_ssh/config";
+
# ZDOTDIR redirect so login shells find ~/.config/zsh/.zprofile etc.
home.file.".zshenv".text = ''
export ZDOTDIR="$HOME/.config/zsh"