-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathflake.nix
More file actions
144 lines (135 loc) · 5.76 KB
/
Copy pathflake.nix
File metadata and controls
144 lines (135 loc) · 5.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
{
description = "forge — metacraft agent system on NixOS";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
deploy-rs.url = "github:serokell/deploy-rs";
deploy-rs.inputs.nixpkgs.follows = "nixpkgs";
sops-nix.url = "github:Mic92/sops-nix";
sops-nix.inputs.nixpkgs.follows = "nixpkgs";
claude-code.url = "github:sadjow/claude-code-nix";
};
outputs = { self, nixpkgs, deploy-rs, sops-nix, claude-code, ... }:
let
system = "x86_64-linux";
# The deployed NixOS system is linux-only, but operators run the
# deploy tooling from whichever machine they're on. Expose devShells
# for the common operator platforms so `nix develop` works there.
devShellSystems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
forEachDevSystem = f:
nixpkgs.lib.genAttrs devShellSystems
(s: f (import nixpkgs { system = s; }) s);
# Authorized SSH pubkeys — single source of truth shared with the
# terraform layer (which reads the same file for aws_key_pair). Both
# sides consume `deployments/agicash-team-forge/authorized-keys`,
# one OpenSSH pubkey per line, `#` for comments. Drift impossible
# by construction.
agicashTeamForgeKeys =
let
raw = nixpkgs.lib.fileContents ./deployments/agicash-team-forge/authorized-keys;
lines = nixpkgs.lib.splitString "\n" raw;
in
nixpkgs.lib.filter
(l: l != "" && !(nixpkgs.lib.hasPrefix "#" l))
lines;
in
{
# Reusable NixOS module — composed by any deployment under deployments/.
nixosModules.default = ./modules/default.nix;
# ---------------------------------------------------------------------
# agicash-team-forge: first concrete deployment.
# ---------------------------------------------------------------------
nixosConfigurations.agicash-team-forge = nixpkgs.lib.nixosSystem {
inherit system;
modules = [
"${nixpkgs}/nixos/modules/virtualisation/amazon-image.nix"
sops-nix.nixosModules.sops
self.nixosModules.default
./deployments/agicash-team-forge/configuration.nix
];
specialArgs = {
sshPublicKeys = agicashTeamForgeKeys;
claudeCode = claude-code.packages.${system}.default;
};
};
deploy.nodes.agicash-team-forge = {
# Placeholder — the real hostname is injected at deploy time via
# `--hostname` by the `nix run .#deploy` app, which reads it from
# `tofu output -raw public_ip`. Direct `deploy .#agicash-team-forge`
# without `--hostname` is intentionally broken so operators are
# routed through the wrapper (single source of truth = tf state).
hostname = "use-nix-run-deploy-not-direct";
sshUser = "root";
profiles.system = {
user = "root";
# Build on the target machine. The EC2 box has the disk + Nix store;
# operator laptops don't need a Linux builder.
remoteBuild = true;
path = deploy-rs.lib.${system}.activate.nixos
self.nixosConfigurations.agicash-team-forge;
};
};
# Only generate deploy checks for systems where deploy-rs.lib exists.
checks = builtins.mapAttrs
(system: lib: lib.deployChecks self.deploy)
deploy-rs.lib;
# Per-operator devShell. `nix develop` puts the full deploy toolchain
# on PATH at versions pinned to this flake's inputs, so two operators
# don't drift on tool versions and a fresh checkout never asks "how
# do I install terraform / sops / age / …".
devShells = forEachDevSystem (pkgs: sys: {
default = pkgs.mkShell {
packages = [
pkgs.opentofu # `tofu` — free, drop-in for terraform
pkgs.awscli2 # `aws`
pkgs.sops # secrets editor; sops-nix workflow
pkgs.age # `age` / `age-keygen` — sops backend
pkgs.jq # used by misc scripts and the harness
deploy-rs.packages.${sys}.default # `deploy` — nix-side deploy
];
};
});
# `nix run .#deploy` — the single deploy entry point.
#
# Reads the box's current public IP from `tofu output -raw public_ip`
# at invocation time and passes it to deploy-rs as `--hostname`, so
# there is never a deploy-config.nix file to forget to update or to
# disagree with terraform state. Extra args pass through to deploy-rs
# (e.g. `nix run .#deploy -- --skip-checks`).
apps = forEachDevSystem (pkgs: sys:
let
script = pkgs.writeShellApplication {
name = "forge-deploy";
runtimeInputs = [
pkgs.opentofu
pkgs.git
deploy-rs.packages.${sys}.default
];
text = ''
set -euo pipefail
repo=$(git rev-parse --show-toplevel)
cd "$repo"
ip=$(tofu -chdir=deployments/agicash-team-forge/terraform output -raw public_ip 2>/dev/null || true)
if [ -z "$ip" ]; then
echo "✗ no terraform output 'public_ip' available." >&2
echo " Provision the box first:" >&2
echo " cd deployments/agicash-team-forge/terraform && tofu apply" >&2
exit 1
fi
echo "→ deploying to $ip" >&2
exec deploy --hostname "$ip" "$@" .#agicash-team-forge
'';
};
in
{
deploy = {
type = "app";
program = "${script}/bin/forge-deploy";
};
});
};
}