Skip to content

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

    • Linux builder support for macOS hosts enables containerized builds on Darwin systems.
    • Distributed builds capability for multi-machine build optimization.
  • Chores

    • Updated build infrastructure with nix-darwin integration.
    • Added initialization utilities for Darwin Linux builder configuration.

✏️ Tip: You can customize this high-level summary in your review settings.

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

coderabbitai bot commented Jan 8, 2026

Walkthrough

The changes introduce nix-darwin support to the flake, adding a complete Darwin host configuration with Linux builder setup, activation scripts, distributed build settings, and shell-based setup utilities for system initialization on macOS.

Changes

Cohort / File(s) Summary
Flake Input & Import
flake.nix
Added nix-darwin input from GitHub and imported nix/hosts.nix to expose Darwin configurations in flake outputs
Darwin Host Configuration
nix/hosts.nix, nix/hosts/darwin-nixostest/darwin-configuration.nix
Created host definition exporting darwinConfigurations.darwin-nixostest and comprehensive system configuration including nix settings, linux-builder control scripts, activation scripts for nix-daemon management, distributed build configuration, and system state version
Package Definitions
nix/packages/default.nix, nix/packages/setup-darwin-linux-builder.nix
Added optional Darwin-specific package setup-darwin-linux-builder providing a shell application that backs up system files, executes darwin-rebuild switch, and handles error-based reversal for Linux builder initialization

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • za-arthur
  • LGUG2Z

Poem

🐰 A rabbit hops through Darwin's green,
With linux-builders in between,
We backup files before we dare,
And activate with nix-rebuild care,
Now macOS and linux share! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(darwin): add nix-darwin host and linux-builder for NixOS tests' accurately and specifically describes the main changes in the PR.
Description check ✅ Passed The PR description clearly explains the purpose, provides usage instructions, and references the related PR, though it does not follow a formal template structure.
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.


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
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).
@jfroche jfroche force-pushed the darwin-linux-builder branch from bdd5fd8 to 1c61ed9 Compare January 16, 2026 19:24
Copy link

@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 +56 to +62
nixpkgs.hostPlatform = "aarch64-darwin";

# Install builder control scripts
environment.systemPackages = [
start-linux-builder
stop-linux-builder
];
Copy link

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

🏁 Script executed:

#!/bin/bash
# Read the file to understand context
file_path="nix/hosts/darwin-nixostest/darwin-configuration.nix"

# Check if file exists
if [ -f "$file_path" ]; then
  echo "=== File content with line numbers ==="
  cat -n "$file_path"
else
  echo "File not found: $file_path"
fi

Repository: supabase/postgres

Length of output: 4788


Remove the hardcoded architecture or clarify intent with a comment.

The aarch64-darwin platform is hardcoded, which will fail on Intel Macs. Since the host directory "darwin-nixostest" lacks architecture specificity, this configuration appears generic and should auto-detect the platform instead.

🔧 Suggested adjustment
-  nixpkgs.hostPlatform = "aarch64-darwin";
+  nixpkgs.hostPlatform = lib.mkDefault pkgs.stdenv.hostPlatform.system;

Alternatively, if this configuration is intentionally ARM-only, rename the directory to darwin-aarch64-nixostest and add a comment explaining the constraint.

📝 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
nixpkgs.hostPlatform = "aarch64-darwin";
# Install builder control scripts
environment.systemPackages = [
start-linux-builder
stop-linux-builder
];
nixpkgs.hostPlatform = lib.mkDefault pkgs.stdenv.hostPlatform.system;
# Install builder control scripts
environment.systemPackages = [
start-linux-builder
stop-linux-builder
];
🤖 Prompt for AI Agents
In `@nix/hosts/darwin-nixostest/darwin-configuration.nix` around lines 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.

Comment on lines +104 to +123
nix.linux-builder = {
enable = true;
ephemeral = true;
maxJobs = 4;
supportedFeatures = [
"kvm"
"benchmark"
"big-parallel"
"nixos-test"
];
config = {
virtualisation = {
darwin-builder = {
diskSize = 40 * 1024;
memorySize = 8 * 1024;
};
cores = 6;
};
};
};
Copy link

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

🏁 Script executed:

# First, let's explore the repository structure
git ls-files | head -20

Repository: supabase/postgres

Length of output: 796


🏁 Script executed:

