nix/eval: remove --write-to
it's broken, can write arbitrary file paths when run as root, and only supports strings and recursive sets of strings. this was only used for manpage generation in a build system that has not woken up since 1976. fixes #974 fixes #227 Change-Id: I4f18599685a3077c15ddc02c759558f986c8c6e4
This commit is contained in:
@@ -225,7 +225,7 @@ let
|
||||
showCategory = cat: ''
|
||||
${optionalString (cat != "") "**${cat}:**"}
|
||||
|
||||
${listOptions (filterAttrs (n: v: v.category == cat) allOptions)}
|
||||
${listOptions (filterAttrs (n: v: v.category == cat && !v.hidden) allOptions)}
|
||||
'';
|
||||
listOptions = opts: concatStringsSep "\n" (attrValues (mapAttrs showOption opts));
|
||||
showOption =
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
synopsis: "`nix eval --write-to` has been removed"
|
||||
cls: [4045]
|
||||
issues: [fj#974, fj#227]
|
||||
category: "Breaking Changes"
|
||||
credits: [horrors]
|
||||
---
|
||||
|
||||
`nix eval --write-to` has been removed since it was underspecified, not widely
|
||||
useful, and prone to security-sensitive misbehaviors. The feature was added in
|
||||
Nix 2.4 purely for internal use in the build system. According to our research
|
||||
it hasn't found any use outside of some distribution packaging scripts. Please
|
||||
use structured outputs formats (such as JSON) instead as they have better type
|
||||
fidelity, don't conflate attributes with paths, and are useful to other tools.
|
||||
@@ -299,6 +299,7 @@ JSON Args::toJSON()
|
||||
if (!flag->labels.empty())
|
||||
j["labels"] = flag->labels;
|
||||
j["experimental-feature"] = flag->experimentalFeature;
|
||||
j["hidden"] = flag->hidden;
|
||||
flags[name] = std::move(j);
|
||||
}
|
||||
|
||||
|
||||
@@ -168,6 +168,8 @@ protected:
|
||||
Strings labels;
|
||||
Handler handler;
|
||||
CompleterClosure completer;
|
||||
/// Whether to hide this flag in generated documentation and CLI specifications.
|
||||
bool hidden = false;
|
||||
|
||||
std::optional<ExperimentalFeature> experimentalFeature;
|
||||
|
||||
|
||||
+17
-42
@@ -32,11 +32,15 @@ struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
|
||||
.handler = {&apply},
|
||||
});
|
||||
|
||||
// `--write-to` was axed because it was not used in-tree, no non-packaging uses out of tree
|
||||
// could be found, and it was rife with misvehavior including arbitrary file writes as root
|
||||
// when run a prepared input. we have opted to remove it instead of trying to make it safe.
|
||||
addFlag({
|
||||
.longName = "write-to",
|
||||
.description = "Write a string or attrset of strings to *path*.",
|
||||
.description = "Previously used to write a string or attrset of strings to *path*.",
|
||||
.labels = {"path"},
|
||||
.handler = {&writeTo},
|
||||
.hidden = true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -59,6 +63,13 @@ struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
|
||||
if (raw && json)
|
||||
throw UsageError("--raw and --json are mutually exclusive");
|
||||
|
||||
if (writeTo) {
|
||||
throw UsageError(
|
||||
"--write-to has been removed because it was insecure and broken, please use "
|
||||
"structured output formats (e.g. via --json) instead"
|
||||
);
|
||||
}
|
||||
|
||||
auto const installableValue = InstallableValue::require(installable);
|
||||
|
||||
auto evaluator = getEvaluator();
|
||||
@@ -75,54 +86,18 @@ struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
|
||||
v = vRes;
|
||||
}
|
||||
|
||||
if (writeTo) {
|
||||
logger->pause();
|
||||
|
||||
if (pathExists(*writeTo))
|
||||
throw Error("path '%s' already exists", *writeTo);
|
||||
|
||||
std::function<void(Value & v, const PosIdx pos, const Path & path, NeverAsync)> recurse;
|
||||
|
||||
recurse = [&](Value & v, const PosIdx pos, const Path & path, NeverAsync)
|
||||
{
|
||||
state->forceValue(v, pos);
|
||||
if (v.type() == nString)
|
||||
// FIXME: disallow strings with contexts?
|
||||
writeFile(path, v.str());
|
||||
else if (v.type() == nAttrs) {
|
||||
if (mkdir(path.c_str(), 0777) == -1)
|
||||
throw SysError("creating directory '%s'", path);
|
||||
for (auto & attr : *v.attrs) {
|
||||
std::string_view name = evaluator->symbols[attr.name];
|
||||
try {
|
||||
if (name == "." || name == "..")
|
||||
throw Error("invalid file name '%s'", name);
|
||||
recurse(*attr.value, attr.pos, concatStrings(path, "/", name), {});
|
||||
} catch (Error & e) {
|
||||
e.addTrace(
|
||||
evaluator->positions[attr.pos],
|
||||
HintFmt("while evaluating the attribute '%s'", name));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
evaluator->errors.make<TypeError>("value at '%s' is not a string or an attribute set", evaluator->positions[pos]).debugThrow();
|
||||
};
|
||||
|
||||
recurse(*v, pos, *writeTo, {});
|
||||
}
|
||||
|
||||
else if (raw) {
|
||||
if (raw) {
|
||||
logger->pause();
|
||||
writeFull(STDOUT_FILENO, *state->coerceToString(noPos, *v, context, "while generating the eval command output"));
|
||||
}
|
||||
|
||||
else if (json) {
|
||||
else if (json)
|
||||
{
|
||||
logger->cout("%s", printValueAsJSON(*state, true, *v, pos, context, false));
|
||||
}
|
||||
|
||||
else {
|
||||
else
|
||||
{
|
||||
logger->cout(
|
||||
"%s",
|
||||
ValuePrinter(
|
||||
|
||||
@@ -41,15 +41,6 @@ R""(
|
||||
# nix eval nix#checks.x86_64-linux --apply builtins.attrNames
|
||||
```
|
||||
|
||||
* Generate a directory with the specified contents:
|
||||
|
||||
```console
|
||||
# nix eval --write-to ./out --expr '{ foo = "bar"; subdir.bla = "123"; }'
|
||||
# cat ./out/foo
|
||||
bar
|
||||
# cat ./out/subdir/bla
|
||||
123
|
||||
|
||||
# Description
|
||||
|
||||
This command evaluates the given Nix expression and prints the
|
||||
@@ -76,9 +67,4 @@ result on standard output.
|
||||
The output is printed exactly as-is, with no quotes, escaping, or trailing
|
||||
newline.
|
||||
|
||||
* With `--write-to` *path*, the evaluation result must be a string or
|
||||
a nested attribute set whose leaf values are strings. These strings
|
||||
are written to files named *path*/*attrpath*. *path* must not
|
||||
already exist.
|
||||
|
||||
)""
|
||||
|
||||
@@ -24,12 +24,4 @@ echo "$missingImpureErrorMsg" | grepQuiet -- --impure || \
|
||||
(! nix eval --expr "(import (builtins.fetchurl { url = \"file://$(pwd)/pure-eval.nix\"; })).x")
|
||||
nix eval --expr "(import (builtins.fetchurl { url = \"file://$(pwd)/pure-eval.nix\"; sha256 = \"$(nix hash file pure-eval.nix --type sha256)\"; })).x"
|
||||
|
||||
rm -rf $TEST_ROOT/eval-out
|
||||
nix eval --store dummy:// --write-to $TEST_ROOT/eval-out --expr '{ x = "foo" + "bar"; y = { z = "bla"; }; }'
|
||||
[[ $(cat $TEST_ROOT/eval-out/x) = foobar ]]
|
||||
[[ $(cat $TEST_ROOT/eval-out/y/z) = bla ]]
|
||||
|
||||
rm -rf $TEST_ROOT/eval-out
|
||||
(! nix eval --store dummy:// --write-to $TEST_ROOT/eval-out --expr '{ "." = "bla"; }')
|
||||
|
||||
(! nix eval --expr '~/foo')
|
||||
|
||||
Reference in New Issue
Block a user