Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: NixOS/nix
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 605bacdc929d
Choose a base ref
...
head repository: NixOS/nix
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 8252a44e9661
Choose a head ref
  • 3 commits
  • 5 files changed
  • 1 contributor

Commits on Nov 26, 2020

  1. 1
    Copy the full SHA
    0287f83 View commit details
  2. 1
    Copy the full SHA
    9a586e3 View commit details
  3. Move to separate file

    edolstra committed Nov 26, 2020
    Copy the full SHA
    8252a44 View commit details
Showing with 113 additions and 44 deletions.
  1. +81 −0 src/libexpr/flake/config.cc
  2. +17 −43 src/libexpr/flake/flake.cc
  3. +1 −1 src/libexpr/flake/flake.hh
  4. +11 −0 src/libmain/progress-bar.cc
  5. +3 −0 src/libutil/logging.hh
81 changes: 81 additions & 0 deletions src/libexpr/flake/config.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "flake.hh"

#include <nlohmann/json.hpp>

namespace nix::flake {

// setting name -> setting value -> allow or ignore.
typedef std::map<std::string, std::map<std::string, bool>> TrustedList;

Path trustedListPath()
{
return getDataDir() + "/nix/trusted-settings.json";
}

static TrustedList readTrustedList()
{
auto path = trustedListPath();
if (!pathExists(path)) return {};
auto json = nlohmann::json::parse(readFile(path));
return json;
}

static void writeTrustedList(const TrustedList & trustedList)
{
writeFile(trustedListPath(), nlohmann::json(trustedList).dump());
}

void ConfigFile::apply()
{
std::set<std::string> whitelist{"bash-prompt", "bash-prompt-suffix"};

for (auto & [name, value] : settings) {

auto baseName = hasPrefix(name, "extra-") ? std::string(name, 6) : name;

// FIXME: Move into libutil/config.cc.
std::string valueS;
if (auto s = std::get_if<std::string>(&value))
valueS = *s;
else if (auto n = std::get_if<int64_t>(&value))
valueS = fmt("%d", n);
else if (auto b = std::get_if<Explicit<bool>>(&value))
valueS = b->t ? "true" : "false";
else if (auto ss = std::get_if<std::vector<std::string>>(&value))
valueS = concatStringsSep(" ", *ss); // FIXME: evil
else
assert(false);

if (!whitelist.count(baseName)) {
auto trustedList = readTrustedList();

bool trusted = false;

if (auto saved = get(get(trustedList, name).value_or(std::map<std::string, bool>()), valueS)) {
trusted = *saved;
} 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') {
if (std::tolower(logger->ask("do you want to permanently mark this value as untrusted (y/N)?").value_or('n')) == 'y') {
trustedList[name][valueS] = false;
writeTrustedList(trustedList);
}
} else {
if (std::tolower(logger->ask("do you want to permanently mark this value as trusted (y/N)?").value_or('n')) == 'y') {
trustedList[name][valueS] = trusted = true;
writeTrustedList(trustedList);
}
}
}

if (!trusted) {
warn("ignoring untrusted flake configuration setting '%s'", name);
continue;
}
}

globalConfig.set(name, valueS);
}
}

}
60 changes: 17 additions & 43 deletions src/libexpr/flake/flake.cc
Original file line number Diff line number Diff line change
@@ -233,28 +233,28 @@ static Flake getFlake(
if (auto nixConfig = vInfo.attrs->get(sNixConfig)) {
expectType(state, tAttrs, *nixConfig->value, *nixConfig->pos);

for (auto & option : *nixConfig->value->attrs) {
forceTrivialValue(state, *option.value, *option.pos);
if (option.value->type == tString)
flake.config.options.insert({option.name, state.forceStringNoCtx(*option.value, *option.pos)});
else if (option.value->type == tInt)
flake.config.options.insert({option.name, state.forceInt(*option.value, *option.pos)});
else if (option.value->type == tBool)
flake.config.options.insert({option.name, state.forceBool(*option.value, *option.pos)});
else if (option.value->isList()) {
for (auto & setting : *nixConfig->value->attrs) {
forceTrivialValue(state, *setting.value, *setting.pos);
if (setting.value->type == tString)
flake.config.settings.insert({setting.name, state.forceStringNoCtx(*setting.value, *setting.pos)});
else if (setting.value->type == tInt)
flake.config.settings.insert({setting.name, state.forceInt(*setting.value, *setting.pos)});
else if (setting.value->type == tBool)
flake.config.settings.insert({setting.name, state.forceBool(*setting.value, *setting.pos)});
else if (setting.value->isList()) {
std::vector<std::string> ss;
for (unsigned int n = 0; n < option.value->listSize(); ++n) {
auto elem = option.value->listElems()[n];
for (unsigned int n = 0; n < setting.value->listSize(); ++n) {
auto elem = setting.value->listElems()[n];
if (elem->type != tString)
throw TypeError("list element in flake configuration option '%s' is %s while a string is expected",
option.name, showType(*option.value));
ss.push_back(state.forceStringNoCtx(*elem, *option.pos));
throw TypeError("list element in flake configuration setting '%s' is %s while a string is expected",
setting.name, showType(*setting.value));
ss.push_back(state.forceStringNoCtx(*elem, *setting.pos));
}
flake.config.options.insert({option.name, ss});
flake.config.settings.insert({setting.name, ss});
}
else
throw TypeError("flake configuration option '%s' is %s",
option.name, showType(*option.value));
throw TypeError("flake configuration setting '%s' is %s",
setting.name, showType(*setting.value));
}
}

@@ -635,30 +635,4 @@ Fingerprint LockedFlake::getFingerprint() const

Flake::~Flake() { }

void ConfigFile::apply()
{
for (auto & [name, value] : options) {
// FIXME: support 'trusted-public-keys' (and other options), but make it TOFU.
if (name != "bash-prompt-suffix" &&
name != "bash-prompt" &&
name != "substituters" &&
name != "extra-substituters")
{
warn("ignoring untrusted flake configuration option '%s'", name);
continue;
}
// FIXME: Move into libutil/config.cc.
if (auto s = std::get_if<std::string>(&value))
globalConfig.set(name, *s);
else if (auto n = std::get_if<int64_t>(&value))
globalConfig.set(name, fmt("%d", n));
else if (auto b = std::get_if<Explicit<bool>>(&value))
globalConfig.set(name, b->t ? "true" : "false");
else if (auto ss = std::get_if<std::vector<std::string>>(&value))
globalConfig.set(name, concatStringsSep(" ", *ss)); // FIXME: evil
else
assert(false);
}
}

}
2 changes: 1 addition & 1 deletion src/libexpr/flake/flake.hh
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ struct ConfigFile
{
using ConfigValue = std::variant<std::string, int64_t, Explicit<bool>, std::vector<std::string>>;

std::map<std::string, ConfigValue> options;
std::map<std::string, ConfigValue> settings;

void apply();
};
11 changes: 11 additions & 0 deletions src/libmain/progress-bar.cc
Original file line number Diff line number Diff line change
@@ -466,6 +466,17 @@ class ProgressBar : public Logger
Logger::writeToStdout(s);
}
}

std::optional<char> ask(std::string_view msg) override
{
auto state(state_.lock());
if (!state->active || !isatty(STDIN_FILENO)) return {};
std::cerr << fmt("\r\e[K%s ", msg);
auto s = trim(readLine(STDIN_FILENO));
if (s.size() != 1) return {};
draw(*state);
return s[0];
}
};

Logger * makeProgressBar(bool printBuildLogs)
3 changes: 3 additions & 0 deletions src/libutil/logging.hh
Original file line number Diff line number Diff line change
@@ -106,6 +106,9 @@ public:
formatHelper(f, args...);
writeToStdout(f.str());
}

virtual std::optional<char> ask(std::string_view s)
{ return {}; }
};

ActivityId getCurActivity();