deploy-rs fails on any boot.initrd.extraFiles shell script with nix flake check
π 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=barecho hi > /tmp/filesomecmd 2> /dev/nullcmd1 | 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
deployCheckswas failing due toboot.initrd.extraFilesincluding 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.nixandunlock.shexample - Suggest a possible PR direction: skip or bypass parsing for
boot.initrd.extraFilesduring schema checks - Draft the issue template and Markdown body for submission
This saved time narrowing down and presenting the issue clearly.
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
Optionally allow opt-out from parsing via __noDeployCheck = true or similar
Donβt evaluate or parse their syntax
π€ ChatGPT assistance note This saved time narrowing down and presenting the issue clearly.
@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?