Skip to content

libstore: pass the derivation being built to the post-build-hook as JSON - #16413

Open
amaanq wants to merge 1 commit into
NixOS:masterfrom
amaanq:post-build-hook-drv-json
Open

libstore: pass the derivation being built to the post-build-hook as JSON#16413
amaanq wants to merge 1 commit into
NixOS:masterfrom
amaanq:post-build-hook-drv-json

Conversation

@amaanq

@amaanq amaanq commented Sep 1, 2026

Copy link
Copy Markdown
Member

Motivation

Currently, a post-build hook only gets DRV_PATH, but the derivation the builder actually ran (the resolved derivation, for CA builds) may not exist on disk as a .drv file at all, so consumers like Hydra can't reconstruct what was actually built.

Context

The hook now receives the JSON form of the BasicDerivation that DerivationBuildingGoal already holds in memory on its standard input.


Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

@github-actions github-actions Bot added documentation with-tests Issues related to testing. PRs with tests have some priority labels Sep 1, 2026
Comment thread doc/manual/rl-next/post-build-hook-drv-json.md Outdated
Comment thread src/libstore/build/derivation-building-goal.cc Outdated
Comment thread tests/functional/post-hook.sh Outdated
@amaanq
amaanq force-pushed the post-build-hook-drv-json branch 3 times, most recently from 0d58607 to a47236c Compare September 1, 2026 22:12
@Ericson2314

Copy link
Copy Markdown
Member

I requested that @amaanq do this based on what I understand @NixOS/cuda-maintainers needs to upgrade their Hydra.

@xokdvium

xokdvium commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Why JSON and not the stable ATerm?

@amaanq
amaanq force-pushed the post-build-hook-drv-json branch from a47236c to 7df0419 Compare September 1, 2026 22:21
@Ericson2314

Copy link
Copy Markdown
Member

@xokdvium because we don't have ATerm for resolved derivations, though I suppose we could fudge an empty inputDrvs.

@Ericson2314

Ericson2314 commented Sep 1, 2026

Copy link
Copy Markdown
Member

I do agree we should get gate unstable behavior, but I also think this will just be much easier for the hooks in practice.

@xokdvium

xokdvium commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

because we don't have ATerm for resolved derivations, though I suppose we could fudge an empty inputDrvs.

Isn't that exactly what we want? empty inputDrvs is perfectly fine in this case

@xokdvium

xokdvium commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

If one wants to opt into converting ATerm -> json can't we carry a plumbing convenience command?

@Ericson2314

Copy link
Copy Markdown
Member

Yes, empty inputDrvs is fine :). (The JSON for resolved derivations just has inputs: [ ....paths.... ] though, which I do like --- "Making illegal states unrepresentable" and all that.

@xokdvium

xokdvium commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

which I do like --- "Making illegal states unrepresentable" and all that.

But aren't we going to pass in the original derivation in case it didn't need to be resolved first? Or would that to be consistent everywhere with remote building? Wasn't the DRV_PATH the unresolved one in the local case at least?

@Ericson2314

Ericson2314 commented Sep 1, 2026

Copy link
Copy Markdown
Member

@xokdvium it is my view that morally we always build a resolved derivation --- the only reason we don't realize input-addressed ones is that it interferes with trustless remote building because of a design flaw in the "derivation masking" (née hashDerivationModulo) algorithm.

Think if we have two input-addressing derivations that produce the same paths, we're only going to build one of them, right? Then it would be a bit arbitrary which one ended up making it to the build hook, right?

@Ericson2314

Copy link
Copy Markdown
Member

Indeed, I wouldn't expose the unresolved drvPath either if I was designing this from scratch.

Comment on lines +1137 to +1138
if (dup2(drvJsonFd.get(), STDIN_FILENO) == -1)
throw SysError("dupping stdin");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems not terribly extensible. What if we wanted to pass more info to the hook? Also how would the hook feature detect that the version of nix is new enough? Do a non-blocking read of stdin?

Can't we use a non-standard file descriptor maybe and pass its number in an env variable?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems not terribly extensible. What if we wanted to pass more info to the hook?

That is why I asked @amaanq to make the top-level record to contain derivation (before I realized the we should include the output map for the CA case too). That puts us in compliance with the JSON guidelines re extensibility.

Can't we use a non-standard file descriptor maybe and pass its number in an env variable?

Yeah sure I am OK with that. I like the socket-activation vibes :)

@xokdvium

xokdvium commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

I wouldn't expose the unresolved drvPath either if I was designing this from scratch.

Sounds like maybe we should also expose RESOLVED_DRV_PATH to the hook for more clarity. That way the hook wouldn't need to guess which case it is

@amaanq
amaanq force-pushed the post-build-hook-drv-json branch from 7df0419 to bedd51c Compare September 2, 2026 00:32
@SomeoneSerge

SomeoneSerge commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

...based on what I understand @NixOS/cuda-maintainers needs to upgrade their Hydra

CC #9272 (it's "pre-", but same logic)

Why JSON and not the stable ATerm?

FWIW it's also substantially easier to consume JSON in an external hook/plug-in, than it is to consume ATerm.

