Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libcmd/include/nix/cmd/installable-flake.hh
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct InstallableFlake : InstallableValue
ExtendedOutputsSpec extendedOutputsSpec;
const flake::LockFlags & lockFlags;
mutable std::shared_ptr<flake::LockedFlake> _lockedFlake;
bool useEvalCache = true;

InstallableFlake(
SourceExprCommand * cmd,
Expand Down
2 changes: 1 addition & 1 deletion src/libcmd/installable-flake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)

std::vector<ref<eval_cache::AttrCursor>> InstallableFlake::getCursors(EvalState & state)
{
auto evalCache = openEvalCache(state, getLockedFlake());
auto evalCache = openEvalCache(state, getLockedFlake(), useEvalCache);

auto root = evalCache->getRoot();

Expand Down
16 changes: 14 additions & 2 deletions src/libexpr/primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "nix/util/sort.hh"
#include "nix/util/mounted-source-accessor.hh"
#include "nix/expr/provenance.hh"
#include "nix/util/override-provenance-source-accessor.hh"

#include <boost/container/small_vector.hpp>
#include <boost/unordered/concurrent_flat_map.hpp>
Expand Down Expand Up @@ -2937,18 +2938,29 @@ static void addPath(
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
// FIXME: make this lazy?
// FIXME: support refs in fetchToStore()?
auto path2 = path.resolveSymlinks();
// Don't use source path provenance if we have a filter applied, since we can't accurately
// record that. Instead, use the current global provenance, since it's better than nothing.
auto path3 = filter
? SourcePath{
make_ref<OverrideProvenanceSourceAccessor>(
path2.accessor, state.evalContext.provenance),
path2.path
}
: path2;

auto dstPath = refs.empty() ? fetchToStore(
state.fetchSettings,
*state.store,
path.resolveSymlinks(),
path3,
settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy,
name,
method,
filter.get(),
state.repair)
: state.store->addToStore(
name,
path.resolveSymlinks(),
path3,
method,
HashAlgorithm::SHA256,
refs,
Expand Down
12 changes: 12 additions & 0 deletions src/libfetchers/include/nix/fetchers/provenance.hh
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,16 @@ struct TreeProvenance : Provenance
nlohmann::json to_json() const override;
};

struct FetchurlProvenance : Provenance
{
std::string url;

FetchurlProvenance(const std::string & url)
: url(url)
{
}

nlohmann::json to_json() const override;
};

} // namespace nix
13 changes: 13 additions & 0 deletions src/libfetchers/provenance.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,17 @@ Provenance::Register registerTreeProvenance("tree", [](nlohmann::json json) {
return make_ref<TreeProvenance>(make_ref<nlohmann::json>(attrsJson));
});

nlohmann::json FetchurlProvenance::to_json() const
{
return nlohmann::json{
{"type", "fetchurl"},
{"url", url},
};
}

Provenance::Register registerFetchurlProvenance("fetchurl", [](nlohmann::json json) {
auto & obj = getObject(json);
return make_ref<FetchurlProvenance>(getString(valueAt(obj, "url")));
});

} // namespace nix
29 changes: 3 additions & 26 deletions src/libfetchers/tarball.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,12 @@
#include "nix/store/store-api.hh"
#include "nix/fetchers/git-utils.hh"
#include "nix/fetchers/fetch-settings.hh"
#include "nix/util/provenance.hh"
#include "nix/fetchers/provenance.hh"

#include <nlohmann/json.hpp>

