-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
327 lines (308 loc) · 14.1 KB
/
Copy pathMakefile
File metadata and controls
327 lines (308 loc) · 14.1 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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# infra bootstrap makefile
#
# tl;dr:
#
# 1. Run 'make bootstrap' to install nix and direnv
# 2. Run 'make verify' to check your installation
# 3. Run 'make setup-user' to generate age keys for secrets (first time only)
# 4. Run 'nix develop' to enter the development environment
# 5. Use 'just ...' to run configuration tasks
#
# This Makefile helps bootstrap a development environment with nix and direnv.
# After bootstrap is complete, see the justfile for managing configurations.
.DEFAULT_GOAL := help
#-------
##@ help
#-------
# based on "https://gist.github.com/prwhite/8168133?permalink_comment_id=4260260#gistcomment-4260260"
.PHONY: help
help: ## Display this help. (Default)
@grep -hE '^(##@|[A-Za-z0-9_ \-]*?:.*##).*$$' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; /^##@/ {print "\n" substr($$0, 5)} /^[A-Za-z0-9_ \-]*?:.*##/ {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
help-sort: ## Display alphabetized version of help (no section headings).
@grep -hE '^[A-Za-z0-9_ \-]*?:.*##.*$$' $(MAKEFILE_LIST) | sort | \
awk 'BEGIN {FS = ":.*?## "}; /^[A-Za-z0-9_ \-]*?:.*##/ {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
HELP_TARGETS_PATTERN ?= test
help-targets: ## Print commands for all targets matching a given pattern. Copy this example into your shell:
help-targets: ## Copy this example into your shell:
help-targets: ## eval "$(make help-targets HELP_TARGETS_PATTERN=bootstrap | sed 's/\x1b\[[0-9;]*m//g')"
@make help-sort | awk '{print $$1}' | grep '$(HELP_TARGETS_PATTERN)' | xargs -I {} printf "printf '___\n\n{}:\n\n'\nmake -n {}\nprintf '\n'\n"
# catch-all pattern rule
#
# This rule matches any targets that are not explicitly defined in this
# Makefile. It prevents 'make' from failing due to unrecognized targets, which
# is particularly useful when passing arguments or targets to sub-Makefiles. The
# '@:' command is a no-op, indicating that nothing should be done for these
# targets within this Makefile.
#
%:
@:
#-------
##@ bootstrap
#-------
.PHONY: bootstrap-prep-darwin
bootstrap-prep-darwin: ## Install darwin prerequisites (Xcode CLI tools + Homebrew) before 'make bootstrap'
@printf "Installing darwin prerequisites...\n\n"
@printf "Step 1: Xcode Command Line Tools\n"
@if xcode-select -p &>/dev/null; then \
printf " ● Xcode CLI tools already installed\n"; \
else \
printf " Installing Xcode CLI tools (this will open a dialog)...\n"; \
xcode-select --install; \
printf " ⏳ Wait for installation to complete, then re-run this target\n"; \
exit 1; \
fi
@printf "\nStep 2: Homebrew\n"
@if command -v brew &>/dev/null; then \
printf " ● Homebrew already installed\n"; \
else \
printf " Installing Homebrew...\n"; \
/bin/bash -c "$$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"; \
fi
@printf "\n● Darwin prerequisites complete!\n"
@printf "Next: Run 'make bootstrap' to install Nix\n"
.PHONY: bootstrap
bootstrap: ## Main bootstrap target that runs all necessary setup steps
bootstrap: install-nix install-direnv
@printf "\n● Bootstrap of nix and direnv complete!\n\n"
@printf "Next steps:\n"
@echo "1. Start a new shell session (to load nix in PATH)"
@echo "2. Run 'make verify' to check your installation"
@echo "3. Run 'make setup-user' to generate age keys (first time setup)"
@echo "4. Run 'nix develop' to enter the development environment"
@echo ""
@printf "Optional: Auto-activate development environment with direnv\n"
@echo " - See https://direnv.net/docs/hook.html to add direnv to your shell"
@echo " - Start a new shell session"
@echo " - cd out and back into the project directory"
@echo " - Run 'direnv allow' to activate"
@echo ""
@printf "For detailed documentation, see docs/new-user-host.md\n"
.PHONY: install-nix
# Download platform-specific binary directly from GitHub Releases.
# This bypasses both the Fastly CDN (HTTP 618 errors) and the shell wrapper
# (which has template placeholders that aren't filled in for raw source files).
# To update version, change NIX_INSTALLER_VERSION below.
# Note: versioning jumped from 0.27.0 to 3.11.3, then back to 2.34.6 when
# NixOS/nix-installer removed the 3.x tags (repo renamed from experimental-nix-installer).
# https://github.com/NixOS/nix-installer/releases
#
# nix-installer 2.34.6 writes /etc/nix/nix.conf in setup_standard_config
# (src/action/common/place_nix_configuration.rs:98-154). Its defaults are
# extra-experimental-features = nix-command, auto-optimise-store = true (Linux
# only), always-allow-substitutes = true, max-jobs = auto, and
# bash-prompt-prefix. flakes is not among them: place_nix_configuration.rs:105-112
# appends flakes, and :126-131 adds extra-nix-path, only when --enable-flakes is
# passed (src/settings.rs:193-204, present since tag 2.34.4). The only other way
# to get flakes is an interactive prompt that --no-confirm suppresses
# (src/cli/subcommand/install/mod.rs:119-137), so a non-interactive install
# without the flag lands nix-command alone. Releases through 2.33.0 wrote
# nix-command flakes unconditionally, which is why the flag is needed at this pin
# and was not needed at the previous one.
#
# flakes is not optional here: install-direnv resolves nixpkgs#direnv and
# 'make verify' runs 'nix flake --help'.
#
# nix-command and flakes is also the set every host declares
# (modules/system/nix-settings.nix:9-12 for NixOS, modules/darwin/base.nix:17-20
# for darwin), so bootstrap and the fleet agree. auto-allocate-uids, which
# modules/darwin/nix-settings.nix:55-59 merges into the darwin set, is
# deliberately omitted. The experimental feature only makes Nix accept the
# setting of the same name, and the setting is true nowhere in this repo except
# magnetite (modules/machines/nixos/magnetite/default.nix:76-83), which pairs it
# with extra-system-features = uid-range for systemd-nspawn tests. Enabling the
# feature alone changes no build behaviour, and the daemonless mode below has no
# daemon to allocate UIDs at all. Bootstrap's nix.conf is transient regardless:
# the first 'just activate' regenerates it from the host's own modules.
#
# trusted-users lets nix accept flake-specified substituters and public keys
# without prompts or warnings.
NIX_INSTALLER_VERSION := 2.34.6
# A usable systemd runtime is detected by the single existence test that
# /run/systemd/system is present if and only if the machine booted under systemd
# (sd_booted(3)). nix-installer makes the same one test in check_systemd_active
# (src/planner/linux.rs:244-254) and names --init none in its own failure text.
# Overridable so both branches of the check can be expanded on a host that does
# not match.
#
# The resulting $$PLANNER_ARGS is expanded unquoted on purpose: it must become
# either three words or no word at all, and quoting it would pass an empty
# argument to the installer on every systemd host.
SYSTEMD_RUNTIME_DIR ?= /run/systemd/system
install-nix: ## Install Nix using the NixOS community installer
@echo "Installing Nix..."
@if command -v nix >/dev/null 2>&1; then \
echo "Nix is already installed."; \
else \
case "$$(uname -s)-$$(uname -m)" in \
Linux-x86_64) PLATFORM="x86_64-linux" ;; \
Linux-aarch64) PLATFORM="aarch64-linux" ;; \
Darwin-arm64) PLATFORM="aarch64-darwin" ;; \
*) echo "Unsupported platform: $$(uname -s)-$$(uname -m)"; exit 1 ;; \
esac; \
PLANNER_ARGS=""; \
case "$$PLATFORM" in \
*-linux) \
if [ ! -d "$(SYSTEMD_RUNTIME_DIR)" ]; then \
if [ "$$(id -u)" -ne 0 ]; then \
echo "Cannot install Nix: no systemd runtime at $(SYSTEMD_RUNTIME_DIR), and this process is uid $$(id -u) rather than root."; \
echo ""; \
echo "Without systemd the only mode this installer supports is 'install linux --init none', which creates a system-wide /nix and the build users but no daemon, leaving the store writable only by root. Running it as a non-root user does not fail early: nix-installer re-executes itself under sudo, and the Nix it leaves behind is unusable by uid $$(id -u)."; \
echo ""; \
echo "A true single-user installation - /nix owned by the invoking user, no build users, no daemon - is not implemented by this Makefile. Re-run as root, or install Nix manually:"; \
echo " https://nix.dev/manual/nix/stable/installation/installing-binary"; \
exit 1; \
fi; \
echo "No systemd runtime at $(SYSTEMD_RUNTIME_DIR); installing root-only Nix with no daemon."; \
PLANNER_ARGS="linux --init none"; \
fi ;; \
esac; \
INSTALLER_URL="https://github.com/NixOS/nix-installer/releases/download/$(NIX_INSTALLER_VERSION)/nix-installer-$$PLATFORM"; \
echo "Platform: $$PLATFORM"; \
echo "Downloading from: $$INSTALLER_URL"; \
max_attempts=3; \
attempt=1; \
while [ $$attempt -le $$max_attempts ]; do \
echo "Attempt $$attempt of $$max_attempts..."; \
if curl --proto '=https' --tlsv1.2 -sSf -L --retry 3 --retry-delay 5 \
"$$INSTALLER_URL" -o /tmp/nix-installer && chmod +x /tmp/nix-installer; then \
/tmp/nix-installer install $$PLANNER_ARGS --no-confirm \
--enable-flakes \
--extra-conf "trusted-users = root @admin @wheel" && break; \
fi; \
attempt=$$((attempt + 1)); \
if [ $$attempt -le $$max_attempts ]; then \
echo "Download or install failed, waiting 10 seconds before retry..."; \
sleep 10; \
fi; \
done; \
if [ $$attempt -gt $$max_attempts ]; then \
echo "Failed to install nix after $$max_attempts attempts"; \
exit 1; \
fi; \
fi
.PHONY: install-direnv
install-direnv: ## Install direnv (requires nix to be installed first)
@echo "Installing direnv..."
@if command -v direnv >/dev/null 2>&1; then \
echo "direnv is already installed."; \
else \
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix profile install nixpkgs#direnv; \
fi
@echo ""
@echo "See https://direnv.net/docs/hook.html if you would like to add direnv to your shell"
#-------
##@ verify
#-------
.PHONY: verify
verify: ## Verify nix installation and environment setup
@printf "\nVerifying installation...\n\n"
@printf "Checking nix installation: "
@if command -v nix >/dev/null 2>&1; then \
printf "● nix found at %s\n" "$$(command -v nix)"; \
nix --version; \
else \
printf "⊘ nix not found\n"; \
printf "Run 'make install-nix' to install nix\n"; \
exit 1; \
fi
@printf "\nChecking nix flakes support: "
@if nix flake --help >/dev/null 2>&1; then \
printf "● flakes enabled\n"; \
else \
printf "⊘ flakes not enabled\n"; \
exit 1; \
fi
@printf "\nChecking direnv installation: "
@if command -v direnv >/dev/null 2>&1; then \
printf "● direnv found\n"; \
else \
printf "⚠️ direnv not found (optional but recommended)\n"; \
printf "Run 'make install-direnv' to install\n"; \
fi
@printf "\nChecking flake validity: "
@if nix flake metadata . >/dev/null 2>&1; then \
printf "● flake is valid\n"; \
else \
printf "⊘ flake has errors\n"; \
exit 1; \
fi
@printf "\nChecking devShell: "
@if [ -n "$$CI" ]; then \
if nix eval --accept-flake-config .#devShells.$$(nix eval --raw --impure --expr builtins.currentSystem).default --apply 'x: "ok"' >/dev/null 2>&1; then \
printf "● devShell evaluates (build verified by checks-devshells job)\n"; \
else \
printf "⊘ devShell evaluation failed\n"; \
exit 1; \
fi; \
else \
if nix develop --accept-flake-config --command bash -c 'command -v age-keygen && command -v ssh-to-age && command -v sops && command -v just' >/dev/null 2>&1; then \
printf "● age-keygen, ssh-to-age, sops, just available\n"; \
else \
printf "⊘ some tools missing from devShell\n"; \
exit 1; \
fi; \
fi
@printf "\n/etc/nix/nix.conf:\n"
@printf "==================\n"
@cat /etc/nix/nix.conf 2>/dev/null || printf "(file not found)\n"
@printf "==================\n"
@if [ -f /etc/nix/nix.custom.conf ]; then \
printf "\n/etc/nix/nix.custom.conf:\n"; \
printf "==================\n"; \
cat /etc/nix/nix.custom.conf; \
printf "==================\n"; \
fi
@printf "\n● All verification checks passed!\n\n"
#-------
##@ setup
#-------
.PHONY: setup-user
setup-user: ## Generate age key for sops-nix secrets (first time user setup)
@printf "\nGenerating age key for secrets management...\n\n"
@. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && \
if [ -f ~/.config/sops/age/keys.txt ]; then \
printf "⚠️ Age key already exists at ~/.config/sops/age/keys.txt\n"; \
printf "To regenerate, manually delete the file first\n"; \
printf "\nYour public key is:\n"; \
nix shell nixpkgs#age -c age-keygen -y ~/.config/sops/age/keys.txt 2>/dev/null || printf "Error reading existing key\n"; \
else \
mkdir -p ~/.config/sops/age; \
nix shell nixpkgs#age -c age-keygen -o ~/.config/sops/age/keys.txt; \
chmod 600 ~/.config/sops/age/keys.txt; \
printf "\n● Age key generated successfully!\n\n"; \
printf "Your public key is:\n"; \
nix shell nixpkgs#age -c age-keygen -y ~/.config/sops/age/keys.txt; \
printf "\n⚠️ IMPORTANT: Back up your private key to Bitwarden!\n"; \
printf "1. Copy the content of ~/.config/sops/age/keys.txt\n"; \
printf "2. Store in Bitwarden as secure note: 'age-key-<username>'\n"; \
printf "3. Send your PUBLIC key (shown above) to the admin\n"; \
printf "\nSee docs/new-user-host.md for complete setup instructions\n"; \
fi
.PHONY: check-secrets
check-secrets: ## Check if you can decrypt shared secrets (requires age key and admin setup)
@printf "\nChecking secrets access...\n\n"
@if [ ! -f ~/.config/sops/age/keys.txt ]; then \
printf "⊘ No age key found. Run 'make setup-user' first\n"; \
exit 1; \
fi
@if nix develop --accept-flake-config --command sops -d secrets/shared.yaml >/dev/null 2>&1; then \
printf "● Successfully decrypted shared secrets!\n"; \
printf "You have proper access to the secrets system\n"; \
else \
printf "⊘ Cannot decrypt shared secrets\n"; \
printf "Possible reasons:\n"; \
printf "1. Admin hasn't added your key to .sops.yaml yet\n"; \
printf "2. Admin hasn't run 'sops updatekeys' after adding you\n"; \
printf "3. Your age key is incorrect\n"; \
printf "\nSend your public key to admin:\n"; \
age-keygen -y ~/.config/sops/age/keys.txt; \
exit 1; \
fi
#-------
##@ clean
#-------
.PHONY: clean
clean: ## Clean any temporary files or build artifacts
@echo "Cleaning up..."
@rm -rf result result-*