Skip to content

Provide the pre-build hook with a JSON serialization of the derivation#424

Open
edolstra wants to merge 2 commits intomainfrom
eelcodolstra/nix-376
Open

Provide the pre-build hook with a JSON serialization of the derivation#424
edolstra wants to merge 2 commits intomainfrom
eelcodolstra/nix-376

Conversation

@edolstra
Copy link
Copy Markdown
Collaborator

@edolstra edolstra commented Apr 15, 2026

Motivation

This allows the hook to inspect derivation attributes such as requiredSystemFeatures.

The hook already gets the path of the derivation as an argument, but the derivation typically doesn't exist when called as a remote build.

Context

Summary by CodeRabbit

  • New Features

    • Pre-build hooks now receive derivation JSON via the NIX_DERIVATION_V4 environment variable, enabling structured inspection of derivation details.
  • Documentation

    • Updated pre-build-hook documentation with usage examples and deprecation guidance for the derivation store path approach.

…vation

The hook gets the path of the derivation as an argument, but the
derivation typically doesn't exist when called as a remote build.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 15, 2026

📝 Walkthrough

Walkthrough

JSON serialization for derivations has been refactored to move logic from Derivation to BasicDerivation, enabling pre-build hooks to receive complete derivation metadata via the NIX_DERIVATION_V4 environment variable. The pre-build hook mechanism now serializes derivations to JSON and writes them to temporary files instead of passing only store paths.

Changes

Cohort / File(s) Summary
Derivation JSON Serialization
src/libstore/derivations.cc, src/libstore/include/nix/store/derivations.hh
Refactored JSON serialization: moved implementation from Derivation serializer to BasicDerivation serializer to handle full JSON structure including inputs.srcs and inputs.drvs. Derivation serializer now delegates to BasicDerivation and reconstructs the drvs subtree.
Pre-build Hook Integration
src/libstore/unix/build/derivation-builder.cc, src/libstore/include/nix/store/globals.hh
Modified getPathsInSandbox() to serialize current derivation to JSON and expose via NIX_DERIVATION_V4 environment variable to pre-build hooks. Updated hook execution with explicit RunOptions and error handling. Documentation updated to describe JSON format and deprecate store-path inspection.
Functional Tests
tests/functional/linux-sandbox.sh, tests/functional/symlink-derivation.nix
Added functional test exercising pre-build hook behavior with NIX_DERIVATION_V4, verifying hook receives derivation name and sandbox paths work correctly. Added new test derivation test_sandbox_paths_2 for sandbox path testing.

Sequence Diagram

sequenceDiagram
    participant Builder as Builder
    participant Serializer as JSON Serializer
    participant TempFile as Temp File
    participant Hook as Pre-build Hook
    participant Sandbox as Sandbox

    Builder->>Serializer: serialize derivation to JSON
    Serializer->>Serializer: construct BasicDerivation JSON
    Serializer->>TempFile: write JSON to temp file
    TempFile-->>Builder: return file path
    Builder->>Hook: execute with NIX_DERIVATION_V4=file_path
    Hook->>TempFile: read derivation JSON
    TempFile-->>Hook: JSON content
    Hook->>Hook: parse derivation name & features
    Hook->>Sandbox: emit extra-sandbox-paths commands
    Sandbox-->>Builder: apply path mappings
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Hark! The derivations now speak in JSON,
Pre-build hooks listen with care,
Temp files scurry with metadata glisten,
Sandboxes bloom from paths laid bare! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly summarizes the main change: providing JSON serialization of the derivation to the pre-build hook, which is the core objective across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch eelcodolstra/nix-376

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

@github-actions github-actions bot temporarily deployed to pull request April 15, 2026 19:54 Inactive
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/libstore/derivations.cc (1)

1526-1561: ⚠️ Potential issue | 🟠 Major

Complete the new BasicDerivation JSON specialization.

This serializer is now public via JSON_IMPL_WITH_XP_FEATURES(nix::BasicDerivation), but it only implements to_json, and the emitted document still omits inputs.drvs. That means direct BasicDerivation serialization does not produce the full v4 derivation shape that adl_serializer<Derivation>::from_json expects, and any future BasicDerivation deserialization will be declared in the header but undefined at link time. Please either make the specialization self-contained (inputs.drvs = {} and a matching from_json) or keep this helper private to Derivation::to_json.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/libstore/derivations.cc` around lines 1526 - 1561, The
adl_serializer<BasicDerivation>::to_json currently emits only partial fields
(omitting inputs.drvs) and lacks a matching
adl_serializer<BasicDerivation>::from_json, so make the specialization
self-contained: update to_json (adl_serializer<BasicDerivation>::to_json) to
emit an empty inputs.drvs array alongside inputs.srcs, and implement
adl_serializer<BasicDerivation>::from_json to parse version, name, outputs,
inputs.srcs into BasicDerivation::inputSrcs, inputs.drvs (accept empty array),
platform/system, builder, args, env, and structuredAttrs (reconstructing
structuredAttrs pointer if present); ensure you use the same symbols
(BasicDerivation, inputSrcs, outputs, platform, builder, args, env,
structuredAttrs, expectedJsonVersionDerivation) and validate JSON version
matching while throwing on invalid shape.
🧹 Nitpick comments (2)
tests/functional/linux-sandbox.sh (1)

112-115: Read the canonical name field in the hook test.

The serializer writes the derivation name at the top level; .env.name only works if that value also happens to be duplicated into the environment map. Switching this to .name makes the test assert the new JSON contract directly.

Proposed change
-jq -r .env.name < "\$NIX_DERIVATION_V4" > "$DEST"
+jq -r .name < "\$NIX_DERIVATION_V4" > "$DEST"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/functional/linux-sandbox.sh` around lines 112 - 115, The test hook
currently extracts the derivation name using jq -r .env.name from the
NIX_DERIVATION_V4 file, but the serializer emits the canonical name at the top
level; update the jq invocation in the hook script to use .name instead of
.env.name (i.e., change jq -r .env.name < "\$NIX_DERIVATION_V4" > "$DEST" to jq
-r .name < "\$NIX_DERIVATION_V4" > "$DEST") so the test reads the top-level name
field directly (symbols: HOOK, NIX_DERIVATION_V4, DEST).
src/libstore/unix/build/derivation-builder.cc (1)

938-940: Write the hook JSON through the temp fd you already created.

Line 939 reopens the file by path instead of writing through tmpFd. Using the descriptor keeps the write tied to the exact inode returned by createTempFile() and avoids an unnecessary second pathname lookup.

Proposed change
-        auto [tmpFd, drvJsonPath] = createTempFile("nix-drv-json");
-        writeFile(drvJsonPath, drvJson.dump());
+        auto [tmpFd, drvJsonPath] = createTempFile("nix-drv-json");
+        writeFile(tmpFd, drvJsonPath, drvJson.dump());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/libstore/unix/build/derivation-builder.cc` around lines 938 - 940, The
code currently reopens drvJsonPath to write the JSON, which negates the
createTempFile() tmpFd guarantee; instead write the hook JSON through the
existing tmpFd returned by createTempFile("nix-drv-json") (use the tmpFd to
write drvJson.dump() and then close the descriptor) so the write is tied to the
same inode and avoid a second pathname lookup—update the writeFile call to
accept/use tmpFd (or perform a direct write to tmpFd) and keep
AutoDelete(drvJsonPath, false) as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/libstore/derivations.cc`:
- Around line 1526-1561: The adl_serializer<BasicDerivation>::to_json currently
emits only partial fields (omitting inputs.drvs) and lacks a matching
adl_serializer<BasicDerivation>::from_json, so make the specialization
self-contained: update to_json (adl_serializer<BasicDerivation>::to_json) to
emit an empty inputs.drvs array alongside inputs.srcs, and implement
adl_serializer<BasicDerivation>::from_json to parse version, name, outputs,
inputs.srcs into BasicDerivation::inputSrcs, inputs.drvs (accept empty array),
platform/system, builder, args, env, and structuredAttrs (reconstructing
structuredAttrs pointer if present); ensure you use the same symbols
(BasicDerivation, inputSrcs, outputs, platform, builder, args, env,
structuredAttrs, expectedJsonVersionDerivation) and validate JSON version
matching while throwing on invalid shape.

---

Nitpick comments:
In `@src/libstore/unix/build/derivation-builder.cc`:
- Around line 938-940: The code currently reopens drvJsonPath to write the JSON,
which negates the createTempFile() tmpFd guarantee; instead write the hook JSON
through the existing tmpFd returned by createTempFile("nix-drv-json") (use the
tmpFd to write drvJson.dump() and then close the descriptor) so the write is
tied to the same inode and avoid a second pathname lookup—update the writeFile
call to accept/use tmpFd (or perform a direct write to tmpFd) and keep
AutoDelete(drvJsonPath, false) as-is.

In `@tests/functional/linux-sandbox.sh`:
- Around line 112-115: The test hook currently extracts the derivation name
using jq -r .env.name from the NIX_DERIVATION_V4 file, but the serializer emits
the canonical name at the top level; update the jq invocation in the hook script
to use .name instead of .env.name (i.e., change jq -r .env.name <
"\$NIX_DERIVATION_V4" > "$DEST" to jq -r .name < "\$NIX_DERIVATION_V4" >
"$DEST") so the test reads the top-level name field directly (symbols: HOOK,
NIX_DERIVATION_V4, DEST).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9726bd19-2eb3-48d0-9294-188c1761590e

📥 Commits

Reviewing files that changed from the base of the PR and between b5c0faf and 6be956b.

📒 Files selected for processing (6)
  • src/libstore/derivations.cc
  • src/libstore/include/nix/store/derivations.hh
  • src/libstore/include/nix/store/globals.hh
  • src/libstore/unix/build/derivation-builder.cc
  • tests/functional/linux-sandbox.sh
  • tests/functional/symlink-derivation.nix

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant