deploy-rs icon indicating copy to clipboard operation
deploy-rs copied to clipboard

deploy-rs fails on any boot.initrd.extraFiles shell script with nix flake check

Open mariaa144 opened this issue 5 months ago β€’ 2 comments

πŸ› Issue

deployChecks fails on shell scripts in boot.initrd.extraFiles with valid sh syntax (=, >, 2>, |) or even echo.


Overview

When using deploy-rs v1.0 with nix 2.28.3, deployChecks fails if a shell script in boot.initrd.extraFiles includes common valid shell syntax like:

  • =
  • >
  • 2>
  • |
  • echo

Even though nixos-rebuild succeeds and the system works correctly at runtime.


Minimal Reproduction

Directory structure:

. β”œβ”€β”€ flake.nix β”œβ”€β”€ flake.lock └── unlock.sh


flake.nix:

{
  description = "Deploy bug with shell script in extraFiles";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
    deploy-rs.url = "github:serokell/deploy-rs";
  };

  outputs = { self, nixpkgs, deploy-rs, ... }:
    let
      system = "x86_64-linux";
    in {
      nixosConfigurations.test = nixpkgs.lib.nixosSystem {
        inherit system;
        modules = [{
          system.stateVersion = "25.05";
          boot.initrd.extraFiles."/unlock.sh" = ./unlock.sh;

          # Required dummy options
          fileSystems."/".device = "/dev/null";

          # Disable bootloader entirely for evaluation
          boot.loader.grub.enable = false;
          boot.loader.systemd-boot.enable = false;
          boot.loader.generic-extlinux-compatible.enable = false;
        }];
      };

      checks = builtins.mapAttrs
        (system: deployLib: deployLib.deployChecks self.deploy)
        deploy-rs.lib;

      deploy.test = {
        hostname = "my-host";
        sshUser = "root";
        profiles.system.path = self.nixosConfigurations.test.config.system.build.toplevel;
      };
    };
}

unlock.sh:

#!/bin/sh
echo "Remote unlock initrd shell"

Each of these causes failure independently:

  • foo=bar
  • echo hi > /tmp/file
  • somecmd 2> /dev/null
  • cmd1 | cmd2

Steps to Reproduce

nix flake check

Fails with:

       error: undefined variable 'echo'
       at /nix/store/vi24zyx5bvl9baxac3x5z2b7273hxdqi-source/unlock.sh:2:1:
            1| #!/bin/sh
            2| echo "example script here"
             | ^
            3|

Environment

  • deploy-rs: 1.0
  • nix: 2.28.3
  • nixos: 25.04 / 25.05
  • system: x86_64-linux

Why This Matters

Shell scripts in boot.initrd.extraFiles are copied verbatim to the initrd and should never be parsed as Nix. This bug blocks valid remote-unlock workflows (e.g. over SSH).

βœ… Suggested Fix

  • Treat extraFiles contents as opaque
  • Don’t evaluate or parse their syntax
  • Optionally allow opt-out from parsing via __noDeployCheck = true or similar
πŸ€– ChatGPT assistance note

I worked with ChatGPT to debug this issue. It helped me:

  • Identify that deployChecks was failing due to boot.initrd.extraFiles including valid shell syntax like =, >, 2>, and |
  • Confirm that the files were being misinterpreted by the Nix expression parser even though they were valid for the initrd
  • Reproduce the issue using a minimal flake.nix and unlock.sh example
  • Suggest a possible PR direction: skip or bypass parsing for boot.initrd.extraFiles during schema checks
  • Draft the issue template and Markdown body for submission

This saved time narrowing down and presenting the issue clearly.

mariaa144 avatar Jul 14 '25 03:07 mariaa144

here's a simplified repro. stay in school kids, dont do drugs, read manuals, etc

nix build .#nixosConfigurations.test.config.system.build.toplevel

{
  description = "Deploy bug with shell script in extraFiles";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils, ... }:
    let
      system = "x86_64-linux";
      pkgs = import nixpkgs { inherit system; };
    in {
      nixosConfigurations.test = nixpkgs.lib.nixosSystem {
        inherit system;
        modules = [{
          system.stateVersion = "25.05";
          boot.initrd.extraFiles."/unlock.sh" = ./unlock.sh;

          # Required dummy options
          fileSystems."/".device = "/dev/null";
          boot.loader.grub.devices = [ "nodev" ];
        }];
      };
    };
}

Treat extraFiles contents as opaque

Image

Optionally allow opt-out from parsing via __noDeployCheck = true or similar

Image

Don’t evaluate or parse their syntax

Image

πŸ€– ChatGPT assistance note This saved time narrowing down and presenting the issue clearly.

Image

notgne2 avatar Jul 15 '25 05:07 notgne2

@notgne2, You are right on! πŸ‘πŸΌ This isn't a deploy-rs bug, or perhaps not a bug at all!? Is this expected behavior? What is the purpose of boot.initrd.extraFiles if not to add files like a shell script into the initrd?

mariaa144 avatar Jul 15 '25 15:07 mariaa144