namespace nix::fetchers {

struct FetchurlProvenance : Provenance
{
std::string url;

FetchurlProvenance(const std::string & url)
: url(url)
{
}

nlohmann::json to_json() const override
{
return nlohmann::json{
{"type", "fetchurl"},
{"url", url},
};
}
};

DownloadFileResult downloadFile(
Store & store,
const Settings & settings,
Expand Down Expand Up @@ -104,13 +86,8 @@ DownloadFileResult downloadFile(
},
hashString(HashAlgorithm::SHA256, sink.s));
info.narSize = sink.s.size();
if (experimentalFeatureSettings.isEnabled(Xp::Provenance)) {
auto sanitizedUrl = request.uri.parsed();
if (sanitizedUrl.authority)
sanitizedUrl.authority->password.reset();
sanitizedUrl.query.clear();
info.provenance = std::make_shared<FetchurlProvenance>(sanitizedUrl.to_string());
}
if (experimentalFeatureSettings.isEnabled(Xp::Provenance))
info.provenance = std::make_shared<FetchurlProvenance>(request.uri.parsed().renderSanitized());
auto source = StringSource{sink.s};
store.addToStore(info, source, NoRepair, NoCheckSigs);
storePath = std::move(info.path);
Expand Down
4 changes: 2 additions & 2 deletions src/libflake/flake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1054,9 +1054,9 @@ std::optional<Fingerprint> LockedFlake::getFingerprint(Store & store, const fetc

Flake::~Flake() {}

ref<eval_cache::EvalCache> openEvalCache(EvalState & state, ref<const LockedFlake> lockedFlake)
ref<eval_cache::EvalCache> openEvalCache(EvalState & state, ref<const LockedFlake> lockedFlake, bool allowEvalCache)
{
auto fingerprint = state.settings.useEvalCache && state.settings.pureEval
auto fingerprint = allowEvalCache && state.settings.useEvalCache && state.settings.pureEval
? lockedFlake->getFingerprint(*state.store, state.fetchSettings)
: std::nullopt;
auto rootLoader = [&state, lockedFlake]() {
Expand Down
3 changes: 2 additions & 1 deletion src/libflake/include/nix/flake/flake.hh
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@ void callFlake(EvalState & state, const LockedFlake & lockedFlake, Value & v);
/**
* Open an evaluation cache for a flake.
*/
ref<eval_cache::EvalCache> openEvalCache(EvalState & state, ref<const LockedFlake> lockedFlake);
ref<eval_cache::EvalCache>
openEvalCache(EvalState & state, ref<const LockedFlake> lockedFlake, bool allowEvalCache = true);

} // namespace flake

Expand Down
1 change: 1 addition & 0 deletions src/libutil/include/nix/util/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ headers = files(
'muxable-pipe.hh',
'nar-accessor.hh',
'os-string.hh',
'override-provenance-source-accessor.hh',
'pool.hh',
'pos-idx.hh',
'pos-table.hh',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include "nix/util/forwarding-source-accessor.hh"

namespace nix {

struct OverrideProvenanceSourceAccessor : ForwardingSourceAccessor
{
OverrideProvenanceSourceAccessor(ref<SourceAccessor> next, std::shared_ptr<const Provenance> provenance)
: ForwardingSourceAccessor(std::move(next))
{
this->provenance = std::move(provenance);
}

std::shared_ptr<const Provenance> getProvenance(const CanonPath & path) override
{
return provenance;
}
};

} // namespace nix
5 changes: 5 additions & 0 deletions src/libutil/include/nix/util/url.hh
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ struct ParsedURL
*/
std::string renderPath(bool encode = false) const;

/**
* Like to_string(), but removes query strings and passwords.
*/
std::string renderSanitized() const;

auto operator<=>(const ParsedURL & other) const noexcept = default;

/**
Expand Down
9 changes: 9 additions & 0 deletions src/libutil/url.cc
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,15 @@ std::string ParsedURL::renderPath(bool encode) const
return concatStringsSep("/", path);
}

std::string ParsedURL::renderSanitized() const
{
auto url = *this;
if (url.authority)
url.authority->password.reset();
url.query.clear();
return url.to_string();
}

std::string ParsedURL::renderAuthorityAndPath() const
{
std::string res;
Expand Down
12 changes: 11 additions & 1 deletion src/nix/prefetch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "nix/util/environment-variables.hh"
#include "nix/util/url.hh"
#include "nix/store/path.hh"
#include "nix/util/override-provenance-source-accessor.hh"
#include "nix/fetchers/provenance.hh"

#include "man-pages.hh"

Expand Down Expand Up @@ -143,7 +145,15 @@ std::tuple<StorePath, Hash> prefetchFile(

Activity act(*logger, lvlChatty, actUnknown, fmt("adding '%s' to the store", url.to_string()));

auto info = store->addToStoreSlow(name, makeFSSourceAccessor(tmpFile), method, hashAlgo, {}, expectedHash);
auto info = store->addToStoreSlow(
name,
{make_ref<OverrideProvenanceSourceAccessor>(
makeFSSourceAccessor(tmpFile),
unpack ? nullptr : std::make_shared<FetchurlProvenance>(url.parsed().renderSanitized()))},
method,
hashAlgo,
{},
expectedHash);
Comment thread
edolstra marked this conversation as resolved.
storePath = info.path;
assert(info.ca);
hash = info.ca->hash;
Expand Down
21 changes: 21 additions & 0 deletions src/nix/provenance-verify.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
R""(

# Examples

* Verify the provenance of a store path:

```console
# nix provenance verify /run/current-system
```

# Description

Verify the provenance of one or more store paths. This checks whether the store paths can be rebuilt from source. Specifically, it verifies the following:

* That source trees can be fetched.
* That flake evaluations result in the instantiation of the desired store paths (most commonly, store derivations).
* That derivations can be successfully rebuilt, producing identical outputs.

A non-zero exit code is returned if any of the verifications fail.

)""
Loading
Loading