# Find files related to darwin-builder or linux-builder
fd "darwin" --type f

Repository: supabase/postgres

Length of output: 156


🏁 Script executed:

# Look for documentation or comments about supportedFeatures
rg "supportedFeatures" -A 3 -B 3

Repository: supabase/postgres

Length of output: 559


🏁 Script executed:

# Check for any nix-darwin or linux-builder related files
fd "linux-builder\|darwin" --type f

Repository: supabase/postgres

Length of output: 43


🏁 Script executed:

cat -n nix/packages/setup-darwin-linux-builder.nix

Repository: supabase/postgres

Length of output: 2361


🏁 Script executed:

# Check if there are any comments or documentation about KVM support in the entire darwin-nixostest directory
rg "kvm\|KVM" --type nix -i

Repository: supabase/postgres

Length of output: 43


🏁 Script executed:

# Look at the full darwin-configuration.nix file to understand context
cat -n nix/hosts/darwin-nixostest/darwin-configuration.nix

Repository: supabase/postgres

Length of output: 4749


🏁 Script executed:

# Search for any CI or tests that might use this configuration
rg "darwin-nixostest\|linux-builder" --type yml --type yaml -B 2 -A 2

Repository: supabase/postgres

Length of output: 88


🏁 Script executed:

# Check if there are any issues or documentation about supportedFeatures in nix files
rg "supportedFeatures" -B 5 -A 5

Repository: supabase/postgres

Length of output: 818


🏁 Script executed:

# Look for any references to darwin-builder in comments or documentation
rg "darwin-builder" --type nix -B 3 -A 3

Repository: supabase/postgres

Length of output: 574


🏁 Script executed:

# Search for nixos-test or other features mentioned
rg "benchmark\|big-parallel\|nixos-test" --type nix

Repository: supabase/postgres

Length of output: 43


🏁 Script executed:

# Search for workflow files that might use this configuration
fd "\.ya?ml" nix/hosts .github/workflows | head -20

Repository: supabase/postgres

Length of output: 789


🏁 Script executed:

# Look at the flake.nix to understand how this configuration is defined
cat -n flake.nix | head -100

Repository: supabase/postgres

Length of output: 2484


🏁 Script executed:

# Search for any references to darwin-nixostest in the repo
rg "darwin-nixostest" -B 2 -A 2

Repository: supabase/postgres

Length of output: 697


🏁 Script executed:

# Check if there are any comments in the configuration about feature support
cat -n nix/hosts/darwin-nixostest/darwin-configuration.nix | grep -A 20 -B 5 "supportedFeatures"

Repository: supabase/postgres

Length of output: 674


🏁 Script executed:

# Look for any README or documentation files in the nix directory
find nix -name "README*" -o -name "*.md"

Repository: supabase/postgres

Length of output: 806


🏁 Script executed:

# Check for any comments or documentation in the hosts.nix file
cat -n nix/hosts.nix

Repository: supabase/postgres

Length of output: 348


🏁 Script executed:

# Search for any references to KVM, nested virtualization, or capabilities in the repo
rg "nested\|virtuali\|capab" --type nix -i

Repository: supabase/postgres

Length of output: 43


🏁 Script executed:

# Look for any notes or issues in git history about this configuration
git log --oneline --all -- nix/hosts/darwin-nixostest/darwin-configuration.nix | head -10

Repository: supabase/postgres

Length of output: 136


🏁 Script executed:

# Show the commit that added this configuration
git show --stat 1c61ed9

Repository: supabase/postgres

Length of output: 45187


🏁 Script executed:

# Check the nix documentation about development workflow and darwin
cat nix/docs/development-workflow.md

Repository: supabase/postgres

Length of output: 3966


🏁 Script executed:

# Check if there's any documentation about darwin or linux-builder setup
cat nix/docs/start-here.md

Repository: supabase/postgres

Length of output: 5176


🏁 Script executed:

# Search for any comments or context about the features in the actual implementation
git show 1c61ed9 -- nix/hosts/darwin-nixostest/darwin-configuration.nix | head -150

Repository: supabase/postgres

Length of output: 4880


🏁 Script executed:

# Look for any issues or documentation about linux-builder features
rg "supportedFeatures\|linux-builder" --type md

Repository: supabase/postgres

Length of output: 43


🏁 Script executed:

