Allow CLI to pass environment variables to FOD builder (#8830)

Add a new experimental `impure-env` setting that is a key-value list of
environment variables to inject into FOD derivations that specify the
corresponding `impureEnvVars`.

This allows clients to make use of this feature (without having to change the
environment of the daemon itself) and might eventually deprecate the current
behaviour (pick whatever is in the environment of the daemon) as it's more
principled and might prevent information leakage.
This commit is contained in:
Ninlives 2023-10-11 19:58:42 +08:00 committed by GitHub
parent 301623f3a3
commit 94e91566ed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 99 additions and 4 deletions

View file

@ -112,6 +112,13 @@ Derivations can declare some infrequently used optional attributes.
> environmental variables come from the environment of the
> `nix-build`.
If the [`configurable-impure-env` experimental
feature](@docroot@/contributing/experimental-features.md#xp-feature-configurable-impure-env)
is enabled, these environment variables can also be controlled
through the
[`impure-env`](@docroot@/command-ref/conf-file.md#conf-impure-env)
configuration setting.
- [`outputHash`]{#adv-attr-outputHash}; [`outputHashAlgo`]{#adv-attr-outputHashAlgo}; [`outputHashMode`]{#adv-attr-outputHashMode}\
These attributes declare that the derivation is a so-called
*fixed-output derivation*, which means that a cryptographic hash of

View file

@ -1135,8 +1135,18 @@ void LocalDerivationGoal::initEnv()
fixed-output derivations is by definition pure (since we
already know the cryptographic hash of the output). */
if (!derivationType->isSandboxed()) {
for (auto & i : parsedDrv->getStringsAttr("impureEnvVars").value_or(Strings()))
env[i] = getEnv(i).value_or("");
auto & impureEnv = settings.impureEnv.get();
if (!impureEnv.empty())
experimentalFeatureSettings.require(Xp::ConfigurableImpureEnv);
for (auto & i : parsedDrv->getStringsAttr("impureEnvVars").value_or(Strings())) {
auto envVar = impureEnv.find(i);
if (envVar != impureEnv.end()) {
env[i] = envVar->second;
} else {
env[i] = getEnv(i).value_or("");
}
}
}
/* Currently structured log messages piggyback on stderr, but we

View file

@ -4,6 +4,7 @@
#include "types.hh"
#include "config.hh"
#include "util.hh"
#include "experimental-features.hh"
#include <map>
#include <limits>
@ -1052,6 +1053,25 @@ public:
```
)"
};
Setting<StringMap> impureEnv {this, {}, "impure-env",
R"(
A list of items, each in the format of:
- `name=value`: Set environment variable `name` to `value`.
If the user is trusted (see `trusted-users` option), when building
a fixed-output derivation, environment variables set in this option
will be passed to the builder if they are listed in [`impureEnvVars`](@docroot@/language/advanced-attributes.md##adv-attr-impureEnvVars).
This option is useful for, e.g., setting `https_proxy` for
fixed-output derivations and in a multi-user Nix installation, or
setting private access tokens when fetching a private repository.
)",
{}, // aliases
true, // document default
Xp::ConfigurableImpureEnv
};
};

View file

@ -12,7 +12,7 @@ struct ExperimentalFeatureDetails
std::string_view description;
};
constexpr std::array<ExperimentalFeatureDetails, 14> xpFeatureDetails = {{
constexpr std::array<ExperimentalFeatureDetails, 15> xpFeatureDetails = {{
{
.tag = Xp::CaDerivations,
.name = "ca-derivations",
@ -221,6 +221,13 @@ constexpr std::array<ExperimentalFeatureDetails, 14> xpFeatureDetails = {{
Allow the use of the `read-only` parameter in [local store](@docroot@/command-ref/new-cli/nix3-help-stores.md#local-store) URIs.
)",
},
{
.tag = Xp::ConfigurableImpureEnv,
.name = "configurable-impure-env",
.description = R"(
Allow the use of the [impure-env](@docroot@/command-ref/conf-file.md#conf-impure-env) setting.
)",
}
}};
static_assert(

View file

@ -31,6 +31,7 @@ enum struct ExperimentalFeature
DynamicDerivations,
ParseTomlTimestamps,
ReadOnlyLocalStore,
ConfigurableImpureEnv,
};
/**

View file

@ -0,0 +1,16 @@
{ var, value }:
with import ./config.nix;
mkDerivation {
name = "test";
buildCommand = ''
echo ${var} = "''$${var}"
echo -n "''$${var}" > "$out"
'';
impureEnvVars = [ var ];
outputHashAlgo = "sha256";
outputHash = builtins.hashString "sha256" value;
}

View file

@ -0,0 +1,33 @@
source common.sh
# Needs the config option 'impure-env' to work
requireDaemonNewerThan "2.18.0pre20230816"
enableFeatures "configurable-impure-env"
restartDaemon
varTest() {
local var="$1"; shift
local value="$1"; shift
nix build --no-link -vL --argstr var "$var" --argstr value "$value" --impure "$@" --file impure-env.nix
clearStore
}
clearStore
startDaemon
varTest env_name value --impure-env env_name=value
echo 'impure-env = set_in_config=config_value' >> "$NIX_CONF_DIR/nix.conf"
set_in_config=daemon_value restartDaemon
varTest set_in_config config_value
varTest set_in_config client_value --impure-env set_in_config=client_value
sed -i -e '/^trusted-users =/d' "$NIX_CONF_DIR/nix.conf"
env_name=daemon_value restartDaemon
varTest env_name daemon_value --impure-env env_name=client_value
killDaemon

View file

@ -121,7 +121,8 @@ nix_tests = \
path-from-hash-part.sh \
toString-path.sh \
read-only-store.sh \
nested-sandboxing.sh
nested-sandboxing.sh \
impure-env.sh
ifeq ($(HAVE_LIBCPUID), 1)
nix_tests += compute-levels.sh