diff --git a/agent.claude.build.md b/agent.claude.build.md deleted file mode 100644 index f83dd6a..0000000 --- a/agent.claude.build.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: build -description: Build agent. Executes an implementation plan with full tooling. Parallelizes independent tasks and writes to the project it lives in. -model: sonnet -tools: Read, Write, Edit, Grep, Glob, Bash, Task, WebFetch, WebSearch ---- - -You are the Build agent and the primary orchestrator (Sonnet). - -Execution model: -1. Take the task list and identify independent tasks. -2. Dispatch independent tasks in parallel using the Task tool. -3. Route low-complexity, mechanical, or high-volume subtasks (boilerplate, - simple edits, file scans, test scaffolding) to Haiku subagents for - efficiency. Handle complex, cross-cutting orchestration yourself. -4. Serialize only where there is a real dependency. - -Scope: -- Full read/write access, limited to the project this agent lives in. -- Do not modify files outside the project root. -- Verify your work (build/lint/tests) before reporting done. diff --git a/agent.claude.plan.md b/agent.claude.plan.md deleted file mode 100644 index f511caa..0000000 --- a/agent.claude.plan.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: plan -description: Planning agent. Explores the codebase and produces an implementation plan without writing code. Use PROACTIVELY for any non-trivial task before building. -model: opusplan -tools: Read, Grep, Glob, Task, WebFetch, WebSearch ---- - -You are the Plan agent. Your job is to understand the task and produce a -clear, ordered implementation plan. You DO NOT modify files. - -Workflow: -1. Delegate cheap, high-volume exploration (file discovery, reading, - grepping, summarizing) to Haiku subagents via the Task tool. -2. Reserve your own reasoning for synthesis and plan design (opusplan). -3. Output a concrete, ordered task list with explicit file paths, the - change required in each, and where work can run in parallel. - -Constraints: -- Never edit, create, or delete files. -- Never run mutating shell commands. -- End every response with a numbered task list ready to hand to the Build agent. diff --git a/caesium.nixos.nix b/caesium.nixos.nix index 43ad6ac..fb547e3 100644 --- a/caesium.nixos.nix +++ b/caesium.nixos.nix @@ -3,6 +3,7 @@ { imports = [ ./caesium.hardware.nix # Crucial: Imports your UUIDs + ./module.firewall.nix ]; time.timeZone = "America/New_York"; @@ -14,10 +15,23 @@ boot.loader.efi.canTouchEfiVariables = true; boot.kernelParams = [ "usbcore.autosuspend=-1" ]; + # --- NETWORKING --- networking.hostName = "caesium"; networking.networkmanager.enable = true; networking.interfaces.enp13s0.wakeOnLan.enable = true; + networking.firewall.enable = true; + + # Declaratively restrict ports to CIDRs! + networking.firewall.restrictedPorts = { + ssh = { + port = 22; + allowedCIDRs = [ + "192.168.1.0/16" + ]; + }; + }; + # --- STORAGE & SSD OPTIMIZATION --- # Enable TRIM for SSD longevity services.fstrim.enable = true; @@ -43,6 +57,9 @@ isNormalUser = true; shell = pkgs.zsh; extraGroups = [ "wheel" "networkmanager" "storage" "docker" ]; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILsZW38Ad1GAhGgfo7LsBzt6M4oo30VafsmNrILPMVio" + ]; }; # --- FILE SYSTEMS (Overrides/Additions) --- @@ -177,6 +194,18 @@ binfmt = true; }; + services.openssh = { + enable = true; + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PermitRootLogin = "no"; + AllowUsers = [ "mbessette" ]; + MaxAuthTries = 3; + PerSourcePenalties = "crash:3600s authfail:3600s max:86400s"; + }; + }; + # --- SYSTEM VERSION --- - system.stateVersion = "24.11"; # Or current stable version + system.stateVersion = "26.05"; # Or current stable version } diff --git a/config.ssh.conf b/config.ssh.conf index 8836215..dff9a70 100644 --- a/config.ssh.conf +++ b/config.ssh.conf @@ -8,5 +8,10 @@ Host germanium User mbessette HostName 192.168.2.254 +Host caesium + Port 22 + User mbessette + HostName 192.168.2.136 + Host * IdentityAgent ~/.1password/agent.sock diff --git a/module.firewall.nix b/module.firewall.nix new file mode 100644 index 0000000..ad91e3a --- /dev/null +++ b/module.firewall.nix @@ -0,0 +1,56 @@ +# firewall-rules.nix +{ config, lib, ... }: + +with lib; + +let + cfg = config.networking.firewall.restrictedPorts; + + ruleOpts = { name, ... }: { + options = { + name = mkOption { + type = types.str; + default = name; + description = "Name of the firewall rule."; + }; + port = mkOption { + # Allow either an integer port (80) or a string range/list ("8000-8010" or "{ 80, 443 }") + type = types.oneOf [ types.port types.str ]; + description = "Target port, port range (e.g. \"8000-8010\"), or list."; + }; + protocol = mkOption { + type = types.enum [ "tcp" "udp" ]; + default = "tcp"; + description = "Transport protocol (tcp or udp)."; + }; + allowedCIDRs = mkOption { + type = types.listOf types.str; + default = [ "0.0.0.0/0" "::/0" ]; + description = "Allowed source CIDRs. Defaults to all IPv4 and IPv6 if omitted."; + }; + }; + }; + + formatCidrRule = rule: cidr: + let + family = if hasInfix ":" cidr then "ip6" else "ip"; + # toString handles both integers (2222) and strings ("8000-8010") cleanly + portStr = toString rule.port; + in + "${family} saddr ${cidr} ${rule.protocol} dport ${portStr} accept comment \"${rule.name}\""; + + formatRule = ruleName: rule: + concatMapStringsSep "\n" (formatCidrRule rule) rule.allowedCIDRs; + +in { + options.networking.firewall.restrictedPorts = mkOption { + type = types.attrsOf (types.submodule ruleOpts); + default = { }; + description = "Declarative map of named firewall rules."; + }; + + config = mkIf (cfg != { }) { + networking.firewall.extraInputRules = + concatMapStringsSep "\n" (ruleName: formatRule ruleName cfg.${ruleName}) (attrNames cfg); + }; +}