libexpr/flake: allow automatic rejection of configuration options from flakes
The `allow-flake-configuration` option allows the user to control whether to
accept configuration options supplied by flakes. Unfortunately, setting this
to false really meant "ask each time" (with an option to remember the choice
for each specific option encountered). Let no mean no, and introduce (and
default to) a separate value for the "ask each time" behaviour.
Co-Authored-By: Jade Lovelace <lix@jade.fyi>
Change-Id: I7ccd67a95bfc92cffc1ebdc972d243f5191cc1b4
This commit is contained in:
parent
5dc85e8b72
commit
a55112898e
9
doc/manual/rl-next/reject-flake-config.md
Normal file
9
doc/manual/rl-next/reject-flake-config.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
synopsis: Allow automatic rejection of configuration options from flakes
|
||||||
|
cls: [1541]
|
||||||
|
credits: [alois31]
|
||||||
|
category: Improvements
|
||||||
|
---
|
||||||
|
|
||||||
|
Setting `accept-flake-config` to `false` now respects user choice by automatically rejecting configuration options set by flakes.
|
||||||
|
The old behaviour of asking each time is still available (and default) by setting it to the special value `ask`.
|
|
@ -51,30 +51,46 @@ void ConfigFile::apply()
|
||||||
else
|
else
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
||||||
if (!whitelist.count(baseName) && !nix::fetchSettings.acceptFlakeConfig) {
|
bool trusted = whitelist.count(baseName);
|
||||||
bool trusted = false;
|
if (!trusted) {
|
||||||
auto trustedList = readTrustedList();
|
switch (nix::fetchSettings.acceptFlakeConfig) {
|
||||||
auto tlname = get(trustedList, name);
|
case AcceptFlakeConfig::True: {
|
||||||
if (auto saved = tlname ? get(*tlname, valueS) : nullptr) {
|
trusted = true;
|
||||||
trusted = *saved;
|
break;
|
||||||
printInfo("Using saved setting for '%s = %s' from ~/.local/share/nix/trusted-settings.json.", name, valueS);
|
|
||||||
} else {
|
|
||||||
// FIXME: filter ANSI escapes, newlines, \r, etc.
|
|
||||||
if (std::tolower(logger->ask(fmt("do you want to allow configuration setting '%s' to be set to '" ANSI_RED "%s" ANSI_NORMAL "' (y/N)?", name, valueS)).value_or('n')) == 'y') {
|
|
||||||
trusted = true;
|
|
||||||
}
|
|
||||||
if (std::tolower(logger->ask(fmt("do you want to permanently mark this value as %s (y/N)?", trusted ? "trusted": "untrusted" )).value_or('n')) == 'y') {
|
|
||||||
trustedList[name][valueS] = trusted;
|
|
||||||
writeTrustedList(trustedList);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!trusted) {
|
case AcceptFlakeConfig::Ask: {
|
||||||
warn("ignoring untrusted flake configuration setting '%s'.\nPass '%s' to trust it", name, "--accept-flake-config");
|
auto trustedList = readTrustedList();
|
||||||
continue;
|
auto tlname = get(trustedList, name);
|
||||||
|
if (auto saved = tlname ? get(*tlname, valueS) : nullptr) {
|
||||||
|
trusted = *saved;
|
||||||
|
printInfo("Using saved setting for '%s = %s' from ~/.local/share/nix/trusted-settings.json.", name, valueS);
|
||||||
|
} else {
|
||||||
|
// FIXME: filter ANSI escapes, newlines, \r, etc.
|
||||||
|
if (std::tolower(logger->ask(fmt("Do you want to allow configuration setting '%s' to be set to '" ANSI_RED "%s" ANSI_NORMAL "' (y/N)? This may allow the flake to gain root, see the nix.conf manual page.", name, valueS)).value_or('n')) == 'y') {
|
||||||
|
trusted = true;
|
||||||
|
} else {
|
||||||
|
warn("you can set '%s' to '%b' to automatically reject configuration options supplied by flakes", "accept-flake-config", false);
|
||||||
|
}
|
||||||
|
if (std::tolower(logger->ask(fmt("do you want to permanently mark this value as %s (y/N)?", trusted ? "trusted": "untrusted" )).value_or('n')) == 'y') {
|
||||||
|
trustedList[name][valueS] = trusted;
|
||||||
|
writeTrustedList(trustedList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case nix::AcceptFlakeConfig::False: {
|
||||||
|
trusted = false;
|
||||||
|
break;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
globalConfig.set(name, valueS);
|
if (trusted) {
|
||||||
|
debug("accepting trusted flake configuration setting '%s'", name);
|
||||||
|
globalConfig.set(name, valueS);
|
||||||
|
} else {
|
||||||
|
warn("ignoring untrusted flake configuration setting '%s', pass '%s' to trust it (may allow the flake to gain root, see the nix.conf manual page)", name, "--accept-flake-config");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,50 @@
|
||||||
|
#include "abstract-setting-to-json.hh"
|
||||||
|
#include "args.hh"
|
||||||
|
#include "config-impl.hh"
|
||||||
#include "fetch-settings.hh"
|
#include "fetch-settings.hh"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
template<> AcceptFlakeConfig BaseSetting<AcceptFlakeConfig>::parse(const std::string & str) const
|
||||||
|
{
|
||||||
|
if (str == "true") return AcceptFlakeConfig::True;
|
||||||
|
else if (str == "ask") return AcceptFlakeConfig::Ask;
|
||||||
|
else if (str == "false") return AcceptFlakeConfig::False;
|
||||||
|
else throw UsageError("option '%s' has invalid value '%s'", name, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> std::string BaseSetting<AcceptFlakeConfig>::to_string() const
|
||||||
|
{
|
||||||
|
if (value == AcceptFlakeConfig::True) return "true";
|
||||||
|
else if (value == AcceptFlakeConfig::Ask) return "ask";
|
||||||
|
else if (value == AcceptFlakeConfig::False) return "false";
|
||||||
|
else abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> void BaseSetting<AcceptFlakeConfig>::convertToArg(Args & args, const std::string & category)
|
||||||
|
{
|
||||||
|
args.addFlag({
|
||||||
|
.longName = name,
|
||||||
|
.description = "Accept Lix configuration options from flakes without confirmation. This allows flakes to gain root access to your machine if you are a trusted user; see the nix.conf manual page for more details.",
|
||||||
|
.category = category,
|
||||||
|
.handler = {[this]() { override(AcceptFlakeConfig::True); }}
|
||||||
|
});
|
||||||
|
args.addFlag({
|
||||||
|
.longName = "ask-" + name,
|
||||||
|
.description = "Ask whether to accept Lix configuration options from flakes.",
|
||||||
|
.category = category,
|
||||||
|
.handler = {[this]() { override(AcceptFlakeConfig::Ask); }}
|
||||||
|
});
|
||||||
|
args.addFlag({
|
||||||
|
.longName = "no-" + name,
|
||||||
|
.description = "Reject Lix configuration options from flakes.",
|
||||||
|
.category = category,
|
||||||
|
.handler = {[this]() { override(AcceptFlakeConfig::False); }}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
FetchSettings::FetchSettings()
|
FetchSettings::FetchSettings()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
enum class AcceptFlakeConfig { False, Ask, True };
|
||||||
|
|
||||||
struct FetchSettings : public Config
|
struct FetchSettings : public Config
|
||||||
{
|
{
|
||||||
FetchSettings();
|
FetchSettings();
|
||||||
|
@ -86,15 +88,21 @@ struct FetchSettings : public Config
|
||||||
"Whether to use flake registries to resolve flake references.",
|
"Whether to use flake registries to resolve flake references.",
|
||||||
{}, true, Xp::Flakes};
|
{}, true, Xp::Flakes};
|
||||||
|
|
||||||
Setting<bool> acceptFlakeConfig{this, false, "accept-flake-config",
|
Setting<AcceptFlakeConfig> acceptFlakeConfig{
|
||||||
|
this, AcceptFlakeConfig::Ask, "accept-flake-config",
|
||||||
R"(
|
R"(
|
||||||
Whether to accept Lix configuration from the `nixConfig` attribute of
|
Whether to accept Lix configuration from the `nixConfig` attribute of
|
||||||
a flake without prompting. This is almost always a very bad idea.
|
a flake. Doing so as a trusted user allows Nix flakes to gain root
|
||||||
|
|
||||||
Setting this setting as a trusted user allows Nix flakes to gain root
|
|
||||||
access on your machine if they set one of the several
|
access on your machine if they set one of the several
|
||||||
trusted-user-only settings that execute commands as root.
|
trusted-user-only settings that execute commands as root.
|
||||||
|
|
||||||
|
If set to `true`, such configuration will be accepted without asking;
|
||||||
|
this is almost always a very bad idea. Setting this to `ask` will
|
||||||
|
prompt the user each time whether to allow a certain configuration
|
||||||
|
option set this way, and offer to optionally remember their choice.
|
||||||
|
When set to `false`, the configuration will be automatically
|
||||||
|
declined.
|
||||||
|
|
||||||
See [multi-user installations](@docroot@/installation/multi-user.md)
|
See [multi-user installations](@docroot@/installation/multi-user.md)
|
||||||
for more details on the Lix security model.
|
for more details on the Lix security model.
|
||||||
)",
|
)",
|
||||||
|
|
|
@ -32,7 +32,7 @@ NIX_CONFIG='
|
||||||
experimental-features = nix-command
|
experimental-features = nix-command
|
||||||
accept-flake-config = true
|
accept-flake-config = true
|
||||||
' nix config show accept-flake-config 1>$TEST_ROOT/stdout 2>$TEST_ROOT/stderr
|
' nix config show accept-flake-config 1>$TEST_ROOT/stdout 2>$TEST_ROOT/stderr
|
||||||
grepQuiet "false" $TEST_ROOT/stdout
|
grepQuiet "ask" $TEST_ROOT/stdout
|
||||||
grepQuiet "Ignoring setting 'accept-flake-config' because experimental feature 'flakes' is not enabled" $TEST_ROOT/stderr
|
grepQuiet "Ignoring setting 'accept-flake-config' because experimental feature 'flakes' is not enabled" $TEST_ROOT/stderr
|
||||||
|
|
||||||
# 'flakes' experimental-feature is disabled after, ignore and warn
|
# 'flakes' experimental-feature is disabled after, ignore and warn
|
||||||
|
@ -40,7 +40,7 @@ NIX_CONFIG='
|
||||||
accept-flake-config = true
|
accept-flake-config = true
|
||||||
experimental-features = nix-command
|
experimental-features = nix-command
|
||||||
' nix config show accept-flake-config 1>$TEST_ROOT/stdout 2>$TEST_ROOT/stderr
|
' nix config show accept-flake-config 1>$TEST_ROOT/stdout 2>$TEST_ROOT/stderr
|
||||||
grepQuiet "false" $TEST_ROOT/stdout
|
grepQuiet "ask" $TEST_ROOT/stdout
|
||||||
grepQuiet "Ignoring setting 'accept-flake-config' because experimental feature 'flakes' is not enabled" $TEST_ROOT/stderr
|
grepQuiet "Ignoring setting 'accept-flake-config' because experimental feature 'flakes' is not enabled" $TEST_ROOT/stderr
|
||||||
|
|
||||||
# 'flakes' experimental-feature is enabled before, process
|
# 'flakes' experimental-feature is enabled before, process
|
||||||
|
|
|
@ -28,6 +28,11 @@ nix build < /dev/null
|
||||||
(! [[ -f post-hook-ran ]])
|
(! [[ -f post-hook-ran ]])
|
||||||
clearStore
|
clearStore
|
||||||
|
|
||||||
|
# likewise with no-accept-flake-config
|
||||||
|
nix build --no-accept-flake-config
|
||||||
|
(! [[ -f post-hook-ran ]])
|
||||||
|
clearStore
|
||||||
|
|
||||||
nix build --accept-flake-config
|
nix build --accept-flake-config
|
||||||
test -f post-hook-ran || fail "The post hook should have ran"
|
test -f post-hook-ran || fail "The post hook should have ran"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue