ci: confine Windows probe shell options to compilation

This commit is contained in:
Moritz Angermann committed 2026-10-17 15:59:54 +09:00
1 parent e039d6ddc1
commit c9e438e8af
2 files changed
+36 -5

No files matched your search

+8 -5
View File
@@ -14,11 +14,14 @@ let
strictDeps = true;
buildInputs = [ cross.windows.mcfgthreads ];
buildPhase = ''
set -euo pipefail
echo '3a2926cd85ed7379700fe62485998a7fe26a9ba09824c370aa5b74e3d5508e5e ${source}/rts-fs/fs.c' | sha256sum -c -
$CC -std=c11 -Werror=vla -pedantic -Wall -Wextra -O1 -static \
-DFS_NAMESPACE=rts -I${source}/rts-fs \
${./windows-fs/Probe.c} ${source}/rts-fs/fs.c -o probe.exe
# Keep strict options local: standard fixup hooks do not use nounset.
(
set -euo pipefail
echo '3a2926cd85ed7379700fe62485998a7fe26a9ba09824c370aa5b74e3d5508e5e ${source}/rts-fs/fs.c' | sha256sum -c -
$CC -std=c11 -Werror=vla -pedantic -Wall -Wextra -O1 -static \
-DFS_NAMESPACE=rts -I${source}/rts-fs \
${./windows-fs/Probe.c} ${source}/rts-fs/fs.c -o probe.exe
)
'';
installPhase = ''
mkdir -p "$out/bin"
+28
View File
@@ -11,6 +11,34 @@ HERE = Path(__file__).resolve().parent
class ProbeDefinition(unittest.TestCase):
def test_build_phase_does_not_leak_nounset_into_fixup(self):
text = (HERE / "check-windows-fs.nix").read_text()
self.assertEqual(text.count("buildPhase = ''\n"), 1)
phase = text.split("buildPhase = ''\n", 1)[1].split("\n '';", 1)[0]
phase = phase.replace("${source}", "/locked-source").replace(
"${./windows-fs/Probe.c}", "/unused-probe.c")
with tempfile.TemporaryDirectory() as temp:
temp = Path(temp)
for name, body in [("sha256sum", "cat >/dev/null"),
("fake-cc", "touch probe.exe")]:
path = temp / name
path.write_text("#!/usr/bin/env bash\n" + body + "\n")
path.chmod(0o755)
# Standard fixup hooks read optional variables without nounset.
suffix = '\n[ -f probe.exe ]\n[ -z "$exit_code" ]\n'
env = dict(os.environ, CC=str(temp / "fake-cc"),
PATH=str(temp) + os.pathsep + os.environ["PATH"])
passed = subprocess.run(["bash", "-c", "set -e\n" + phase + suffix],
cwd=temp, env=env, capture_output=True, text=True, timeout=10)
self.assertEqual(passed.returncode, 0, passed.stderr)
# The same phase without its option-isolating subshell reproduces
# the real packaging failure, independently of the C compiler.
unscoped = phase.replace(" (\n", "", 1).rsplit(" )", 1)[0]
failed = subprocess.run(["bash", "-c", "set -e\n" + unscoped + suffix],
cwd=temp, env=env, capture_output=True, text=True, timeout=10)
self.assertNotEqual(failed.returncode, 0)
self.assertIn("exit_code: unbound variable", failed.stderr)
def render(self, *, linux=True, x64=True, native=True):
# Use throwing compiler-project attributes: this C check must not
# accidentally grow a GHC planning/bootstrap dependency.