diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 72fea31775e..4acfd91969a 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -15,6 +15,8 @@ #include #include +#include + #ifndef _WIN32 # include #endif @@ -267,6 +269,20 @@ const ExternalBuilder * Settings::findExternalDerivationBuilderIfSupported(const return nullptr; } +std::optional Settings::getHostName() +{ + if (hostName != "") + return hostName; + +#ifndef _WIN32 + char hostname[_POSIX_HOST_NAME_MAX + 1]; + if (gethostname(hostname, sizeof(hostname)) == 0) + return std::string(hostname); +#endif + + return std::nullopt; +} + std::string nixVersion = PACKAGE_VERSION; const std::string determinateNixVersion = DETERMINATE_NIX_VERSION; diff --git a/src/libstore/include/nix/store/globals.hh b/src/libstore/include/nix/store/globals.hh index 37130521bbf..89cc430b5c0 100644 --- a/src/libstore/include/nix/store/globals.hh +++ b/src/libstore/include/nix/store/globals.hh @@ -1441,6 +1441,16 @@ public: * derivation, or else returns a null pointer. */ const ExternalBuilder * findExternalDerivationBuilderIfSupported(const Derivation & drv); + + Setting hostName{ + this, + "", + "host-name", + R"( + The name of this host for recording build provenance. If unset, the Unix host name is used. + )"}; + + std::optional getHostName(); }; // FIXME: don't use a global variable. diff --git a/src/libstore/include/nix/store/provenance.hh b/src/libstore/include/nix/store/provenance.hh index ee7771c0a33..602a5bf3381 100644 --- a/src/libstore/include/nix/store/provenance.hh +++ b/src/libstore/include/nix/store/provenance.hh @@ -18,6 +18,11 @@ struct BuildProvenance : Provenance */ OutputName output; + /** + * The hostname of the machine on which the derivation was built, if known. + */ + std::optional buildHost; + /** * The provenance of the derivation, if known. */ @@ -25,9 +30,14 @@ struct BuildProvenance : Provenance // FIXME: do we need anything extra for CA derivations? - BuildProvenance(const StorePath & drvPath, const OutputName & output, std::shared_ptr next) + BuildProvenance( + const StorePath & drvPath, + const OutputName & output, + std::optional buildHost, + std::shared_ptr next) : drvPath(drvPath) , output(output) + , buildHost(std::move(buildHost)) , next(std::move(next)) { } diff --git a/src/libstore/provenance.cc b/src/libstore/provenance.cc index 914a55e1668..4a5bcf31ebd 100644 --- a/src/libstore/provenance.cc +++ b/src/libstore/provenance.cc @@ -9,6 +9,7 @@ nlohmann::json BuildProvenance::to_json() const {"type", "build"}, {"drv", drvPath.to_string()}, {"output", output}, + {"buildHost", buildHost}, {"next", next ? next->to_json() : nlohmann::json(nullptr)}, }; } @@ -18,8 +19,12 @@ Provenance::Register registerBuildProvenance("build", [](nlohmann::json json) { std::shared_ptr next; if (auto p = optionalValueAt(obj, "next"); p && !p->is_null()) next = Provenance::from_json(*p); - return make_ref( - StorePath(getString(valueAt(obj, "drv"))), getString(valueAt(obj, "output")), next); + std::optional buildHost; + if (auto p = optionalValueAt(obj, "buildHost")) + buildHost = p->get>(); + auto buildProv = make_ref( + StorePath(getString(valueAt(obj, "drv"))), getString(valueAt(obj, "output")), buildHost, next); + return buildProv; }); nlohmann::json CopiedProvenance::to_json() const diff --git a/src/libstore/unix/build/derivation-builder.cc b/src/libstore/unix/build/derivation-builder.cc index efb79daa9f9..bb18f210942 100644 --- a/src/libstore/unix/build/derivation-builder.cc +++ b/src/libstore/unix/build/derivation-builder.cc @@ -1868,7 +1868,8 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs() newInfo.deriver = drvPath; newInfo.ultimate = true; if (drvProvenance) - newInfo.provenance = std::make_shared(drvPath, outputName, drvProvenance); + newInfo.provenance = + std::make_shared(drvPath, outputName, settings.getHostName(), drvProvenance); store.signPathInfo(newInfo); finish(newInfo.path); diff --git a/src/nix/provenance-show.md b/src/nix/provenance-show.md index 565ae05bf0b..b57f009db0f 100644 --- a/src/nix/provenance-show.md +++ b/src/nix/provenance-show.md @@ -8,7 +8,7 @@ R""( # nix provenance show /run/current-system /nix/store/k145bdxhdb89i4fkvgdisdz1yh2wiymm-nixos-system-machine-25.05.20251210.d2b1213 ← copied from cache.flakehub.com - ← built from derivation /nix/store/w3p3xkminq61hs00kihd34w1dglpj5s9-nixos-system-machine-25.05.20251210.d2b1213.drv (output out) + ← built from derivation /nix/store/w3p3xkminq61hs00kihd34w1dglpj5s9-nixos-system-machine-25.05.20251210.d2b1213.drv (output out) on build-machine ← instantiated from flake output github:my-org/my-repo/6b03eb949597fe96d536e956a2c14da9901dbd21?dir=machine#nixosConfigurations.machine.config.system.build.toplevel ``` diff --git a/src/nix/provenance.cc b/src/nix/provenance.cc index e32e2fe7935..803bc9676cc 100644 --- a/src/nix/provenance.cc +++ b/src/nix/provenance.cc @@ -57,9 +57,11 @@ struct CmdProvenanceShow : StorePathsCommand provenance = copied->next; } else if (auto build = std::dynamic_pointer_cast(provenance)) { logger->cout( - "← built from derivation " ANSI_BOLD "%s" ANSI_NORMAL " (output " ANSI_BOLD "%s" ANSI_NORMAL ")", + "← built from derivation " ANSI_BOLD "%s" ANSI_NORMAL " (output " ANSI_BOLD "%s" ANSI_NORMAL + ") on " ANSI_BOLD "%s" ANSI_NORMAL, store.printStorePath(build->drvPath), - build->output); + build->output, + build->buildHost.value_or("unknown host").c_str()); provenance = build->next; } else if (auto flake = std::dynamic_pointer_cast(provenance)) { // Collapse subpath/tree provenance into the flake provenance for legibility. diff --git a/tests/functional/common/init.sh b/tests/functional/common/init.sh index 98ae42cd4ce..41e1851160a 100755 --- a/tests/functional/common/init.sh +++ b/tests/functional/common/init.sh @@ -52,6 +52,7 @@ gc-reserved-space = 0 substituters = flake-registry = $TEST_ROOT/registry.json show-trace = true +host-name = test-host include nix.conf.extra trusted-users = $(whoami) ${_NIX_TEST_EXTRA_CONFIG:-} diff --git a/tests/functional/flakes/provenance.sh b/tests/functional/flakes/provenance.sh index 4f831b91ffe..af4e3767220 100644 --- a/tests/functional/flakes/provenance.sh +++ b/tests/functional/flakes/provenance.sh @@ -18,6 +18,7 @@ builder=$(nix eval --raw "$flake1Dir#packages.$system.default._builder") # Building a derivation should have tree+subpath+flake+build provenance. [[ $(nix path-info --json --json-format 1 "$outPath" | jq ".\"$outPath\".provenance") = $(cat <