Repository navigation
Build volatile checks as fixed-output derivations with lib.caisson.mkVolatileCheck - #159
Merged
Merged
Conversation
`lib.caisson.mkVolatileCheck { pkgs, name, program, impureEnvVars ? [ ] }`
returns the derivation of a check of a volatile category. It is a
fixed-output derivation, which Nix lets reach the network. Its builder,
the bash of `pkgs` with no `PATH`, runs the program and, when the
program exits with status 0, writes the pass marker: a file holding
the line `pass`, declared by its flat sha256 hash. The name of the
derivation is `<name>-<hash>`, with the hash part of the store path of
the program, so a changed program gets a new marker path and the same
program keeps it. A failure leaves nothing in the store. The
derivation is a plain `derivation`, so its `drvAttrs` keep the
program, and topside reads the inputs of the marker from their
context.
The check record of a caisson top now refuses a check of a volatile
category whose derivation has `drvAttrs` that declare no `outputHash`:
reading the `volatile` field of its entry fails. `topside check` reads
that field for every check it runs. The `checks` output reads no
property of a category, and reading `volatile` there would evaluate
the declarations of the category for every `nix flake check`, so the
output does not refuse.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pinned-world suite checks the name of the derivation `mkVolatileCheck` returns: it changes with the program and stays the same for the same program, whatever `impureEnvVars` hold. It checks the fixed output, the `drvAttrs` and their context, the refusal of a program outside the store, and the refusal, in the check record, of a check of a volatile category whose derivation is not a fixed-output derivation. The volatile checks of the existing probes become fixed-output derivations. tests/volatile-checks/check.sh builds a passing check and finds its marker with `nix path-info`, builds it again with `--rebuild`, then builds a failing check and finds no marker. The `volatile-checks` job of the check workflow runs it on the runner, since a check of `nix flake check` cannot run `nix build`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A check of a volatile category depends on something outside the build, such as a service reached over the network. This PR adds the function that builds the derivation of such a check, and it makes a caisson top refuse a check of a volatile category whose derivation cannot reach the network.
lib.caisson.mkVolatileCheckThe function returns a fixed-output derivation, the kind of derivation Nix lets reach the network.
pkgs, run with noPATH. It runs the program. When the program exits with status 0, the builder writes the pass marker, a file holding the linepass. The output hash is the flat sha256 of that file, so every marker declares the same hash.<name>-<hash>.<hash>is the 32-character hash part of the store path of the program. A changed program therefore gets a new marker path, and the same program keeps its marker path.impureEnvVarsleave the marker path unchanged.programis an executable in the Nix store. It can be a derivation that is an executable file, a string naming an executable inside a store path (lib.getExe), or a path. A string outside the store is refused. The builder sets noPATH, so the program has to carry the commands it runs, aswriteShellApplicationdoes withruntimeInputs.derivation, so it keepsdrvAttrs. topside reads the inputs of the marker frombuiltins.getContext (builtins.toJSON drv.drvAttrs). The context holds the program and the bash.A pass leaves the marker in the store, and a failure leaves nothing.
Refusal
The check record of a caisson top refuses a check of a volatile category when the
drvAttrsof its derivation declare nooutputHash: reading thevolatilefield of its entry fails, and the other fields still read.topside checkreads that field for every check it runs. The refusal accepts any fixed-output derivation, not only thosemkVolatileCheckreturns.The refusal lives in the record and not in the
checksoutput, because of its evaluation cost. Reading whether a category is volatile evaluates thecheckCategoriessubmodules that declare it, and on main thechecksoutput reads no property of a category. Refusing in thechecksoutput made theeval-weightcheck fail locally:moduleSystemEvalsrose from 28 to 30 inminimal-consumer-totaland from 11 to 13 incaisson-overhead. With the refusal in the record,eval-weightpasses at the committed baseline. The probes in the pinned-world suite whose categories are volatile (nas-1-bootsand theartifactcheck of the stub integration) are now fixed-output derivations.Tests
volatileCheckNamesItsMarkerForTheProgram: the name and output path change with the program and stay the same for the same program, with or withoutimpureEnvVars. The test also covers thelib.getExeform, the fixed-output attributes,system, the context ofdrvAttrs, and the refusal of a program outside the store.volatileChecksAreFixedOutputDerivations: a hermetic derivation under a volatile category is refused in thevolatilefield of its record entry, while itscategory, itsrequiredFeaturesand thechecksoutput still read. The derivationmkVolatileCheckreturns is accepted. The unit test of a declared volatile category now gives its check a fixed-outputdrvAttrs.tests/volatile-checks/check.sh, run by the newvolatile-checksjob of the check workflow, builds checks in the real store. A passing check writes its marker at the declared path, holdingpass, andnix path-infofinds it. Building it again with--rebuildkeeps the marker. A failing check fails to build, andnix path-infofinds no marker at its output path. The script runs outside the sandbox, because a check ofnix flake checkcannot runnix build.Locally: the pinned-world check evaluates,
tests/volatile-checks/check.shpasses, andnix flake checkpasses.tests/check.shof topside#14 passes against this branch, with the hand-writtenpassMarkerof its fixture replaced bymkVolatileCheck. The fixture adds itsprobebuilder variable to thedrvAttrsthe helper returns. The topside script ran in a local clone, and nothing was pushed to topside.🤖 Generated with Claude Code