Skip to content

feat(darwin): add nix-darwin host and linux-builder for NixOS tests#1999

Merged
samrose merged 3 commits intodevelopfrom
darwin-linux-builder
Feb 5, 2026
Merged

feat(darwin): add nix-darwin host and linux-builder for NixOS tests#1999
samrose merged 3 commits intodevelopfrom
darwin-linux-builder

Conversation

@jfroche
Copy link
Collaborator

@jfroche jfroche commented Jan 8, 2026

Running NixOS tests on macOS requires a Linux VM capable of building NixOS VMs. This adds a nix-darwin configuration that provisions an ephemeral QEMU linux-builder with support for aarch64-linux and x86_64-linux builds.

Usage:

nix run github:supabase/postgres#setup-darwin-linux-builder

Enables running NixOS integration tests from macOS development machines (see #1989).

Summary by CodeRabbit

  • New Features

    • macOS support integrated with nix-darwin and a preconfigured Darwin host that runs an ephemeral Linux builder VM for cross-building and testing (6 cores, 8GB, 40GB); distributed builds and Nix experimental features enabled.
    • Activation steps include daemon readiness checks and builder control scripts; verification tooling included.
  • Documentation

    • Added a detailed guide for running NixOS tests on macOS, VM workflow, verification, and troubleshooting.
  • Chores

    • Exposed command-line utilities to install, start/stop, and verify the Linux builder.

@jfroche jfroche requested review from a team as code owners January 8, 2026 17:27
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

📝 Walkthrough

Walkthrough

Adds nix-darwin as a flake input and imports a new nix/hosts.nix. Introduces a darwin host configuration darwin-nixostest that sets hostPlatform, nix settings, activation scripts, enables and configures a linux-builder VM (ephemeral, 6 cores, 8GiB, 40GiB), and enables distributed builds. Adds package derivations setup-darwin-linux-builder and verify-darwin-linux-builder, a documentation page nix/docs/nixos-tests-on-macos.md, and a mkdocs nav entry for that doc.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

nix, docs

Suggested reviewers

  • samrose
  • hunleyd
  • za-arthur
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description lacks clear alignment with the template structure and is missing key details about changes across the many files modified. Expand the description to explain the new files and configurations added (e.g., host definitions, builder scripts, documentation) to match repository standards.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: adding a nix-darwin host configuration and Linux builder for running NixOS tests on macOS.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch darwin-linux-builder

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jfroche jfroche force-pushed the darwin-linux-builder branch from 2eaa972 to bdd5fd8 Compare January 9, 2026 17:26
@samrose samrose requested a review from a team as a code owner January 15, 2026 22:41
Base automatically changed from update-nixpkgs to develop January 16, 2026 00:23
@jfroche jfroche force-pushed the darwin-linux-builder branch from bdd5fd8 to 1c61ed9 Compare January 16, 2026 19:24
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@nix/hosts/darwin-nixostest/darwin-configuration.nix`:
- Around line 56-62: The file hardcodes nixpkgs.hostPlatform = "aarch64-darwin",
which will break on Intel Macs; replace that hardcoded value with an
auto-detected platform (e.g. set nixpkgs.hostPlatform to builtins.currentSystem
or derive the arch from builtins.currentSystem) so the configuration is generic,
and keep environment.systemPackages as-is; alternatively, if this is intended to
be ARM-only, rename the directory to indicate aarch64 (e.g.
darwin-aarch64-nixostest) and add a comment next to the nixpkgs.hostPlatform
assignment clarifying the ARM-only constraint.
- Around line 104-123: Remove the unsupported "kvm" feature from the linux
builder's advertised supportedFeatures so macOS-hosted QEMU VMs don't get
scheduled for KVM-only builds: in the nix.linux-builder block update
supportedFeatures to only include the actual macOS/QEMU-supported entries (e.g.,
"benchmark", "big-parallel", and "nixos-test" if validated) and ensure nothing
else in the darwin-builder config (virtualisation.darwin-builder, diskSize,
memorySize, cores) claims KVM support.

In `@nix/packages/setup-darwin-linux-builder.nix`:
- Around line 27-33: The revert() function currently skips restoration when the
target file is a symlink; update revert() so it restores backups even if /etc
files are symlinks: for each file in the loop, check if the backup
"$file.before-nix-darwin" exists ( -f ) and if the target is a symlink ( -L ),
remove the symlink (sudo rm "$file") before moving the backup into place (sudo
mv "$file.before-nix-darwin" "$file"); keep the existing branch for non-symlink
files but ensure both cases handle presence of the backup and use sudo for
removals/moves to avoid permission issues in the revert() function.
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aa78cb3 and 1c61ed9.

⛔ Files ignored due to path filters (1)
  • flake.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • flake.nix
  • nix/hosts.nix
  • nix/hosts/darwin-nixostest/darwin-configuration.nix
  • nix/packages/default.nix
  • nix/packages/setup-darwin-linux-builder.nix
🔇 Additional comments (10)
nix/packages/default.nix (1)

87-89: Darwin-only exposure looks good.

Keeps non-Darwin package sets clean while still surfacing the setup utility where it’s needed.

flake.nix (2)

14-14: Confirm nix-darwin is pinned in flake.lock.

Please ensure the lock file was refreshed so this new input is reproducible.


49-49: LGTM wiring nix/hosts.nix into outputs.

nix/hosts.nix (1)

1-8: LGTM exporting the darwin-nixostest system.

Please verify inputs.nix-darwin.lib.darwinSystem is available in the pinned nix-darwin version.

nix/hosts/darwin-nixostest/darwin-configuration.nix (5)

3-29: Start script flow looks solid.

Checks for the existing service and handles load errors cleanly.


31-52: Stop script handling is clear and safe.


79-103: Activation guard and daemon readiness loop look good.


125-127: LGTM enabling distributed builds and setting stateVersion.


64-77: These configuration options are valid and fully supported.

extra-substituters, extra-trusted-substituters, and extra-trusted-public-keys are standard Nix configuration options that append to their respective lists without replacing defaults. The repository's own flake.nix uses these options, and nix-darwin translates nix.settings directly to /etc/nix/nix.conf. This configuration is correct and follows best practices.

nix/packages/setup-darwin-linux-builder.nix (1)

45-45: Avoid hard‑coding the feature branch in darwin-rebuild.

Using github:supabase/postgres/darwin-linux-builder will break once the branch is deleted and decouples the script from the revision that built it. However, the proposed fix is not valid—${inputs.self} cannot be interpolated into a runtime shell script.

To fix this properly, pass the flake URL as a Nix string value at build time. For example, modify nix/packages/setup-darwin-linux-builder.nix to receive and use self as a parameter, or update nix/packages/default.nix to pass the flake location explicitly:

-setup-darwin-linux-builder = pkgs.callPackage ./setup-darwin-linux-builder.nix { inherit inputs; };
+setup-darwin-linux-builder = pkgs.callPackage ./setup-darwin-linux-builder.nix { inherit inputs self; };

Then in the script, interpolate the flake URL as a proper string during Nix evaluation (not as a shell variable).

Likely an incorrect or invalid review comment.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 27 to 34
revert() {
for file in /etc/nix/nix.conf /etc/bashrc /etc/zshrc; do
if [[ ! -L "$file" && -f "$file.before-nix-darwin" ]]; then
echo " Restoring original $file"
sudo mv "$file.before-nix-darwin" "$file"
fi
done
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Rollback won’t restore backups after nix-darwin symlinks files.

revert skips restoration when the target is a symlink, but darwin-rebuild typically creates symlinks in /etc. On failure, the originals remain stranded and the symlinked config persists.

🔧 Proposed fix
-        if [[ ! -L "$file" && -f "$file.before-nix-darwin" ]]; then
-          echo "  Restoring original $file"
-          sudo mv "$file.before-nix-darwin" "$file" 
+        if [[ -f "$file.before-nix-darwin" ]]; then
+          echo "  Restoring original $file"
+          sudo rm -f "$file"
+          sudo mv "$file.before-nix-darwin" "$file"
         fi
🤖 Prompt for AI Agents
In `@nix/packages/setup-darwin-linux-builder.nix` around lines 27 - 33, The
revert() function currently skips restoration when the target file is a symlink;
update revert() so it restores backups even if /etc files are symlinks: for each
file in the loop, check if the backup "$file.before-nix-darwin" exists ( -f )
and if the target is a symlink ( -L ), remove the symlink (sudo rm "$file")
before moving the backup into place (sudo mv "$file.before-nix-darwin" "$file");
keep the existing branch for non-symlink files but ensure both cases handle
presence of the backup and use sudo for removals/moves to avoid permission
issues in the revert() function.

@jfroche jfroche force-pushed the darwin-linux-builder branch from 1c61ed9 to bf37c1a Compare January 26, 2026 13:08
@jfroche jfroche self-assigned this Jan 29, 2026
@jfroche jfroche force-pushed the darwin-linux-builder branch from 2076540 to 73ac74f Compare February 5, 2026 14:35
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@nix/hosts/darwin-nixostest/darwin-configuration.nix`:
- Around line 3-29: The start-linux-builder shell app currently uses `launchctl
list | grep org.nixos.linux-builder` which matches loaded but non-running jobs;
update the start logic in the start-linux-builder text to verify the service PID
(so it only treats the job as running when PID is numeric) or switch to
`launchctl print system/org.nixos.linux-builder` and check for a "pid =" line;
modify the initial existence check and the post-load check (both in the
start-linux-builder block) to use one of these PID-aware approaches so the
script will attempt to load the service when it is loaded but not running and
only exit 0 when a real PID is present.
🧹 Nitpick comments (1)
flake.nix (1)

16-16: Align nix-darwin with the main nixpkgs input to avoid duplicate nixpkgs instances.

Set nix-darwin.inputs.nixpkgs.follows = "nixpkgs" so nix-darwin reuses your primary nixpkgs input. This prevents separate Nixpkgs graphs, reduces evaluation overhead, and ensures all packages are from the same revision.

♻️ Proposed adjustment
   nix-darwin.url = "github:nix-darwin/nix-darwin";
+  nix-darwin.inputs.nixpkgs.follows = "nixpkgs";

Comment on lines +3 to +29
start-linux-builder = pkgs.writeShellApplication {
name = "start-linux-builder";
text = ''
echo "Starting linux-builder..."

if sudo launchctl list | grep -q org.nixos.linux-builder; then
echo "linux-builder is already running"
exit 0
fi

# Use load instead of start to re-enable the service
if sudo launchctl load -w /Library/LaunchDaemons/org.nixos.linux-builder.plist 2>/dev/null; then
echo "linux-builder started successfully"
else
echo "Error: Could not start linux-builder"
echo "Make sure nix-darwin is configured with linux-builder enabled"
exit 1
fi

# Check if it's running
sleep 2
if sudo launchctl list | grep -q org.nixos.linux-builder; then
echo "linux-builder is now running"
else
echo "Warning: linux-builder may not have started properly"
fi
'';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

launchctl list output format PID field macOS how to detect running job

💡 Result:

launchctl list prints three columns (header often shows PID Status Label):

  • PID: the job’s process ID if it is currently running; otherwise it’s shown as -. [1]
  • Status: the job’s last exit status (negative values mean it was killed by a signal; e.g. -15 = SIGTERM). [1]
  • Label: the launchd job label. [1]

Detect whether a specific job is running (using launchctl list)

If the job appears in the output and the PID column is not -, it’s running. [1]

Example:

label="com.example.myjob"
pid="$(launchctl list | awk -v l="$label" '$3==l {print $1}')"
if [ -n "$pid" ] && [ "$pid" != "-" ]; then
  echo "running (pid=$pid)"
else
  echo "not running (loaded but not running, or not loaded)"
fi

Note on stability / better check

Apple’s launchctl(1) warns the output is not an API and may change. [2] For more reliable state/details, use launchctl print <domain>/<label> (e.g., gui/$UID/<label> or system/<label>). [3]

Sources: [1] launchctl list description (man page excerpt) via Stack Overflow/Server Fault quoting man launchctl; [2] Apple launchctl(1) man page warning; [3] launchctl print description. [1] (stackoverflow.com) [2] (manp.gs) [3] (stackoverflow.com)

Citations:


🌐 Web query:

launchctl print alternative to launchctl list macOS check if job running

💡 Result:

Use launchctl print (Apple calls it the recommended alternative to the legacy launchctl list).[2]

Check whether a specific job is running

Pick the right domain, then look for a PID / running state in the output:

  • LaunchDaemon (system-wide):
launchctl print system/<label>
  • LaunchAgent (GUI login session for your user):
launchctl print gui/$(id -u)/<label>

If the job is running, print will include its current state and typically a PID (where applicable), since print “includes … its current state”.[1]

Practical one-liners

  • “Is it loaded at all?” (errors if not loaded):
launchctl print gui/$(id -u)/<label> >/dev/null 2>&1 && echo loaded || echo not-loaded
  • “Show just state/PID lines”:
launchctl print gui/$(id -u)/<label> 2>/dev/null | egrep 'state =|pid ='

Domain target forms you’ll commonly use are system/<service-name> and gui/<uid>/<service-name>.[1]

Sources:
[1] launchctl(1) man page (domain/service targets; print shows current state) (manp.gs)
[2] launchctl(1) man page (list recommended alternative: print; list PID column meaning) (keith.github.io)

Citations:


Start script may exit even when the job is loaded but not running.

launchctl list | grep matches loaded jobs regardless of running state (PID is "-" when not running). The script can incorrectly skip starting a stopped service. Check the PID field to ensure the job is actually running.

🐛 Proposed fix (awk-based)
-      if sudo launchctl list | grep -q org.nixos.linux-builder; then
+      if sudo launchctl list | awk '$3=="org.nixos.linux-builder" && $1 != "-" {found=1} END{exit !found}'; then
           echo "linux-builder is already running"
           exit 0
       fi

Alternatively, use the more robust launchctl print (Apple's recommended replacement for launchctl list):

if sudo launchctl print system/org.nixos.linux-builder 2>/dev/null | grep -q "pid ="; then
🤖 Prompt for AI Agents
In `@nix/hosts/darwin-nixostest/darwin-configuration.nix` around lines 3 - 29, The
start-linux-builder shell app currently uses `launchctl list | grep
org.nixos.linux-builder` which matches loaded but non-running jobs; update the
start logic in the start-linux-builder text to verify the service PID (so it
only treats the job as running when PID is numeric) or switch to `launchctl
print system/org.nixos.linux-builder` and check for a "pid =" line; modify the
initial existence check and the post-load check (both in the start-linux-builder
block) to use one of these PID-aware approaches so the script will attempt to
load the service when it is loaded but not running and only exit 0 when a real
PID is present.

Running NixOS tests on macOS requires a Linux VM capable of building
NixOS VMs. This adds a nix-darwin configuration that provisions an
ephemeral QEMU linux-builder with support for aarch64-linux and
x86_64-linux builds.

Usage:

    nix run github:supabase/postgres#setup-darwin-linux-builder

Enables running NixOS integration tests from macOS development machines
(see #1989).
Document the linux-builder setup for macOS users who want to run
NixOS tests locally using the nix-darwin configuration.
@jfroche jfroche force-pushed the darwin-linux-builder branch from 73ac74f to 0248b9b Compare February 5, 2026 15:23
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@nix/docs/nixos-tests-on-macos.md`:
- Around line 60-61: Fix the grammatical error and improve clarity in the
sentence that currently reads "If the nix build exit immediately with success,
it means that the result was fetched from cache and the test passed previously."
Change "exit" to "exits" and rephrase for clarity (for example: "If the nix
build exits immediately with a success, it means the result was fetched from
cache and the test passed previously. To force a re-run of the test, use the
`--rebuild` flag:") so the meaning is unambiguous and flows smoothly.

In `@nix/hosts/darwin-nixostest/darwin-configuration.nix`:
- Around line 45-48: The stop script currently uses "sudo launchctl list | grep
-q org.nixos.linux-builder" which treats a loaded-but-stopped job as "still
running"; change the detection to be PID-aware by querying the specific job
(e.g., sudo launchctl list org.nixos.linux-builder) and parse the PID column to
ensure it's a positive integer before warning. Update the conditional that sets
STATUS and prints "Warning: linux-builder is still running" to only trigger when
the parsed PID > 0, and keep writing the STATUS variable (from the launchctl
list output) for debugging when present.
🧹 Nitpick comments (1)
nix/docs/nixos-tests-on-macos.md (1)

97-104: Improve status check documentation.

The launchctl list | grep command shows loaded jobs regardless of running state. The PID column (first field) indicates whether the VM is actually running ("-" means not running, a number means running). Consider clarifying this for users.

📝 Suggested improvement
 ### Checking VM status

 ```bash
 sudo launchctl list | grep linux-builder

-If the VM is running, you'll see a line containing org.nixos.linux-builder.
+If the VM is loaded, you'll see a line containing org.nixos.linux-builder.
+The first column shows the PID if running, or - if loaded but not running.

</details>

</blockquote></details>

</blockquote></details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment on lines +60 to +61
If the nix build exit immediately with success, it means that the result was fetched from cache and the test passed previously.
To force a re-run of the test, use the `--rebuild` flag:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix grammar and improve clarity.

The sentence has a grammatical error ("exit" should be "exits") and could be clearer.

📝 Suggested fix
-If the nix build exit immediately with success, it means that the result was fetched from cache and the test passed previously.
+If the nix build exits immediately, the result was fetched from cache and the test passed previously.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
If the nix build exit immediately with success, it means that the result was fetched from cache and the test passed previously.
To force a re-run of the test, use the `--rebuild` flag:
If the nix build exits immediately, the result was fetched from cache and the test passed previously.
To force a re-run of the test, use the `--rebuild` flag:
🧰 Tools
🪛 LanguageTool

[style] ~60-~60: ‘with success’ might be wordy. Consider a shorter alternative.
Context: ...res. If the nix build exit immediately with success, it means that the result was fetched f...

(EN_WORDINESS_PREMIUM_WITH_SUCCESS)

🤖 Prompt for AI Agents
In `@nix/docs/nixos-tests-on-macos.md` around lines 60 - 61, Fix the grammatical
error and improve clarity in the sentence that currently reads "If the nix build
exit immediately with success, it means that the result was fetched from cache
and the test passed previously." Change "exit" to "exits" and rephrase for
clarity (for example: "If the nix build exits immediately with a success, it
means the result was fetched from cache and the test passed previously. To force
a re-run of the test, use the `--rebuild` flag:") so the meaning is unambiguous
and flows smoothly.

Comment on lines +45 to +48
if sudo launchctl list | grep -q org.nixos.linux-builder; then
echo "Warning: linux-builder is still running"
STATUS=$(sudo launchctl list | grep org.nixos.linux-builder || true)
echo "Current status: $STATUS"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same launchctl list | grep detection issue in stop script.

The stop script has the same problem: a loaded-but-not-running job will trigger the "still running" warning incorrectly. Consider using the same PID-aware check suggested for the start script.

🐛 Proposed fix
-      if sudo launchctl list | grep -q org.nixos.linux-builder; then
+      if sudo launchctl list | awk '$3=="org.nixos.linux-builder" && $1 != "-" {found=1} END{exit !found}'; then
           echo "Warning: linux-builder is still running"
🤖 Prompt for AI Agents
In `@nix/hosts/darwin-nixostest/darwin-configuration.nix` around lines 45 - 48,
The stop script currently uses "sudo launchctl list | grep -q
org.nixos.linux-builder" which treats a loaded-but-stopped job as "still
running"; change the detection to be PID-aware by querying the specific job
(e.g., sudo launchctl list org.nixos.linux-builder) and parse the PID column to
ensure it's a positive integer before warning. Update the conditional that sets
STATUS and prints "Warning: linux-builder is still running" to only trigger when
the parsed PID > 0, and keep writing the STATUS variable (from the launchctl
list output) for debugging when present.

Copy link
Collaborator

@samrose samrose left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good overall. The documentation is thorough and the error handling with the backup/restore trap is a nice touch.

The setup script modifies critical system files (/etc/nix/nix.conf, /etc/bashrc, /etc/zshrc) and has error handling via a trap to restore backups on failure. However, there is no automated testing to verify the setup process works correctly or that the documentation steps produce the expected results.

The helper scripts use launchctl load/unload but rely on grepping launchctl list output for status checks, which could be fragile.

A few possible ways to improve this

  1. Add a verification script or check subcommand

Consider adding a verify-darwin-linux-builder script that checks:

  • The launchd service exists and is loaded
  • The builder responds to a simple build request (e.g., nix build --system aarch64-linux nixpkgs#hello)
  • The nix.conf contains the expected substituters and trusted keys
  • The nixos-test feature is available in the builder's supported features

This could be run as part of CI on a macOS runner or manually after setup.

  1. Add a smoke test to CI

If you have access to macOS runners (GitHub provides macos-14 with M1), you could add a workflow that:

  • Runs the setup script
  • Verifies the linux-builder starts
  • Runs a minimal NixOS test (or at least builds a simple Linux derivation)
  • Runs the documented verification commands from the docs

This would catch regressions when the nix-darwin input is updated or when darwin-configuration.nix is modified.

  1. Test the documented commands

The documentation includes several verification steps:
nix build --system x86_64-linux nixpkgs#hello
nix build --system aarch64-linux nixpkgs#hello
nix build .#checks.aarch64-darwin.ext-pgjwt -L

It would be good to have CI run these (or a subset) to ensure the documentation stays accurate as the configuration evolves.

  1. Consider idempotency testing

The setup script should be safe to run multiple times. Testing that running it twice does not break the system or leave duplicate backups would be useful.

Would you be open to adding at least a basic verification script that developers can run after setup to confirm everything is working? That would also serve as executable documentation.

@samrose
Copy link
Collaborator

samrose commented Feb 5, 2026

Going to approve without requesting testing above due to the complexity we can revisit it later. Documenting is enough for now.

Add verify-darwin-linux-builder script that checks:
- Launchd service status (running vs loaded-but-stopped)
- Nix configuration via nix config show (substituters, trusted keys, experimental features)
- Builder features from /etc/nix/machines (includes nixos-test)
- Builder responsiveness (test build with 60s timeout)

The script is available via:
- nix run .#verify-darwin-linux-builder (standalone)
- verify-darwin-linux-builder (after setup, as system package)

Setup now runs verification automatically after darwin-rebuild.
@jfroche jfroche force-pushed the darwin-linux-builder branch from 02c0242 to 810bc9f Compare February 5, 2026 18:18
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@nix/packages/verify-darwin-linux-builder.nix`:
- Around line 79-85: The FEATURES extraction is grabbing stray "-" and numeric
fields because it uses a regex instead of the specific columns; update the block
that sets FEATURES (referencing MACHINES_FILE and FEATURES) to extract columns 6
and 7 from /etc/nix/machines (the supported-features and mandatory-features) —
e.g. use awk to print $6 and $7, filter out empty values, deduplicate and join
them into a single space-separated string, and keep the existing behavior around
check_pass and the || true fallback so the script still tolerates missing/empty
fields.

Comment on lines 79 to 85
MACHINES_FILE="/etc/nix/machines"
if [[ -f "$MACHINES_FILE" ]]; then
FEATURES=$(grep -oE '\-\s+[^[:space:]]+' "$MACHINES_FILE" | tr '\n' ' ' || true)
if grep -q "nixos-test" "$MACHINES_FILE"; then
check_pass "nixos-test feature supported"
echo " Available features: $FEATURES"
else
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Nix /etc/nix/machines file format supported-features mandatory-features columns documentation

💡 Result:

In Nix, /etc/nix/machines is the default file used by the builders = @/etc/nix/machines`` setting in nix.conf, and it contains one machine specification per line (or `;`-separated), with space-separated columns. Only the first column is required; to keep a column at its default you can use `-`. [1]

/etc/nix/machines columns (in order)

  1. store URI / host: typically ssh://[user@]host (for backward compatibility, ssh:// may be omitted) [1]
  2. systems: comma-separated Nix system types (defaults to the local system if omitted) [1]
  3. ssh identity file: path to the SSH key to use (or -) [1]
  4. max-jobs: max parallel builds on that machine [1]
  5. speed-factor: positive integer used to prefer faster machines (taking load into account) [1]
  6. supported-features (a.k.a. supported system features): comma-separated; the builder is usable only if it supports all features listed in the derivation’s requiredSystemFeatures [1]
  7. mandatory-features (called required system features in the manual): comma-separated; the builder is usable only if all of the machine’s required features are present in the derivation’s requiredSystemFeatures [1]
  8. public host key: base64-encoded host key (optional; if omitted SSH uses known_hosts) [1]

Documentation

This is documented under the builders setting in the Nix manual’s nix.conf / configuration file reference. [1][2]


Extract features from /etc/nix/machines accurately.

The current regex captures the "-" placeholder from the ssh identity file column and numeric fields, producing misleading "Available features" output. The supported-features and mandatory-features are in columns 6 and 7 respectively, which the current pattern doesn't extract.

♻️ Proposed fix
-      FEATURES=$(grep -oE '\-\s+[^[:space:]]+' "$MACHINES_FILE" | tr '\n' ' ' || true)
+      FEATURES=$(awk '{print $6 (NF>=7 ? " " $7 : "")}' "$MACHINES_FILE" | tr ',' ' ' | tr '\n' ' ' || true)
🤖 Prompt for AI Agents
In `@nix/packages/verify-darwin-linux-builder.nix` around lines 79 - 85, The
FEATURES extraction is grabbing stray "-" and numeric fields because it uses a
regex instead of the specific columns; update the block that sets FEATURES
(referencing MACHINES_FILE and FEATURES) to extract columns 6 and 7 from
/etc/nix/machines (the supported-features and mandatory-features) — e.g. use awk
to print $6 and $7, filter out empty values, deduplicate and join them into a
single space-separated string, and keep the existing behavior around check_pass
and the || true fallback so the script still tolerates missing/empty fields.

@samrose samrose added this pull request to the merge queue Feb 5, 2026
Merged via the queue into develop with commit ae34501 Feb 5, 2026
21 checks passed
@samrose samrose deleted the darwin-linux-builder branch February 5, 2026 19:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants