Skip to content

Commit

Permalink
Allow restricting possible runtime references
Browse files Browse the repository at this point in the history
Adds a new derivation attribute `__visibleReferences` which restricts the
list of paths that are searched in build outputs in order to establish
runtime references.

Setting this attribute requires the experimental feature
`invisible-references` to be enabled.

Useful when creating filesystem images containing their own embedded Nix
store: setting `__visibleReferences = [];` makes them self-contained
blobs of data with no runtime dependencies.
  • Loading branch information
ncfavier committed Oct 10, 2022
1 parent ac0fb38 commit bfa55c3
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 4 deletions.
25 changes: 22 additions & 3 deletions doc/manual/src/language/advanced-attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,25 @@ Derivations can declare some infrequently used optional attributes.
dependency on `foobar` or any other derivation depending recursively
on `foobar`.

- [`__visibleReferences`]{#adv-attr-__visibleReferences}\
The **experimental** attribute `__visibleReferences` restricts the set of
store paths that Nix will consider when scanning for runtime
dependencies. By default, this set includes build inputs, output
paths, and paths built by recursive Nix invocations. Setting this
attribute will restrict the set to the given list.
For example,

```nix
__visibleReferences = [];
```

effectively produces a blob of data without any runtime dependencies.
This is useful when generating self-contained filesystem images with
their own embedded Nix store: hashes found inside such an image refer
to the embedded store and not to the host's Nix store.

This is only allowed if the `invisible-references` experimental feature is enabled.

- [`exportReferencesGraph`]{#adv-attr-exportReferencesGraph}\
This attribute allows builders access to the references graph of
their inputs. The attribute is a list of inputs in the Nix store
Expand Down Expand Up @@ -207,13 +226,13 @@ Derivations can declare some infrequently used optional attributes.
the hash in either hexadecimal or base-32 notation. (See the
[`nix-hash` command](../command-ref/nix-hash.md) for information
about converting to and from base-32 notation.)

- [`__contentAddressed`]{#adv-attr-__contentAddressed}
If this **experimental** attribute is set to true, then the derivation
outputs will be stored in a content-addressed location rather than the
traditional input-addressed one.
This only has an effect if the `ca-derivation` experimental feature is enabled.
This only has an effect if the `ca-derivations` experimental feature is enabled.

Setting this attribute also requires setting `outputHashMode` and `outputHashAlgo` like for *fixed-output derivations* (see above).

- [`passAsFile`]{#adv-attr-passAsFile}\
Expand Down
21 changes: 20 additions & 1 deletion src/libstore/build/local-derivation-goal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2138,12 +2138,31 @@ DrvOutputs LocalDerivationGoal::registerOutputs()

/* The paths that can be referenced are the input closures, the
output paths, and any paths that have been built via recursive
Nix calls. */
Nix calls; this list is restricted to the paths in the
__visibleReferences derivation attribute, if present. */
StorePathSet referenceablePaths;
for (auto & p : inputPaths) referenceablePaths.insert(p);
for (auto & i : scratchOutputs) referenceablePaths.insert(i.second);
for (auto & p : addedPaths) referenceablePaths.insert(p);

if (auto visibleReferences = parsedDrv->getStringsAttr("__visibleReferences")) {
settings.requireExperimentalFeature(Xp::InvisibleReferences);

StorePathSet spec;
for (auto & i : *visibleReferences) {
if (worker.store.isStorePath(i))
spec.insert(worker.store.parseStorePath(i));
else
throw BuildError("derivation attribute __visibleReferences contains an illegal reference '%s'", i);
}

StorePathSet tmp;
std::set_intersection(referenceablePaths.begin(), referenceablePaths.end(),
spec.begin(), spec.end(),
std::inserter(tmp, tmp.begin()));
referenceablePaths = std::move(tmp);
}

/* FIXME `needsHashRewrite` should probably be removed and we get to the
real reason why we aren't using the chroot dir */
auto toRealPathChroot = [&](const Path & p) -> Path {
Expand Down
1 change: 1 addition & 0 deletions src/libutil/experimental-features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ std::map<ExperimentalFeature, std::string> stringifiedXpFeatures = {
{ Xp::NoUrlLiterals, "no-url-literals" },
{ Xp::FetchClosure, "fetch-closure" },
{ Xp::ReplFlake, "repl-flake" },
{ Xp::InvisibleReferences, "invisible-references" },
};

const std::optional<ExperimentalFeature> parseExperimentalFeature(const std::string_view & name)
Expand Down
1 change: 1 addition & 0 deletions src/libutil/experimental-features.hh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum struct ExperimentalFeature
NoUrlLiterals,
FetchClosure,
ReplFlake,
InvisibleReferences,
};

/**
Expand Down
1 change: 1 addition & 0 deletions src/nix/develop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ static StorePath getDerivationEnvironment(ref<Store> store, ref<Store> evalStore
drv.env.erase("allowedRequisites");
drv.env.erase("disallowedReferences");
drv.env.erase("disallowedRequisites");
drv.env.erase("__visibleReferences");

/* Rehash and write the derivation. FIXME: would be nice to use
'buildDerivation', but that's privileged. */
Expand Down
11 changes: 11 additions & 0 deletions tests/check-refs.nix
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,15 @@ rec {
disallowedReferences = [test5];
};

test11 = makeTest 11 {
buildCommand = "echo ${dep} > $out";
__visibleReferences = [];
disallowedReferences = [dep];
};

test12 = makeTest 12 {
buildCommand = "echo ${dep} ${src} > $out";
__visibleReferences = [dep];
};

}
11 changes: 11 additions & 0 deletions tests/check-refs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,14 @@ nix-build -o $RESULT check-refs.nix -A test7

# test10 should succeed (no disallowed references).
nix-build -o $RESULT check-refs.nix -A test10

if isDaemonNewer 2.12pre20220922; then
# test11 should succeed (no referenceable paths).
test11=$(nix-build --extra-experimental-features invisible-references -o $RESULT check-refs.nix -A test11)
[[ -z $(nix-store -q --references "$test11") ]]

# test12 should succeed.
test12=$(nix-build --extra-experimental-features invisible-references -o $RESULT check-refs.nix -A test12)
nix-store -q --references "$test12" | grep -q "$dep"
! nix-store -q --references "$test12" | grep -q aux-ref
fi

0 comments on commit bfa55c3

Please sign in to comment.