diff --git a/assets/zed/settings.json b/assets/zed/settings.json deleted file mode 100644 index e48db6f..0000000 --- a/assets/zed/settings.json +++ /dev/null @@ -1,53 +0,0 @@ -// Zed settings — tracked in dotfiles, symlinked into ~/.config/zed/settings.json -// by home-manager (xdg.configFile in nixos/home/danny/home.nix). -// -// Because this is a symlink to a nix-store file, editing it from inside Zed -// will fail (read-only). Edit THIS file in dotfiles, commit, and rebuild -// (`darwin-rebuild switch --flake .`). To see Zed's full default settings, -// run `zed: open default settings` from the command palette. -{ - "sticky_scroll": { - "enabled": true - }, - "edit_predictions": { - "provider": "ollama" - }, - "buffer_font_family": "JetBrains Mono", - "cli_default_open_behavior": "existing_window", - "project_panel": { - "dock": "left" - }, - "outline_panel": { - "dock": "left" - }, - "collaboration_panel": { - "dock": "left" - }, - "git_panel": { - "dock": "left" - }, - "agent": { - "dock": "right", - "default_model": { - "provider": "ollama", - "model": "llama3.2:latest" - } - }, - "disable_ai": false, - "minimap": { - "show": "auto" - }, - "telemetry": { - "diagnostics": false, - "metrics": false - }, - "base_keymap": "VSCode", - "vim_mode": true, - "ui_font_size": 16, - "buffer_font_size": 15, - "theme": { - "mode": "system", - "light": "One Light", - "dark": "One Dark" - } -} diff --git a/docs/server-installer-usb.md b/docs/server-installer-usb.md index 295f227..4c69d53 100644 --- a/docs/server-installer-usb.md +++ b/docs/server-installer-usb.md @@ -94,45 +94,16 @@ sudo dd if=result/iso/nixos-minimal-*.iso of=/dev/sdX status=progress bs=4M ## Live-system WiFi (optional, custom ISO only) -The minimal installer ISO runs NetworkManager, so live-system WiFi must be a -declarative NetworkManager profile. `networking.wireless` / wpa_supplicant does -**not** work here — NixOS asserts you cannot combine `networking.networkmanager` -with `networking.wireless.networks`. - -Create `nixos/installer-wifi.nix` (gitignored — it holds the PSK): +Create `nixos/installer-wifi.nix` (gitignored): ```nix { - networking.networkmanager.ensureProfiles.profiles.installer-wifi = { - connection = { - id = "installer-wifi"; - type = "wifi"; - }; - wifi = { - mode = "infrastructure"; - ssid = "YourSSID"; - }; - wifi-security = { - auth-alg = "open"; - key-mgmt = "wpa-psk"; - psk = "your-password"; - }; - ipv4.method = "auto"; - ipv6.method = "auto"; - }; + networking.wireless.enable = true; + networking.wireless.networks."YourSSID".psk = "your-password"; } ``` -`flake-modules/installer-iso.nix` auto-includes this file when present (via a -`builtins.pathExists` check) — no flake edit needed. Because the file is -gitignored, the flake only sees it once it is staged: - -- **`build-installer-iso-on-server.sh`** copies the file to the build host and - runs `git add -f` automatically. -- For a **direct `nix build`**, run `git add -f nixos/installer-wifi.nix` first - (staging is enough — never commit it; it contains the PSK). - -Then rebuild the ISO on Linux. +Add to flake's installer-iso modules, rebuild ISO on Linux. ## Installed-system WiFi (optional) diff --git a/flake-modules/clan.nix b/flake-modules/clan.nix index e4a7944..f8b1293 100644 --- a/flake-modules/clan.nix +++ b/flake-modules/clan.nix @@ -21,8 +21,6 @@ let sunkenShipZTv6 = "fdd5:53a2:de33:d269:6499:93d5:53a2:de33"; phantomShipZTv6 = "fdd5:53a2:de33:d269:6499:936c:48a:bbdc"; vpsRelayZTv6 = "fdd5:53a2:de33:d269:6499:9305:339f:2ed3"; - distantShoreZTv6 = "fdd5:53a2:de33:d269:6499:93b6:ef1a:c3b3"; - foreignPortZTv6 = "fdd5:53a2:de33:d269:6499:9389:9b18:6c52"; # Shared across both servers: /etc/hosts entries so data-mesher's # libp2p /dns/.clan/... bootstrap multiaddrs resolve over ZT. @@ -31,8 +29,6 @@ let "${sunkenShipZTv6}" = [ "sunken-ship.clan" ]; "${phantomShipZTv6}" = [ "phantom-ship.clan" ]; "${vpsRelayZTv6}" = [ "vps-relay.clan" ]; - "${distantShoreZTv6}" = [ "distant-shore.clan" ]; - "${foreignPortZTv6}" = [ "foreign-port.clan" ]; }; }; in { @@ -51,8 +47,6 @@ in { inventory.machines.sunken-ship = { }; inventory.machines.phantom-ship = { }; inventory.machines.vps-relay = { }; - inventory.machines.distant-shore = { }; - inventory.machines.foreign-port = { }; # ZeroTier mesh VPN. sunken-ship is the controller (manages network # membership); phantom-ship is a peer. The mac joins manually as an @@ -64,8 +58,6 @@ in { roles.peer.machines.phantom-ship = { }; roles.peer.machines.sunken-ship = { }; roles.peer.machines.vps-relay = { }; - roles.peer.machines.distant-shore = { }; - roles.peer.machines.foreign-port = { }; }; # data-mesher — signed-file gossip protocol over libp2p (port 7946). @@ -78,8 +70,6 @@ in { module.input = "clan-core"; roles.default.machines.sunken-ship = { }; roles.default.machines.phantom-ship = { }; - roles.default.machines.distant-shore = { }; - roles.default.machines.foreign-port = { }; roles.bootstrap.machines.sunken-ship = { }; }; @@ -97,8 +87,6 @@ in { }; roles.default.machines.sunken-ship.settings.action = "switch"; roles.default.machines.phantom-ship.settings.action = "switch"; - roles.default.machines.distant-shore.settings.action = "switch"; - roles.default.machines.foreign-port.settings.action = "switch"; }; # `clan machines update` connection target. Priority 2000 > ZT's 900 @@ -123,18 +111,6 @@ in { host = "89.167.39.251"; user = "danny"; }; - # distant-shore: LAN IP for the first update (not yet on ZT). Swap to - # its generated ZT IPv6 after it joins the mesh, like the others. - roles.default.machines.distant-shore.settings = { - host = "192.168.1.182"; - user = "danny"; - }; - # foreign-port: WiFi-only LAN IP for the first update; swap to its - # generated ZT IPv6 after it joins the mesh. - roles.default.machines.foreign-port.settings = { - host = "192.168.1.223"; - user = "danny"; - }; }; # Preserve current network / init stack (no systemd-networkd/resolved, @@ -149,9 +125,8 @@ in { } clanHostsModule ../nixos/hosts/sunken-ship.nix + config.flake.nixosModules.dotfiles-rebuild config.flake.nixosModules.server-debug-tools - config.flake.nixosModules.monitoring-node-exporter - config.flake.nixosModules.monitoring-prometheus-server inputs.home-manager.nixosModules.home-manager (hmModule { user = "danny"; @@ -171,56 +146,6 @@ in { } clanHostsModule ../nixos/hosts/vps-relay.nix - config.flake.nixosModules.monitoring-node-exporter - inputs.home-manager.nixosModules.home-manager - (hmModule { - user = "danny"; - homeDirectory = "/home/danny"; - stateVersion = "25.11"; - }) - ]; - }; - - # distant-shore — ThinkPad X13 Gen 2, WiFi, Secure Boot via shim+MOK - # (installed standalone, then migrated into clan). targetHost is the LAN - # IP for the first `clan machines update`; switch to its ZT IPv6 once the - # mesh is up. buildHost = sunken-ship: it's an x86_64 builder whose key is - # already in distant-shore's authorized_keys, so the closure copy works - # (building on distant-shore itself needs a fragile self-SSH). - machines.distant-shore = { - imports = [ - { - clan.core.enableRecommendedDefaults = false; - clan.core.networking.targetHost = "danny@192.168.1.182"; - clan.core.networking.buildHost = "danny@sunken-ship"; - } - clanHostsModule - ../nixos/hosts/distant-shore.nix - config.flake.nixosModules.monitoring-node-exporter - inputs.home-manager.nixosModules.home-manager - (hmModule { - user = "danny"; - homeDirectory = "/home/danny"; - stateVersion = "25.11"; - }) - ]; - }; - - # foreign-port — WiFi-only laptop server, locally-signed boot chain - # (installed standalone, migrated into clan). targetHost is the LAN IP - # for the first `clan machines update`; switch to its ZT IPv6 once the - # mesh is up. buildHost = sunken-ship for the closure copy (avoids - # self-SSH). - machines.foreign-port = { - imports = [ - { - clan.core.enableRecommendedDefaults = false; - clan.core.networking.targetHost = "danny@192.168.1.223"; - clan.core.networking.buildHost = "danny@sunken-ship"; - } - clanHostsModule - ../nixos/hosts/foreign-port.nix - config.flake.nixosModules.monitoring-node-exporter inputs.home-manager.nixosModules.home-manager (hmModule { user = "danny"; @@ -240,8 +165,8 @@ in { clanHostsModule inputs.nix-openclaw.nixosModules.openclaw-gateway ../nixos/hosts/phantom-ship.nix + config.flake.nixosModules.dotfiles-rebuild config.flake.nixosModules.server-debug-tools - config.flake.nixosModules.monitoring-node-exporter inputs.home-manager.nixosModules.home-manager (hmModule { user = "danny"; diff --git a/flake-modules/installer-iso.nix b/flake-modules/installer-iso.nix index 03609ab..fc18929 100644 --- a/flake-modules/installer-iso.nix +++ b/flake-modules/installer-iso.nix @@ -1,13 +1,9 @@ { inputs, self, ... }: { # Custom minimal installer ISO (build with: nix build .#installer-iso). - # nixos/installer-wifi.nix (gitignored) is auto-included when present, to - # preconfigure live-system WiFi. See docs/server-installer-usb.md. + # Optional: add ./installer-wifi.nix (gitignored) to modules for live WiFi. flake.nixosConfigurations.installer-iso = inputs.nixpkgs.lib.nixosSystem { system = "x86_64-linux"; - modules = [ ../nixos/installer-iso.nix ] - ++ inputs.nixpkgs.lib.optional - (builtins.pathExists ../nixos/installer-wifi.nix) - ../nixos/installer-wifi.nix; + modules = [ ../nixos/installer-iso.nix ]; }; flake.packages.x86_64-linux.installer-iso = diff --git a/flake-modules/nixos-modules.nix b/flake-modules/nixos-modules.nix index 3dd7929..a466a58 100644 --- a/flake-modules/nixos-modules.nix +++ b/flake-modules/nixos-modules.nix @@ -1,9 +1,8 @@ # Expose reusable NixOS modules via `flake.nixosModules`. # # Consume from a host's flake-module via: -# modules = [ config.flake.nixosModules.server-debug-tools ]; +# modules = [ config.flake.nixosModules.dotfiles-rebuild ]; { ... }: { + flake.nixosModules.dotfiles-rebuild = ../modules/dotfiles-rebuild.nix; flake.nixosModules.server-debug-tools = ../modules/server-debug-tools.nix; - flake.nixosModules.monitoring-node-exporter = ../modules/monitoring-node-exporter.nix; - flake.nixosModules.monitoring-prometheus-server = ../modules/monitoring-prometheus-server.nix; } diff --git a/flake.lock b/flake.lock index 59c41ec..106a124 100644 --- a/flake.lock +++ b/flake.lock @@ -9,18 +9,22 @@ "nixpkgs": [ "nixpkgs" ], + "systems": "systems", "treefmt-nix": "treefmt-nix" }, "locked": { - "lastModified": 1779453564, - "narHash": "sha256-q7iVGGhZYtAwsjf7sIKcYD5IgsTTTobWP/EStaDCUZc=", - "rev": "81e4c9cded645d0384812dd6b8f05bd2475ffe64", - "type": "tarball", - "url": "https://git.clan.lol/api/v1/repos/clan/clan-community/archive/81e4c9cded645d0384812dd6b8f05bd2475ffe64.tar.gz" + "lastModified": 1776708356, + "narHash": "sha256-Smv2algQmojsu0m9EEXs+Oy0Tg/SjwI5WN66u/BaxYs=", + "ref": "fix/dm-pull-deploy-hyphen-hostnames", + "rev": "796ee625b60941bb959039924bfc39e5d13481cc", + "revCount": 46, + "type": "git", + "url": "https://git.clan.lol/dannydannydanny/clan-community.git" }, "original": { - "type": "tarball", - "url": "https://git.clan.lol/clan/clan-community/archive/main.tar.gz" + "ref": "fix/dm-pull-deploy-hyphen-hostnames", + "type": "git", + "url": "https://git.clan.lol/dannydannydanny/clan-community.git" } }, "clan-core": { @@ -36,15 +40,15 @@ "nixpkgs" ], "sops-nix": "sops-nix", - "systems": "systems", + "systems": "systems_2", "treefmt-nix": "treefmt-nix_2" }, "locked": { - "lastModified": 1778462753, - "narHash": "sha256-/9qWZbrwoVWP0YWuC1Z5HMEb/oy6rNsjypUKTuk1PB4=", - "rev": "09551fdb27a7e5712bef371e9271034d503242ed", + "lastModified": 1776557977, + "narHash": "sha256-j+UWg3fR6jWKPqkPoqRf1a6nR1b/AnZXDuh04H+voUc=", + "rev": "e9ced950bedc726492e5cb52139bf5f17258dc69", "type": "tarball", - "url": "https://git.clan.lol/api/v1/repos/clan/clan-core/archive/09551fdb27a7e5712bef371e9271034d503242ed.tar.gz" + "url": "https://git.clan.lol/api/v1/repos/clan/clan-core/archive/e9ced950bedc726492e5cb52139bf5f17258dc69.tar.gz" }, "original": { "type": "tarball", @@ -67,11 +71,11 @@ ] }, "locked": { - "lastModified": 1776654564, - "narHash": "sha256-5bpzOOXsaAr4g25/ghtKdYO17xg0l+MieCcWgqx24eY=", - "rev": "ad23733ebc47284dc1158db43218cf4027824aee", + "lastModified": 1776506822, + "narHash": "sha256-WlxAhXEoDHbkfFw3uNYra0CXce7pBk314x9chPu7ycE=", + "rev": "c3f48f5931b27bb9cc58de8799d36ecefb867d98", "type": "tarball", - "url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/ad23733ebc47284dc1158db43218cf4027824aee.tar.gz" + "url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/c3f48f5931b27bb9cc58de8799d36ecefb867d98.tar.gz" }, "original": { "type": "tarball", @@ -86,11 +90,11 @@ ] }, "locked": { - "lastModified": 1776613567, - "narHash": "sha256-gC9Cp5ibBmGD5awCA9z7xy6MW6iJufhazTYJOiGlCUI=", + "lastModified": 1773889306, + "narHash": "sha256-PAqwnsBSI9SVC2QugvQ3xeYCB0otOwCacB1ueQj2tgw=", "owner": "nix-community", "repo": "disko", - "rev": "32f4236bfc141ae930b5ba2fb604f561fed5219d", + "rev": "5ad85c82cc52264f4beddc934ba57f3789f28347", "type": "github" }, "original": { @@ -106,11 +110,11 @@ ] }, "locked": { - "lastModified": 1777713215, - "narHash": "sha256-8GzXDOXckDWwST8TY5DbwYFjdvQLlP7K9CLSVx6iTTo=", + "lastModified": 1773889306, + "narHash": "sha256-PAqwnsBSI9SVC2QugvQ3xeYCB0otOwCacB1ueQj2tgw=", "owner": "nix-community", "repo": "disko", - "rev": "63b4e7e6cf75307c1d26ac3762b886b5b0247267", + "rev": "5ad85c82cc52264f4beddc934ba57f3789f28347", "type": "github" }, "original": { @@ -163,11 +167,11 @@ ] }, "locked": { - "lastModified": 1777988971, - "narHash": "sha256-qIoWPDs+0/8JecyYgE3gpKQxW/4bLW/gp45vow9ioCQ=", + "lastModified": 1775087534, + "narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "0678d8986be1661af6bb555f3489f2fdfc31f6ff", + "rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b", "type": "github" }, "original": { @@ -178,7 +182,7 @@ }, "flake-utils": { "inputs": { - "systems": "systems_2" + "systems": "systems_3" }, "locked": { "lastModified": 1731533236, @@ -196,7 +200,7 @@ }, "flake-utils_2": { "inputs": { - "systems": "systems_3" + "systems": "systems_4" }, "locked": { "lastModified": 1681202837, @@ -219,11 +223,11 @@ ] }, "locked": { - "lastModified": 1778444552, - "narHash": "sha256-f18pIiR9q/p1vHY93gmAum7aHhQOG49oGvAB9+lptRo=", + "lastModified": 1776184304, + "narHash": "sha256-No6QGBmIv5ChiwKCcbkxjdEQ/RO2ZS1gD7SFy6EZ7rc=", "owner": "nix-community", "repo": "home-manager", - "rev": "dcebe66f958673729896eec2de4abfd86ef22d21", + "rev": "3c7524c68348ef79ce48308e0978611a050089b2", "type": "github" }, "original": { @@ -261,11 +265,11 @@ ] }, "locked": { - "lastModified": 1777594677, - "narHash": "sha256-h90sHwoRJLRvaTpZroTvU2JRHDFj0czUafM8eqLe1RI=", + "lastModified": 1774991950, + "narHash": "sha256-kScKj3qJDIWuN9/6PMmgy5esrTUkYinrO5VvILik/zw=", "owner": "nix-community", "repo": "home-manager", - "rev": "899c08a15beae5da51a5cecd6b2b994777a948da", + "rev": "f2d3e04e278422c7379e067e323734f3e8c585a7", "type": "github" }, "original": { @@ -317,11 +321,11 @@ ] }, "locked": { - "lastModified": 1777780666, - "narHash": "sha256-8wURyQMdDkGUarSTKOGdCuFfYiwa3HbzwscUfn3STDE=", + "lastModified": 1775037210, + "narHash": "sha256-KM2WYj6EA7M/FVZVCl3rqWY+TFV5QzSyyGE2gQxeODU=", "owner": "nix-darwin", "repo": "nix-darwin", - "rev": "8c62fba0854ba15c8917aed18894dbccb48a3777", + "rev": "06648f4902343228ce2de79f291dd5a58ee12146", "type": "github" }, "original": { @@ -335,18 +339,17 @@ "inputs": { "flake-utils": "flake-utils", "home-manager": "home-manager_2", - "nix-openclaw-tools": "nix-openclaw-tools", + "nix-steipete-tools": "nix-steipete-tools", "nixpkgs": [ "nixpkgs" - ], - "qmd": "qmd" + ] }, "locked": { - "lastModified": 1778353239, - "narHash": "sha256-g0yC+loN19X3Xyn6RuBHeWzevH7Qymt0REW+kyGuCLY=", + "lastModified": 1776183358, + "narHash": "sha256-uRWaRXGhkyGWMbNgQcmx0+RPzPLenVGopkNHgAEfmBQ=", "owner": "openclaw", "repo": "nix-openclaw", - "rev": "e2ea91056fdd0836bef96326a2b687277dbe3e1c", + "rev": "53aac0dce0810c40c75793fdad3d41b0f7e7baaf", "type": "github" }, "original": { @@ -355,24 +358,6 @@ "type": "github" } }, - "nix-openclaw-tools": { - "inputs": { - "nixpkgs": "nixpkgs" - }, - "locked": { - "lastModified": 1778060041, - "narHash": "sha256-tXWkN1VnwFG8XlRqW/e7VwbKnUfyU9tB7YDm9QHJXTY=", - "owner": "openclaw", - "repo": "nix-openclaw-tools", - "rev": "4c1cee3c7eaf68f9de0f756be1484534f5bb5f34", - "type": "github" - }, - "original": { - "owner": "openclaw", - "repo": "nix-openclaw-tools", - "type": "github" - } - }, "nix-select": { "locked": { "lastModified": 1763303120, @@ -386,17 +371,35 @@ "url": "https://git.clan.lol/clan/nix-select/archive/main.tar.gz" } }, + "nix-steipete-tools": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1773561580, + "narHash": "sha256-wT0bKTp45YnMkc4yXQvk943Zz/rksYiIjEXGdWzxnic=", + "owner": "openclaw", + "repo": "nix-steipete-tools", + "rev": "cd4c429ff3b3aaef9f92e59812cf2baf5704b86f", + "type": "github" + }, + "original": { + "owner": "openclaw", + "repo": "nix-steipete-tools", + "type": "github" + } + }, "nixos-wsl": { "inputs": { "flake-compat": "flake-compat", "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1777732699, - "narHash": "sha256-2uX/XtOWZ/oy2rerRynVhqVA//ZXZ3Fo60PikLHEPQc=", + "lastModified": 1776255237, + "narHash": "sha256-LQjlc0VEn55WAT4BiI8sIsokb/2FNlcbBD+Xr3MTE24=", "owner": "nix-community", "repo": "NixOS-WSL", - "rev": "5482f113fd31ebac131d1ebeb2ae90bf0d5e41f5", + "rev": "9a8c2a85f1ffdcecfb0f9c52c5a73c49ceb43911", "type": "github" }, "original": { @@ -424,11 +427,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1776169885, - "narHash": "sha256-l/iNYDZ4bGOAFQY2q8y5OAfBBtrDAaPuRQqWaFHVRXM=", + "lastModified": 1773734432, + "narHash": "sha256-IF5ppUWh6gHGHYDbtVUyhwy/i7D261P7fWD1bPefOsw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "4bd9165a9165d7b5e33ae57f3eecbcb28fb231c9", + "rev": "cda48547b432e8d3b18b4180ba07473762ec8558", "type": "github" }, "original": { @@ -440,11 +443,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1778274207, - "narHash": "sha256-I4puXmX1iovcCHZlRmztO3vW0mAbbRvq4F8wgIMQ1MM=", + "lastModified": 1776255774, + "narHash": "sha256-psVTpH6PK3q1htMJpmdz1hLF5pQgEshu7gQWgKO6t6Y=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b3da656039dc7a6240f27b2ef8cc6a3ef3bccae7", + "rev": "566acc07c54dc807f91625bb286cb9b321b5f42a", "type": "github" }, "original": { @@ -468,32 +471,6 @@ "type": "indirect" } }, - "qmd": { - "inputs": { - "flake-utils": [ - "nix-openclaw", - "flake-utils" - ], - "nixpkgs": [ - "nix-openclaw", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1775429264, - "narHash": "sha256-bqIVaNRTa8H5vrw3RwsD7QdtTa0xNvRuEVzlzE1hIBQ=", - "owner": "tobi", - "repo": "qmd", - "rev": "65cd1b3fd02891d1ee0eefa751620918664fa321", - "type": "github" - }, - "original": { - "owner": "tobi", - "ref": "v2.1.0", - "repo": "qmd", - "type": "github" - } - }, "root": { "inputs": { "clan-community": "clan-community", @@ -532,6 +509,21 @@ } }, "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { "locked": { "lastModified": 1774449309, "narHash": "sha256-brhZ8DmuGtzkCYHJg4HEd602amKm89Y9ytsFZ5uWD1w=", @@ -547,7 +539,7 @@ "type": "github" } }, - "systems_2": { + "systems_3": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", @@ -562,7 +554,7 @@ "type": "github" } }, - "systems_3": { + "systems_4": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", @@ -646,11 +638,11 @@ ] }, "locked": { - "lastModified": 1778394798, - "narHash": "sha256-/jR8bModWv0ji305ecMgAB+2eaXLZiYdH+9Z4JIRkuA=", + "lastModified": 1776317517, + "narHash": "sha256-JP1XVRabZquf7pnXvRUjp7DV+EBrB6Qmp3+vG3HMy/k=", "owner": "0xc000022070", "repo": "zen-browser-flake", - "rev": "45bc54456044b96492923739bfae633e1a4352e1", + "rev": "0a7be59e988bb2cb452080f59aaabae70bc415ae", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 2970510..30e7d71 100644 --- a/flake.nix +++ b/flake.nix @@ -29,9 +29,10 @@ clan-core.inputs.nixpkgs.follows = "nixpkgs"; clan-core.inputs.flake-parts.follows = "flake-parts"; - # clan-community: dm-pull-deploy etc. Back on upstream main since - # clan/clan-community#25 (machine.name hyphen sanitization) merged. - clan-community.url = "https://git.clan.lol/clan/clan-community/archive/main.tar.gz"; + # clan-community: dm-pull-deploy etc. Pinned to our fork's fix branch + # until clan/clan-community#25 (machine.name hyphen sanitization) lands. + # Swap back to `archive/main.tar.gz` when merged. + clan-community.url = "git+https://git.clan.lol/dannydannydanny/clan-community.git?ref=fix/dm-pull-deploy-hyphen-hostnames"; clan-community.inputs.nixpkgs.follows = "nixpkgs"; clan-community.inputs.clan-core.follows = "clan-core"; }; diff --git a/modules/dotfiles-rebuild.nix b/modules/dotfiles-rebuild.nix new file mode 100644 index 0000000..de6ac87 --- /dev/null +++ b/modules/dotfiles-rebuild.nix @@ -0,0 +1,44 @@ +# Shared auto-rebuild-from-git service for homelab hosts. +# +# Every 15 min: git fetch origin, fast-forward main, and if there were any +# new commits run nixos-rebuild switch against `#`. +# +# Assumes /etc/dotfiles is an already-cloned checkout of the dotfiles repo. +{ config, lib, pkgs, ... }: +let + dotfilesDir = "/etc/dotfiles"; + flakeRef = "${dotfilesDir}#${config.networking.hostName}"; +in { + environment.systemPackages = [ pkgs.git ]; + + # Trust /etc/dotfiles as root even though it's owned by `danny`. + # nix/libgit2 reads safe.directory from /etc/gitconfig; the GIT_CONFIG_* + # env vars on the service only affect the git CLI, not nix. + programs.git.enable = true; + programs.git.config.safe.directory = [ dotfilesDir ]; + + systemd.services.dotfiles-rebuild = { + description = "Pull dotfiles and run nixos-rebuild if repo changed"; + path = with pkgs; [ git nix nixos-rebuild ]; + environment.GIT_CONFIG_COUNT = "1"; + environment.GIT_CONFIG_KEY_0 = "safe.directory"; + environment.GIT_CONFIG_VALUE_0 = dotfilesDir; + script = '' + set -euo pipefail + cd ${dotfilesDir} + git fetch origin + if [ "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)" ]; then + exit 0 + fi + git pull origin main + exec nixos-rebuild switch --flake ${flakeRef} + ''; + serviceConfig.Type = "oneshot"; + }; + + systemd.timers.dotfiles-rebuild = { + wantedBy = [ "timers.target" ]; + timerConfig.OnCalendar = "*-*-* *:00/15:00"; # every 15 minutes + timerConfig.RandomizedDelaySec = "2min"; + }; +} diff --git a/modules/monitoring-node-exporter.nix b/modules/monitoring-node-exporter.nix deleted file mode 100644 index 7e08ae0..0000000 --- a/modules/monitoring-node-exporter.nix +++ /dev/null @@ -1,12 +0,0 @@ -# Prometheus node_exporter — exposes host metrics on :9100, scoped to the -# ZeroTier mesh so only sunken-ship (the Prometheus server) can scrape it. -{ ... }: { - services.prometheus.exporters.node = { - enable = true; - port = 9100; - listenAddress = "[::]"; - enabledCollectors = [ "systemd" ]; - }; - - networking.firewall.interfaces."zt+".allowedTCPPorts = [ 9100 ]; -} diff --git a/modules/monitoring-prometheus-server.nix b/modules/monitoring-prometheus-server.nix deleted file mode 100644 index 9aedc14..0000000 --- a/modules/monitoring-prometheus-server.nix +++ /dev/null @@ -1,134 +0,0 @@ -# Prometheus + Alertmanager + Grafana on sunken-ship. -# -# Scrape targets are the clan ZeroTier IPv6s — kept in sync with -# vars/per-machine//zerotier/zerotier-ip/value. -# -# Telegram receiver uses the existing @HarakatBot. Drop the bot token at -# /etc/alertmanager/telegram-token (mode 0400, root) before rebuild — same -# manual-secret pattern as the other Telegram bots in the repo. -# -# Routing: critical alerts repeat every 1h, everything else every 4h. -{ ... }: -let - sunkenShipZTv6 = "fdd5:53a2:de33:d269:6499:93d5:53a2:de33"; - phantomShipZTv6 = "fdd5:53a2:de33:d269:6499:936c:48a:bbdc"; - vpsRelayZTv6 = "fdd5:53a2:de33:d269:6499:9305:339f:2ed3"; - - target = ip: "[${ip}]:9100"; -in { - services.prometheus = { - enable = true; - port = 9090; - listenAddress = "[::1]"; - - globalConfig = { - scrape_interval = "30s"; - evaluation_interval = "30s"; - }; - - scrapeConfigs = [{ - job_name = "node"; - static_configs = [{ - targets = [ - (target sunkenShipZTv6) - (target phantomShipZTv6) - (target vpsRelayZTv6) - ]; - labels.job = "node"; - }]; - }]; - - ruleFiles = [ - (builtins.toFile "host-rules.yml" (builtins.toJSON { - groups = [{ - name = "hosts"; - rules = [{ - alert = "HostDown"; - expr = ''up{job="node"} == 0''; - for = "5m"; - labels.severity = "critical"; - annotations = { - summary = "{{ $labels.instance }} is down"; - description = "{{ $labels.instance }} has been unreachable for 5 minutes."; - }; - }]; - }]; - })) - ]; - - alertmanagers = [{ - static_configs = [{ targets = [ "[::1]:9093" ]; }]; - }]; - - alertmanager = { - enable = true; - port = 9093; - listenAddress = "[::1]"; - configuration = { - route = { - receiver = "telegram-default"; - group_by = [ "alertname" ]; - group_wait = "30s"; - group_interval = "5m"; - repeat_interval = "4h"; - routes = [{ - matchers = [ ''severity="critical"'' ]; - receiver = "telegram-critical"; - group_wait = "10s"; - group_interval = "1m"; - repeat_interval = "1h"; - }]; - }; - receivers = [ - { - name = "telegram-default"; - telegram_configs = [{ - bot_token_file = "/etc/alertmanager/telegram-token"; - chat_id = 66070351; - api_url = "https://api.telegram.org"; - parse_mode = ""; - }]; - } - { - name = "telegram-critical"; - telegram_configs = [{ - bot_token_file = "/etc/alertmanager/telegram-token"; - chat_id = 66070351; - api_url = "https://api.telegram.org"; - parse_mode = ""; - message = '' - CRITICAL: {{ .CommonLabels.alertname }} - {{ range .Alerts }}{{ .Annotations.summary }} - {{ .Annotations.description }} - {{ end }}''; - }]; - } - ]; - }; - }; - }; - - services.grafana = { - enable = true; - settings.server = { - http_addr = "::"; - http_port = 3000; - domain = "sunken-ship.clan"; - }; - # Drop a random 32+ char string at /etc/grafana/secret-key (mode 0400, - # owned by grafana:grafana) before rebuild — same manual-secret pattern - # as /etc/alertmanager/telegram-token. Used to encrypt secrets stored - # in Grafana's DB; nothing to rotate on a fresh install. - settings.security.secret_key = "$__file{/etc/grafana/secret-key}"; - provision.datasources.settings.datasources = [{ - name = "Prometheus"; - type = "prometheus"; - url = "http://[::1]:9090"; - isDefault = true; - }]; - }; - - # Grafana on the ZeroTier mesh only. Prometheus + Alertmanager bind to - # localhost so they're not reachable off-host. - networking.firewall.interfaces."zt+".allowedTCPPorts = [ 3000 ]; -} diff --git a/nixos/disko-distant-shore.nix b/nixos/disko-distant-shore.nix deleted file mode 100644 index ab35aac..0000000 --- a/nixos/disko-distant-shore.nix +++ /dev/null @@ -1,37 +0,0 @@ -# Declarative disk layout for distant-shore (ThinkPad X13 Gen 2 — 256 GB -# SK Hynix NVMe). UEFI/systemd-boot, no encryption: it's a headless, -# WiFi-only server that must reboot unattended (clan dm-pull-deploy), so -# a LUKS passphrase prompt at boot would hang it. Mirrors sunken-ship's -# plain-ext4 choice. Device is wiped + repartitioned at install time by -# clan/nixos-anywhere. -{ - disko.devices = { - disk.main = { - type = "disk"; - device = "/dev/nvme0n1"; - content = { - type = "gpt"; - partitions = { - ESP = { - size = "512M"; - type = "EF00"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - mountOptions = [ "fmask=0022" "dmask=0022" ]; - }; - }; - root = { - size = "100%"; - content = { - type = "filesystem"; - format = "ext4"; - mountpoint = "/"; - }; - }; - }; - }; - }; - }; -} diff --git a/nixos/disko-foreign-port.nix b/nixos/disko-foreign-port.nix deleted file mode 100644 index a928620..0000000 --- a/nixos/disko-foreign-port.nix +++ /dev/null @@ -1,36 +0,0 @@ -# Declarative disk layout for distant-shore. UEFI/systemd-boot, no -# encryption: it's a headless, WiFi-only server that must reboot -# unattended (clan dm-pull-deploy), so a LUKS passphrase prompt at boot -# would hang it. Mirrors sunken-ship's plain-ext4 choice. Device is wiped -# + repartitioned at install time by clan/nixos-anywhere. -{ - disko.devices = { - disk.main = { - type = "disk"; - device = "/dev/nvme0n1"; - content = { - type = "gpt"; - partitions = { - ESP = { - size = "512M"; - type = "EF00"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - mountOptions = [ "fmask=0022" "dmask=0022" ]; - }; - }; - root = { - size = "100%"; - content = { - type = "filesystem"; - format = "ext4"; - mountpoint = "/"; - }; - }; - }; - }; - }; - }; -} diff --git a/nixos/fish.nix b/nixos/fish.nix index 1d72d26..9d04f51 100644 --- a/nixos/fish.nix +++ b/nixos/fish.nix @@ -24,38 +24,6 @@ set fish_greeting 🐟: (set_color yellow; date +%T; set_color green; date --iso-8601 2>/dev/null; or date +%F; set_color normal) - # gco: smart `git checkout` — if the branch is checked out in another - # worktree, cd there instead of failing with "already used by worktree at". - function gco --description 'git checkout, but cd into worktree if the branch lives there' - if test (count $argv) -eq 0 - git checkout - return $status - end - - set -l branch $argv[1] - set -l target_ref "refs/heads/$branch" - set -l wt_path "" - set -l current_wt "" - for line in (git worktree list --porcelain 2>/dev/null) - switch $line - case 'worktree *' - set current_wt (string replace -r '^worktree ' "" -- $line) - case "branch $target_ref" - set wt_path $current_wt - break - end - end - - set -l here (git rev-parse --show-toplevel 2>/dev/null) - if test -n "$wt_path"; and test "$wt_path" != "$here" - echo "→ cd $wt_path (branch '$branch' is checked out in another worktree)" - cd $wt_path - return $status - end - - git checkout $argv - end - # Alacritty palette follows macOS appearance; refresh when opening a shell (LaunchAgent also polls). if test (uname -s) = Darwin bash ~/dotfiles/scripts/alacritty-sync-system-theme.sh >/dev/null 2>&1 & diff --git a/nixos/home/danny/home.nix b/nixos/home/danny/home.nix index b57def5..16d9adf 100644 --- a/nixos/home/danny/home.nix +++ b/nixos/home/danny/home.nix @@ -88,35 +88,6 @@ catppuccin tmux-fzf extrakto - # tmux-resurrect: prefix + Ctrl-s saves, prefix + Ctrl-r restores. - # Snapshot lives at ~/.tmux/resurrect/last (window layout, working - # dirs, pane contents if enabled). Survives force-quits / reboots - # / kernel panics. - # - # @resurrect-processes: programs to restart on restore. Default - # list covers vim/emacs/less/top/etc. but NOT nvim, claude, or - # ssh. The "~name->cmd" form re-runs the original argv; bare - # names match argv-less invocations. Without this, restored panes - # come back as plain fish prompts in the right directory. - { - plugin = resurrect; - extraConfig = '' - set -g @resurrect-capture-pane-contents 'on' - set -g @resurrect-strategy-nvim 'session' - set -g @resurrect-processes 'nvim "~nvim->nvim *" claude "~claude->claude --continue" ssh "~ssh->ssh *"' - ''; - } - # tmux-continuum: auto-saves every 15min and auto-restores on - # tmux server start. With this, the next force-quit just costs - # you up to 15min of recent terminal activity, not the whole - # workspace. - { - plugin = continuum; - extraConfig = '' - set -g @continuum-restore 'on' - set -g @continuum-save-interval '15' - ''; - } ]; }; @@ -171,11 +142,6 @@ xdg.configFile."alacritty/catppuccin-mocha-colors.toml".source = ../../../assets/alacritty/catppuccin-mocha-colors.toml; - # Zed: settings.json is a read-only symlink to assets/zed/settings.json. - # To change a setting, edit the asset file and rebuild — editing via Zed's - # UI will fail because the target is in the nix store. - xdg.configFile."zed/settings.json".source = ../../../assets/zed/settings.json; - # Alacritty: base config + imported active-colors.toml (updated without rebuild) programs.alacritty = { enable = true; @@ -262,10 +228,9 @@ # alacritty # TODO: configured via programs.alacritty above, so not needed here # warp-terminal # TODO: Bloat # vscodium # TODO: Bloat - zed-editor + # zed-editor # TODO: Bloat code-cursor cursor-cli - cinny-desktop # Matrix client (Tauri wrapper around the Cinny web app) dfu-util # USB DFU firmware flasher (Flipper Zero etc.) discord mapscii diff --git a/nixos/hosts/distant-shore-hardware.nix b/nixos/hosts/distant-shore-hardware.nix deleted file mode 100644 index 3c52633..0000000 --- a/nixos/hosts/distant-shore-hardware.nix +++ /dev/null @@ -1,18 +0,0 @@ -# Do not modify this file! It was generated by ‘nixos-generate-config’ -# and may be overwritten by future invocations. Please make changes -# to /etc/nixos/configuration.nix instead. -{ config, lib, pkgs, modulesPath, ... }: - -{ - imports = - [ (modulesPath + "/installer/scan/not-detected.nix") - ]; - - boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" ]; - boot.extraModulePackages = [ ]; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} diff --git a/nixos/hosts/distant-shore.nix b/nixos/hosts/distant-shore.nix deleted file mode 100644 index 33a7026..0000000 --- a/nixos/hosts/distant-shore.nix +++ /dev/null @@ -1,114 +0,0 @@ -# NixOS server on a ThinkPad X13 Gen 2 (Intel i5-1145G7, 16 GB). -# WiFi-only, headless, unattended auto-rebuild via clan dm-pull-deploy. -# No LUKS (mirrors sunken-ship) so reboots don't block on a passphrase. -# -# Blank-slate server for now — no application services. Give it a purpose -# later (just add services here and let dm-pull-deploy roll it out). -{ config, lib, pkgs, ... }: - -{ - imports = [ - ./distant-shore-hardware.nix - ../disko-distant-shore.nix - ]; - - boot.loader.systemd-boot.enable = true; - # Secure Boot is enforced and the BIOS supervisor password is unknown, so - # we can't enrol our own SB keys. Instead, shim (MS-signed) is placed on - # the ESP and chain-loads systemd-boot; the NVRAM boot entry points at - # shim. We manage that entry imperatively via efibootmgr; letting bootctl - # touch EFI variables would replace it on every rebuild. - boot.loader.efi.canTouchEfiVariables = false; - boot.loader.efi.efiSysMountPoint = "/boot"; # matches disko ESP mountpoint - - # --- Secure Boot via shim + MOK (no firmware key enrolment possible) ------ - # The firmware trusts Microsoft-signed shim; shim trusts our enrolled MOK. - # On every bootloader install we: (1) sign systemd-boot with the MOK and - # drop it where shim chain-loads it (grubx64.efi), (2) install shim as the - # firmware-booted binary (+ MokManager), (3) MOK-sign every kernel image - # systemd-boot will hand off to (shim verifies them via the shim-lock - # protocol). Re-runs on each nixos-rebuild so auto-deployed generations - # stay bootable. Keys + shim live in /etc/secrets (outside the repo). - boot.loader.systemd-boot.extraInstallCommands = '' - # NixOS's bootloader-install systemd unit runs with a minimal PATH that - # doesn't include coreutils, so use absolute paths for cp/mv. - KEY=/etc/secrets/MOK.key - CRT=/etc/secrets/MOK.crt - sb() { ${pkgs.sbsigntool}/bin/sbsign --key "$KEY" --cert "$CRT" --output "$2" "$1"; } - # systemd-boot -> shim's chain-load target - sb /boot/EFI/systemd/systemd-bootx64.efi /boot/EFI/BOOT/grubx64.efi - # shim (MS-signed) is what the firmware boots; MokManager beside it - ${pkgs.coreutils}/bin/cp -f /etc/secrets/shimx64.efi /boot/EFI/BOOT/BOOTX64.EFI - ${pkgs.coreutils}/bin/cp -f /etc/secrets/mmx64.efi /boot/EFI/BOOT/mmx64.efi - # MOK-sign each kernel (skip already-signed; never touch initrds) - for k in /boot/EFI/nixos/*bzImage.efi; do - [ -e "$k" ] || continue - if ! ${pkgs.sbsigntool}/bin/sbverify --cert "$CRT" "$k" >/dev/null 2>&1; then - ${pkgs.sbsigntool}/bin/sbsign --key "$KEY" --cert "$CRT" --output "$k.tmp" "$k" \ - && ${pkgs.coreutils}/bin/mv -f "$k.tmp" "$k" - fi - done - ''; - - networking.hostName = "distant-shore"; - # WiFi via NetworkManager. The wpa_supplicant stack hit two issues on this - # box: (1) it strips CAP_CHOWN so wpa couldn't create its ctrl_interface, - # and (2) dhcpcd didn't grab a lease after the (late) association at boot, - # needing a manual restart — fatal for an unattended headless server. NM - # handles association + DHCP atomically and connected first-try here. - # The PSK stays out of the repo: it's substituted from /etc/secrets/nm.env - # ($PSK_INTENO) into the declared profile at activation. - networking.networkmanager.enable = true; - networking.networkmanager.ensureProfiles.environmentFiles = [ "/etc/secrets/nm.env" ]; - networking.networkmanager.ensureProfiles.profiles."Inteno-89FE" = { - connection = { id = "Inteno-89FE"; type = "wifi"; autoconnect = true; }; - wifi = { ssid = "Inteno-89FE"; mode = "infrastructure"; }; - wifi-security = { key-mgmt = "wpa-psk"; psk = "$PSK_INTENO"; }; - ipv4.method = "auto"; - ipv6.method = "auto"; - }; - hardware.enableRedistributableFirmware = true; # iwlwifi for the Intel AX201 WiFi - time.timeZone = "Europe/Copenhagen"; - - # It's a laptop acting as a server: keep running with the lid shut. - services.logind.settings.Login.HandleLidSwitch = "ignore"; - services.logind.settings.Login.HandleLidSwitchExternalPower = "ignore"; - - # Reduce screen burn-in / power: blank the TTY after a minute. - boot.kernelParams = [ "consoleblank=60" ]; - - nix.settings.experimental-features = [ "nix-command" "flakes" ]; - programs.nix-ld.enable = true; # run dynamically linked binaries (e.g. Claude Code remote CLI) - nix.settings.trusted-users = [ "root" "danny" ]; - system.stateVersion = "25.11"; - - users.users.danny = { - isNormalUser = true; - extraGroups = [ "wheel" "video" "audio" ]; - openssh.authorizedKeys.keys = [ - # Mac admin / fleet key (~/.ssh/id_ed25519_sunken_ship) — the key the - # Mac uses to reach the fleet; clan machines update relies on it. - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKW/akfIiVU5o63YrTAJVZhMj7kXfYHOnXDtlpVFW7pf danny@mac-admin" - # Per-host key (~/.ssh/id_ed25519_distant_shore) — plain `ssh distant-shore`. - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH61JOiOOPrAXekakAwTJg5yCSDfOIjlSvMYkpXrarAf distant-shore" - # sunken-ship (dm-pull-deploy push node) — reach distant-shore over ZT. - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB9t4YAaoHvVouqp+qyFOq8o3SAtXMiAmjF6J0ldyx4g danny@sunken-ship" - ]; - }; - users.users.root.openssh.authorizedKeys.keys = - config.users.users.danny.openssh.authorizedKeys.keys; - - services.openssh = { - enable = true; - settings = { - PasswordAuthentication = false; - KbdInteractiveAuthentication = false; - }; - }; - - security.sudo.wheelNeedsPassword = false; - - # mokutil — manage MOK enrolment for the shim chain; sbsigntool — inspect - # signatures on bootloader/kernel images when debugging. - environment.systemPackages = with pkgs; [ git mokutil sbsigntool ]; -} diff --git a/nixos/hosts/foreign-port-hardware.nix b/nixos/hosts/foreign-port-hardware.nix deleted file mode 100644 index 3c52633..0000000 --- a/nixos/hosts/foreign-port-hardware.nix +++ /dev/null @@ -1,18 +0,0 @@ -# Do not modify this file! It was generated by ‘nixos-generate-config’ -# and may be overwritten by future invocations. Please make changes -# to /etc/nixos/configuration.nix instead. -{ config, lib, pkgs, modulesPath, ... }: - -{ - imports = - [ (modulesPath + "/installer/scan/not-detected.nix") - ]; - - boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" ]; - boot.extraModulePackages = [ ]; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} diff --git a/nixos/hosts/foreign-port.nix b/nixos/hosts/foreign-port.nix deleted file mode 100644 index 9705b6e..0000000 --- a/nixos/hosts/foreign-port.nix +++ /dev/null @@ -1,111 +0,0 @@ -# NixOS laptop server. WiFi-only, headless, unattended auto-rebuild via -# clan dm-pull-deploy. No LUKS (mirrors sunken-ship) so reboots don't -# block on a passphrase. -# -# Blank-slate server for now — no application services. Give it a purpose -# later (just add services here and let dm-pull-deploy roll it out). -{ config, lib, pkgs, ... }: - -{ - imports = [ - ./foreign-port-hardware.nix - ../disko-foreign-port.nix - ]; - - boot.loader.systemd-boot.enable = true; - # Firmware-locked Secure Boot: we can't enrol our own keys into the - # firmware key DB, so a vendor-signed shim is the firmware-booted binary - # and chain-loads a locally-signed systemd-boot + kernel. The NVRAM - # entry points at shim; bootctl is kept away from EFI variables so - # rebuilds don't clobber the entry. - boot.loader.efi.canTouchEfiVariables = false; - boot.loader.efi.efiSysMountPoint = "/boot"; # matches disko ESP mountpoint - - # --- Locally-signed boot chain -------------------------------------------- - # On every bootloader install: re-sign systemd-boot and every kernel - # image, refresh the shim binary on the ESP, and place the helper binary - # beside it. Re-runs on each nixos-rebuild so auto-deployed generations - # stay bootable. Signing material lives in /etc/secrets, never the repo. - boot.loader.systemd-boot.extraInstallCommands = '' - # NixOS's bootloader-install systemd unit runs with a minimal PATH that - # doesn't include coreutils, so use absolute paths for cp/mv. - KEY=/etc/secrets/MOK.key - CRT=/etc/secrets/MOK.crt - sb() { ${pkgs.sbsigntool}/bin/sbsign --key "$KEY" --cert "$CRT" --output "$2" "$1"; } - # systemd-boot -> shim's chain-load target - sb /boot/EFI/systemd/systemd-bootx64.efi /boot/EFI/BOOT/grubx64.efi - # shim is the firmware-booted binary; helper binary sits beside it - ${pkgs.coreutils}/bin/cp -f /etc/secrets/shimx64.efi /boot/EFI/BOOT/BOOTX64.EFI - ${pkgs.coreutils}/bin/cp -f /etc/secrets/mmx64.efi /boot/EFI/BOOT/mmx64.efi - # sign each kernel (skip if already signed; leave initrds untouched) - for k in /boot/EFI/nixos/*bzImage.efi; do - [ -e "$k" ] || continue - if ! ${pkgs.sbsigntool}/bin/sbverify --cert "$CRT" "$k" >/dev/null 2>&1; then - ${pkgs.sbsigntool}/bin/sbsign --key "$KEY" --cert "$CRT" --output "$k.tmp" "$k" \ - && ${pkgs.coreutils}/bin/mv -f "$k.tmp" "$k" - fi - done - ''; - - networking.hostName = "foreign-port"; - # WiFi via NetworkManager. The wpa_supplicant stack hit two issues on this - # box: (1) it strips CAP_CHOWN so wpa couldn't create its ctrl_interface, - # and (2) dhcpcd didn't grab a lease after the (late) association at boot, - # needing a manual restart — fatal for an unattended headless server. NM - # handles association + DHCP atomically and connected first-try here. - # The PSK stays out of the repo: it's substituted from /etc/secrets/nm.env - # ($PSK_INTENO) into the declared profile at activation. - networking.networkmanager.enable = true; - networking.networkmanager.ensureProfiles.environmentFiles = [ "/etc/secrets/nm.env" ]; - networking.networkmanager.ensureProfiles.profiles."Inteno-89FE-5GHz" = { - connection = { id = "Inteno-89FE-5GHz"; type = "wifi"; autoconnect = true; }; - wifi = { ssid = "Inteno-89FE-5GHz"; mode = "infrastructure"; }; - wifi-security = { key-mgmt = "wpa-psk"; psk = "$PSK_INTENO"; }; - ipv4.method = "auto"; - ipv6.method = "auto"; - }; - hardware.enableRedistributableFirmware = true; # WiFi firmware blobs - time.timeZone = "Europe/Copenhagen"; - - # It's a laptop acting as a server: keep running with the lid shut. - services.logind.settings.Login.HandleLidSwitch = "ignore"; - services.logind.settings.Login.HandleLidSwitchExternalPower = "ignore"; - - # Reduce screen burn-in / power: blank the TTY after a minute. - boot.kernelParams = [ "consoleblank=60" ]; - - nix.settings.experimental-features = [ "nix-command" "flakes" ]; - programs.nix-ld.enable = true; # run dynamically linked binaries (e.g. Claude Code remote CLI) - nix.settings.trusted-users = [ "root" "danny" ]; - system.stateVersion = "25.11"; - - users.users.danny = { - isNormalUser = true; - extraGroups = [ "wheel" "video" "audio" ]; - openssh.authorizedKeys.keys = [ - # Mac admin / fleet key (~/.ssh/id_ed25519_sunken_ship) — the key the - # Mac uses to reach the fleet; clan machines update relies on it. - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKW/akfIiVU5o63YrTAJVZhMj7kXfYHOnXDtlpVFW7pf danny@mac-admin" - # TODO: add a per-host key (~/.ssh/id_ed25519_foreign_port) for - # plain `ssh foreign-port`. Generate when convenient. - # sunken-ship (dm-pull-deploy push node) — reach foreign-port over ZT. - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB9t4YAaoHvVouqp+qyFOq8o3SAtXMiAmjF6J0ldyx4g danny@sunken-ship" - ]; - }; - users.users.root.openssh.authorizedKeys.keys = - config.users.users.danny.openssh.authorizedKeys.keys; - - services.openssh = { - enable = true; - settings = { - PasswordAuthentication = false; - KbdInteractiveAuthentication = false; - }; - }; - - security.sudo.wheelNeedsPassword = false; - - # mokutil + sbsigntool — manage the shim trust chain and inspect signed - # bootloader/kernel images when debugging. - environment.systemPackages = with pkgs; [ git mokutil sbsigntool ]; -} diff --git a/nixos/hosts/phantom-ship.nix b/nixos/hosts/phantom-ship.nix index 26b3e90..6e981dc 100644 --- a/nixos/hosts/phantom-ship.nix +++ b/nixos/hosts/phantom-ship.nix @@ -48,13 +48,10 @@ in }; networking.firewall.trustedInterfaces = [ "enp0s31f6" ]; - # KomTolk (:8080), Shelfish (:8081), Scuttle (:8082), Bananasimulator - # (:8083), Forgejo (:3000), Escape Hormuz (:8090), bon (:8091), - # notes (:8092), TDPixi (:8093) are reachable only over the ZeroTier mesh — - # the vps-relay Caddy reverse-proxies into them. Same pattern as - # sunken-ship's bbbot. Not in global allowedTCPPorts, so the WAN side - # stays closed. - networking.firewall.interfaces."zt+".allowedTCPPorts = [ 3000 8080 8081 8082 8083 8084 8090 8091 8092 8093 ]; + # Forgejo's HTTP backend is only allowed on the ZeroTier interface so + # vps-relay's Caddy can reach it via the ZT mesh. Same pattern as + # bbbot on sunken-ship — port 3000 is never exposed on WAN/Wi-Fi. + networking.firewall.interfaces."zt+".allowedTCPPorts = [ 3000 ]; hardware.enableRedistributableFirmware = true; # iwlwifi (Intel 8260) + GPU + BT firmware @@ -111,7 +108,7 @@ in # Passwordless sudo for wheel. security.sudo.wheelNeedsPassword = false; environment.systemPackages = with pkgs; [ - git # clone/bootstrap and dm-pull-deploy + git # clone/bootstrap and dotfiles-rebuild timer nodejs # npm for openclaw plugin installs python3 # node-gyp dependency for openclaw plugins wakeonlan # wake rusty-anchor: wakeonlan 00:16:cb:87:20:ba @@ -168,20 +165,10 @@ in }; }; - # OpenClaw gateway needs write access to its config dir and repo clones; - # shelfish wants its DB outside the rsynced code dir. + # OpenClaw gateway needs write access to its config dir and repo clones. systemd.tmpfiles.rules = [ "d /etc/openclaw 0775 root openclaw - -" "d /var/lib/openclaw/repos 0750 openclaw openclaw - -" - "d /home/danny/.local/share/shelfish 0755 danny users - -" - "d /home/danny/.local/share/scuttle 0755 danny users - -" - "d /home/danny/.local/share/bananasimulator 0755 danny users - -" - "d /home/danny/.local/share/bananasimulator-beta 0755 danny users - -" - "d /home/danny/.local/share/komtolk 0755 danny users - -" - "d /home/danny/.local/share/escape_hormuz 0755 danny users - -" - "d /home/danny/.local/share/scuttle/tiles 0755 danny users - -" - "d /home/danny/.local/share/bon 0755 danny users - -" - "d /home/danny/.local/share/bon/images 0755 danny users - -" ]; # Hara Gmail MCP server (path 1: IMAP+SMTP). Replaced by an OAuth2 @@ -242,41 +229,20 @@ in # Code deployed out-of-band via rsync to /home/danny/shipyard/ # (staying in-tree in ~/python-projects/26_shipyard/ until spun out to its own repo). # Bot token (not in repo): ~danny/.secrets/telegram-bot-token-shipyard - # Data (feedback.jsonl, feedback.db, pointer cache, feedback_media/): - # ~danny/.local/share/shipyard/ - # - # Feedback now accepts photos / voice / video / docs / stickers etc. - # Phase A captures + stores raw files; Phase B derives OCR text - # (tesseract), speech transcripts (whisper-cpp), poster frames - # (ffmpeg) and PDF text (pdftotext) — all via subprocess, so each - # tool degrades gracefully if missing. + # Data (feedback.jsonl, pointer cache): ~danny/.local/share/shipyard/ systemd.services.shipyard = let pythonEnv = pkgs.python3.withPackages (ps: with ps; [ python-telegram-bot httpx - pillow # EXIF strip on captured photos ]); - # tesseract with English + Russian tessdata — vyscul writes in - # Russian, screenshots can land in either language. - tesseractWithLangs = pkgs.tesseract.override { - enableLanguages = [ "eng" "rus" ]; - }; in { description = "Shipyard Telegram bot (mini-app launcher + feedback)"; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; - path = [ - pythonEnv - pkgs.ffmpeg # video/animation posters, sticker decode - tesseractWithLangs # photo OCR - pkgs.whisper-cpp # voice/audio transcription - pkgs.poppler-utils # pdftotext (document handling) - ]; + path = [ pythonEnv ]; environment = { SHIPYARD_BOT_TOKEN_FILE = "/home/danny/.secrets/telegram-bot-token-shipyard"; - # Owner-only commands (/admin, /grant, /revoke) — anyone else gets ignored. - SHIPYARD_OWNER_ID = "66070351"; # @DannyDannyDanny }; serviceConfig = { WorkingDirectory = "/home/danny/shipyard"; @@ -287,347 +253,6 @@ in }; }; - # Shelfish — Goodreads-flavoured book club Mini App. - # Public traffic comes through vps-relay's Caddy → ZeroTier → here. - # See vps-relay.nix for the public-facing virtualHost. We never expose - # this host's IP directly. - # Code deployed out-of-band via rsync to /home/danny/shelfish/ - # (staying in-tree in ~/python-projects/27_shelfish/ until spun out). - # Auth: validates Telegram WebApp initData against shipyard's bot token - # (the bot that publishes shelfish via shipyard's project list). - # DB lives outside the rsynced code dir so deploys don't clobber state. - # (tmpfiles rule for the DB dir is bundled into the OpenClaw block above.) - systemd.services.shelfish = let - pythonEnv = pkgs.python3.withPackages (ps: with ps; [ - fastapi - uvicorn - httpx - python-telegram-bot - ]); - in { - description = "Shelfish FastAPI server (book club Mini App)"; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pythonEnv ]; - environment = { - SHIPYARD_BOT_TOKEN_FILE = "/home/danny/.secrets/telegram-bot-token-shipyard"; - SH_DB_PATH = "/home/danny/.local/share/shelfish/shelfish.db"; - }; - serviceConfig = { - WorkingDirectory = "/home/danny/shelfish"; - ExecStart = "${pythonEnv}/bin/python -m uvicorn server:app --host :: --port 8081"; - Restart = "on-failure"; - RestartSec = 10; - User = "danny"; - }; - }; - - # Scuttle — topdown tilt-to-move multiplayer Mini App. - # Same vps-relay-fronted ZT path as shelfish; binds to :: so the - # ZeroTier IPv6 address can reach it. - # Code rsync'd from ~/python-projects/26_scuttle/ to /home/danny/scuttle/ - # DB at ~/.local/share/scuttle/scuttle.db. - systemd.services.scuttle = let - pythonEnv = pkgs.python3.withPackages (ps: with ps; [ - fastapi - uvicorn - httpx - websockets - python-telegram-bot - ]); - in { - description = "Scuttle FastAPI + WebSocket game server (geo: Østerbro)"; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pythonEnv ]; - environment = { - SHIPYARD_BOT_TOKEN_FILE = "/home/danny/.secrets/telegram-bot-token-shipyard"; - SC_DB_PATH = "/home/danny/.local/share/scuttle/scuttle.db"; - SC_TILES_DIR = "/home/danny/.local/share/scuttle/tiles"; - }; - serviceConfig = { - WorkingDirectory = "/home/danny/scuttle"; - ExecStart = "${pythonEnv}/bin/python -m uvicorn server:app --host :: --port 8082"; - Restart = "on-failure"; - RestartSec = 10; - User = "danny"; - }; - }; - - # Bananasimulator — the actual project at https://bananasimulator.dannydannydanny.me - # (was a placeholder in shipyard's apps.json for ages). You ARE a banana. - # Code rsync'd from ~/python-projects/26_bananasimulator/ to /home/danny/bananasimulator/ - systemd.services.bananasimulator = let - pythonEnv = pkgs.python3.withPackages (ps: with ps; [ - fastapi - uvicorn - httpx - python-telegram-bot - ]); - in { - description = "Bananasimulator FastAPI server"; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pythonEnv ]; - environment = { - SHIPYARD_BOT_TOKEN_FILE = "/home/danny/.secrets/telegram-bot-token-shipyard"; - BS_DB_PATH = "/home/danny/.local/share/bananasimulator/bananasimulator.db"; - BS_RIPE_MIN_PER_STAGE = "2"; # 2 min/stage → 30 min to compost in production - }; - serviceConfig = { - WorkingDirectory = "/home/danny/bananasimulator"; - ExecStart = "${pythonEnv}/bin/python -m uvicorn server:app --host :: --port 8083"; - Restart = "on-failure"; - RestartSec = 10; - User = "danny"; - }; - }; - - # Bananasimulator BETA — cheat-instance for testing the full progression - # end-to-end. Separate DB, exposes /api/cheat/* (gated by BS_BETA_MODE=1) - # so the frontend cheat menu can seed canonical states and reset. - # Faster ripening (0.2 min/stage = ~3 min to compost) so cycles are - # testable in real time. Same code base; deploy to a sibling dir. - # vhost in vps-relay.nix → bananasimulator-beta.dannydannydanny.me. - systemd.services.bananasimulator-beta = let - pythonEnv = pkgs.python3.withPackages (ps: with ps; [ - fastapi - uvicorn - httpx - python-telegram-bot - ]); - in { - description = "Bananasimulator BETA (cheat instance) FastAPI server"; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pythonEnv ]; - environment = { - SHIPYARD_BOT_TOKEN_FILE = "/home/danny/.secrets/telegram-bot-token-shipyard"; - BS_DB_PATH = "/home/danny/.local/share/bananasimulator-beta/bananasimulator.db"; - BS_RIPE_MIN_PER_STAGE = "0.2"; # ~3 min to compost — testable in real time - BS_BETA_MODE = "1"; # exposes /api/cheat/* + flips beta=true in /api/me - }; - serviceConfig = { - WorkingDirectory = "/home/danny/bananasimulator-beta"; - ExecStart = "${pythonEnv}/bin/python -m uvicorn server:app --host :: --port 8084"; - Restart = "on-failure"; - RestartSec = 10; - User = "danny"; - }; - }; - - # Escape Hormuz — turn-based boat-race Mini App (Hara's first build). - # Code lives at /home/danny/escape_hormuz/. Same vps-relay-fronted ZT path - # as the others; binds :: so the ZeroTier IPv6 address is reachable. - systemd.services.escape-hormuz = let - pythonEnv = pkgs.python3.withPackages (ps: with ps; [ - fastapi - uvicorn - python-telegram-bot - ]); - in { - description = "Escape Hormuz FastAPI server (turn-based boat race)"; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pythonEnv ]; - environment = { - SHIPYARD_BOT_TOKEN_FILE = "/home/danny/.secrets/telegram-bot-token-shipyard"; - DB_PATH = "/home/danny/.local/share/escape_hormuz/escape_hormuz.db"; - MINIAPP_URL = "https://escapehormuz.dannydannydanny.me"; - }; - serviceConfig = { - WorkingDirectory = "/home/danny/escape_hormuz"; - ExecStart = "${pythonEnv}/bin/python -m uvicorn server:app --host :: --port 8090"; - Restart = "on-failure"; - RestartSec = 10; - User = "danny"; - }; - }; - - # Ollama — local LLM runtime, used by bon's structured-data extraction - # step. Listens on 127.0.0.1:11434 only (not exposed over ZT). - # 3B is bon's default — 7B was tested but ran ~3.6 min/receipt vs ~30s - # for 3B on phantom-ship CPU, with no real accuracy gain (still picked - # line items as merchant on header-less OCR; that's an OCR problem, - # not a model problem). Both kept loaded so we can A/B without a pull. - services.ollama = { - enable = true; - host = "127.0.0.1"; - port = 11434; - loadModels = [ - "qwen2.5:3b-instruct" # ~2.5 GB — current default - "qwen2.5:7b-instruct" # ~4.7 GB — A/B testing only - ]; - }; - - # bon — receipt scanner Mini App (camera capture + gallery + OCR + extract). - # Code rsync'd from ~/python-projects/26_bon/ to /home/danny/bon/ - # Images on disk under /home/danny/.local/share/bon/images// - # OCR via tesseract (binary on PATH; server uses subprocess directly). - # Structured extraction via local Ollama (qwen2.5:3b-instruct). - systemd.services.bon = let - pythonEnv = pkgs.python3.withPackages (ps: with ps; [ - fastapi - uvicorn - python-telegram-bot - python-multipart - pillow - httpx # for the Ollama HTTP call from extract.py - ]); - # English-only for now — Danish receipts in DK are mostly English chars - # plus prices, which `eng` handles fine. Add more languages later if - # vyscul or other testers report missed text. - tesseractEng = pkgs.tesseract.override { - enableLanguages = [ "eng" ]; - }; - in { - description = "bon FastAPI server (receipt scanner)"; - after = [ "network-online.target" "ollama.service" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pythonEnv tesseractEng ]; - environment = { - SHIPYARD_BOT_TOKEN_FILE = "/home/danny/.secrets/telegram-bot-token-shipyard"; - BON_DB_PATH = "/home/danny/.local/share/bon/bon.db"; - BON_IMAGES_DIR = "/home/danny/.local/share/bon/images"; - BON_OLLAMA_URL = "http://127.0.0.1:11434"; - BON_OLLAMA_MODEL = "qwen2.5:3b-instruct"; - }; - serviceConfig = { - WorkingDirectory = "/home/danny/bon"; - ExecStart = "${pythonEnv}/bin/python -m uvicorn server:app --host :: --port 8091"; - Restart = "on-failure"; - RestartSec = 10; - User = "danny"; - }; - }; - - # KomTolk (formerly translate-platform) — Copenhagen translation gigs Mini App. - # Code rsync'd from ~/python-projects/26_komtolk/ to /home/danny/komtolk/ - systemd.services.komtolk = let - pythonEnv = pkgs.python3.withPackages (ps: with ps; [ - fastapi - uvicorn - httpx - python-telegram-bot - ]); - in { - description = "KomTolk FastAPI server (Copenhagen translation gigs)"; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pythonEnv ]; - environment = { - SHIPYARD_BOT_TOKEN_FILE = "/home/danny/.secrets/telegram-bot-token-shipyard"; - KT_DB_PATH = "/home/danny/.local/share/komtolk/komtolk.db"; - }; - serviceConfig = { - WorkingDirectory = "/home/danny/komtolk"; - ExecStart = "${pythonEnv}/bin/python -m uvicorn server:app --host :: --port 8080"; - Restart = "on-failure"; - RestartSec = 10; - User = "danny"; - }; - }; - - # notes — tiny markdown blog + apex landing page. - # One service serves two hostnames via Host-header switch: - # notes.dannydannydanny.me → blog - # dannydannydanny.me → landing - # Code rsync'd from ~/python-projects/26_notes/ to /home/danny/notes/ - systemd.services.notes = let - pythonEnv = pkgs.python3.withPackages (ps: with ps; [ - fastapi - uvicorn - markdown - jinja2 - ]); - in { - description = "notes — markdown blog + landing page"; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pythonEnv ]; - serviceConfig = { - WorkingDirectory = "/home/danny/notes"; - ExecStart = "${pythonEnv}/bin/python -m uvicorn server:app --host :: --port 8092"; - Restart = "on-failure"; - RestartSec = 10; - User = "danny"; - }; - }; - - # TDPixi — Idle Tower Defence Telegram Mini App by @plasmagoat. - # Pure static serve, no DB. Code rsync'd to /home/danny/tdpixi/. - # Upstream: https://github.com/plasmagoat/TDPixi - systemd.services.tdpixi = let - pythonEnv = pkgs.python3.withPackages (ps: with ps; [ - fastapi - uvicorn - ]); - in { - description = "tdpixi — Idle Tower Defence Mini App"; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pythonEnv ]; - serviceConfig = { - WorkingDirectory = "/home/danny/tdpixi"; - ExecStart = "${pythonEnv}/bin/python -m uvicorn server:app --host :: --port 8093"; - Restart = "on-failure"; - RestartSec = 10; - User = "danny"; - }; - }; - - # Hara morning heartbeat — daily email check + Telegram good-morning ping. - # Runs claude in print mode with the Gmail MCP, then sends output via Bot API. - # Token lives in ~/.claude/channels/telegram/.env (managed by the telegram plugin). - systemd.services.hara-heartbeat = { - description = "Hara morning heartbeat (email check + Telegram ping)"; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - path = [ pkgs.claude-code pkgs.curl pkgs.jq pkgs.gnused ]; - environment = { - HOME = "/home/danny"; - }; - serviceConfig = { - Type = "oneshot"; - User = "danny"; - Group = "users"; - WorkingDirectory = "/home/danny"; - EnvironmentFile = "/etc/claude-channels/env"; - }; - script = '' - set -euo pipefail - CHAT_ID="66070351" - BOT_TOKEN=$(grep '^TELEGRAM_BOT_TOKEN=' /home/danny/.claude/channels/telegram/.env | cut -d= -f2-) - MSG=$(${pkgs.claude-code}/bin/claude -p \ - "You are Hara, a concise cat-energy AI assistant. Read ~/.hara/HEARTBEAT.md. Check Gmail for all three accounts (danielth95, powerhouseplayer, wildstylewarrior) for urgent unread emails — security alerts, invoices, anything requiring a decision; skip newsletters and marketing. Compose a short message for Danny: flag urgent emails if any, otherwise just a brief check-in. One message, very short, cat energy." \ - --mcp-config /etc/hara/mcp-servers.json \ - 2>/dev/null | ${pkgs.gnused}/bin/sed 's/\*\*//g; s/\*//g; s/__//g; s/_//g') - ${pkgs.curl}/bin/curl -sf -X POST \ - "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \ - -H "Content-Type: application/json" \ - -d "{\"chat_id\": $CHAT_ID, \"text\": $(echo "$MSG" | ${pkgs.jq}/bin/jq -Rs .)}" \ - > /dev/null - ''; - }; - - systemd.timers.hara-heartbeat = { - wantedBy = [ "timers.target" ]; - timerConfig = { - OnCalendar = "06:07"; - Timezone = "Europe/Copenhagen"; - Persistent = true; - }; - }; - # Forgejo — self-hosted Git forge. Phase 1 of the de-platform-from-GitHub # roadmap (vimwiki/diary/2026-05-03.md). Public URL git.dannydannydanny.me # is fronted by Caddy on vps-relay reverse-proxying over ZT to :3000 here. @@ -658,7 +283,6 @@ in }; }; - # Deploys flow through clan dm-pull-deploy: the dm-pull-deploy.path - # watcher rebuilds when sunken-ship announces a new origin/main rev. - # The legacy pull-based dotfiles-rebuild module was retired 2026-05-19. + # Auto-rebuild service/timer + safe.directory provided by the + # shared dotfiles-rebuild NixOS module (see nixos/modules/dotfiles-rebuild.nix). } diff --git a/nixos/hosts/sunken-ship.nix b/nixos/hosts/sunken-ship.nix index c929d84..e305c03 100644 --- a/nixos/hosts/sunken-ship.nix +++ b/nixos/hosts/sunken-ship.nix @@ -72,7 +72,7 @@ # x86_64-linux builds here via ssh-ng://danny@sunken-ship-zt). nix.settings.trusted-users = [ "root" "danny" ]; environment.systemPackages = with pkgs; [ - git # clone/bootstrap, repo-pull timers, dm-pull-deploy push + git # clone/bootstrap and dotfiles-rebuild timer brightnessctl # manual backlight; replaces removed `light` from nixpkgs uxplay # AirPlay mirroring receiver alsa-utils # aplay, amixer, arecord for audio debugging @@ -95,10 +95,7 @@ networking.firewall = { allowedTCPPorts = [ 7000 7001 7100 4533 ]; allowedUDPPorts = [ 5353 6000 6001 7011 ]; - # 8080: bbbot HTTP backend. 8081: bbbot SHIPYARD STAGING (B3Bot beta). - # 8091: mulbo-server companion service. All ZT-only — see vps-relay.nix - # for the reverse proxies that expose them publicly. - interfaces."zt+".allowedTCPPorts = [ 8080 8081 8091 ]; + interfaces."zt+".allowedTCPPorts = [ 8080 ]; }; # Navidrome — self-hosted music streaming server (Subsonic API). @@ -110,25 +107,9 @@ Address = "0.0.0.0"; Port = 4533; MusicFolder = "/srv/music"; - # Auto-delete `missing=1` rows during scan so transient files - # (e.g. mulbo dedupe quarantine ones) don't accumulate as stale - # track IDs that Substreamer caches and then 500s on. Without - # this, Navidrome keeps missing rows forever (default behaviour - # preserves play history; we trade that for client-cache hygiene). - # Valid values: never | always | full. `always` purges on every - # scan (selective + full); risk on transient missing is fine - # here (stable local disk). - Scanner.PurgeMissing = "always"; }; }; - # Navidrome's Subsonic API path field is tag-virtual; only the internal - # SQLite has real fs paths. mulbo-server reads navidrome.db ro to - # power /folders + POST /tracks resolution. UMask=0027 makes new DB - # files (and WAL rotations) group-readable; the tmpfile rule fixes the - # existing files written under the previous 0600 umask. - systemd.services.navidrome.serviceConfig.UMask = lib.mkForce "0027"; - # Persist the bind mount so navidrome can read music outside ProtectHome. fileSystems."/srv/music" = { device = "/home/danny/music"; @@ -158,29 +139,23 @@ }; }; - # BigBiggerBiggestBot — Mini App backend (no Telegram polling). + # BigBiggerBiggestBot — Telegram fitness tracker with Mini App. # Code: https://github.com/DannyDannyDanny/bigbiggerbiggestbot cloned at /home/danny/tg_fitness_bot - # Bot token (used only for validating Telegram WebApp initData HMACs): - # ~danny/.secrets/bigbiggerbiggestbot + # Bot token: ~danny/.secrets/bigbiggerbiggestbot # Deployment: fitness-bot-pull timer below runs every 15 min, git pulls, restarts service on changes. # # Mini App URL is fronted by Caddy on the vps-relay host at # https://bbbot.dannydannydanny.me (VPS → ZeroTier → localhost:8080). - # start.py honors WEBAPP_URL to skip starting its own cloudflared - # Quick Tunnel when the stable URL from the VPS is already set. - # - # The slash-command bot (bot.py) was removed in May 2026 — the Mini App - # is now the only interface. No python-telegram-bot dependency required. - # ExecStartPost re-publishes the bot's chat-side presence (menu button, - # description, cleared command list) every time the service starts. - # Idempotent against the Telegram API. Errors are non-fatal (`-` prefix). + # The bot's start.py honors WEBAPP_URL to skip starting its own + # cloudflared Quick Tunnel when we've got a stable URL from the VPS. systemd.services.fitness-bot = let pythonEnv = pkgs.python3.withPackages (ps: with ps; [ + python-telegram-bot python-dotenv aiohttp ]); in { - description = "BigBiggerBiggestBot Mini App backend"; + description = "BigBiggerBiggestBot Telegram fitness tracker"; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; @@ -191,7 +166,6 @@ serviceConfig = { WorkingDirectory = "/home/danny/tg_fitness_bot"; ExecStart = "${pythonEnv}/bin/python start.py"; - ExecStartPost = "-${pythonEnv}/bin/python scripts/set-bot-presence.py"; Restart = "on-failure"; RestartSec = 10; User = "danny"; @@ -226,278 +200,6 @@ timerConfig.RandomizedDelaySec = "2min"; }; - # ── Shipyard staging — B3Bot beta tenant under shipyard_poc_bot ────── - # Mini-App-only HTTP server (no Telegram polling — shipyard_poc_bot on - # phantom-ship owns the polling loop; this service only validates Telegram - # WebApp initData HMACs against the shared bot token). - # - # Working dir: /home/danny/tg_fitness_bot_shipyard (separate clone of the - # same repo, gitignored workouts.db kept across pulls). - # Branch: origin/staging (push there to deploy here; push to origin/main for prod). - # Token file: /home/danny/.secrets/shipyard_poc_bot.env - # File contents: BOT_TOKEN= - # Service won't start until this file exists (ConditionPathExists). - # Mini App URL: https://b3.dannydannydanny.me (vps-relay Caddy → - # ZT IPv6 → here:8081). Stable across restarts — listed in - # ~/python-projects/26_shipyard/apps.json. - # Workflow: git push origin :staging → wait ~15 min → tap B3Bot - # beta in shipyard_poc_bot's launcher → test → git push :main. - systemd.services.fitness-bot-shipyard = let - pythonEnv = pkgs.python3.withPackages (ps: with ps; [ - python-dotenv - aiohttp - ]); - in { - description = "BigBiggerBiggestBot — SHIPYARD STAGING instance"; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pythonEnv ]; - environment.API_HOST = "::"; - environment.API_PORT = "8081"; - # Stable URL fronted by vps-relay's Caddy → ZT → here:8081. - # WEBAPP_URL set tells start.py to skip cloudflared entirely. - environment.WEBAPP_URL = "https://b3.dannydannydanny.me"; - unitConfig.ConditionPathExists = "/home/danny/.secrets/shipyard_poc_bot.env"; - serviceConfig = { - WorkingDirectory = "/home/danny/tg_fitness_bot_shipyard"; - EnvironmentFile = "/home/danny/.secrets/shipyard_poc_bot.env"; - ExecStart = "${pythonEnv}/bin/python start.py"; - Restart = "on-failure"; - RestartSec = 10; - User = "danny"; - }; - }; - - systemd.services.fitness-bot-shipyard-pull = { - description = "Pull shipyard fitness bot from origin/staging and restart if changed"; - path = with pkgs; [ git systemd ]; - environment.GIT_CONFIG_COUNT = "1"; - environment.GIT_CONFIG_KEY_0 = "safe.directory"; - environment.GIT_CONFIG_VALUE_0 = "/home/danny/tg_fitness_bot_shipyard"; - script = '' - set -euo pipefail - if [ ! -d /home/danny/tg_fitness_bot_shipyard/.git ]; then - echo "Shipyard working dir not bootstrapped yet — skipping pull." - exit 0 - fi - cd /home/danny/tg_fitness_bot_shipyard - git fetch origin - if [ "$(git rev-parse HEAD)" = "$(git rev-parse origin/staging)" ]; then - exit 0 - fi - git pull origin staging - systemctl restart fitness-bot-shipyard - ''; - serviceConfig.Type = "oneshot"; - }; - - systemd.timers.fitness-bot-shipyard-pull = { - wantedBy = [ "timers.target" ]; - # Offset from prod (07/15), mulbo (11/15), and dotfiles-rebuild. - timerConfig.OnCalendar = "*-*-* *:13/15:00"; - timerConfig.RandomizedDelaySec = "2min"; - }; - - # Mulbo companion service (Phase 5: uploads + dedup index + folders). - # Wire spec: ~danny/python-projects/20_mulbo/SERVER_API.md. - # Bootstrap (one-time): git clone git@github.com:DannyDannyDanny/python-projects.git /home/danny/python-projects - # (uses sunken-ship's id_ed25519 as a read-only deploy key on the repo) - # ZT-only via the firewall rule above (port 8091). Runs as `danny` so - # writes go through to /home/danny/music/mulbo-uploads, which Navidrome - # reads via the existing /srv/music ro bind-mount with no mount changes. - systemd.tmpfiles.rules = [ - "d /home/danny/music/mulbo-uploads 0755 danny users -" - # One-time fix for the existing navidrome.db (+ WAL/SHM) created - # under the old 0600 umask. UMask=0027 above keeps future writes - # group-readable. - "z /var/lib/navidrome/navidrome.db 0640 navidrome navidrome -" - "z /var/lib/navidrome/navidrome.db-wal 0640 navidrome navidrome -" - "z /var/lib/navidrome/navidrome.db-shm 0640 navidrome navidrome -" - ]; - - systemd.services.mulbo-server = let - pythonEnv = pkgs.python312.withPackages (ps: with ps; [ - fastapi - uvicorn - python-multipart - mutagen # tag writeback (enrich.write_tags); needed by the - # /enrich/revert endpoint which reuses enrich.py. - numpy # FFT for spectral-rolloff analysis (quality.py); used - # by chromaprint-dupe winner picker in --spectral mode. - ]); - in { - description = "Mulbo companion service (uploads, dedup, folders)"; - after = [ "network-online.target" "navidrome.service" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - # ffmpeg: PCM extraction for quality.py's spectral-rolloff probe - # (chromaprint-dupe winner picker in --spectral mode). Without it, - # the subprocess silently fails and rolloff returns 0Hz. - path = with pkgs; [ ffmpeg ]; - environment = { - MULBO_UPLOADS_DIR = "/home/danny/music/mulbo-uploads"; - MULBO_INDEX_DB = "/var/lib/mulbo-server/index.db"; - MULBO_MUSIC_ROOT = "/srv/music"; # ro view via bind-mount; reads + hashing - MULBO_MUSIC_WRITE_ROOT = "/home/danny/music"; # underlying rw path; deletes + quarantines - MULBO_NAVIDROME_URL = "http://localhost:4533"; - MULBO_BIND_HOST = "::"; - MULBO_BIND_PORT = "8091"; - PYTHONUNBUFFERED = "1"; # immediate journal output - }; - serviceConfig = { - WorkingDirectory = "/home/danny/python-projects/20_mulbo"; - ExecStart = "${pythonEnv}/bin/python mulbo_server/app.py"; - Restart = "on-failure"; - RestartSec = 5; - User = "danny"; - # Read-only access to navidrome.db (+WAL/SHM) — see UMask override - # on the navidrome service above. - SupplementaryGroups = [ "navidrome" ]; - StateDirectory = "mulbo-server"; # /var/lib/mulbo-server, owned by danny - # Navidrome credentials — file format: KEY=value lines. - # Required keys: MULBO_NAVIDROME_USER, MULBO_NAVIDROME_PASS. - # Created manually on sunken-ship (mode 600, owned by danny): - # echo -e "MULBO_NAVIDROME_USER=DannyDannyDanny\nMULBO_NAVIDROME_PASS=..." > ~/.secrets/mulbo-server-navidrome - # chmod 600 ~/.secrets/mulbo-server-navidrome - EnvironmentFile = "/home/danny/.secrets/mulbo-server-navidrome"; - }; - }; - - # Pull mulbo (python-projects repo) and restart service if repo changed. - # Repo lives at /home/danny/python-projects (must be cloned manually first - # — see bootstrap note above). DBs/state live in /var/lib/mulbo-server, - # not in the repo, so they survive pulls. - systemd.services.mulbo-pull = { - description = "Pull mulbo repo and restart mulbo-server if changed"; - # openssh: `git fetch origin` over an SSH remote forks `ssh`; without - # it git dies with "cannot run ssh: No such file or directory" and the - # unit fails (shows up as system `degraded`). - path = with pkgs; [ git openssh systemd ]; - environment = { - GIT_CONFIG_COUNT = "1"; - GIT_CONFIG_KEY_0 = "safe.directory"; - GIT_CONFIG_VALUE_0 = "/home/danny/python-projects"; - }; - script = '' - set -euo pipefail - cd /home/danny/python-projects - git fetch origin - if [ "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)" ]; then - exit 0 - fi - git pull origin main - systemctl restart mulbo-server - ''; - serviceConfig.Type = "oneshot"; - }; - - systemd.timers.mulbo-pull = { - wantedBy = [ "timers.target" ]; - timerConfig.OnCalendar = "*-*-* *:11/15:00"; # every 15 min, offset from fitness-bot-pull and dotfiles-rebuild - timerConfig.RandomizedDelaySec = "2min"; - }; - - # dm-pull-deploy push automation. sunken-ship is the push node for the - # clan dm-pull-deploy instance (wired in flake-modules/clan.nix), but - # the upstream module only ships a manual `dm-send-deploy` binary — no - # scheduler. This timer announces the latest origin/main rev over - # data-mesher gossip; the watchers (dm-pull-deploy.path on sunken + - # phantom) compare and only rebuild when the rev actually changes, so - # re-announcing the same rev is a cheap no-op. This is the replacement - # for the legacy dotfiles-rebuild pull timer (being retired). - # - # dm-send-deploy self-discovers the rev via `git ls-remote` and signs - # with /run/secrets/vars/dm-pull-deploy-signing-key — needs root. - systemd.services.dm-pull-deploy-push = { - description = "Announce latest origin/main rev via data-mesher (dm-pull-deploy push)"; - serviceConfig = { - Type = "oneshot"; - ExecStart = "/run/current-system/sw/bin/dm-send-deploy"; - User = "root"; - }; - }; - - systemd.timers.dm-pull-deploy-push = { - wantedBy = [ "timers.target" ]; - timerConfig.OnCalendar = "*-*-* *:04/15:00"; # every 15 min, offset from the other pull timers - timerConfig.RandomizedDelaySec = "2min"; - timerConfig.Persistent = true; - }; - - # One-shot backfill: walks Navidrome's media_file, computes - # (sha256, chromaprint) per file, populates mulbo-server's tracks_index - # with the corresponding navidrome_track_id. Idempotent — existing rows - # left alone. Without this, /tracks/by-hash misses for every existing - # offshore track and `mulbo reconcile-local` duplicates content. - # - # Trigger manually: sudo systemctl start mulbo-server-backfill - # Follow progress: journalctl -fu mulbo-server-backfill - systemd.services.mulbo-server-backfill = let - pythonEnv = pkgs.python312.withPackages (ps: with ps; [ ]); - in { - description = "Backfill mulbo-server tracks_index from Navidrome catalog"; - after = [ "mulbo-server.service" ]; - requires = [ "mulbo-server.service" ]; - path = [ pkgs.chromaprint ]; # provides fpcalc - environment = { - MULBO_INDEX_DB = "/var/lib/mulbo-server/index.db"; - MULBO_NAVIDROME_DB = "/var/lib/navidrome/navidrome.db"; - MULBO_MUSIC_ROOT = "/srv/music"; - PYTHONUNBUFFERED = "1"; - }; - serviceConfig = { - Type = "oneshot"; - WorkingDirectory = "/home/danny/python-projects/20_mulbo"; - ExecStart = "${pythonEnv}/bin/python mulbo_server/backfill.py"; - User = "danny"; - SupplementaryGroups = [ "navidrome" ]; # ro access to navidrome.db - StateDirectory = "mulbo-server"; # so /var/lib/mulbo-server/index.db stays writable - TimeoutSec = "8h"; # full backfill on 274 GB ≈ 1h, leave headroom - }; - }; - - # Phase 7.5 enrichment one-shot. For tracks where Navidrome's tags - # are empty/Unknown, runs three sources (filename heuristics, yt-dlp - # for SoundCloud `[]` patterns, AcoustID+MusicBrainz), votes the - # results, and writes back via mutagen with strict-replacement - # (never touches user-set tags). - # - # Trigger: sudo systemctl start mulbo-server-enrich - # Follow progress: journalctl -fu mulbo-server-enrich - systemd.services.mulbo-server-enrich = let - pythonEnv = pkgs.python312.withPackages (ps: with ps; [ - mutagen # tag writeback - ]); - in { - description = "Enrich Navidrome tracks with empty/Unknown metadata"; - after = [ "mulbo-server.service" ]; - requires = [ "mulbo-server.service" ]; - path = with pkgs; [ yt-dlp chromaprint ]; # yt-dlp for SC/YT lookups, chromaprint for AcoustID's -plain fingerprint - environment = { - MULBO_INDEX_DB = "/var/lib/mulbo-server/index.db"; - MULBO_NAVIDROME_DB = "/var/lib/navidrome/navidrome.db"; - MULBO_MUSIC_ROOT = "/srv/music"; - MULBO_MUSIC_WRITE_ROOT = "/home/danny/music"; - PYTHONUNBUFFERED = "1"; - }; - serviceConfig = { - Type = "oneshot"; - WorkingDirectory = "/home/danny/python-projects/20_mulbo"; - ExecStart = "${pythonEnv}/bin/python mulbo_server/enrich.py"; - User = "danny"; - SupplementaryGroups = [ "navidrome" ]; - StateDirectory = "mulbo-server"; - # Add MULBO_ACOUSTID_KEY to the secrets file to enable the - # AcoustID source. yt-dlp source needs no key. Filename source - # needs nothing. - EnvironmentFile = "/home/danny/.secrets/mulbo-server-navidrome"; - TimeoutSec = "8h"; - }; - }; - - # Deploys now flow through clan dm-pull-deploy: the dm-pull-deploy-push - # timer above announces origin/main, and the dm-pull-deploy.path watcher - # rebuilds on change. The legacy pull-based dotfiles-rebuild module was - # retired 2026-05-19. + # Auto-rebuild service/timer + safe.directory provided by the + # shared dotfiles-rebuild NixOS module (see nixos/modules/dotfiles-rebuild.nix). } diff --git a/nixos/hosts/vps-relay.nix b/nixos/hosts/vps-relay.nix index cedcbfa..5bd653a 100644 --- a/nixos/hosts/vps-relay.nix +++ b/nixos/hosts/vps-relay.nix @@ -46,13 +46,8 @@ isNormalUser = true; extraGroups = [ "wheel" ]; openssh.authorizedKeys.keys = [ - # Mac admin key (~/.ssh/id_ed25519_sunken_ship on the laptop — the - # key the Mac uses to reach the fleet). Used for `clan machines - # update vps-relay` from the Mac and at install via clan. - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKW/akfIiVU5o63YrTAJVZhMj7kXfYHOnXDtlpVFW7pf danny@mac-admin" - # sunken-ship's own key, so the push node can SSH into vps-relay - # over ZeroTier for mesh introspection / debugging. - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB9t4YAaoHvVouqp+qyFOq8o3SAtXMiAmjF6J0ldyx4g danny@sunken-ship" + # Same pubkey used to reach sunken-ship; set at install via clan. + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKW/akfIiVU5o63YrTAJVZhMj7kXfYHOnXDtlpVFW7pf danny@sunken-ship" ]; }; users.users.root.openssh.authorizedKeys.keys = @@ -106,74 +101,11 @@ "bbbot.dannydannydanny.me".extraConfig = '' reverse_proxy http://[fdd5:53a2:de33:d269:6499:93d5:53a2:de33]:8080 ''; - # B3Bot beta — bbbot's staging tenant under shipyard_poc_bot. - # Same backend host as bbbot prod, port 8081. - "b3.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:93d5:53a2:de33]:8081 - ''; - # Shelfish — phantom-ship's ZT IPv6. - "shelfish.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8081 - ''; - # Scuttle — same backend, different port. WebSocket upgrade is - # transparent under reverse_proxy. - "scuttle.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8082 - ''; - # Bananasimulator — same backend, port 8083. - "bananasimulator.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8083 - ''; - # Bananasimulator BETA — separate service on port 8084 with - # BS_BETA_MODE=1 (cheat menu + faster ripening for testing). - "bananasimulator-beta.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8084 - ''; - # KomTolk (formerly translate-platform) — same backend, port 8080. - "komtolk.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8080 - ''; # Forgejo on phantom-ship — Phase 1 of the de-platform-from-GitHub # roadmap (vimwiki/diary/2026-05-03.md). "git.dannydannydanny.me".extraConfig = '' reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:3000 ''; - # Escape Hormuz — turn-based boat-race Mini App, port 8090. - "escapehormuz.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8090 - ''; - # bon — receipt scanner Mini App, port 8091. Camera capture in - # the WebView needs HTTPS, which Caddy terminates here. - "bon.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8091 - ''; - # TDPixi — Idle Tower Defence Mini App by @plasmagoat, port 8093. - "tdpixi.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8093 - ''; - # notes — markdown blog (notes.X) + apex landing (X). Same backend - # service on phantom :8092 routes by Host header. - "notes.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8092 - ''; - "dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8092 - ''; - # kf — Kyranna Fardi architecture portfolio. Same notes service on - # phantom :8092, routed by Host header (PORTFOLIO_HOST). - "kf.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8092 - ''; - # map — curated-architecture world map by Kyranna. Same notes - # service on phantom :8092, routed by Host header (MAP_HOST). - "map.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8092 - ''; - # studio — Kyranna's private art-learning archive. Same notes - # service on phantom :8092, routed by Host header (STUDIO_HOST). - "studio.dannydannydanny.me".extraConfig = '' - reverse_proxy http://[fdd5:53a2:de33:d269:6499:936c:48a:bbdc]:8092 - ''; }; }; diff --git a/nixos/neovim.nix b/nixos/neovim.nix index 51ae100..59a6f85 100644 --- a/nixos/neovim.nix +++ b/nixos/neovim.nix @@ -41,7 +41,6 @@ end -- General options - vim.opt.cursorline = true vim.opt.mouse = "a" vim.opt.listchars = { tab = "→ ", space = "·", nbsp = "␣", trail = "•", eol = "¶", precedes = "«", extends = "»" } vim.opt.clipboard:append("unnamedplus") @@ -58,39 +57,6 @@ end, }) - -- Treesitter highlighting: parser-driven syntax highlighting (richer - -- than the regex-based default). Leaving `indent` off — it's still - -- buggy in several languages (python, yaml). - require'nvim-treesitter.configs'.setup { - highlight = { enable = true }, - } - - -- Sticky scroll: pin enclosing scopes (functions, classes, YAML keys, - -- etc.) to the top of the window as you scroll deeper. Same idea as - -- Zed/VS Code's "Sticky Scroll". `mode = 'topline'` matches Zed's - -- "scrolled past" feel; switch to 'cursor' if you'd rather it track - -- the cursor instead of the viewport. - require'treesitter-context'.setup { - enable = true, - max_lines = 5, - mode = 'topline', - trim_scope = 'outer', - } - - -- Fish: expand tabs to spaces. Fish renders raw \t in the commandline - -- as the Unicode glyph ␉ (U+2409) and wrap-indents each line to the - -- column of the opening quote, which mangles Alt-E multiline edits. - -- Using spaces sidesteps the issue entirely. - vim.api.nvim_create_autocmd("FileType", { - pattern = "fish", - callback = function() - vim.opt_local.expandtab = true - vim.opt_local.tabstop = 2 - vim.opt_local.shiftwidth = 2 - vim.opt_local.softtabstop = 2 - end, - }) - -- Keymaps vim.keymap.set("n", "S", ":%s//g", { desc = "Replace all" }) vim.keymap.set("n", "w", ":w", { desc = "Save file" }) @@ -106,8 +72,6 @@ catppuccin-nvim # theme goyo-vim # write prose limelight-vim # prose paragraph highlighter - nvim-treesitter.withAllGrammars # parsers (also makes vim.treesitter.foldexpr work for markdown) - nvim-treesitter-context # sticky scroll: pin parent scopes at top of window ]; }; } diff --git a/nixos/pkgs/hara-gmail-mcp/default.nix b/nixos/pkgs/hara-gmail-mcp/default.nix index 6d62d10..e82523e 100644 --- a/nixos/pkgs/hara-gmail-mcp/default.nix +++ b/nixos/pkgs/hara-gmail-mcp/default.nix @@ -6,7 +6,7 @@ python3Packages.buildPythonApplication { pname = "hara-gmail-mcp"; - version = "0.2.0"; + version = "0.1.0"; pyproject = true; src = ./.; nativeBuildInputs = [ python3Packages.setuptools ]; diff --git a/nixos/pkgs/hara-gmail-mcp/pyproject.toml b/nixos/pkgs/hara-gmail-mcp/pyproject.toml index fb1db6d..b2a985e 100644 --- a/nixos/pkgs/hara-gmail-mcp/pyproject.toml +++ b/nixos/pkgs/hara-gmail-mcp/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "hara-gmail-mcp" -version = "0.2.0" +version = "0.1.0" description = "Gmail MCP server for Hara (IMAP+SMTP, throwaway pre-OAuth2)" requires-python = ">=3.11" dependencies = [ diff --git a/nixos/pkgs/hara-gmail-mcp/src/hara_gmail_mcp/imap_client.py b/nixos/pkgs/hara-gmail-mcp/src/hara_gmail_mcp/imap_client.py index de204e6..34f2e29 100644 --- a/nixos/pkgs/hara-gmail-mcp/src/hara_gmail_mcp/imap_client.py +++ b/nixos/pkgs/hara-gmail-mcp/src/hara_gmail_mcp/imap_client.py @@ -153,34 +153,6 @@ def read_email( ) -def mark_read( - store: AccountStore, - email_addr: str, - uid: str, - mailbox: str = "INBOX", -) -> None: - """Mark a message as read by adding the \\Seen flag.""" - account = store.get(email_addr) - password = store.password_for(email_addr) - with _open(account, password, mailbox) as conn: - conn.uid("store", uid, "+FLAGS", r"(\Seen)") - - -def archive( - store: AccountStore, - email_addr: str, - uid: str, - mailbox: str = "INBOX", -) -> None: - """Archive a message: copy to All Mail then delete from INBOX.""" - account = store.get(email_addr) - password = store.password_for(email_addr) - with _open(account, password, mailbox) as conn: - conn.uid("copy", uid, "[Gmail]/All Mail") - conn.uid("store", uid, "+FLAGS", r"(\Deleted)") - conn.expunge() - - def _fetch_summary(conn: imaplib.IMAP4_SSL, uid: str) -> MessageSummary: typ, data = conn.uid( "fetch", diff --git a/nixos/pkgs/hara-gmail-mcp/src/hara_gmail_mcp/server.py b/nixos/pkgs/hara-gmail-mcp/src/hara_gmail_mcp/server.py index 0310786..797d41c 100644 --- a/nixos/pkgs/hara-gmail-mcp/src/hara_gmail_mcp/server.py +++ b/nixos/pkgs/hara-gmail-mcp/src/hara_gmail_mcp/server.py @@ -1,15 +1,14 @@ """Hara Gmail MCP server. -Exposes a small toolset for reading and writing mail across the configured -Gmail accounts. +Exposes a small toolset for reading and (later) replying to mail across +the configured Gmail accounts. v1 ships read-only tools; reply/archive/label +follow once Hara is using these reliably. Tools: list_accounts() list configured accounts list_inbox(email, limit) recent messages from an account search(email, query, limit) IMAP SEARCH wrapper read_email(email, uid) full body of one message - mark_read(email, uid) mark a message as read - archive(email, uid) archive a message (remove from INBOX) """ from __future__ import annotations @@ -22,7 +21,7 @@ from dataclasses import asdict from mcp.server.fastmcp import FastMCP from .accounts import AccountStore -from .imap_client import archive, list_inbox, mark_read, read_email, search +from .imap_client import list_inbox, read_email, search logger = logging.getLogger("hara_gmail_mcp") @@ -93,36 +92,6 @@ def gmail_read_email(email: str, uid: str) -> str: return json.dumps(asdict(msg), ensure_ascii=False) -@mcp.tool() -def gmail_mark_read(email: str, uid: str) -> str: - """Mark a message as read (sets the \\Seen flag). - - Args: - email: which configured account - uid: the message UID (returned by gmail_list_inbox or gmail_search) - - Returns: - JSON object with ok and uid. - """ - mark_read(_get_store(), email, uid=uid) - return json.dumps({"ok": True, "uid": uid}) - - -@mcp.tool() -def gmail_archive(email: str, uid: str) -> str: - """Archive a message (copies to All Mail, removes from INBOX). - - Args: - email: which configured account - uid: the message UID (returned by gmail_list_inbox or gmail_search) - - Returns: - JSON object with ok and uid. - """ - archive(_get_store(), email, uid=uid) - return json.dumps({"ok": True, "uid": uid}) - - def main() -> None: logging.basicConfig( level=os.environ.get("HARA_GMAIL_LOG_LEVEL", "INFO"), diff --git a/scripts/build-installer-iso-on-server.sh b/scripts/build-installer-iso-on-server.sh index e7bd002..d969b68 100755 --- a/scripts/build-installer-iso-on-server.sh +++ b/scripts/build-installer-iso-on-server.sh @@ -5,17 +5,12 @@ # host: SSH host (default: sunken-ship) # output_dir: where to save the ISO on your Mac (default: .) # Override SSH key: SSH_KEY=~/.ssh/my_key ./scripts/build-installer-iso-on-server.sh -# -# If nixos/installer-wifi.nix exists locally (gitignored), it is copied into -# the build and the ISO gets preconfigured live-system WiFi. flake-modules/ -# installer-iso.nix auto-includes it via a builtins.pathExists check. set -euo pipefail HOST="${1:-sunken-ship}" OUT="${2:-.}" -REPO_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) -# Default to the sunken-ship SSH key when targeting that host. +# Use sunken-ship key if not set (AGENTS.md) if [[ -n "${SSH_KEY:-}" ]]; then SSH_OPTS=(-i "$SSH_KEY") elif [[ "$HOST" == "sunken-ship" ]] && [[ -f ~/.ssh/id_ed25519_sunken_ship ]]; then @@ -24,37 +19,23 @@ else SSH_OPTS=() fi -echo "Pushing main so the server can clone the latest..." -git -C "$REPO_ROOT" push origin main 2>/dev/null || true +echo "Pushing branch so server can pull..." +git push origin server-installer-usb 2>/dev/null || true -echo "On $HOST: clone main into ~/dotfiles-iso-build..." +echo "On $HOST: clone branch, build ISO..." ssh "${SSH_OPTS[@]}" "$HOST" 'set -e BUILD_DIR=~/dotfiles-iso-build rm -rf "$BUILD_DIR" - git clone --branch main https://github.com/DannyDannyDanny/dotfiles.git "$BUILD_DIR" -' - -# Optional live-system WiFi: the module is gitignored, so a fresh clone never -# has it. Copy it in and stage it (git add -f) so the flake sees it -- a flake -# build only includes git-tracked files. -if [[ -f "$REPO_ROOT/nixos/installer-wifi.nix" ]]; then - echo "Found nixos/installer-wifi.nix - including live-system WiFi in the ISO." - scp "${SSH_OPTS[@]}" "$REPO_ROOT/nixos/installer-wifi.nix" \ - "$HOST:dotfiles-iso-build/nixos/installer-wifi.nix" - ssh "${SSH_OPTS[@]}" "$HOST" 'cd ~/dotfiles-iso-build && git add -f nixos/installer-wifi.nix' -fi - -echo "On $HOST: build ISO (flake is at the repo root)..." -ssh "${SSH_OPTS[@]}" "$HOST" 'set -e - cd ~/dotfiles-iso-build + git clone --branch server-installer-usb https://github.com/DannyDannyDanny/dotfiles.git "$BUILD_DIR" + cd "$BUILD_DIR/nixos" nix build .#installer-iso ls -la result/iso/ ' -ISO_NAME=$(ssh "${SSH_OPTS[@]}" "$HOST" 'ls ~/dotfiles-iso-build/result/iso/*.iso 2>/dev/null | head -1') +ISO_NAME=$(ssh "${SSH_OPTS[@]}" "$HOST" 'ls ~/dotfiles-iso-build/nixos/result/iso/*.iso 2>/dev/null | head -1') ISO_NAME=$(basename "$ISO_NAME") echo "Copying $ISO_NAME to $OUT ..." -scp "${SSH_OPTS[@]}" "$HOST:dotfiles-iso-build/result/iso/$ISO_NAME" "$OUT/" +scp "${SSH_OPTS[@]}" "$HOST:~/dotfiles-iso-build/nixos/result/iso/$ISO_NAME" "$OUT/" echo "Done. ISO at $OUT/$ISO_NAME" echo "Write to USB: diskutil unmountDisk diskN && sudo dd if=$OUT/$ISO_NAME of=/dev/rdiskN bs=4m" diff --git a/sops/machines/distant-shore/key.json b/sops/machines/distant-shore/key.json deleted file mode 100755 index f580056..0000000 --- a/sops/machines/distant-shore/key.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "publickey": "age1hjhqyuvcjuh62xh9m5ek3aa2rluaz8c28hgh2pm435jkqtpry9ssdn2l0z", - "type": "age" - } -] \ No newline at end of file diff --git a/sops/machines/foreign-port/key.json b/sops/machines/foreign-port/key.json deleted file mode 100755 index 6aa3307..0000000 --- a/sops/machines/foreign-port/key.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "publickey": "age1lwl2z6ymqjshknr79277qnr7hvffcc8n7qdqt98sz3t709a5yutq8d7gka", - "type": "age" - } -] \ No newline at end of file diff --git a/sops/secrets/distant-shore-age.key/secret b/sops/secrets/distant-shore-age.key/secret deleted file mode 100644 index 27a5780..0000000 --- a/sops/secrets/distant-shore-age.key/secret +++ /dev/null @@ -1,14 +0,0 @@ -{ - "data": "ENC[AES256_GCM,data:WTerGWNmve9/q+TLYi8HoGUQI0UgYMZN2zuC/FABX0MC6VuUsz9Doz36X8lsy+MRJzcHNPqdaHmAHopY/hODHLBirfUPLVZjEKI=,iv:ilp+cJivxY2us1jO85dWUHAqLJSsJ7ZKpmYMyi2476I=,tag:H0k2CZDhcH9lYSxz6BAPrg==,type:str]", - "sops": { - "age": [ - { - "recipient": "age1g6y8gvcampqj5y3yzdajke2h5n7k6ckdg6a424cghy5325px7cmqjmmd28", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZS2ZhQlJacmR4R3JMek5l\nZlFRajM4VllmK2R6NFlRMEkwNUJOL05OUUhzCmpWQ0gxQ1BHUkZOVm80QzRUc1BY\nTDNRZDZOL3EyS1FWK1A4UUd6MTFaTjAKLS0tIEUxU3hBSkZqRmc5d0dXZm0rNTYw\nQ0hrZUF5dDJLN0MvM2RQZlVFZkNPc28Kvq8yV+VwqQIuG1SPI/mMYbGwuD7oUOeR\nCzAuZvqGtludjW7+wX5uIwRzHMudU/yP/iME8vsDC3dL6sf75+arHg==\n-----END AGE ENCRYPTED FILE-----\n" - } - ], - "lastmodified": "2026-06-07T16:36:36Z", - "mac": "ENC[AES256_GCM,data:g35f5YmoneVewxmTh3E8ECDGAl0OwUj4v/2bjFs9Dd7MaT3in7PHvu30jJ4WHalYC8pkT5IlpBwsp1nVUnKsgh+2V+jN4JiGizlvTwByaYoalOoGZStIyQa+k8XRQqoUDbV3ESdI5q+dwS5PCWYIOH3MoA0o5b42iQPghrViaeY=,iv:v0UUy4LtQ5SRLB01vbcfNpcm8zgs1Vp3KCK552peXlA=,tag:45b8czXYtNh02q7P42FJmQ==,type:str]", - "version": "3.12.2" - } -} diff --git a/sops/secrets/distant-shore-age.key/users/danny b/sops/secrets/distant-shore-age.key/users/danny deleted file mode 120000 index 215639b..0000000 --- a/sops/secrets/distant-shore-age.key/users/danny +++ /dev/null @@ -1 +0,0 @@ -../../../users/danny \ No newline at end of file diff --git a/sops/secrets/foreign-port-age.key/secret b/sops/secrets/foreign-port-age.key/secret deleted file mode 100644 index 2ba1f0f..0000000 --- a/sops/secrets/foreign-port-age.key/secret +++ /dev/null @@ -1,14 +0,0 @@ -{ - "data": "ENC[AES256_GCM,data:MH/ib8WAbzucbm2dhhoo6ESSSLKtKMWmjUwtpAOZhU7KyhOoechpJRSkBBmFV4LzbSP1qeaFbid6USJBnRsxkoz6XvhMzP0kzS0=,iv:9sPwc/JIlo5mzxelNzLCB26k2f+n2C9tB8Y/HEdPvHw=,tag:hJBhzTMsTWd9PDydS4aosg==,type:str]", - "sops": { - "age": [ - { - "recipient": "age1g6y8gvcampqj5y3yzdajke2h5n7k6ckdg6a424cghy5325px7cmqjmmd28", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6L2JGejlzQlhiNFhES1lT\nNTZsNFFMT1NzZEV0T28rNDA3STJ1UXNRcUZFCkxoenpFYWJicHpGVDhtMUdwNXBo\nS29EazVsRGFST2ZodDJMTkxQN2I1RjAKLS0tIFpib0RoOTJ6bkU0b1F6NnRaV3lF\nVHhvYjNOUUtMbGF5ejdaVk5WdGt2d1kKNU5JR1nIYPQLALUM3wRO945Sk6GLxJpn\nTVmVUEgXcwHcSij10a/cQOyPXNNnsfIC+WJFMJcjHfsjBnwS5W/Bgw==\n-----END AGE ENCRYPTED FILE-----\n" - } - ], - "lastmodified": "2026-06-07T19:41:18Z", - "mac": "ENC[AES256_GCM,data:mVobAhXUhbs49+g0bXfi4TjPG667F7pM8Kk518a7kRZ/HtN2kLYcSyl3XpspTosAs4x3QbFQUbFCgsBgqx+gS6xlw3OAJXM3iG2fNu2qoj9Q7viAEHoWVHwT+ftjA0qVTUf0BDD1r4ow6BNhe6kQy5bQqVu0MhjDfsK9BNTXAu4=,iv:aFHo3bQKgr1XSnwGUajkSFa4UftTWdZbPtXY05N7qOM=,tag:VymYJf4XFLaEGvxQmvF6rA==,type:str]", - "version": "3.12.2" - } -} diff --git a/sops/secrets/foreign-port-age.key/users/danny b/sops/secrets/foreign-port-age.key/users/danny deleted file mode 120000 index 215639b..0000000 --- a/sops/secrets/foreign-port-age.key/users/danny +++ /dev/null @@ -1 +0,0 @@ -../../../users/danny \ No newline at end of file diff --git a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.cert/machines/distant-shore b/vars/per-machine/distant-shore/data-mesher-node-identity/identity.cert/machines/distant-shore deleted file mode 120000 index 2f4e8ad..0000000 --- a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.cert/machines/distant-shore +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/machines/distant-shore \ No newline at end of file diff --git a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.cert/secret b/vars/per-machine/distant-shore/data-mesher-node-identity/identity.cert/secret deleted file mode 100644 index 58ead86..0000000 --- a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.cert/secret +++ /dev/null @@ -1,18 +0,0 @@ -{ - "data": "ENC[AES256_GCM,data:esTlopK7VkLLnWvxsLoZtAGgbYKWKfu0XJde2fzxDuOaf9yUCU6NHpnyRAZnChceEZ3frwS7Lh/LWqX9CTKQ1LHTV8HrJERSERDzrQDHbIXFLtDbeF+qN7M1wYFEwCUa8PVAg4XHMN/ZGy6H71+J8UrktcbxcHUr+8L3pj4DZb5930kT3U02rzSoan8zb4zMhGqA0keq9QJ04uNJEN2Bly1kCBvdgc7kVUBNHwS78s+jfsa3PyOiLy5AI4CEbQ5r/xBjNgY/aSEOzRMoZtVWUFlh5Kxc47gz7MlK2x/2iXyCIAw3qeTIxor30GIL,iv:QbSPukR5aMrhBfYOM6lOb0qSEPm4oEqqQp59WDv0p6Y=,tag:KrMyGleLjIhT1LTlS3S63g==,type:str]", - "sops": { - "age": [ - { - "recipient": "age1g6y8gvcampqj5y3yzdajke2h5n7k6ckdg6a424cghy5325px7cmqjmmd28", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyWlpRS1hhQThqaFUyNE4y\nYU1YVDFtazZnSHpTOWRFQkZYVThsRk9RQ1RZCnI4ZlFacTRRSHlub2hWVTNSSkhN\ndWExR202RG1nZ2dQTzQ5LzBNNW1kc2sKLS0tIHZlZXNhSm9wdElTZzRXZjQxaDAx\nRXpvcEkwK3dMNHZ2M21OSFluWnhDOFEKv0/yC/Llmhsm3+kV3AUJ2PPF817rOyL5\n6GkqTrb/gB8q8jnQabDr2sHUz7AB4w7zlQaNLRSo3Ba8KFbW7GZNRg==\n-----END AGE ENCRYPTED FILE-----\n" - }, - { - "recipient": "age1hjhqyuvcjuh62xh9m5ek3aa2rluaz8c28hgh2pm435jkqtpry9ssdn2l0z", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvcEdVdTBsUThiOE1EVWZW\nYXh2NUNCZTVieUZKbjByY2dSZVU2c0Q4L2hBCm1mNzVrcTRTTFpUTkJDZlArYTBZ\nWXhEMERmd1J3VTYxa2dWTlFxOW45N00KLS0tIHNLVzRCdDJGdWk2K0JoY1dJbzIz\nQU9DR2tXU3l2aU9YMGd1RjBGbUJYM0UKYmdAj535wvaGxN6m2VBBVtWRAD5RzQ7K\nbiJjvf8NH4A0aO9RVTFCevqRXUOKBu7jNIpFFfEyUEGHEUCWOuVSlA==\n-----END AGE ENCRYPTED FILE-----\n" - } - ], - "lastmodified": "2026-06-07T16:36:36Z", - "mac": "ENC[AES256_GCM,data:QVkNUsAO6BsVoPAL5GG1/DProapF8ryaUGDr8Y8mYPpD1Y2YXAF2sBRJ4FWkFZkWl4L2sp5DLXfqs+z0tpvi6rpG0jfpgJzy3Du2QKnk5W78WENlK+M74tSzAUfCUPn6RodykLJ8ik+EvxR+yxRmfjStAWsS6eqoTYowa4TGeJ0=,iv:qousMcaNKMtl8hGcfiS1WYBe0ftyb9ohHdBG+gqTio0=,tag:j64zgZpB7cmDfPcq4csjMQ==,type:str]", - "version": "3.12.2" - } -} diff --git a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.cert/users/danny b/vars/per-machine/distant-shore/data-mesher-node-identity/identity.cert/users/danny deleted file mode 120000 index 48e5c60..0000000 --- a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.cert/users/danny +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/users/danny \ No newline at end of file diff --git a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.key/machines/distant-shore b/vars/per-machine/distant-shore/data-mesher-node-identity/identity.key/machines/distant-shore deleted file mode 120000 index 2f4e8ad..0000000 --- a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.key/machines/distant-shore +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/machines/distant-shore \ No newline at end of file diff --git a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.key/secret b/vars/per-machine/distant-shore/data-mesher-node-identity/identity.key/secret deleted file mode 100644 index 50edf19..0000000 --- a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.key/secret +++ /dev/null @@ -1,18 +0,0 @@ -{ - "data": "ENC[AES256_GCM,data:kAzaF+nxyux0zwjoqC5QYrx5UyEhMPW0v9hGcYUXExZl6ShMMgCWhKN82al2jY6OnU/CQ7UT9USH6PC+eecimyM6A5YXQ0GvvU3uus0t46GKqXqcGVl4BdgVO6tm8ienIcfjF6ml3LyvMXirjDdIluVkrH/P0vM=,iv:BSQrtg9kgBHRkCV8+nODNyPX3PchkTEjPPTYy5JZrfo=,tag:dPtjxWqDh1Bce9rlW6czyw==,type:str]", - "sops": { - "age": [ - { - "recipient": "age1g6y8gvcampqj5y3yzdajke2h5n7k6ckdg6a424cghy5325px7cmqjmmd28", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMNkR1YTZNU1FyU2VWaUJR\nbjBOc0RSMW1SL1ZkZ1ozVHRmcVdkS01sdkZnCndTbGJlOVFrdDJHVDUxS1JFUmcy\nZS9jWGhRbWFCeGZOMHQwdzYxTFlrSjgKLS0tIEFaZmFzOXdXVjVOeUJuMDdpQ3hK\ndnRkUytmZk1zaXhUTSt1OTljUkNYK2MKpe6f3GHGCfduiidzYh0qaKEBaKyBZY4s\ne/f5QvZVApMiI4HFkOwFmNITOv6JdjGMQOw+OI6po0nqg0mqVnNIVA==\n-----END AGE ENCRYPTED FILE-----\n" - }, - { - "recipient": "age1hjhqyuvcjuh62xh9m5ek3aa2rluaz8c28hgh2pm435jkqtpry9ssdn2l0z", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpa0p1NCtUeGFLRzJFOFQv\nVXh4MThqOVR4TU9SK3Mrc21Ga1BPdUZrM1c0CmJxQzNyam56aTdUVVB5NVhEenlV\nOTkwb2YyRWdoVXc4K2VEaXhwZXM3TEUKLS0tIEFBajAycEQzelNoR2tCU3l6cVJo\nc3lHbWJZQWFQTkVxd0lBamxlQStZWlkKopG1Z2E0Smt/z/y1+cQeTKUKyJKBXzZr\nCQNkGfi1Dk/7n/WeKwePHWVF/19WqVfOIZW0E3tOKOIqDQZa0Io1Nw==\n-----END AGE ENCRYPTED FILE-----\n" - } - ], - "lastmodified": "2026-06-07T16:36:36Z", - "mac": "ENC[AES256_GCM,data:B6UAFOrK0QIngkf5OA3+BnLAouBvsr0AbW8lKI8RH7ylGQNOyXfnN06fYshi+jQyu5EAZBqovfSZzgcTDm7MDRAjzzmTToT5ekHPZnquleU/F7pF/D7JF78M6rQyw3uG0nwhnJcRqlCAXy+56++kTJhoKEW+B5fUsbvlHTmxwLk=,iv:BXDbLObPBXsL3Uj+TRwIFtNDRzWYJeM0mJyDDluz70s=,tag:eTANaLmNaUUSYBNcIhuIFQ==,type:str]", - "version": "3.12.2" - } -} diff --git a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.key/users/danny b/vars/per-machine/distant-shore/data-mesher-node-identity/identity.key/users/danny deleted file mode 120000 index 48e5c60..0000000 --- a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.key/users/danny +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/users/danny \ No newline at end of file diff --git a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.pub/value b/vars/per-machine/distant-shore/data-mesher-node-identity/identity.pub/value deleted file mode 100644 index 8f2058b..0000000 --- a/vars/per-machine/distant-shore/data-mesher-node-identity/identity.pub/value +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PUBLIC KEY----- -MCowBQYDK2VwAyEAABhcRTNvFEyWkyRBX17KkM5nDuqOvR1xTY5vDqTygvk= ------END PUBLIC KEY----- diff --git a/vars/per-machine/distant-shore/data-mesher-node-identity/peer.id/value b/vars/per-machine/distant-shore/data-mesher-node-identity/peer.id/value deleted file mode 100644 index f748b68..0000000 --- a/vars/per-machine/distant-shore/data-mesher-node-identity/peer.id/value +++ /dev/null @@ -1 +0,0 @@ -12D3KooW9pjiKnqmnHSwGRhgyUqKeFydDUE8RvYJDAqHb5PZvzue \ No newline at end of file diff --git a/vars/per-machine/distant-shore/dm-pull-deploy-status-key/signing.key/machines/distant-shore b/vars/per-machine/distant-shore/dm-pull-deploy-status-key/signing.key/machines/distant-shore deleted file mode 120000 index 2f4e8ad..0000000 --- a/vars/per-machine/distant-shore/dm-pull-deploy-status-key/signing.key/machines/distant-shore +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/machines/distant-shore \ No newline at end of file diff --git a/vars/per-machine/distant-shore/dm-pull-deploy-status-key/signing.key/secret b/vars/per-machine/distant-shore/dm-pull-deploy-status-key/signing.key/secret deleted file mode 100644 index 7c824e7..0000000 --- a/vars/per-machine/distant-shore/dm-pull-deploy-status-key/signing.key/secret +++ /dev/null @@ -1,18 +0,0 @@ -{ - "data": "ENC[AES256_GCM,data:tLR5iZ7Iro3BuBJlpvkKO7RrA9X2pO2H9Isi6jc8y8krh+a89Eug0PCNb4U/aSASjQgDfZgwg9+SU1y4iIoc3qC4sxw3f4uTdjCWRDEgfAvY3DVWiWI/EbWcfX7bVvl/GCQtHSwBW5z3KwhJV2McLK6Fpblx6fM=,iv:exFXncN3SA9zqSTFxX6o3kstwMGL9y8x0IOqJVNqK+I=,tag:dEkDG3meaWoq74hkRHbplg==,type:str]", - "sops": { - "age": [ - { - "recipient": "age1g6y8gvcampqj5y3yzdajke2h5n7k6ckdg6a424cghy5325px7cmqjmmd28", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3YWliNzFKWnZqdnZYeHRs\nVy8wdk1ZZWpJTlg2WWc4eEpUM2diZEFoamg0CnJnVDZJT3lWaUZlV3NHY1NpN0tW\nMXdRTnNGSjBhSFpLY0xvaER6UDI5RlEKLS0tIDloRHJFV2I1RVN6TXh6dmd5dzV0\nZ1AvZmpOM0VkaVZjNHlFdFBNd0FhTVkKEVFjtN66i+8f7P03ODYgoWZsTUiEcPiL\nYaV4UZKbjnp3SKTAeWk1P/lEj5DkicW3hq0ONQf2xrYriCpAc3/gKw==\n-----END AGE ENCRYPTED FILE-----\n" - }, - { - "recipient": "age1hjhqyuvcjuh62xh9m5ek3aa2rluaz8c28hgh2pm435jkqtpry9ssdn2l0z", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0VG1wZE52RFQ2ekl1R1ZY\nN2pmYWd1cStGZzU0Tk1LTmNuMnc5c1UwMnlVCmJrMjB6Qzc5ZUE3aXhmUmVuTTN1\neVFWbGhOUUNYUFJJVHF0OGtaR1FvVG8KLS0tIFp4aHgwN1QvWVVnaTNDVG42SXVB\nYVlLRndmQ1ovQjFMcHZYU0dqNS9ML2sKtHjmgLODafDcmrpYQyXRc/ajAR2saGs8\nlh4NVYYYwoXE6sNKSXwzgXXSjGEXGTVLxVvp9OKnSloI5/LsbrxANQ==\n-----END AGE ENCRYPTED FILE-----\n" - } - ], - "lastmodified": "2026-06-07T16:36:37Z", - "mac": "ENC[AES256_GCM,data:20RiSc6b3o3xy23NDQRw4pcSf/akdcUMO6ciSFSZMQrhreYPBEa+Tb85qqqZ0dqQHRQFanzE3Usomp+Ux4FhFfSsCxljxdOjkQCAfkQKrg+GQ7/NOUhgdVQtep2+gT7MFrEzo5Jv8kctNuT18kqUjv5CwCOR35QJ98yHeAUULoo=,iv:ocUDNN4vhOX9pCUJKqQiBRhjTHbdRdw96csN6EWFdUg=,tag:Lps0aJy0ctWU5ilCUn9Uww==,type:str]", - "version": "3.12.2" - } -} diff --git a/vars/per-machine/distant-shore/dm-pull-deploy-status-key/signing.key/users/danny b/vars/per-machine/distant-shore/dm-pull-deploy-status-key/signing.key/users/danny deleted file mode 120000 index 48e5c60..0000000 --- a/vars/per-machine/distant-shore/dm-pull-deploy-status-key/signing.key/users/danny +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/users/danny \ No newline at end of file diff --git a/vars/per-machine/distant-shore/dm-pull-deploy-status-key/signing.pub/value b/vars/per-machine/distant-shore/dm-pull-deploy-status-key/signing.pub/value deleted file mode 100644 index ea47b41..0000000 --- a/vars/per-machine/distant-shore/dm-pull-deploy-status-key/signing.pub/value +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PUBLIC KEY----- -MCowBQYDK2VwAyEAPVF7m/+s1YroGdvSMxPwKmenJjk4yNrP8tNtZGHEhJI= ------END PUBLIC KEY----- diff --git a/vars/per-machine/distant-shore/zerotier/zerotier-identity-secret/machines/distant-shore b/vars/per-machine/distant-shore/zerotier/zerotier-identity-secret/machines/distant-shore deleted file mode 120000 index 2f4e8ad..0000000 --- a/vars/per-machine/distant-shore/zerotier/zerotier-identity-secret/machines/distant-shore +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/machines/distant-shore \ No newline at end of file diff --git a/vars/per-machine/distant-shore/zerotier/zerotier-identity-secret/secret b/vars/per-machine/distant-shore/zerotier/zerotier-identity-secret/secret deleted file mode 100644 index ed43256..0000000 --- a/vars/per-machine/distant-shore/zerotier/zerotier-identity-secret/secret +++ /dev/null @@ -1,18 +0,0 @@ -{ - "data": "ENC[AES256_GCM,data:9BN/+IBbsAmgABYuTEZvgB3cJOwiZ1aKu5GqcBEvCBoY3K4T5lDPqHrwdH48msu9/KD435SSz336+Stq8bQB87AXdfDMEhVIUwi8SV/CQg3urXvyqp0+lkbbrP9xyFzcH16L7NDmfD/SlZeFXQoPA3YHLvoYSsWnfjzHqrt0600IhAgq0TK+c+5hCzke9k89pgOrO6ypueHV+6GMx0g4JMcwq17bqT3fOQZ+hHSp9uOWDP1kJrO2TktwR/9AWAN+IG1sjUcaKYg+W34pG4XDkNPnp30NPfXSGMXjrM++MkIxyow1zFeSRI+bP5iLQEFpm1AvFFRdYIGN66hQVCgv0kxaOEJknlrG4QT4TyEJ,iv:MUsdjMEBvuaFkJJ6t3NNDrgECjheLJ0FtdrBsztOKZ8=,tag:lTcmyWAoKYPUhDjkHTd+Iw==,type:str]", - "sops": { - "age": [ - { - "recipient": "age1g6y8gvcampqj5y3yzdajke2h5n7k6ckdg6a424cghy5325px7cmqjmmd28", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLQ0Y3Y1N5aEo5ZDQwZ2g4\neXBDMldtWU42cUFaaTBmS1B6YW5QWktNcVZvCjBMYmNKWjR6cmVIRjhNK2Y2aWg5\nM093ZFhFWW0yZnVrOUxGQ3MzSGY5UkUKLS0tICtTbHFTMUtGQWEycGNDNFlXcTBS\nWmNWbDZSNE5sWUpzQ0dTNTgyemhNdzgKdPZIFY/m3IpEMH1PGsYToyLe9Qzj6LpW\nJhOTJbT9L0dTfE3OzdaG8BkwCkb8XCWxzveLPTLPCOvbP8DmOpjjHA==\n-----END AGE ENCRYPTED FILE-----\n" - }, - { - "recipient": "age1hjhqyuvcjuh62xh9m5ek3aa2rluaz8c28hgh2pm435jkqtpry9ssdn2l0z", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvcXQ4NjE4d00ramdsemhI\nb1dxcldHS040TkVyL2lxUjdxL3J1WUlCdEZNCnExMDRqcmh5MGUxNFpJd3k4MzZT\nMXljSW5ncWxlSGRsYlJBdkoxQjIyZHMKLS0tIEhUSkRpeXhOM3BnTEsrNEpDb1I2\nUlhvZzFjRVNCcng2c3lsYS8vZHVHN00KFMMGm6BJY7/cn5WSP/RgjK6bVo4r7ps2\nkMcPoyMyenPiZrzWdL4iIb5azFB3CI8DAQS84Mt6KPR/wkYNoErxJg==\n-----END AGE ENCRYPTED FILE-----\n" - } - ], - "lastmodified": "2026-06-07T16:36:38Z", - "mac": "ENC[AES256_GCM,data:Cy3KGFXu58LAWSCUYJGpMeJxBboQxEPS1TzoK8iCFUyTT7Xfak9M9omaBd2r2fEel61iuSDVoDvQbZgNy2RwuiG0HhTXliMXR6G4oOheQIsSQix81tOWoPipu77qoeVkOSUDRhBzHdQVQQmiN7VJvw1kHvCq20u2ZM0057vf91g=,iv:uAmwqd0gpCD7pTFWwgKdkKjjxVadnHeRYUEv+vUgvL8=,tag:iDbx80+08AqhvdZIXJzdgQ==,type:str]", - "version": "3.12.2" - } -} diff --git a/vars/per-machine/distant-shore/zerotier/zerotier-identity-secret/users/danny b/vars/per-machine/distant-shore/zerotier/zerotier-identity-secret/users/danny deleted file mode 120000 index 48e5c60..0000000 --- a/vars/per-machine/distant-shore/zerotier/zerotier-identity-secret/users/danny +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/users/danny \ No newline at end of file diff --git a/vars/per-machine/distant-shore/zerotier/zerotier-ip/value b/vars/per-machine/distant-shore/zerotier/zerotier-ip/value deleted file mode 100644 index 1de93b8..0000000 --- a/vars/per-machine/distant-shore/zerotier/zerotier-ip/value +++ /dev/null @@ -1 +0,0 @@ -fdd5:53a2:de33:d269:6499:93b6:ef1a:c3b3 \ No newline at end of file diff --git a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.cert/machines/foreign-port b/vars/per-machine/foreign-port/data-mesher-node-identity/identity.cert/machines/foreign-port deleted file mode 120000 index 96f5ba3..0000000 --- a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.cert/machines/foreign-port +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/machines/foreign-port \ No newline at end of file diff --git a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.cert/secret b/vars/per-machine/foreign-port/data-mesher-node-identity/identity.cert/secret deleted file mode 100644 index 768ab41..0000000 --- a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.cert/secret +++ /dev/null @@ -1,18 +0,0 @@ -{ - "data": "ENC[AES256_GCM,data:wnNPCB0+f3dcxMW1/pcFZFauUVYTC1mfWoWBV2EJmyRzZS3Uux5Un3R/GbYQeDSFZDLzLH+zCZFaxq3mpb3NGTTUzF8vnGMk/OnjlolA8OjAfiODI0mahTiQA7WcWSk1hkkZ15Ri1o+uyumx9hmvJU3dIsKIJe7AizCzwP5bHg1jgRhG2wPKKyIDWKoh4JTlR6SxK6/tOaUPx2gb2ddz2Lk56Xdw7GCbb/9I9D6sRwxdWMCoWFKdTllLsdsD48b8Jfq4ewD+LudYEtiVByk5SpyOjQoAmMLYaGlD+nxFgZz53hePRIXnp0fL0pm4,iv:fA607yxD/yHJatEiGh1SVGDcqKxB+EFeyCUQeF/Z5hA=,tag:glaq+MBCp6ptKqDsw4RM/Q==,type:str]", - "sops": { - "age": [ - { - "recipient": "age1g6y8gvcampqj5y3yzdajke2h5n7k6ckdg6a424cghy5325px7cmqjmmd28", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0MklDUkpWbEdFcFgxTVJZ\ndEs1OTJtZFhVaEsyb2pobGlUOGhtcTY4RWpVCjFDV3lqRmNGclZMbTR3UXlhcjJv\nVEY1Tjk1YWR4Tmt0SmgvR3laZnNIRUkKLS0tIHB1TURnYmVzZW4xSERMR0ZrRXl5\nbWVJbW1keGkyUkhuQXE0MEFTaXFsS1EKHlsS3FDr9RuMBRU5r4T3bCZWZn38V3k+\nfLUfuZK2IF+xyD7kEiBuATB57wwfd8RzZ1lBwz4fD4jlb+fz0BXoJQ==\n-----END AGE ENCRYPTED FILE-----\n" - }, - { - "recipient": "age1lwl2z6ymqjshknr79277qnr7hvffcc8n7qdqt98sz3t709a5yutq8d7gka", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6TnNqc284WkZqdXNLVFBU\nRTJndEFmNjY0Q1YyUnRPLy9jWllpSy9ZaFNFCkFkNmpYenQ2dk1Fb2dRZTNvM0Jl\nemNqUmdjQmpJQUF4M3ZNRmo4UEhXOHcKLS0tIFp4OTZJTGR1algxTEVWemdkQTB5\nME4xTTdlelN6bXJiTGRSM1VSWG5vZUEKOYc71rLx7RTq4DR6ZggrtgllK58sYJ6h\ngw156OTQl3fKWxlrKDd1l4o72M1qmfAIQ1z5YJJ+CfNPk/iMz/R3rQ==\n-----END AGE ENCRYPTED FILE-----\n" - } - ], - "lastmodified": "2026-06-07T19:41:18Z", - "mac": "ENC[AES256_GCM,data:AkcOoNTxMNkpF0SrwFlNujBrB8fxL1diu+mGq/kbsiWIj6UqvVD+dimDSvTgVqvnU4HF7/7b9zKriC6SbG42Kz8zScFv7m3idD2tHr+7SE/iR7CowDQs70CRMo1b85wLq8WAxhfQb93NHdum6I2biNVIf0ZXs1+kZ2iNBxtjqfQ=,iv:kWOCWCe953ekq0n0HLe3S2JprIBnBe9QXwIzDFyQMH8=,tag:tLz7VZwj7RrbpJ7QTrBqcg==,type:str]", - "version": "3.12.2" - } -} diff --git a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.cert/users/danny b/vars/per-machine/foreign-port/data-mesher-node-identity/identity.cert/users/danny deleted file mode 120000 index 48e5c60..0000000 --- a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.cert/users/danny +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/users/danny \ No newline at end of file diff --git a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.key/machines/foreign-port b/vars/per-machine/foreign-port/data-mesher-node-identity/identity.key/machines/foreign-port deleted file mode 120000 index 96f5ba3..0000000 --- a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.key/machines/foreign-port +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/machines/foreign-port \ No newline at end of file diff --git a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.key/secret b/vars/per-machine/foreign-port/data-mesher-node-identity/identity.key/secret deleted file mode 100644 index a79bb25..0000000 --- a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.key/secret +++ /dev/null @@ -1,18 +0,0 @@ -{ - "data": "ENC[AES256_GCM,data:1Hq98rN3U+8DcxIFJpYkvv31gUpSm0WBjfZxivYn7/ZkH6zbJ57fzeU+9PH9SRF6QBuekZKZNIBup3fteI5VqQ/moEyQE9aSvnqGCrkcamDwDQfN5GwKX+rb7W96atESRm/VqhgDWC2KTc3892515gBPpkDG+nc=,iv:tAlghG1jpDPcYgTvEzAlnB2upAetl8mz8IIQercHe4k=,tag:mz3fvVlKolg5JzrjhBNPaw==,type:str]", - "sops": { - "age": [ - { - "recipient": "age1g6y8gvcampqj5y3yzdajke2h5n7k6ckdg6a424cghy5325px7cmqjmmd28", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlaEk2Z1NMZnVtNlJPdXgw\nTWNaTFBCRXo3T2JRUEY2Q2hBY0xpMVV6ckE0ClJOVUpKNDZTcEhGS2RzQm1tSjNp\ndmxQWjl5aHord0RUMHRvTlhyMkVqc1UKLS0tIHlDRXlReUgzZVdLcE9kMFhsTDRq\nOGxpZE9KcUR0VEhyOE9VUkVUVlIyRlEKsnU17famN/qr2M8BdvVpRl5bSWseegrZ\nnB9yljvm+pxsE55xM1WyguNfUwXtHj0YTiVgBl5PIUolj3/J8R76sg==\n-----END AGE ENCRYPTED FILE-----\n" - }, - { - "recipient": "age1lwl2z6ymqjshknr79277qnr7hvffcc8n7qdqt98sz3t709a5yutq8d7gka", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjTGdDVlB0RGlTcng3M3pE\nNzEvNFpBUzF0aDJDaUJFTFFGWlB3bEVVdHhFClZOZGNDanlMTkxIMk9lbzVGRzAv\nZG93NUFFL3NIM3Z0TlhucFlMTTYwc3MKLS0tIFFQcTIwekNEM0k0MElGZys2QldS\nMDZpRVk5OVNZYVVWSWJDTFZqVFdiRWcKgwuwZgKhKx1PiQwH2CgMoCl0WUQR5Rv9\nx4mpZgkoD5pkEx896117CyAy2BRzrDWo+4SsjEijSMlDynYsbxLReA==\n-----END AGE ENCRYPTED FILE-----\n" - } - ], - "lastmodified": "2026-06-07T19:41:18Z", - "mac": "ENC[AES256_GCM,data:DX9+9MH8ZPtc6sPbYSc+54soAIXJWWEoEWBZdbJ6gT5RhVdzUjMHuEbmb9eMcb+nVu4KSUCoXiJOT9XActSU2dcTNIIiLX1lqpw0aWRS2sAWM+Go4hT4/P98z/0vcsdN/uQOBl3cDlygqKhN9GSoPfJTMT+QTSZsVjxwYxW1pPM=,iv:B9RiMMX+yS1Y+3E1ifTJI30pvLrah5SCPwW6CZKZGNU=,tag:MA007hv+nMIMutOdl5ewkQ==,type:str]", - "version": "3.12.2" - } -} diff --git a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.key/users/danny b/vars/per-machine/foreign-port/data-mesher-node-identity/identity.key/users/danny deleted file mode 120000 index 48e5c60..0000000 --- a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.key/users/danny +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/users/danny \ No newline at end of file diff --git a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.pub/value b/vars/per-machine/foreign-port/data-mesher-node-identity/identity.pub/value deleted file mode 100644 index b450f2b..0000000 --- a/vars/per-machine/foreign-port/data-mesher-node-identity/identity.pub/value +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PUBLIC KEY----- -MCowBQYDK2VwAyEAZqy+mwYOfJy3GSHfeC80TFn1c0kYte5zzzbwrP8xww0= ------END PUBLIC KEY----- diff --git a/vars/per-machine/foreign-port/data-mesher-node-identity/peer.id/value b/vars/per-machine/foreign-port/data-mesher-node-identity/peer.id/value deleted file mode 100644 index f9982a8..0000000 --- a/vars/per-machine/foreign-port/data-mesher-node-identity/peer.id/value +++ /dev/null @@ -1 +0,0 @@ -12D3KooWGjAXheQGEfy13JQJP8pSrwcivxoXw5ijRzesfXVDFuyW \ No newline at end of file diff --git a/vars/per-machine/foreign-port/dm-pull-deploy-status-key/signing.key/machines/foreign-port b/vars/per-machine/foreign-port/dm-pull-deploy-status-key/signing.key/machines/foreign-port deleted file mode 120000 index 96f5ba3..0000000 --- a/vars/per-machine/foreign-port/dm-pull-deploy-status-key/signing.key/machines/foreign-port +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/machines/foreign-port \ No newline at end of file diff --git a/vars/per-machine/foreign-port/dm-pull-deploy-status-key/signing.key/secret b/vars/per-machine/foreign-port/dm-pull-deploy-status-key/signing.key/secret deleted file mode 100644 index cd27ea5..0000000 --- a/vars/per-machine/foreign-port/dm-pull-deploy-status-key/signing.key/secret +++ /dev/null @@ -1,18 +0,0 @@ -{ - "data": "ENC[AES256_GCM,data:dDO6hu8prxHvoP41Oxky0mGGbrwqcCcrrkg0tbr/Sv8K16gNoQaX2wvaRDExOmt0BZkv5Oe8p5pvKudmm5JN0AS7oaPexW0lE+vFJ+zrRpq01c5BbCYZ0SuuafJ3VmRS/dlYU0/SZ4MyK3eijLzX3rGHPOi3b0g=,iv:hbh49ExGMYyshxcus/5sTIs/ZcOL9pod/3H/oHG1Qs8=,tag:fjHnl2uunGEU0i2FtgZB+g==,type:str]", - "sops": { - "age": [ - { - "recipient": "age1g6y8gvcampqj5y3yzdajke2h5n7k6ckdg6a424cghy5325px7cmqjmmd28", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZNTlkTWVleld5K3Q5Vklm\nMlphdVduQ0RKY0pEVGdVTm5scHRWR0lNVjAwClV4V3drQnFLUkhpUVk1ZElGcFM1\ncit3UTdURExTRDVjVW1ZdklTZzRINDAKLS0tIHFMYnNycmh1Y0h4OC9UNUtHUmMw\nVXdpVk9QWHlBYmtCS3FOam9SWnRFZG8KDnggBRH/wSh1tfiCGOn1sF/Fdfxkf1us\n7Lzxexrmh+lllns/KY2of9L2HUgDavp+ju/5QVFfT7O3SuSTB6aoow==\n-----END AGE ENCRYPTED FILE-----\n" - }, - { - "recipient": "age1lwl2z6ymqjshknr79277qnr7hvffcc8n7qdqt98sz3t709a5yutq8d7gka", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5eVpNUmV5QlllaXlPaGgr\ndXZYMURzT3I4UWxWSHBSbnAyZVNsOWNaZ2xJClhkRmZ2ejBYVCtkTVBZZE82YXE5\nWkdZWFJFM0lVQXFFYm5rYnRVZDFEdlkKLS0tIHZ5OUgzcFRLZnFWK3pDUUtWUUJj\nWFF4Zk5IeDl5VFNQWlVsTk1lQWlLQmMKJzaOm0cwOshmwoO+eHovf6i6mGkezjIP\ncXJlDaJyxfPKJxc36XlJ5KT9c4RqTX7WFOifHoKRh4EN58KnvtFj+A==\n-----END AGE ENCRYPTED FILE-----\n" - } - ], - "lastmodified": "2026-06-07T19:41:18Z", - "mac": "ENC[AES256_GCM,data:UX7265pubBBssugQk4pZsQH5WedsmnqFa77bJQZwu2ixNUTkO9VfR8r9CUiugDOmbDj9Y7TJtoN4JR+v6hBmDOnjHO5w0WO5dONNJebGmO+pGU7r/K6WwSGi5nPANiYjGuHqYZwq7PJe8ZCF/vu/ZI8q7iJijw6xGWuGHaP/Gvw=,iv:Ezo1z5n+pHPdhjh9l+HvmsgElEwJR4eoMPtZKdDhHAI=,tag:57yLRXReSRz098sDxyiQZQ==,type:str]", - "version": "3.12.2" - } -} diff --git a/vars/per-machine/foreign-port/dm-pull-deploy-status-key/signing.key/users/danny b/vars/per-machine/foreign-port/dm-pull-deploy-status-key/signing.key/users/danny deleted file mode 120000 index 48e5c60..0000000 --- a/vars/per-machine/foreign-port/dm-pull-deploy-status-key/signing.key/users/danny +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/users/danny \ No newline at end of file diff --git a/vars/per-machine/foreign-port/dm-pull-deploy-status-key/signing.pub/value b/vars/per-machine/foreign-port/dm-pull-deploy-status-key/signing.pub/value deleted file mode 100644 index 6131304..0000000 --- a/vars/per-machine/foreign-port/dm-pull-deploy-status-key/signing.pub/value +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PUBLIC KEY----- -MCowBQYDK2VwAyEA6xYjcIT5B5NDduIARf2EAoE+vsnZK+NWcyiI0fQc0Fg= ------END PUBLIC KEY----- diff --git a/vars/per-machine/foreign-port/zerotier/zerotier-identity-secret/machines/foreign-port b/vars/per-machine/foreign-port/zerotier/zerotier-identity-secret/machines/foreign-port deleted file mode 120000 index 96f5ba3..0000000 --- a/vars/per-machine/foreign-port/zerotier/zerotier-identity-secret/machines/foreign-port +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/machines/foreign-port \ No newline at end of file diff --git a/vars/per-machine/foreign-port/zerotier/zerotier-identity-secret/secret b/vars/per-machine/foreign-port/zerotier/zerotier-identity-secret/secret deleted file mode 100644 index 5fd8d79..0000000 --- a/vars/per-machine/foreign-port/zerotier/zerotier-identity-secret/secret +++ /dev/null @@ -1,18 +0,0 @@ -{ - "data": "ENC[AES256_GCM,data:PO0Thn6D7kcIGWr7MwmS8H58+9JYSDDGQZlx28B7T6noXTA6tWqMJlqY4aMn1dXJ1CKAqV4q5VZpd/kP9KQvSL4DRnRrFteRe0C+k/mlLfwsWVqLGFY7eqoG1QTZwc4w8cw3FB7R0YUfxRlHq3mIyrbf+8POX2Rq2r5L5GNWVkGTKZOPRtNawPxTrUgfVM4B9ksc1vtTZeWn1GymSwevnt4KPX/8efFAgIclTUHh+Eh+F9xSU9efnkT+Phsh3QLf+3+UHiXQXlpMgwuKrvBJdHWLxJz/3aTpU2+nByqv0IANhGhR8ut0EbFXr8Zr1pIYrt4mWCAyYJvnwxR6iljQ1zyhI0GXUNAHJPQ7wRYq,iv:yDOBYu2+HK/KfS/hbR5QgOi2QHp9RzGPiKxojQX2s8c=,tag:q6s6LemFyoFBEq+ojd4D6A==,type:str]", - "sops": { - "age": [ - { - "recipient": "age1g6y8gvcampqj5y3yzdajke2h5n7k6ckdg6a424cghy5325px7cmqjmmd28", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1bEkwSUhxR0JQR2psZ3Uy\nUlFpWi93NTBhZ0s0TlpkQ2VkVUdDWHIyNmhFClBhVFBnb1h0c2o2cm9OODZpZWMy\nQTB2YmxnWmN5Ylo4M1JHMVVVdklWeWMKLS0tIDBSY2NQdmRTZnA1QUtnaHloUFJJ\nb0VvZGlwSko0UitTa2t6TDZ4bnhsSWMKt5awUoFdny/Qg5krgUAzHeqIoIhprPmF\nBNleiSJdAvSsK53a7CT2rGInnl3dcrtpkEWluK7WJlFTJBdekMwQuA==\n-----END AGE ENCRYPTED FILE-----\n" - }, - { - "recipient": "age1lwl2z6ymqjshknr79277qnr7hvffcc8n7qdqt98sz3t709a5yutq8d7gka", - "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6TFZjRjk4Wm8vcEcxN0ZP\na05yd282UmR3NllXM2MyeUpSb0VuWURvTHp3CmJzL0cwcU5WWGJuME1KcmtxSFVw\nL1lFdzg3Z2t4TXBiaWduZ2tSZXc3bjAKLS0tIEp6NWpIMlhoSEtvQ3IyNXJNVnE1\nb1lSczR2eG1JY1NScnkyNWMxWWN0aWcKrnfv9dGrWpmBjt8u+FdtwojU5hLDyV/Z\n6vgaW35SvFYLYR53Zo18MPkYbqGcaNldyr68qbYMLxqVdQUJwv3LSg==\n-----END AGE ENCRYPTED FILE-----\n" - } - ], - "lastmodified": "2026-06-07T19:41:19Z", - "mac": "ENC[AES256_GCM,data:joT4cUsVDxTVJqF9OJyETkC0lxQ6sT3XonBIjy80/PZ6cs7lcEyboWWSVuBcG+CTPzcUv1uXmdNjUBNc/TDdF8P0vEGnMBgmNRnSrxb0OwENW+c08GOB+c4AJev58H+V1wmzmyr9NJAKxpvQaE/cWIS1wS7c5QdiKAj8HsYd2ns=,iv:H2xSAU0jTH0bKS+P5W+FwbOtzl/Wb5xTfirkZMmtPq8=,tag:o+b9ESO3d8XnIU/bcH09zw==,type:str]", - "version": "3.12.2" - } -} diff --git a/vars/per-machine/foreign-port/zerotier/zerotier-identity-secret/users/danny b/vars/per-machine/foreign-port/zerotier/zerotier-identity-secret/users/danny deleted file mode 120000 index 48e5c60..0000000 --- a/vars/per-machine/foreign-port/zerotier/zerotier-identity-secret/users/danny +++ /dev/null @@ -1 +0,0 @@ -../../../../../../sops/users/danny \ No newline at end of file diff --git a/vars/per-machine/foreign-port/zerotier/zerotier-ip/value b/vars/per-machine/foreign-port/zerotier/zerotier-ip/value deleted file mode 100644 index 79b3db0..0000000 --- a/vars/per-machine/foreign-port/zerotier/zerotier-ip/value +++ /dev/null @@ -1 +0,0 @@ -fdd5:53a2:de33:d269:6499:9389:9b18:6c52 \ No newline at end of file