# Check the PR that added this configuration
git log --all --oneline --grep="darwin\|linux-builder" | head -20

Repository: supabase/postgres

Length of output: 888


🏁 Script executed:

# Search online for nix-darwin linux-builder documentation or issues
# Let's check what the actual feature requirements are
rg "benchmark\|big-parallel\|nixos-test" --type nix -B 2 -A 2

Repository: supabase/postgres

Length of output: 43


🏁 Script executed:

# Look at the nix-darwin source to understand linux-builder better
cat flake.lock | grep -A 5 "nix-darwin"

Repository: supabase/postgres

Length of output: 747


🏁 Script executed:

# Look for any existing issues or documentation in the repo about feature support
rg "kvm\|nested" --type nix --type md -i

Repository: supabase/postgres

Length of output: 43


🏁 Script executed:

# Check if there are any test results or CI logs that might indicate feature success/failure
find . -name "*.log" -o -name "*test*" -type f | grep -i darwin | head -10

Repository: supabase/postgres

Length of output: 43


🏁 Script executed:

# Search for nix-darwin module documentation in the repo
fd "modules\|options" | xargs grep -l "linux-builder" 2>/dev/null | head -5

Repository: supabase/postgres

Length of output: 43


🏁 Script executed:

# Check git history for any issues or fixes related to this configuration
git log --all --oneline -- "nix/hosts/darwin-nixostest/" | head -10

Repository: supabase/postgres

Length of output: 136


🌐 Web query:

nix-darwin linux-builder KVM support macOS QEMU nested virtualization

💡 Result:

Short answer

  • nix-darwin’s linux-builder can expose a Linux builder VM and declare "kvm" as a supported feature, but whether KVM-backed nested VMs actually work depends on the host hypervisor support — not nix-darwin itself. [1][2]
  • On macOS you do not get Linux KVM; QEMU on macOS uses the Hypervisor.framework (accel=hvf) rather than Linux KVM, and macOS/QEMU lacks some features (virtfs, etc.) compared to Linux KVM. [3][4]
  • Apple Silicon: M1 does not support hardware nested virtualization, M2/M3+ have improved CPU capability but macOS Hypervisor/Virtualization framework support for nested virt is limited/only recently evolving — in practice nested virtualization inside a linux-builder on Apple Silicon is generally not possible or unreliable today. [2][5][6]

Relevant sources

  1. nix-darwin / linux-builder docs and example config (how to enable linux-builder and expose "kvm" feature). [NixOS wiki: NixOS virtual machines on macOS]. [2]
  2. darwin.linux-builder / nixpkgs docs and examples (how linux-builder is launched from macOS). [darwin.linux-builder docs]. [4]
  3. OSX‑KVM / macOS QEMU projects and notes on running macOS under QEMU on Linux/macOS. [OSX‑KVM (NixOS wiki)]. [1]
  4. QEMU on macOS uses Hypervisor.framework (hvf) not KVM; some QEMU features (virtfs) are missing on macOS. (See QEMU/hvf discussion and issue threads). [QEMU hvf docs/patches; nixpkgs issue re: virtfs]. [6][3]
  5. Notes on nested virtualization support on Apple Silicon (M1 lacks nested‑virt; M2/M3 have more CPU capability but software/framework support is limited). [NixOS wiki discussion; macOS nested-virt threads]. [2][5]
  6. Recent bug/issue reports showing practical limits (virtfs, missing nested support in QEMU/hvf and in projects like UTM/Parallels). [nixpkgs issues; UTM/Parallels KB]. [3][7]

If you want, tell me:

  • your Mac model (Intel vs M1/M2/M3/M4) and macOS version, and I’ll give specific practical steps or a recommended setup (e.g., use darwin.linux-builder + QEMU accel=hvf on Intel, or use a remote Linux builder / cloud builder when nested KVM is required).

Remove unsupported kvm feature from supportedFeatures.

QEMU on macOS uses the Hypervisor.framework (hvf), not KVM. Advertising kvm in supportedFeatures will schedule KVM-dependent builds to this builder, where they will fail. Keep only the features actually supported by the macOS-hosted QEMU VM: benchmark, big-parallel, and nixos-test (if confirmed to work without KVM).

🤖 Prompt for AI Agents
In `@nix/hosts/darwin-nixostest/darwin-configuration.nix` around lines 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.

Comment on lines +27 to +33
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

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.

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