Skip to content

fix(actions): install Nix with an in-tree action - #508

Draft
iainlane wants to merge 9 commits into
mainfrom
codex/in-tree-nix-installer
Draft

iainlane wants to merge 9 commits into
mainfrom
codex/in-tree-nix-installer

Conversation

@iainlane

@iainlane iainlane commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Hosted macOS CI can fail before Nix is installed because mdutil -i off /nix returns an error while the upstream installer configures Spotlight. Spotlight is not required for Nix, but the installer treats that error as fatal.

Add actions/install-nix, adapted from nix-quick-install-action v35 with its licence and source revision. Spotlight failures produce a warning; volume creation, ownership and installation failures still stop the job. CI, release and reusable publishing workflows resolve the action from their own Cupboard revision.

Keep the same single-user Nix 2.34.7 archives. Centralise the archive and Nix pins, remove unused version selection, tmpfs, KVM, archive overrides and configuration inputs, and preserve GitHub authentication, profile and certificate setup. Database registration remains bounded to three attempts.

Validation: focused regression tests reproduce the fatal Spotlight behaviour before the fix and pass afterwards. They also cover mandatory setup failures, all four supported archive selections and database-registration exhaustion. ShellCheck, actionlint, zizmor and workflow/reference tests pass. All local check groups passed: server, workspace unit, action, script, end-to-end, remote-store, conformance, type, format, lint, dependency, migration and generated-file checks. All hosted CI workflows passed on 944d3c6f, including real installations and conformance on Linux and macOS for both architectures.

The upstream Nix installer aborts if Spotlight cannot disable indexing
on a newly created macOS store volume. Hosted CI has failed at that step
even though Spotlight is not required to install or run Nix.

Adapt the v35 single-user installer into an internal action and make
Spotlight failures warnings. Volume creation, ownership changes and
installation failures still stop the job. Keep the upstream licence and
revision beside the script, and continue using its prebuilt Nix 2.34.7
archives.

Centralise the Nix and archive-release pins. Remove unused version
selection, tmpfs, KVM, archive overrides and configuration inputs;
workflows already apply their Nix settings after installation. Preserve
GitHub authentication and the runner's profile and certificate setup.

Use self-repository action references throughout CI, release and
reusable publishing workflows so each caller uses the installer from the
same Cupboard revision. Regression tests inject Spotlight and mandatory
setup failures and check bounded database registration.
Replacing the single-user installer with a daemon can change how Nix
uses the SSH configuration from a publication job. A successful
installation alone does not establish that private flake inputs, remote
builders and build observation still work.

Add an independent three-platform CI trial of NixOS/nix-installer-action
and Nix 2.35.3. Exercise job-scoped credentials against a loopback SSH
server, require remote dispatch with local builds disabled, and run the
publication and remote-store suites. The trial fails when a required
test is skipped.

The production installer and conformance oracle remain unchanged.
The first hosted trial could not exercise local builds or SSH. The build
expression used builtins.currentSystem in pure evaluation, and OpenSSH
rejected the authorised-key path because its parent was /tmp.

Allow impure evaluation for both test derivations and create the SSH
fixture under the runner home directory. Keep OpenSSH mode checks
enabled and leave the daemon and production SSH configuration unchanged.
A failed remote build alone cannot distinguish an invalid SSH fixture
from a daemon that does not use the job's SSH configuration.

Connect directly to the same ssh-ng store with the same environment
before requesting a daemon build. A failure in the build then follows a
verified client connection, which makes the trial result specific to
remote dispatch.
The Nix daemon starts remote build hooks with its own environment. The
client's NIX_SSHOPTS therefore configures direct SSH stores but does not
configure daemon-dispatched builders. The installer trial reproduced
this difference on Linux and macOS.

Add a bundled TypeScript action that creates a build-hook adapter for
each invocation. The adapter restores the job's SSH options and executes
the existing hook with its arguments and protocol descriptors intact.
Pass the override through NIX_CONFIG so trusted daemon connections
receive it, and remove the adapter in the action's post step.

Check daemon trust before creating the override. The hosted trial runs
the action bundles and tests accepted and rejected builder credentials
with local builds disabled. Separate the loopback fixture's output lock
from the scheduler's lock so the shared test store can execute the
remote build.
The SSH fixture deliberately rejects keys and host pins before testing
valid credentials. Recent OpenSSH servers accumulate a per-source
penalty for those failures and can drop the later loopback connections
before authentication starts. The macOS trial hit that limit.

Inspect the fixture server's effective settings and disable
PerSourcePenalties when supported. Keep all key and host-pin checks
enabled. This changes only the isolated test server.
Remote builder preparation resolved the hook with the runner's PATH and
permissions, although a daemon executes it with its own environment.
That could select another Nix executable or reject a root-only hook.
Preparation also succeeded when the store could not execute the adapter.

Probe execution through the selected store before exporting the
override. A TypeScript worker resolves the hook with the store's
permissions and PATH. Disable local builds and builders during the probe
so it cannot execute a derivation or contact a remote machine. Preserve
Nix's error when the probe fails, and remove the invocation directory on
failure.

The trial previously accepted unrelated SSH failures and used only a
shared-store loopback builder. Assert server-side authentication
refusals and exercise input transfer, output copy-back and build
observation with a separate Linux builder. Test the production installer
and nested action cleanup on all three trial platforms. Require the
expected test inventory so removed tests cannot leave the trial green.
The installer trial's reporter imported a workspace helper while Vitest
loaded its configuration. Hosted Node could strip types but could not
transform that helper's parameter properties, so the suites never
started. Use a local string comparator and test configuration imports
with native TypeScript transformation disabled.

The production prepare action also failed during job setup because
Nothing but Nix declared a tag-pinned post action. GitHub checks that
dependency even when disk cleanup is disabled. Use the exact commit from
wimpysworld/nothing-but-nix#52, whose only manifest change pins the post
action to its v3 commit.
The post-action pin fix has not been released upstream. Its commit
exists only in a fork, so the upstream repository reference fails the
online provenance checks.

Use the organisation-owned v10.0.1 tag instead. The fork changes only
the transitive post-action SHA pin; the disk-cleanup code and inputs
remain unchanged.
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.

1 participant