Archived
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ec7033439 | ||
|
|
9133afd444 | ||
|
|
eeec9ce302 | ||
|
|
a62c4fc023 | ||
|
|
97ede62f6d |
No files matched your search
@@ -7,7 +7,7 @@ servers and workstation.
|
|||||||
|
|
||||||
The flake exposes NixOS configurations named `<platform>-<buildtype>`
|
The flake exposes NixOS configurations named `<platform>-<buildtype>`
|
||||||
(platforms: `linode`, `proxmox`, `lxc`; build types: `minimal`, `nix-cache`,
|
(platforms: `linode`, `proxmox`, `lxc`; build types: `minimal`, `nix-cache`,
|
||||||
`server`, `docker`, `gui`, `pxe-boot`), generated from `modules/platforms/*`
|
`server`, `docker`, `gui`, `pxe-boot`, `tailscale-exit-node`), generated from `modules/platforms/*`
|
||||||
and `modules/build-types/*` by the `mkTarget` function in `flake.nix`. Not
|
and `modules/build-types/*` by the `mkTarget` function in `flake.nix`. Not
|
||||||
every combination is built — `pxe-boot` has no `linode` variant. See
|
every combination is built — `pxe-boot` has no `linode` variant. See
|
||||||
`README.md` for the full current target list; treat `flake.nix` as the
|
`README.md` for the full current target list; treat `flake.nix` as the
|
||||||
|
|||||||
@@ -62,8 +62,9 @@ There is no test suite — "correctness" here means the flake evaluates and
|
|||||||
sweeps: after editing one or two hosts/modules, evaluate just the
|
sweeps: after editing one or two hosts/modules, evaluate just the
|
||||||
`nixosConfigurations.<host>` you touched (plus any `config.system.build.tarball`
|
`nixosConfigurations.<host>` you touched (plus any `config.system.build.tarball`
|
||||||
/`diskoImagesScript`/package output affected) rather than looping over every
|
/`diskoImagesScript`/package output affected) rather than looping over every
|
||||||
host — `codex-maintenance.sh` evaluates 18 hosts plus every package/tarball/
|
host — `codex-maintenance.sh` evaluates every `nixosConfigurations` host plus
|
||||||
image variant now and is slow to run after each small change. Reserve a full
|
every package/tarball/image variant and is slow to run after each small
|
||||||
|
change. Reserve a full
|
||||||
`codex-maintenance.sh` run for changes that plausibly affect every host
|
`codex-maintenance.sh` run for changes that plausibly affect every host
|
||||||
(`modules/common/*`, `flake.nix`, `variables.nix`) or as a final check before
|
(`modules/common/*`, `flake.nix`, `variables.nix`) or as a final check before
|
||||||
committing. This is a session-workflow preference only — it does not apply to
|
committing. This is a session-workflow preference only — it does not apply to
|
||||||
@@ -164,7 +165,7 @@ removing a host.
|
|||||||
`vzdump` backup-archive metadata this doesn't have), no install step —
|
`vzdump` backup-archive metadata this doesn't have), no install step —
|
||||||
see `docs/auto-installer.md`.
|
see `docs/auto-installer.md`.
|
||||||
- `modules/build-types/*.nix` — what a system is for:
|
- `modules/build-types/*.nix` — what a system is for:
|
||||||
minimal/server/docker/gui/pxe-boot/nix-cache.
|
minimal/server/docker/gui/pxe-boot/nix-cache/tailscale-exit-node.
|
||||||
- `modules/common/configuration.nix` — base NixOS config imported by every
|
- `modules/common/configuration.nix` — base NixOS config imported by every
|
||||||
host: locale, users, nix settings, git.
|
host: locale, users, nix settings, git.
|
||||||
- `modules/common/home.nix` / `hosts/nixos/home.nix` — Home Manager config for
|
- `modules/common/home.nix` / `hosts/nixos/home.nix` — Home Manager config for
|
||||||
|
|||||||
@@ -18,22 +18,23 @@ list:
|
|||||||
|
|
||||||
| Target | Purpose |
|
| Target | Purpose |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `linode-minimal` | Minimal NixOS host profile on a Linode VPS (real, deployed) |
|
| `linode-minimal` | Minimal NixOS host profile on a Linode VPS |
|
||||||
| `proxmox-minimal` | Minimal NixOS host profile on Proxmox (real, deployed — previously the flat `nix-minimal` target) |
|
| `proxmox-minimal` | Minimal NixOS host profile on Proxmox — previously the flat `nix-minimal` target |
|
||||||
| `lxc-minimal` | Minimal NixOS host profile in a Proxmox LXC container |
|
| `lxc-minimal` | Minimal NixOS host profile in a Proxmox LXC container |
|
||||||
| `linode-nix-cache` / `proxmox-nix-cache` / `lxc-nix-cache` | Local Nix binary cache and remote builder (`lxc-nix-cache` is the real, deployed one — previously `proxmox-nix-cache`, itself previously the flat `nix-cache` target) |
|
| `linode-nix-cache` / `proxmox-nix-cache` / `lxc-nix-cache` | Local Nix binary cache and remote builder — previously the flat `nix-cache` target |
|
||||||
| `linode-server` / `proxmox-server` / `lxc-server` | Storage, NFS, backup, and monitoring exporter host (`proxmox-server` is the real, deployed one — previously the flat `server` target) |
|
| `linode-server` / `proxmox-server` / `lxc-server` | Storage, NFS, backup, and monitoring exporter host — previously the flat `server` target |
|
||||||
| `linode-docker` / `proxmox-docker` / `lxc-docker` | Docker host for the main container stack (`proxmox-docker` is the real, deployed one — previously the flat `docker` target) |
|
| `linode-docker` / `proxmox-docker` / `lxc-docker` | Docker host for the main container stack — previously the flat `docker` target |
|
||||||
| `linode-gui` / `proxmox-gui` / `lxc-gui` | Cinnamon desktop workstation (`proxmox-gui` is the real, deployed one — previously the flat `nixos` target) |
|
| `linode-gui` / `proxmox-gui` / `lxc-gui` | Cinnamon desktop workstation — previously the flat `nixos` target |
|
||||||
| `proxmox-pxe-boot` / `lxc-pxe-boot` | HTTP/iPXE boot asset host (`proxmox-pxe-boot` is the real, deployed one — previously the flat `pxe-boot` target) |
|
| `proxmox-pxe-boot` / `lxc-pxe-boot` | HTTP/iPXE boot asset host — previously the flat `pxe-boot` target |
|
||||||
| `linode-tailscale-exit-node` / `proxmox-tailscale-exit-node` / `lxc-tailscale-exit-node` | Tailscale exit node (no deployed target yet; `lxc-tailscale-exit-node` is the one planned for actual use) |
|
| `linode-tailscale-exit-node` / `proxmox-tailscale-exit-node` / `lxc-tailscale-exit-node` | Tailscale exit node |
|
||||||
|
|
||||||
This table is the only place "(real, deployed)" status is tracked — there's
|
Which variant of a given buildtype is actually deployed isn't tracked
|
||||||
no separate machine-readable copy to keep in sync. `scripts/create-proxmox-resource.sh`
|
anywhere in this repo — that's live infrastructure state, not something a
|
||||||
guards against creating a same-identity duplicate of an already-deployed host
|
committed file can keep accurate, and it changes independently of the code.
|
||||||
by checking the Proxmox node itself (live `qm`/`pct` state) rather than any
|
Check the Proxmox node itself, or `/etc/flake-target` on a running host (see
|
||||||
file in this repo, since a static list can't track whether a resource still
|
below), if you need to know what's really out there right now.
|
||||||
actually exists.
|
`scripts/create-proxmox-resource.sh`'s duplicate-host guard works the same
|
||||||
|
way: it checks the Proxmox node directly rather than any file here.
|
||||||
|
|
||||||
Each buildtype's `hosts/<name>/host.nix` carries the per-machine identity
|
Each buildtype's `hosts/<name>/host.nix` carries the per-machine identity
|
||||||
(hostname, hostId, per-machine secrets, `system.stateVersion`) that must stay
|
(hostname, hostId, per-machine secrets, `system.stateVersion`) that must stay
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ see "LXC hosts" immediately below for why those are different.**
|
|||||||
## LXC hosts
|
## LXC hosts
|
||||||
|
|
||||||
`lxc-*` targets (`lxc-minimal`, `lxc-nix-cache`, `lxc-server`, `lxc-docker`,
|
`lxc-*` targets (`lxc-minimal`, `lxc-nix-cache`, `lxc-server`, `lxc-docker`,
|
||||||
`lxc-gui`, `lxc-pxe-boot`) are **not** installed via `auto-install.sh` — the
|
`lxc-gui`, `lxc-pxe-boot`, `lxc-tailscale-exit-node`) are **not** installed via `auto-install.sh` — the
|
||||||
interactive menu deliberately excludes them. Don't try to select one there;
|
interactive menu deliberately excludes them. Don't try to select one there;
|
||||||
`nixos-install` would bind-mount `/` onto `/mnt` (LXC containers have no raw
|
`nixos-install` would bind-mount `/` onto `/mnt` (LXC containers have no raw
|
||||||
disk to partition) and then refuse to touch the filesystem it's currently
|
disk to partition) and then refuse to touch the filesystem it's currently
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# Spec: Refactor Flake Targets into Platform × Build-Type Matrix
|
# Spec: Refactor Flake Targets into Platform × Build-Type Matrix
|
||||||
|
|
||||||
|
**Status: implemented.** `flake.nix`'s `generatedTargets`/`mkTarget` and
|
||||||
|
`modules/platforms/*`/`modules/build-types/*` are the result of this spec —
|
||||||
|
kept here for historical rationale only (referenced from `CLAUDE.md`'s
|
||||||
|
"Composition pattern" section), not as an active or open plan. The "Open
|
||||||
|
Questions" below were resolved during implementation; don't treat them as
|
||||||
|
outstanding. A `tailscale-exit-node` build type was added later, beyond this
|
||||||
|
spec's original scope.
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
|
|
||||||
The flake at `~/nixos` currently defines these output targets (flat, ad-hoc naming):
|
The flake at `~/nixos` currently defines these output targets (flat, ad-hoc naming):
|
||||||
|
|||||||
@@ -122,13 +122,25 @@ Add a pre-commit hook (or a `nix flake check` step) running `gitleaks protect --
|
|||||||
|
|
||||||
## Definition of done
|
## Definition of done
|
||||||
|
|
||||||
- [ ] Milestone 1 inventory complete and reviewed
|
**Status as of 2026-07-20:** Milestones 1–3 are done — sops-nix is fully
|
||||||
- [ ] All hosts have per-host age keys; admin key backed up outside the repo
|
wired (`.sops.yaml`, `secrets/*.yaml`, referenced via `hashedPasswordFile`/
|
||||||
- [ ] Every inventoried secret migrated to sops-nix, referenced via `*File`/`sops.secrets.*.path`, nothing plaintext in the working tree
|
`*File`/`sops.secrets.*.path` throughout), and history has been scrubbed
|
||||||
- [ ] `nixos-rebuild dry-build` and at least one real `switch` verified per host
|
with `git-filter-repo` + force-push (this removed a GitHub fine-grained PAT
|
||||||
- [ ] Working-tree scanner sweep clean
|
that had been committed in plaintext in `flake.nix`/`common/home.nix`
|
||||||
- [ ] History rewritten with `git-filter-repo`, force-pushed, full-history scanner sweep clean
|
between 2025-07-16 and 2026-02-09, later migrated to sops but never scrubbed
|
||||||
- [ ] All other clones deleted and re-cloned from the rewritten history
|
from history until now). **Milestone 4 is not confirmed** — whether that PAT
|
||||||
- [ ] Every credential in the original inventory rotated (not just re-encrypted)
|
(or any other historically-plaintext credential) was actually rotated, not
|
||||||
- [ ] Pre-commit secret scanning hook added
|
just re-encrypted, isn't something this repo can attest to; that's an
|
||||||
- [ ] `secrets-inventory.md` deleted from the working directory (never committed)
|
operator action against the issuing service (GitHub, etc.), not a repo
|
||||||
|
change. Do that before considering this fully closed.
|
||||||
|
|
||||||
|
- [x] Milestone 1 inventory complete and reviewed
|
||||||
|
- [x] All hosts have per-host age keys; admin key backed up outside the repo
|
||||||
|
- [x] Every inventoried secret migrated to sops-nix, referenced via `*File`/`sops.secrets.*.path`, nothing plaintext in the working tree
|
||||||
|
- [x] `nixos-rebuild dry-build` and at least one real `switch` verified per host
|
||||||
|
- [x] Working-tree scanner sweep clean
|
||||||
|
- [x] History rewritten with `git-filter-repo`, force-pushed, full-history scanner sweep clean
|
||||||
|
- [ ] All other clones deleted and re-cloned from the rewritten history — every clone that existed before 2026-07-20's rewrite (any other machine, WSL instance, or CI checkout) needs this
|
||||||
|
- [ ] Every credential in the original inventory rotated (not just re-encrypted) — **the GitHub PAT found in history specifically still needs this**
|
||||||
|
- [x] Pre-commit secret scanning hook added (`.githooks/pre-commit`, `gitleaks protect --staged`)
|
||||||
|
- [x] `secrets-inventory.md` deleted from the working directory (never committed)
|
||||||
@@ -1,14 +1,22 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
export NIX_CONFIG="${NIX_CONFIG:-}
|
||||||
# shellcheck source=lib/nix-bootstrap.sh
|
experimental-features = nix-command flakes
|
||||||
source "${script_dir}/lib/nix-bootstrap.sh"
|
accept-flake-config = false
|
||||||
# shellcheck source=lib/nix-eval.sh
|
warn-dirty = false
|
||||||
source "${script_dir}/lib/nix-eval.sh"
|
"
|
||||||
|
|
||||||
MODE="${1:-validate}"
|
MODE="${1:-validate}"
|
||||||
|
|
||||||
|
ensure_nix_profile() {
|
||||||
|
if [ -f /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh ]; then
|
||||||
|
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
|
||||||
|
elif [ -f "$HOME/.nix-profile/etc/profile.d/nix.sh" ]; then
|
||||||
|
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
ensure_nix_profile
|
ensure_nix_profile
|
||||||
|
|
||||||
if ! command -v nix >/dev/null 2>&1; then
|
if ! command -v nix >/dev/null 2>&1; then
|
||||||
@@ -16,7 +24,8 @@ if ! command -v nix >/dev/null 2>&1; then
|
|||||||
exit 127
|
exit 127
|
||||||
fi
|
fi
|
||||||
|
|
||||||
hosts="$(list_flake_targets .)"
|
hosts_json="$(nix eval --json --no-use-registries --no-accept-flake-config .#nixosConfigurations --apply builtins.attrNames)"
|
||||||
|
hosts="$(echo "$hosts_json" | jq -r '.[]')"
|
||||||
|
|
||||||
echo "Hosts:"
|
echo "Hosts:"
|
||||||
echo "$hosts"
|
echo "$hosts"
|
||||||
@@ -35,17 +44,17 @@ fi
|
|||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Checking Nix formatting with nixpkgs-fmt..."
|
echo "Checking Nix formatting with nixpkgs-fmt..."
|
||||||
nix run "${NIX_EVAL_FLAGS[@]}" github:NixOS/nixpkgs/nixos-25.11#nixpkgs-fmt -- --check .
|
nix run --no-use-registries --no-accept-flake-config github:NixOS/nixpkgs/nixos-25.11#nixpkgs-fmt -- --check .
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Running statix lint..."
|
echo "Running statix lint..."
|
||||||
nix run "${NIX_EVAL_FLAGS[@]}" github:NixOS/nixpkgs/nixos-25.11#statix -- check .
|
nix run --no-use-registries --no-accept-flake-config github:NixOS/nixpkgs/nixos-25.11#statix -- check .
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Evaluating host toplevel derivations..."
|
echo "Evaluating host toplevel derivations..."
|
||||||
for host in $hosts; do
|
for host in $hosts; do
|
||||||
echo "==> $host"
|
echo "==> $host"
|
||||||
nix eval --raw "${NIX_EVAL_FLAGS[@]}" ".#nixosConfigurations.${host}.config.system.build.toplevel.drvPath"
|
nix eval --raw --no-use-registries --no-accept-flake-config ".#nixosConfigurations.${host}.config.system.build.toplevel.drvPath"
|
||||||
|
|
||||||
# lxc-* hosts deploy via a directly pct-restore-able tarball instead of
|
# lxc-* hosts deploy via a directly pct-restore-able tarball instead of
|
||||||
# nixos-install (see docs/auto-installer.md); proxmox-* hosts can
|
# nixos-install (see docs/auto-installer.md); proxmox-* hosts can
|
||||||
@@ -55,21 +64,22 @@ for host in $hosts; do
|
|||||||
case "$host" in
|
case "$host" in
|
||||||
lxc-*)
|
lxc-*)
|
||||||
echo "==> $host (tarball)"
|
echo "==> $host (tarball)"
|
||||||
nix eval --raw "${NIX_EVAL_FLAGS[@]}" ".#nixosConfigurations.${host}.config.system.build.tarball.drvPath"
|
nix eval --raw --no-use-registries --no-accept-flake-config ".#nixosConfigurations.${host}.config.system.build.tarball.drvPath"
|
||||||
;;
|
;;
|
||||||
proxmox-*)
|
proxmox-*)
|
||||||
echo "==> $host (diskoImagesScript)"
|
echo "==> $host (diskoImagesScript)"
|
||||||
nix eval --raw "${NIX_EVAL_FLAGS[@]}" ".#nixosConfigurations.${host}.config.system.build.diskoImagesScript.drvPath"
|
nix eval --raw --no-use-registries --no-accept-flake-config ".#nixosConfigurations.${host}.config.system.build.diskoImagesScript.drvPath"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Evaluating buildable packages..."
|
echo "Evaluating buildable packages..."
|
||||||
packages="$(nix eval --json "${NIX_EVAL_FLAGS[@]}" .#packages.x86_64-linux --apply builtins.attrNames | jq -r '.[]')"
|
packages_json="$(nix eval --json --no-use-registries --no-accept-flake-config .#packages.x86_64-linux --apply builtins.attrNames)"
|
||||||
|
packages="$(echo "$packages_json" | jq -r '.[]')"
|
||||||
for pkg in $packages; do
|
for pkg in $packages; do
|
||||||
echo "==> packages.x86_64-linux.${pkg}"
|
echo "==> packages.x86_64-linux.${pkg}"
|
||||||
nix eval --raw "${NIX_EVAL_FLAGS[@]}" ".#packages.x86_64-linux.${pkg}"
|
nix eval --raw --no-use-registries --no-accept-flake-config ".#packages.x86_64-linux.${pkg}"
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ "$MODE" == "dry-run" ]]; then
|
if [[ "$MODE" == "dry-run" ]]; then
|
||||||
@@ -77,16 +87,16 @@ if [[ "$MODE" == "dry-run" ]]; then
|
|||||||
echo "Running dry-run builds for all hosts. This will not create result symlinks."
|
echo "Running dry-run builds for all hosts. This will not create result symlinks."
|
||||||
for host in $hosts; do
|
for host in $hosts; do
|
||||||
echo "==> Dry-run build: $host"
|
echo "==> Dry-run build: $host"
|
||||||
nix build --dry-run --no-link "${NIX_EVAL_FLAGS[@]}" ".#nixosConfigurations.${host}.config.system.build.toplevel"
|
nix build --dry-run --no-link --no-use-registries --no-accept-flake-config ".#nixosConfigurations.${host}.config.system.build.toplevel"
|
||||||
|
|
||||||
case "$host" in
|
case "$host" in
|
||||||
lxc-*)
|
lxc-*)
|
||||||
echo "==> Dry-run build: $host (tarball)"
|
echo "==> Dry-run build: $host (tarball)"
|
||||||
nix build --dry-run --no-link "${NIX_EVAL_FLAGS[@]}" ".#nixosConfigurations.${host}.config.system.build.tarball"
|
nix build --dry-run --no-link --no-use-registries --no-accept-flake-config ".#nixosConfigurations.${host}.config.system.build.tarball"
|
||||||
;;
|
;;
|
||||||
proxmox-*)
|
proxmox-*)
|
||||||
echo "==> Dry-run build: $host (diskoImagesScript)"
|
echo "==> Dry-run build: $host (diskoImagesScript)"
|
||||||
nix build --dry-run --no-link "${NIX_EVAL_FLAGS[@]}" ".#nixosConfigurations.${host}.config.system.build.diskoImagesScript"
|
nix build --dry-run --no-link --no-use-registries --no-accept-flake-config ".#nixosConfigurations.${host}.config.system.build.diskoImagesScript"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@@ -95,7 +105,7 @@ if [[ "$MODE" == "dry-run" ]]; then
|
|||||||
echo "Running dry-run builds for all packages."
|
echo "Running dry-run builds for all packages."
|
||||||
for pkg in $packages; do
|
for pkg in $packages; do
|
||||||
echo "==> Dry-run build: packages.x86_64-linux.${pkg}"
|
echo "==> Dry-run build: packages.x86_64-linux.${pkg}"
|
||||||
nix build --dry-run --no-link "${NIX_EVAL_FLAGS[@]}" ".#packages.x86_64-linux.${pkg}"
|
nix build --dry-run --no-link --no-use-registries --no-accept-flake-config ".#packages.x86_64-linux.${pkg}"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
+15
-7
@@ -1,11 +1,19 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
export NIX_CONFIG="${NIX_CONFIG:-}
|
||||||
# shellcheck source=lib/nix-bootstrap.sh
|
experimental-features = nix-command flakes
|
||||||
source "${script_dir}/lib/nix-bootstrap.sh"
|
accept-flake-config = false
|
||||||
# shellcheck source=lib/nix-eval.sh
|
warn-dirty = false
|
||||||
source "${script_dir}/lib/nix-eval.sh"
|
"
|
||||||
|
|
||||||
|
ensure_nix_profile() {
|
||||||
|
if [ -f /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh ]; then
|
||||||
|
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
|
||||||
|
elif [ -f "$HOME/.nix-profile/etc/profile.d/nix.sh" ]; then
|
||||||
|
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
install_nix_if_missing() {
|
install_nix_if_missing() {
|
||||||
if command -v nix >/dev/null 2>&1; then
|
if command -v nix >/dev/null 2>&1; then
|
||||||
@@ -71,13 +79,13 @@ if ! command -v jq >/dev/null 2>&1; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Available NixOS hosts:"
|
echo "Available NixOS hosts:"
|
||||||
hosts="$(list_flake_targets .)"
|
hosts="$(nix eval --json --no-use-registries --no-accept-flake-config .#nixosConfigurations --apply builtins.attrNames | jq -r '.[]')"
|
||||||
echo "$hosts"
|
echo "$hosts"
|
||||||
|
|
||||||
echo "Evaluating all host toplevel derivations..."
|
echo "Evaluating all host toplevel derivations..."
|
||||||
for host in $hosts; do
|
for host in $hosts; do
|
||||||
echo "==> Evaluating $host"
|
echo "==> Evaluating $host"
|
||||||
nix eval --raw "${NIX_EVAL_FLAGS[@]}" ".#nixosConfigurations.${host}.config.system.build.toplevel.drvPath"
|
nix eval --raw --no-use-registries --no-accept-flake-config ".#nixosConfigurations.${host}.config.system.build.toplevel.drvPath"
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "Codex setup complete."
|
echo "Codex setup complete."
|
||||||
@@ -26,8 +26,6 @@ set -euo pipefail
|
|||||||
repo_root="$(cd "$(dirname "$0")/.." && pwd)"
|
repo_root="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
# shellcheck source=env.sh
|
# shellcheck source=env.sh
|
||||||
source "${repo_root}/scripts/env.sh"
|
source "${repo_root}/scripts/env.sh"
|
||||||
# shellcheck source=lib/nix-eval.sh
|
|
||||||
source "${repo_root}/scripts/lib/nix-eval.sh"
|
|
||||||
|
|
||||||
sync_keys="${repo_root}/scripts/sync-host-keys.sh"
|
sync_keys="${repo_root}/scripts/sync-host-keys.sh"
|
||||||
|
|
||||||
@@ -242,21 +240,15 @@ platform_prefix="lxc"
|
|||||||
[[ -z "$memory" ]] && memory="$PROXMOX_DEFAULT_MEMORY_MB"
|
[[ -z "$memory" ]] && memory="$PROXMOX_DEFAULT_MEMORY_MB"
|
||||||
|
|
||||||
# --- discover / resolve the flake target from --host --------------------
|
# --- discover / resolve the flake target from --host --------------------
|
||||||
# Emits "<target>\t<hostName>" pairs for every ${platform_prefix}-* flake
|
|
||||||
# target -- the one source both --list and the --host lookup below read
|
|
||||||
# from, so they can never see a different set of targets from each other.
|
|
||||||
targets_for_platform() {
|
|
||||||
local target
|
|
||||||
for target in $(list_flake_targets "$repo_root" 2>/dev/null | grep -- "^${platform_prefix}-"); do
|
|
||||||
printf '%s\t%s\n' "$target" "$(flake_target_hostname "$repo_root" "$target")"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
list_hosts() {
|
list_hosts() {
|
||||||
local target hostname
|
local target hostname
|
||||||
while IFS=$'\t' read -r target hostname; do
|
for target in $(nix eval --json --no-use-registries --no-accept-flake-config \
|
||||||
|
"${repo_root}#nixosConfigurations" --apply builtins.attrNames 2>/dev/null \
|
||||||
|
| jq -r --arg p "${platform_prefix}-" '.[] | select(startswith($p))'); do
|
||||||
|
hostname="$(nix eval --raw --no-use-registries --no-accept-flake-config \
|
||||||
|
"${repo_root}#nixosConfigurations.${target}.config.networking.hostName" 2>/dev/null)"
|
||||||
printf ' %-12s -> %s\n' "$hostname" "$target"
|
printf ' %-12s -> %s\n' "$hostname" "$target"
|
||||||
done < <(targets_for_platform)
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ "$do_list" -eq 1 ]]; then
|
if [[ "$do_list" -eq 1 ]]; then
|
||||||
@@ -271,12 +263,16 @@ if [[ -z "$host" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
flake_target=""
|
flake_target=""
|
||||||
while IFS=$'\t' read -r target hostname; do
|
for target in $(nix eval --json --no-use-registries --no-accept-flake-config \
|
||||||
if [[ "$hostname" == "$host" ]]; then
|
"${repo_root}#nixosConfigurations" --apply builtins.attrNames \
|
||||||
|
| jq -r --arg p "${platform_prefix}-" '.[] | select(startswith($p))'); do
|
||||||
|
hn="$(nix eval --raw --no-use-registries --no-accept-flake-config \
|
||||||
|
"${repo_root}#nixosConfigurations.${target}.config.networking.hostName")"
|
||||||
|
if [[ "$hn" == "$host" ]]; then
|
||||||
flake_target="$target"
|
flake_target="$target"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done < <(targets_for_platform)
|
done
|
||||||
|
|
||||||
if [[ -z "$flake_target" ]]; then
|
if [[ -z "$flake_target" ]]; then
|
||||||
echo "ERROR: no ${platform_prefix}-* target has hostName '${host}'." >&2
|
echo "ERROR: no ${platform_prefix}-* target has hostName '${host}'." >&2
|
||||||
@@ -324,6 +320,7 @@ for id in $(pct list 2>/dev/null | awk 'NR>1{print $1}'); do
|
|||||||
n="$(pct config "$id" 2>/dev/null | grep -oP '^hostname:\s*\K\S+' || true)"
|
n="$(pct config "$id" 2>/dev/null | grep -oP '^hostname:\s*\K\S+' || true)"
|
||||||
[[ "$n" == "$target" ]] && echo "lxc ${id} ${n}"
|
[[ "$n" == "$target" ]] && echo "lxc ${id} ${n}"
|
||||||
done
|
done
|
||||||
|
exit 0
|
||||||
REMOTE_SCRIPT
|
REMOTE_SCRIPT
|
||||||
)" || ssh_check_status=$?
|
)" || ssh_check_status=$?
|
||||||
if [[ "$ssh_check_status" -ne 0 ]]; then
|
if [[ "$ssh_check_status" -ne 0 ]]; then
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Shared Nix bootstrap for scripts/codex-setup.sh and
|
|
||||||
# scripts/codex-maintenance.sh: the nix.conf settings both need in effect
|
|
||||||
# before a single `nix` command runs (flakes enabled, never honor a flake
|
|
||||||
# input's own nixConfig, no "dirty tree" warning spam), plus a helper to
|
|
||||||
# pull an already-installed Nix's daemon/profile script onto PATH if it
|
|
||||||
# isn't there yet. Source this instead of copying it -- see CLAUDE.md.
|
|
||||||
export NIX_CONFIG="${NIX_CONFIG:-}
|
|
||||||
experimental-features = nix-command flakes
|
|
||||||
accept-flake-config = false
|
|
||||||
warn-dirty = false
|
|
||||||
"
|
|
||||||
|
|
||||||
ensure_nix_profile() {
|
|
||||||
if [ -f /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh ]; then
|
|
||||||
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
|
|
||||||
elif [ -f "$HOME/.nix-profile/etc/profile.d/nix.sh" ]; then
|
|
||||||
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Shared flake-introspection helpers for scripts/*.sh. Source alongside
|
|
||||||
# env.sh:
|
|
||||||
# source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/nix-eval.sh"
|
|
||||||
#
|
|
||||||
# NIX_EVAL_FLAGS: --no-use-registries so a call here never resolves through
|
|
||||||
# the user's global flake registry (every call targets this repo's own
|
|
||||||
# flake, or an explicit github: ref, not a registry alias); --no-accept-flake-config
|
|
||||||
# so a flake input's own nixConfig (e.g. a dependency's substituters) is
|
|
||||||
# never honored -- matches accept-flake-config = false already set repo-wide
|
|
||||||
# (see lib/nix-bootstrap.sh / CLAUDE.md). Reuse this array rather than
|
|
||||||
# retyping the two flags at each call site.
|
|
||||||
declare -a NIX_EVAL_FLAGS=(--no-use-registries --no-accept-flake-config)
|
|
||||||
|
|
||||||
# list_flake_targets <flake_ref>
|
|
||||||
# Prints the attribute names under <flake_ref>#nixosConfigurations, one per
|
|
||||||
# line, e.g.:
|
|
||||||
# list_flake_targets . # from inside the repo
|
|
||||||
# list_flake_targets "$repo_root" # from anywhere
|
|
||||||
list_flake_targets() {
|
|
||||||
local flake_ref="$1"
|
|
||||||
nix eval --json "${NIX_EVAL_FLAGS[@]}" \
|
|
||||||
"${flake_ref}#nixosConfigurations" --apply builtins.attrNames \
|
|
||||||
| jq -r '.[]'
|
|
||||||
}
|
|
||||||
|
|
||||||
# flake_target_hostname <flake_ref> <target>
|
|
||||||
# Prints one nixosConfigurations target's config.networking.hostName.
|
|
||||||
# Empty (not an error under set -e) if the target doesn't exist or the
|
|
||||||
# eval otherwise fails -- callers that need to distinguish "empty" from
|
|
||||||
# "eval failed" should check $? themselves instead of relying on this.
|
|
||||||
flake_target_hostname() {
|
|
||||||
local flake_ref="$1" target="$2"
|
|
||||||
nix eval --raw "${NIX_EVAL_FLAGS[@]}" \
|
|
||||||
"${flake_ref}#nixosConfigurations.${target}.config.networking.hostName" 2>/dev/null
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Shared SSH-host-key / age-conversion helpers for scripts/sync-host-keys.sh
|
|
||||||
# and scripts/prepare-host-key.sh -- both generate the same kind of key
|
|
||||||
# (ed25519, no passphrase, the sops-nix age-derivation input) and convert it
|
|
||||||
# to an age recipient the same way; kept in one place so the two can't
|
|
||||||
# drift apart.
|
|
||||||
#
|
|
||||||
# Uses NIX_OPTS (an array of extra `nix-shell` options -- see env.sh's
|
|
||||||
# nix_extra_opts) if the caller has already set it, so a decision to avoid
|
|
||||||
# an unreachable nix-cache is reused here instead of probed again. Falls
|
|
||||||
# back to no extra options if the caller never sourced env.sh.
|
|
||||||
if ! declare -p NIX_OPTS >/dev/null 2>&1; then
|
|
||||||
declare -a NIX_OPTS=()
|
|
||||||
fi
|
|
||||||
|
|
||||||
# generate_host_ed25519_key <hostname> <keyfile>
|
|
||||||
# Writes <keyfile> and <keyfile>.pub. Caller is responsible for refusing to
|
|
||||||
# overwrite an existing keyfile -- this always runs ssh-keygen fresh.
|
|
||||||
generate_host_ed25519_key() {
|
|
||||||
local hostname="$1" keyfile="$2"
|
|
||||||
nix-shell "${NIX_OPTS[@]}" -p openssh --run \
|
|
||||||
"ssh-keygen -t ed25519 -N '' -C '${hostname}' -f '${keyfile}'" >/dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
# ssh_pubkey_to_age <pubkeyfile>
|
|
||||||
# Prints the age public key derived from an ed25519 SSH public key file.
|
|
||||||
ssh_pubkey_to_age() {
|
|
||||||
local pubkeyfile="$1"
|
|
||||||
nix-shell "${NIX_OPTS[@]}" -p ssh-to-age --run "ssh-to-age -i '${pubkeyfile}'"
|
|
||||||
}
|
|
||||||
@@ -23,10 +23,6 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
repo_root="$(cd "$(dirname "$0")/.." && pwd)"
|
repo_root="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
# shellcheck source=env.sh
|
|
||||||
source "${repo_root}/scripts/env.sh"
|
|
||||||
# shellcheck source=lib/ssh-host-keys.sh
|
|
||||||
source "${repo_root}/scripts/lib/ssh-host-keys.sh"
|
|
||||||
|
|
||||||
hostname="${1:?usage: scripts/prepare-host-key.sh <hostname>}"
|
hostname="${1:?usage: scripts/prepare-host-key.sh <hostname>}"
|
||||||
sops_yaml="${repo_root}/.sops.yaml"
|
sops_yaml="${repo_root}/.sops.yaml"
|
||||||
@@ -45,10 +41,9 @@ if [[ -f "$keyfile" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
nix_extra_opts
|
nix-shell -p openssh --run "ssh-keygen -t ed25519 -N '' -C '${hostname}' -f '${keyfile}'" >/dev/null
|
||||||
generate_host_ed25519_key "$hostname" "$keyfile"
|
|
||||||
|
|
||||||
age_pub="$(ssh_pubkey_to_age "${keyfile}.pub")"
|
age_pub="$(nix-shell -p ssh-to-age --run "ssh-to-age -i '${keyfile}.pub'")"
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
|
|||||||
@@ -31,10 +31,6 @@ editor="${repo_root}/scripts/lib/sync-host-keys-edit-sops.py"
|
|||||||
|
|
||||||
# shellcheck source=env.sh
|
# shellcheck source=env.sh
|
||||||
source "${repo_root}/scripts/env.sh"
|
source "${repo_root}/scripts/env.sh"
|
||||||
# shellcheck source=lib/nix-eval.sh
|
|
||||||
source "${repo_root}/scripts/lib/nix-eval.sh"
|
|
||||||
# shellcheck source=lib/ssh-host-keys.sh
|
|
||||||
source "${repo_root}/scripts/lib/ssh-host-keys.sh"
|
|
||||||
|
|
||||||
mkdir -p "$keydir"
|
mkdir -p "$keydir"
|
||||||
|
|
||||||
@@ -122,10 +118,12 @@ EOF
|
|||||||
}
|
}
|
||||||
|
|
||||||
discover_targets() {
|
discover_targets() {
|
||||||
|
nix eval --json --no-use-registries --no-accept-flake-config \
|
||||||
|
"${repo_root}#nixosConfigurations" --apply builtins.attrNames \
|
||||||
|
| jq -r '.[] | select(. != "installer")'
|
||||||
# installer is the one nixosConfigurations target that doesn't import
|
# installer is the one nixosConfigurations target that doesn't import
|
||||||
# sops-nix at all (see CLAUDE.md's "Security Notes" -- hardcoded login
|
# sops-nix at all (see CLAUDE.md's "Security Notes" -- hardcoded login
|
||||||
# password instead) -- config.sops.secrets doesn't exist for it.
|
# password instead) -- config.sops.secrets doesn't exist for it.
|
||||||
list_flake_targets "$repo_root" | grep -v '^installer$'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
locally_managed_hosts() {
|
locally_managed_hosts() {
|
||||||
@@ -161,7 +159,7 @@ queue_host_sync() {
|
|||||||
echo "[dry-run] ${host}: would generate host key"
|
echo "[dry-run] ${host}: would generate host key"
|
||||||
else
|
else
|
||||||
echo "==> ${host}: generating host key"
|
echo "==> ${host}: generating host key"
|
||||||
generate_host_ed25519_key "$host" "$keyfile"
|
nix-shell "${NIX_OPTS[@]}" -p openssh --run "ssh-keygen -t ed25519 -N '' -C '${host}' -f '${keyfile}'" >/dev/null
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "==> ${host}: host key already present"
|
echo "==> ${host}: host key already present"
|
||||||
@@ -172,7 +170,7 @@ queue_host_sync() {
|
|||||||
if [[ "$dry_run" -eq 1 ]]; then
|
if [[ "$dry_run" -eq 1 ]]; then
|
||||||
age_pub="dry-run-placeholder-not-a-real-key"
|
age_pub="dry-run-placeholder-not-a-real-key"
|
||||||
else
|
else
|
||||||
age_pub="$(ssh_pubkey_to_age "${keyfile}.pub")"
|
age_pub="$(nix-shell "${NIX_OPTS[@]}" -p ssh-to-age --run "ssh-to-age -i '${keyfile}.pub'")"
|
||||||
fi
|
fi
|
||||||
add_keys_json="$(jq --arg host "$host" --arg key "$age_pub" \
|
add_keys_json="$(jq --arg host "$host" --arg key "$age_pub" \
|
||||||
'. + [{host: $host, age_key: $key}]' <<<"$add_keys_json")"
|
'. + [{host: $host, age_key: $key}]' <<<"$add_keys_json")"
|
||||||
|
|||||||
Reference in new issue
Block a user