The hook now receives the JSON form of the BasicDerivation

I've already argued this before, I believe the "proper" approach (conveniently, we don't necessarily need "proper", imo it's ok to change hook interfaces) would be to have in place a protocol that lets you inquire about any path referenced in the context of the current "build request". Essentially, my reasoning was:

Details - pre-build-hook gets a drvPath, but it's basically a string of random characters, unless you can access the drv structure, so "why pass the drvPath in the first place?" - the drv structure contains inputDrvs and inputSrcs, but they are, too, basically random strings unless you can also access the corresponding drv structures or file paths, or access a database where you compare these ids against other ids. If can't access that, then by the same token "why include input{Drv,Src}s in the response at all?"

@Ericson2314

Ericson2314 commented Sep 2, 2026

Copy link
Copy Markdown
Member

@SomeoneSerge we could definitely e.g. rig up the hook to run with the daemon protocol or something so one can inquire about input and output paths to their heart's content :)

@xokdvium

xokdvium commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

FWIW it's also substantially easier to consume JSON in an external hook/plug-in, than it is to consume ATerm.

Hence why my suggestion to have a plumbing command to convert the stable ATerm into the experimental and very unstable JSON variant that's only really available in the XP cli if one opts into that. Wouldn't want to use to even bother with that can of worms now and maybe we can just have the internal plumbing be in the usual representation.

@Ericson2314

Ericson2314 commented Sep 2, 2026

Copy link
Copy Markdown
Member

Maybe nix derivation show should also support derivations on standard input then? Though an awkward part of that is that the ATerm doesn't contain the derivation's name --- it is not actually self-contained.

@xokdvium

xokdvium commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Though an awkward part of that is that the ATerm doesn't contain the derivation's name --- it is not actually self-contained.

But that's already available in the DRV_PATH, no?

@amaanq
amaanq force-pushed the post-build-hook-drv-json branch from bedd51c to 59e567b Compare September 2, 2026 19:08
@Ericson2314

Ericson2314 commented Sep 2, 2026

Copy link
Copy Markdown
Member

True, it is. and we can do DRV_NAME too. (Or stick it in the JSON.)

@amaanq
amaanq force-pushed the post-build-hook-drv-json branch 2 times, most recently from c210442 to df9b767 Compare September 2, 2026 20:55
@github-actions github-actions Bot added the new-cli Relating to the "nix" command label Sep 2, 2026
Comment on lines +1170 to +1181
/* closeExtraFDs() closes everything above stderr, hence the detour via stdin and stdout. */
if (dup2(STDIN_FILENO, drvAtermFdNum) == -1)
throw SysError("dupping the derivation file onto fd %d", drvAtermFdNum);
if (dup2(STDOUT_FILENO, buildInfoJsonFdNum) == -1)
throw SysError("dupping the build info file onto fd %d", buildInfoJsonFdNum);
if (dup2(STDERR_FILENO, STDOUT_FILENO) == -1)
throw SysError("cannot dup stderr into stdout");
AutoCloseFD fdDevNull = open("/dev/null", O_RDONLY | O_CLOEXEC);
if (!fdDevNull)
throw SysError("opening /dev/null");
if (dup2(fdDevNull.get(), STDIN_FILENO) == -1)
throw SysError("dupping /dev/null onto stdin");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just have a generic FD dup action which handles all of this internally. I.e. not use startProcess but instead have spawnProgram that does all of this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could land that in a prep PR as I think there are a few places that use it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have started working on that locally, so maybe a couple of days until that's beat into shape?

@amaanq
amaanq force-pushed the post-build-hook-drv-json branch from df9b767 to 9cef817 Compare September 3, 2026 19:44
@xokdvium

xokdvium commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Btw @Ericson2314, wasn't the issue with CUDA hydra the pre-build-hook, not post? I'm not sure why we are touching post- one here then.

@GaetanLepage

Copy link
Copy Markdown
Contributor

Btw @Ericson2314, wasn't the issue with CUDA hydra the pre-build-hook, not post? I'm not sure why we are touching post- one here then.

Hi! Here is the patch we apply to Hydra to fix our use case: https://github.com/nixos-cuda/infra/blob/master/hosts/hydra/hydra/0001-hydra-queue-runner-make-drv-available-to-remote-pre-build-hook.patch

@xokdvium

xokdvium commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Hi! Here is the patch we apply to Hydra to fix our use case: https://github.com/nixos-cuda/infra/blob/master/hosts/hydra/hydra/0001-hydra-queue-runner-make-drv-available-to-remote-pre-build-hook.patch

That's not great... because it ships around the whole derivation closure and unused sources. Hence why the idea here is to stuff ATerm into a side-channel and not write to the store (because then all the references have to be copied as well).

@GaetanLepage

Copy link
Copy Markdown
Contributor

That's not great... because it ships around the whole derivation closure and unused sources. Hence why the idea here is to stuff ATerm into a side-channel and not write to the store (because then all the references have to be copied as well).

Definitely. It's just a dirty workaround. I trust you on the better solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation new-cli Relating to the "nix" command with-tests Issues related to testing. PRs with tests have some priority

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

5 participants