supabase-postgres.git / summary / log / commit / refs
commit ae34501d4f83138f081fedabc15405b4e745897d
Author: Jean-François Roche <jfroche@pyxel.be>
Commit: GitHub <noreply@github.com>
Date: Thu Feb 05 19:08:57 2026 +0000
feat(darwin): add nix-darwin host and linux-builder for NixOS tests (#1999)
* feat(darwin): add nix-darwin host and linux-builder for NixOS tests
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 https://github.com/supabase/postgres/pull/1989).
* docs: add guide for running NixOS tests on macOS
Document the linux-builder setup for macOS users who want to run
NixOS tests locally using the nix-darwin configuration.
* feat: add verification script for darwin-linux-builder
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.
flake.lock | 21 +++
flake.nix | 3 +
nix/docs/nixos-tests-on-macos.md | 189 +++++++++++++++++++++
nix/hosts.nix | 11 ++
.../darwin-nixostest/darwin-configuration.nix | 135 +++++++++++++++
nix/mkdocs.yml | 1 +
nix/packages/default.nix | 6 +
nix/packages/setup-darwin-linux-builder.nix | 75 ++++++++
nix/packages/verify-darwin-linux-builder.nix | 129 ++++++++++++++
9 files changed, 570 insertions(+)
diff --git a/flake.lock b/flake.lock
index d2f12141..839994d6 100644
--- a/flake.lock
+++ b/flake.lock
@@ -131,6 +131,26 @@
"type": "github"
}
},
+ "nix-darwin": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1767718503,
+ "narHash": "sha256-V+VkFs0aSG0ca8p/N3gib7FAf4cq9jyr5Gm+ZBrHQpo=",
+ "owner": "nix-darwin",
+ "repo": "nix-darwin",
+ "rev": "9f48ffaca1f44b3e590976b4da8666a9e86e6eb1",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-darwin",
+ "repo": "nix-darwin",
+ "type": "github"
+ }
+ },
"nix-editor": {
"inputs": {
"nixpkgs": [
@@ -262,6 +282,7 @@
"flake-parts": "flake-parts",
"flake-utils": "flake-utils",
"git-hooks": "git-hooks",
+ "nix-darwin": "nix-darwin",
"nix-editor": "nix-editor",
"nix-eval-jobs": "nix-eval-jobs",
"nix2container": "nix2container",
diff --git a/flake.nix b/flake.nix
index 2145185d..4d9ccdbe 100644
--- a/flake.nix
+++ b/flake.nix
@@ -13,6 +13,8 @@
flake-utils.url = "github:numtide/flake-utils";
git-hooks.inputs.nixpkgs.follows = "nixpkgs";
git-hooks.url = "github:cachix/git-hooks.nix";
+ nix-darwin.inputs.nixpkgs.follows = "nixpkgs";
+ nix-darwin.url = "github:nix-darwin/nix-darwin";
nix-editor.inputs.nixpkgs.follows = "nixpkgs";
nix-editor.inputs.utils.follows = "flake-utils";
nix-editor.url = "github:snowfallorg/nix-editor";
@@ -47,6 +49,7 @@
nix/devShells.nix
nix/fmt.nix
nix/hooks.nix
+ nix/hosts.nix
nix/nixpkgs.nix
nix/packages
nix/overlays
diff --git a/nix/docs/nixos-tests-on-macos.md b/nix/docs/nixos-tests-on-macos.md
new file mode 100644
index 00000000..ae43b4f7
--- /dev/null
+++ b/nix/docs/nixos-tests-on-macos.md
@@ -0,0 +1,189 @@
+## Prerequisites
+
+Running NixOS tests on macOS requires a Linux builder VM because NixOS tests need a Linux environment.
+This project includes a nix-darwin configuration that sets up a linux-builder VM automatically.
+
+You need:
+- macOS with Apple Silicon (aarch64-darwin)
+- Nix installed (see [Getting Started](start-here.md)) preferably a recent version (2.30+)
+
+## Setup
+
+Run the setup script to configure nix-darwin with the linux-builder:
+
+```bash
+nix run .#setup-darwin-linux-builder
+```
+
+Note that you don't have to checkout the repository to run the setup, you can run it directly from GitHub:
+
+```bash
+nix run github:supabase/postgres#setup-darwin-linux-builder
+```
+
+This command will:
+- Back up existing system files (`/etc/nix/nix.conf`, `/etc/bashrc`, `/etc/zshrc`)
+- Configure nix-darwin with the linux-builder VM
+- Install helper scripts for managing the builder
+
+The linux-builder VM is configured with:
+- 6 CPU cores
+- 8GB RAM
+- 40GB disk
+- Support for both x86_64-linux and aarch64-linux builds
+- The `nixos-test` feature required for running NixOS tests
+
+After setup completes, restart your shell to access the helper commands.
+
+## Verify the setup
+
+The setup script runs verification automatically after configuration.
+You can also run verification manually at any time:
+
+```bash
+nix run .#verify-darwin-linux-builder
+```
+
+Or after setup, use the installed command:
+
+```bash
+verify-darwin-linux-builder
+```
+
+The verification script checks:
+
+1. Launchd service status (running vs loaded-but-stopped)
+2. Nix configuration via `nix config show` (substituters, trusted keys, experimental features)
+3. Builder features (`/etc/nix/machines` includes `nixos-test`)
+4. Builder responsiveness (test build of `nixpkgs#hello` for aarch64-linux)
+
+Each check reports pass/fail with actionable guidance on failures.
+
+You can also manually test that the linux-builder is working by building a simple package for Linux:
+
+```bash
+nix build --system x86_64-linux nixpkgs#hello
+nix build --system aarch64-linux nixpkgs#hello
+```
+
+If both commands succeed, the linux-builder is ready for NixOS tests.
+
+## Running NixOS tests
+
+NixOS tests are defined in `nix/ext/tests/` and exposed as flake checks.
+To run a test on macOS, use the `aarch64-darwin` system attribute:
+
+```bash
+nix build .#checks.aarch64-darwin.ext-pgjwt -L
+```
+
+The `-L` flag shows logs during the build, which is helpful for seeing test progress and debugging failures.
+
+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:
+
+```bash
+nix build .#checks.aarch64-darwin.ext-pgjwt -L --rebuild
+```
+
+### Available tests
+
+List all available checks with:
+
+```bash
+nix flake show --json 2>/dev/null | jq -r '.checks["aarch64-darwin"] | keys[]' | sort
+```
+
+Extension tests follow the naming pattern `ext-<extension_name>`:
+
+```bash
+nix build .#checks.aarch64-darwin.ext-pgjwt -L
+nix build .#checks.aarch64-darwin.ext-postgis -L
+nix build .#checks.aarch64-darwin.ext-vector -L
+nix build .#checks.aarch64-darwin.ext-pg_graphql -L
+```
+
+## Managing the linux-builder VM
+
+The setup installs two helper commands for controlling the VM:
+
+```bash
+stop-linux-builder # Stop the VM (pauses resource usage)
+start-linux-builder # Start the VM again
+```
+
+As the VM can consume significant resources, you may want to stop it when not running tests using `stop-linux-builder`.
+When stopped with `stop-linux-builder`, the service is unloaded to prevent automatic restart.
+Use `start-linux-builder` to re-enable and start the service.
+
+### 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`.
+
+## Troubleshooting
+
+### Tests fail with "builder not available"
+
+Ensure the linux-builder is running:
+
+```bash
+start-linux-builder
+```
+
+Then verify with a simple build:
+
+```bash
+nix build --system aarch64-linux nixpkgs#hello
+```
+
+### VM won't start after reboot
+
+If the VM doesn't start automatically, run:
+
+```bash
+start-linux-builder
+```
+
+The VM is configured as ephemeral, meaning it's recreated fresh on each start.
+This ensures a clean environment but requires re-downloading cached build artifacts.
+
+### Slow first build
+
+The first NixOS test run may download significant data.
+Subsequent runs benefit from the Nix store cache and the project's binary cache at `nix-postgres-artifacts.s3.amazonaws.com`.
+
+## How it works
+
+The linux-builder is a QEMU virtual machine managed by nix-darwin.
+When you run a build targeting Linux (like NixOS tests), Nix automatically delegates the build to this VM.
+
+Key configuration from `nix/hosts/darwin-nixostest/darwin-configuration.nix`:
+
+```nix
+nix.linux-builder = {
+ enable = true;
+ ephemeral = true;
+ maxJobs = 4;
+ supportedFeatures = [
+ "kvm"
+ "benchmark"
+ "big-parallel"
+ "nixos-test" # Required for NixOS integration tests
+ ];
+ config = {
+ virtualisation = {
+ darwin-builder = {
+ diskSize = 40 * 1024; # 40GB
+ memorySize = 8 * 1024; # 8GB
+ };
+ cores = 6;
+ };
+ };
+};
+```
+
+The `nixos-test` supported feature is what enables running NixOS VM tests from macOS.
diff --git a/nix/hosts.nix b/nix/hosts.nix
new file mode 100644
index 00000000..f8f7c394
--- /dev/null
+++ b/nix/hosts.nix
@@ -0,0 +1,11 @@
+{ inputs, self, ... }:
+{
+ flake = {
+ darwinConfigurations = {
+ darwin-nixostest = inputs.nix-darwin.lib.darwinSystem {
+ specialArgs = { inherit self; };
+ modules = [ ./hosts/darwin-nixostest/darwin-configuration.nix ];
+ };
+ };
+ };
+}
diff --git a/nix/hosts/darwin-nixostest/darwin-configuration.nix b/nix/hosts/darwin-nixostest/darwin-configuration.nix
new file mode 100644
index 00000000..210880b9
--- /dev/null
+++ b/nix/hosts/darwin-nixostest/darwin-configuration.nix
@@ -0,0 +1,135 @@
+{
+ lib,
+ pkgs,
+ self,
+ ...
+}:
+let
+ 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
+ '';
+ };
+ stop-linux-builder = pkgs.writeShellApplication {
+ name = "stop-linux-builder";
+ text = ''
+ echo "Stopping linux-builder..."
+
+ # Use unload instead of stop because KeepAlive=true will restart it
+ if sudo launchctl unload -w /Library/LaunchDaemons/org.nixos.linux-builder.plist 2>/dev/null; then
+ echo "linux-builder stopped successfully"
+ else
+ echo "Warning: Could not stop linux-builder (it may not be running)"
+ fi
+
+ # Check if it's still running
+ sleep 1
+ 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"
+ else
+ echo "linux-builder is not running"
+ fi
+ '';
+ };
+ verify-darwin-linux-builder = self.packages.aarch64-darwin.verify-darwin-linux-builder;
+in
+{
+ nixpkgs.hostPlatform = "aarch64-darwin";
+
+ # Install builder control scripts
+ environment.systemPackages = [
+ start-linux-builder
+ stop-linux-builder
+ verify-darwin-linux-builder
+ ];
+
+ nix.settings = {
+ experimental-features = [
+ "nix-command"
+ "flakes"
+ ];
+ always-allow-substitutes = true;
+ max-jobs = "auto";
+ trusted-users = [ "@admin" ];
+ extra-substituters = [ "https://nix-postgres-artifacts.s3.amazonaws.com" ];
+ extra-trusted-substituters = [ "https://nix-postgres-artifacts.s3.amazonaws.com" ];
+ extra-trusted-public-keys = [
+ "nix-postgres-artifacts:dGZlQOvKcNEjvT7QEAJbcV6b6uk7VF/hWMjhYleiaLI="
+ ];
+ };
+
+ nix.extraOptions = ''
+ !include nix.custom.conf
+ '';
+
+ # accept existing nix.custom.conf
+ system.activationScripts.checks.text = lib.mkForce "";
+ system.activationScripts.nix-daemon.text = lib.mkForce ''
+ if ! diff /etc/nix/nix.conf /run/current-system/etc/nix/nix.conf &> /dev/null || ! diff /etc/nix/machines /run/current-system/etc/nix/machines &> /dev/null; then
+ echo "reloading nix-daemon..." >&2
+ launchctl kill HUP system/org.nixos.nix-daemon
+ fi
+ max_wait=30
+ waited=0
+ while ! nix-store --store daemon -q --hash ${pkgs.stdenv.shell} &>/dev/null; do
+ if [ $waited -ge $max_wait ]; then
+ echo "ERROR: nix-daemon failed to start after $max_wait seconds" >&2
+ exit 1
+ fi
+ echo "waiting for nix-daemon" >&2
+ launchctl kickstart system/org.nixos.nix-daemon
+ sleep 1
+ waited=$((waited + 1))
+ done
+ '';
+
+ 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;
+ };
+ };
+ };
+
+ nix.distributedBuilds = true;
+
+ system.stateVersion = 6;
+}
diff --git a/nix/mkdocs.yml b/nix/mkdocs.yml
index a6e2bc7a..bf7c4752 100644
--- a/nix/mkdocs.yml
+++ b/nix/mkdocs.yml
@@ -31,6 +31,7 @@ nav:
- Adding Tests: adding-tests.md
- Migration Tests: migration-tests.md
- Testing PG Upgrade Scripts: testing-pg-upgrade-scripts.md
+ - NixOS Tests on macOS: nixos-tests-on-macos.md
- References: references.md
validation:
diff --git a/nix/packages/default.nix b/nix/packages/default.nix
index 2c63f222..224684a6 100644
--- a/nix/packages/default.nix
+++ b/nix/packages/default.nix
@@ -86,6 +86,12 @@
cargo-pgrx_0_14_3
;
}
+ // lib.optionalAttrs pkgs.stdenv.isDarwin {
+ setup-darwin-linux-builder = pkgs.callPackage ./setup-darwin-linux-builder.nix {
+ inherit inputs self;
+ };
+ verify-darwin-linux-builder = pkgs.callPackage ./verify-darwin-linux-builder.nix { };
+ }
// lib.filterAttrs (n: _v: n != "override" && n != "overrideAttrs" && n != "overrideDerivation") (
pkgs.callPackage ../postgresql/default.nix {
inherit self';
diff --git a/nix/packages/setup-darwin-linux-builder.nix b/nix/packages/setup-darwin-linux-builder.nix
new file mode 100644
index 00000000..58d1787f
--- /dev/null
+++ b/nix/packages/setup-darwin-linux-builder.nix
@@ -0,0 +1,75 @@
+{
+ inputs,
+ self,
+ stdenv,
+ writeShellApplication,
+}:
+writeShellApplication {
+ name = "setup-darwin-linux-builder";
+ runtimeInputs = [
+ inputs.nix-darwin.packages.${stdenv.hostPlatform.system}.darwin-rebuild
+ ];
+ text = ''
+ set -euo pipefail
+
+ echo "Configuring nix-darwin linux-builder..."
+ echo ""
+
+ # Backup files that nix-darwin will manage
+ echo "Preparing for nix-darwin..."
+ for file in /etc/nix/nix.conf /etc/bashrc /etc/zshrc; do
+ if [[ -f "$file" && ! -L "$file" ]]; then
+ echo " Backing up $file"
+ sudo mv "$file" "$file.before-nix-darwin"
+ fi
+ done
+ echo ""
+
+ 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
+ }
+ trap revert ERR SIGINT SIGTERM
+
+ echo "This will configure your system with:"
+ echo " - NixOS linux-builder VM (ephemeral)"
+ echo " - 6 cores, 8GB RAM, 40GB disk"
+ echo " - Support for x86_64-linux and aarch64-linux builds"
+ echo ""
+ echo "Running darwin-rebuild switch..."
+ echo ""
+
+ sudo darwin-rebuild switch --refresh --flake ${self}#darwin-nixostest
+
+ echo ""
+ echo "Configuration complete!"
+ echo ""
+
+ echo "Running verification..."
+ echo ""
+ if nix run ${self}#verify-darwin-linux-builder; then
+ echo ""
+ echo "Setup and verification successful!"
+ else
+ echo ""
+ echo "Setup completed but verification found issues."
+ echo "Review the failures above and try:"
+ echo " nix run .#verify-darwin-linux-builder"
+ echo ""
+ echo "to re-run verification after addressing any issues."
+ exit 1
+ fi
+
+ echo ""
+ echo "To control the linux builder vm, you can use:"
+ echo " stop-linux-builder # stop the linux builder vm"
+ echo " start-linux-builder # start the linux builder vm"
+ echo " verify-darwin-linux-builder # verify the setup is working"
+ echo ""
+ echo "If this is the first install, you may need to restart your shell to use these scripts."
+ '';
+}
diff --git a/nix/packages/verify-darwin-linux-builder.nix b/nix/packages/verify-darwin-linux-builder.nix
new file mode 100644
index 00000000..fda6f118
--- /dev/null
+++ b/nix/packages/verify-darwin-linux-builder.nix
@@ -0,0 +1,129 @@
+{
+ coreutils,
+ gawk,
+ gnugrep,
+ writeShellApplication,
+}:
+writeShellApplication {
+ name = "verify-darwin-linux-builder";
+ runtimeInputs = [
+ coreutils
+ gawk
+ gnugrep
+ ];
+ text = ''
+ set -euo pipefail
+
+ PASS=0
+ FAIL=0
+
+ check_pass() {
+ echo " [PASS] $1"
+ PASS=$((PASS + 1))
+ }
+
+ check_fail() {
+ echo " [FAIL] $1"
+ echo " $2"
+ FAIL=$((FAIL + 1))
+ }
+
+ echo "Verifying darwin-linux-builder configuration..."
+ echo ""
+
+ echo "1. Checking launchd service status..."
+ if sudo launchctl list org.nixos.linux-builder &>/dev/null; then
+ SERVICE_OUTPUT=$(sudo launchctl list org.nixos.linux-builder 2>/dev/null || true)
+ PID=$(echo "$SERVICE_OUTPUT" | grep -E "^\s*\"PID\"" | grep -oE '[0-9]+' || echo "-")
+ if [[ "$PID" != "-" && -n "$PID" ]]; then
+ check_pass "linux-builder service is running (PID: $PID)"
+ else
+ check_fail "linux-builder service is loaded but not running" \
+ "Run: start-linux-builder"
+ fi
+ else
+ check_fail "linux-builder service not found" \
+ "Run: nix run .#setup-darwin-linux-builder"
+ fi
+
+ echo ""
+ echo "2. Checking nix configuration..."
+ NIX_CONFIG=$(nix config show 2>/dev/null || true)
+ if [[ -n "$NIX_CONFIG" ]]; then
+ if echo "$NIX_CONFIG" | grep -q "nix-postgres-artifacts.s3.amazonaws.com"; then
+ check_pass "Substituter configured for nix-postgres-artifacts"
+ else
+ check_fail "Missing substituter for nix-postgres-artifacts" \
+ "Expected: nix-postgres-artifacts.s3.amazonaws.com in substituters"
+ fi
+
+ if echo "$NIX_CONFIG" | grep -q "nix-postgres-artifacts:dGZlQOvKcNEjvT7QEAJbcV6b6uk7VF/hWMjhYleiaLI="; then
+ check_pass "Trusted public key configured"
+ else
+ check_fail "Missing trusted public key" \
+ "Expected signing key for nix-postgres-artifacts in trusted-public-keys"
+ fi
+
+ if echo "$NIX_CONFIG" | grep -qE "experimental-features.*nix-command" && \
+ echo "$NIX_CONFIG" | grep -qE "experimental-features.*flakes"; then
+ check_pass "Experimental features enabled (nix-command, flakes)"
+ else
+ check_fail "Missing experimental features" \
+ "Expected: nix-command and flakes in experimental-features"
+ fi
+ else
+ check_fail "Could not read nix configuration" \
+ "Run: nix config show"
+ fi
+
+ echo ""
+ echo "3. Checking builder features..."
+ MACHINES_FILE="/etc/nix/machines"
+ if [[ -f "$MACHINES_FILE" ]]; then
+ # machines file format: uri systems key maxjobs speedfactor features mandatory-features public-key
+ # Features are in field 6 (1-indexed), comma-separated
+ FEATURES=$(awk '{print $6}' "$MACHINES_FILE" | tr ',' ' ' || true)
+ if grep -q "nixos-test" "$MACHINES_FILE"; then
+ check_pass "nixos-test feature supported"
+ echo " Available features: $FEATURES"
+ else
+ check_fail "nixos-test feature not configured" \
+ "Expected: nixos-test in $MACHINES_FILE"
+ fi
+ else
+ check_fail "machines file not found" \
+ "Expected: $MACHINES_FILE"
+ fi
+
+ echo ""
+ echo "4. Testing builder responsiveness..."
+ echo " Building nixpkgs#hello for aarch64-linux (timeout: 60s)..."
+ if timeout 60 nix build --system aarch64-linux nixpkgs#hello --no-link --print-out-paths 2>/dev/null; then
+ check_pass "Builder is responsive and can build aarch64-linux packages"
+ else
+ EXIT_CODE=$?
+ if [[ $EXIT_CODE -eq 124 ]]; then
+ check_fail "Builder timed out after 60 seconds" \
+ "The builder may be unresponsive or overloaded. Try: stop-linux-builder && start-linux-builder"
+ else
+ check_fail "Builder failed to build test package" \
+ "Check builder logs: sudo launchctl list org.nixos.linux-builder"
+ fi
+ fi
+
+ echo ""
+ echo "========================================"
+ echo "Verification complete: $PASS passed, $FAIL failed"
+ echo "========================================"
+
+ if [[ $FAIL -gt 0 ]]; then
+ echo ""
+ echo "Some checks failed. Review the failures above for guidance."
+ exit 1
+ else
+ echo ""
+ echo "All checks passed! The darwin-linux-builder is ready for use."
+ exit 0
+ fi
+ '';
+}
[parent: cb314c17dd4e]