Don't allow arbitrary computations in flake attributes
E.g. you can write 'edition = 201909' but not 'edition = 201909 + 0'. Fixes #3075.
This commit is contained in:
parent
2fa7f2a56a
commit
c87840ae14
|
@ -141,12 +141,12 @@ const Value *getPrimOp(const Value &v) {
|
|||
}
|
||||
|
||||
|
||||
string showType(const Value & v)
|
||||
string showType(ValueType type)
|
||||
{
|
||||
switch (v.type) {
|
||||
switch (type) {
|
||||
case tInt: return "an integer";
|
||||
case tBool: return "a boolean";
|
||||
case tString: return v.string.context ? "a string with context" : "a string";
|
||||
case tString: return "a string";
|
||||
case tPath: return "a path";
|
||||
case tNull: return "null";
|
||||
case tAttrs: return "a set";
|
||||
|
@ -155,14 +155,27 @@ string showType(const Value & v)
|
|||
case tApp: return "a function application";
|
||||
case tLambda: return "a function";
|
||||
case tBlackhole: return "a black hole";
|
||||
case tPrimOp: return "a built-in function";
|
||||
case tPrimOpApp: return "a partially applied built-in function";
|
||||
case tExternal: return "an external value";
|
||||
case tFloat: return "a float";
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
string showType(const Value & v)
|
||||
{
|
||||
switch (v.type) {
|
||||
case tString: return v.string.context ? "a string with context" : "a string";
|
||||
case tPrimOp:
|
||||
return fmt("the built-in function '%s'", string(v.primOp->name));
|
||||
case tPrimOpApp:
|
||||
return fmt("the partially applied built-in function '%s'", string(getPrimOp(v)->primOp->name));
|
||||
case tExternal: return v.external->showType();
|
||||
case tFloat: return "a float";
|
||||
default:
|
||||
return showType(v.type);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -338,6 +338,7 @@ private:
|
|||
|
||||
|
||||
/* Return a string representing the type of the value `v'. */
|
||||
string showType(ValueType type);
|
||||
string showType(const Value & v);
|
||||
|
||||
/* Decode a context string ‘!<name>!<path>’ into a pair <path,
|
||||
|
|
|
@ -195,6 +195,18 @@ static SourceInfo fetchFlake(EvalState & state, const FlakeRef & resolvedRef)
|
|||
else abort();
|
||||
}
|
||||
|
||||
static void expectType(EvalState & state, ValueType type,
|
||||
Value & value, const Pos & pos)
|
||||
{
|
||||
if (value.type == tThunk &&
|
||||
((type == tAttrs && dynamic_cast<ExprAttrs *>(value.thunk.expr)) ||
|
||||
(type == tLambda && dynamic_cast<ExprLambda *>(value.thunk.expr))))
|
||||
state.forceValue(value, pos);
|
||||
if (value.type != type)
|
||||
throw Error("expected %s but got %s at %s",
|
||||
showType(type), showType(value.type), pos);
|
||||
}
|
||||
|
||||
Flake getFlake(EvalState & state, const FlakeRef & flakeRef)
|
||||
{
|
||||
SourceInfo sourceInfo = fetchFlake(state, flakeRef);
|
||||
|
@ -219,9 +231,10 @@ Flake getFlake(EvalState & state, const FlakeRef & flakeRef)
|
|||
throw Error("source tree referenced by '%s' does not contain a '%s/flake.nix' file", resolvedRef, resolvedRef.subdir);
|
||||
|
||||
Value vInfo;
|
||||
// FIXME: don't evaluate vInfo.
|
||||
state.evalFile(realFlakeFile, vInfo); // FIXME: symlink attack
|
||||
|
||||
state.forceAttrs(vInfo);
|
||||
expectType(state, tAttrs, vInfo, Pos(state.symbols.create(realFlakeFile), 0, 0));
|
||||
|
||||
auto sEdition = state.symbols.create("edition");
|
||||
auto sEpoch = state.symbols.create("epoch"); // FIXME: remove soon
|
||||
|
@ -231,7 +244,8 @@ Flake getFlake(EvalState & state, const FlakeRef & flakeRef)
|
|||
edition = vInfo.attrs->get(sEpoch);
|
||||
|
||||
if (edition) {
|
||||
flake.edition = state.forceInt(*(**edition).value, *(**edition).pos);
|
||||
expectType(state, tInt, *(**edition).value, *(**edition).pos);
|
||||
flake.edition = (**edition).value->integer;
|
||||
if (flake.edition > 201909)
|
||||
throw Error("flake '%s' requires unsupported edition %d; please upgrade Nix", flakeRef, flake.edition);
|
||||
if (flake.edition < 201909)
|
||||
|
@ -239,26 +253,30 @@ Flake getFlake(EvalState & state, const FlakeRef & flakeRef)
|
|||
} else
|
||||
throw Error("flake '%s' lacks attribute 'edition'", flakeRef);
|
||||
|
||||
if (auto description = vInfo.attrs->get(state.sDescription))
|
||||
flake.description = state.forceStringNoCtx(*(**description).value, *(**description).pos);
|
||||
if (auto description = vInfo.attrs->get(state.sDescription)) {
|
||||
expectType(state, tString, *(**description).value, *(**description).pos);
|
||||
flake.description = (**description).value->string.s;
|
||||
}
|
||||
|
||||
auto sInputs = state.symbols.create("inputs");
|
||||
auto sUri = state.symbols.create("uri");
|
||||
auto sFlake = state.symbols.create("flake");
|
||||
|
||||
if (std::optional<Attr *> inputs = vInfo.attrs->get(sInputs)) {
|
||||
state.forceAttrs(*(**inputs).value, *(**inputs).pos);
|
||||
expectType(state, tAttrs, *(**inputs).value, *(**inputs).pos);
|
||||
|
||||
for (Attr inputAttr : *(*(**inputs).value).attrs) {
|
||||
state.forceAttrs(*inputAttr.value, *inputAttr.pos);
|
||||
expectType(state, tAttrs, *inputAttr.value, *inputAttr.pos);
|
||||
|
||||
FlakeInput input(FlakeRef(inputAttr.name));
|
||||
|
||||
for (Attr attr : *(inputAttr.value->attrs)) {
|
||||
if (attr.name == sUri) {
|
||||
input.ref = state.forceStringNoCtx(*attr.value, *attr.pos);
|
||||
expectType(state, tString, *attr.value, *attr.pos);
|
||||
input.ref = std::string(attr.value->string.s);
|
||||
} else if (attr.name == sFlake) {
|
||||
input.isFlake = state.forceBool(*attr.value, *attr.pos);
|
||||
expectType(state, tBool, *attr.value, *attr.pos);
|
||||
input.isFlake = attr.value->boolean;
|
||||
} else
|
||||
throw Error("flake input '%s' has an unsupported attribute '%s', at %s",
|
||||
inputAttr.name, attr.name, *attr.pos);
|
||||
|
@ -271,7 +289,7 @@ Flake getFlake(EvalState & state, const FlakeRef & flakeRef)
|
|||
auto sOutputs = state.symbols.create("outputs");
|
||||
|
||||
if (auto outputs = vInfo.attrs->get(sOutputs)) {
|
||||
state.forceFunction(*(**outputs).value, *(**outputs).pos);
|
||||
expectType(state, tLambda, *(**outputs).value, *(**outputs).pos);
|
||||
flake.vOutputs = (**outputs).value;
|
||||
|
||||
if (flake.vOutputs->lambda.fun->matchAttrs) {
|
||||
|
|
Loading…
Reference in a new issue