From c5f348db959b87a4b61806830989d5e927921c00 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 7 Nov 2025 00:16:03 -0500 Subject: [PATCH 1/3] Test output checks referring to other outputs `allowedReferences` and friends can, in addition to supporting store paths (and placeholders, but because those will be rewritten to store paths), they also support to refering to other outputs in the derivation by name. We update the tests in order to cover for that. (While we are at it, also introduce some scratch variables for paths and placeholders to make the C++ literalsf for this test more concise.) --- .../advanced-attributes-structured-attrs.json | 6 +- .../derivation/ca/advanced-attributes.json | 4 +- .../data/derivation/ca/all_set.json | 6 +- .../ca/structuredAttrs_all_set.json | 6 +- .../advanced-attributes-structured-attrs.json | 18 +++--- .../derivation/ia/advanced-attributes.json | 8 +-- .../data/derivation/ia/all_set.json | 6 +- .../ia/structuredAttrs_all_set.json | 6 +- .../derivation-advanced-attrs.cc | 63 ++++++++++++------- .../advanced-attributes-structured-attrs.nix | 10 ++- .../derivation/advanced-attributes.nix | 10 ++- .../advanced-attributes-structured-attrs.drv | 2 +- .../derivation/ca/advanced-attributes.drv | 2 +- .../advanced-attributes-structured-attrs.drv | 2 +- .../derivation/ia/advanced-attributes.drv | 2 +- 15 files changed, 95 insertions(+), 56 deletions(-) diff --git a/src/libstore-tests/data/derivation/ca/advanced-attributes-structured-attrs.json b/src/libstore-tests/data/derivation/ca/advanced-attributes-structured-attrs.json index 2a4e70558..95122ad41 100644 --- a/src/libstore-tests/data/derivation/ca/advanced-attributes-structured-attrs.json +++ b/src/libstore-tests/data/derivation/ca/advanced-attributes-structured-attrs.json @@ -69,7 +69,8 @@ "outputChecks": { "bin": { "disallowedReferences": [ - "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g" + "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g", + "dev" ], "disallowedRequisites": [ "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8" @@ -84,7 +85,8 @@ "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9" ], "allowedRequisites": [ - "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z" + "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z", + "bin" ] } }, diff --git a/src/libstore-tests/data/derivation/ca/advanced-attributes.json b/src/libstore-tests/data/derivation/ca/advanced-attributes.json index 55dbe62e0..6b77459bc 100644 --- a/src/libstore-tests/data/derivation/ca/advanced-attributes.json +++ b/src/libstore-tests/data/derivation/ca/advanced-attributes.json @@ -11,9 +11,9 @@ "__sandboxProfile": "sandcastle", "allowSubstitutes": "", "allowedReferences": "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9", - "allowedRequisites": "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z", + "allowedRequisites": "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z bin", "builder": "/bin/bash", - "disallowedReferences": "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g", + "disallowedReferences": "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g dev", "disallowedRequisites": "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8", "exportReferencesGraph": "refs1 /164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9 refs2 /nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv", "impureEnvVars": "UNICORN", diff --git a/src/libstore-tests/data/derivation/ca/all_set.json b/src/libstore-tests/data/derivation/ca/all_set.json index e06eada01..198356c64 100644 --- a/src/libstore-tests/data/derivation/ca/all_set.json +++ b/src/libstore-tests/data/derivation/ca/all_set.json @@ -23,10 +23,12 @@ "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9" ], "allowedRequisites": [ - "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z" + "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z", + "bin" ], "disallowedReferences": [ - "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g" + "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g", + "dev" ], "disallowedRequisites": [ "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8" diff --git a/src/libstore-tests/data/derivation/ca/structuredAttrs_all_set.json b/src/libstore-tests/data/derivation/ca/structuredAttrs_all_set.json index 2a321897c..f566c48dd 100644 --- a/src/libstore-tests/data/derivation/ca/structuredAttrs_all_set.json +++ b/src/libstore-tests/data/derivation/ca/structuredAttrs_all_set.json @@ -23,7 +23,8 @@ "allowedReferences": null, "allowedRequisites": null, "disallowedReferences": [ - "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g" + "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g", + "dev" ], "disallowedRequisites": [ "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8" @@ -46,7 +47,8 @@ "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9" ], "allowedRequisites": [ - "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z" + "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z", + "bin" ], "disallowedReferences": [], "disallowedRequisites": [], diff --git a/src/libstore-tests/data/derivation/ia/advanced-attributes-structured-attrs.json b/src/libstore-tests/data/derivation/ia/advanced-attributes-structured-attrs.json index e07d1294b..bbd68e087 100644 --- a/src/libstore-tests/data/derivation/ia/advanced-attributes-structured-attrs.json +++ b/src/libstore-tests/data/derivation/ia/advanced-attributes-structured-attrs.json @@ -5,9 +5,9 @@ ], "builder": "/bin/bash", "env": { - "bin": "/nix/store/33qms3h55wlaspzba3brlzlrm8m2239g-advanced-attributes-structured-attrs-bin", - "dev": "/nix/store/wyfgwsdi8rs851wmy1xfzdxy7y5vrg5l-advanced-attributes-structured-attrs-dev", - "out": "/nix/store/7cxy4zx1vqc885r4jl2l64pymqbdmhii-advanced-attributes-structured-attrs" + "bin": "/nix/store/cnpasdljgkhnwaf78cf3qygcp4qbki1c-advanced-attributes-structured-attrs-bin", + "dev": "/nix/store/ijq6mwpa9jbnpnl33qldfqihrr38kprx-advanced-attributes-structured-attrs-dev", + "out": "/nix/store/h1vh648d3p088kdimy0r8ngpfx7c3nzw-advanced-attributes-structured-attrs" }, "inputs": { "drvs": { @@ -33,13 +33,13 @@ "name": "advanced-attributes-structured-attrs", "outputs": { "bin": { - "path": "33qms3h55wlaspzba3brlzlrm8m2239g-advanced-attributes-structured-attrs-bin" + "path": "cnpasdljgkhnwaf78cf3qygcp4qbki1c-advanced-attributes-structured-attrs-bin" }, "dev": { - "path": "wyfgwsdi8rs851wmy1xfzdxy7y5vrg5l-advanced-attributes-structured-attrs-dev" + "path": "ijq6mwpa9jbnpnl33qldfqihrr38kprx-advanced-attributes-structured-attrs-dev" }, "out": { - "path": "7cxy4zx1vqc885r4jl2l64pymqbdmhii-advanced-attributes-structured-attrs" + "path": "h1vh648d3p088kdimy0r8ngpfx7c3nzw-advanced-attributes-structured-attrs" } }, "structuredAttrs": { @@ -66,7 +66,8 @@ "outputChecks": { "bin": { "disallowedReferences": [ - "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar" + "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar", + "dev" ], "disallowedRequisites": [ "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev" @@ -81,7 +82,8 @@ "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" ], "allowedRequisites": [ - "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev" + "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev", + "bin" ] } }, diff --git a/src/libstore-tests/data/derivation/ia/advanced-attributes.json b/src/libstore-tests/data/derivation/ia/advanced-attributes.json index 372b4fbb9..e2de9431b 100644 --- a/src/libstore-tests/data/derivation/ia/advanced-attributes.json +++ b/src/libstore-tests/data/derivation/ia/advanced-attributes.json @@ -11,14 +11,14 @@ "__sandboxProfile": "sandcastle", "allowSubstitutes": "", "allowedReferences": "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo", - "allowedRequisites": "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev", + "allowedRequisites": "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev bin", "builder": "/bin/bash", - "disallowedReferences": "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar", + "disallowedReferences": "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar dev", "disallowedRequisites": "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev", "exportReferencesGraph": "refs1 /nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo refs2 /nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv", "impureEnvVars": "UNICORN", "name": "advanced-attributes", - "out": "/nix/store/wyhpwd748pns4k7svh48wdrc8kvjk0ra-advanced-attributes", + "out": "/nix/store/ymqmybkq5j4nd1xplw6ccdpbjnfi017v-advanced-attributes", "preferLocalBuild": "1", "requiredSystemFeatures": "rainbow uid-range", "system": "my-system" @@ -47,7 +47,7 @@ "name": "advanced-attributes", "outputs": { "out": { - "path": "wyhpwd748pns4k7svh48wdrc8kvjk0ra-advanced-attributes" + "path": "ymqmybkq5j4nd1xplw6ccdpbjnfi017v-advanced-attributes" } }, "system": "my-system", diff --git a/src/libstore-tests/data/derivation/ia/all_set.json b/src/libstore-tests/data/derivation/ia/all_set.json index 62b6cdf97..8731ca3a2 100644 --- a/src/libstore-tests/data/derivation/ia/all_set.json +++ b/src/libstore-tests/data/derivation/ia/all_set.json @@ -23,10 +23,12 @@ "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" ], "allowedRequisites": [ - "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev" + "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev", + "bin" ], "disallowedReferences": [ - "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar" + "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar", + "dev" ], "disallowedRequisites": [ "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev" diff --git a/src/libstore-tests/data/derivation/ia/structuredAttrs_all_set.json b/src/libstore-tests/data/derivation/ia/structuredAttrs_all_set.json index 0fa383589..67fa634cf 100644 --- a/src/libstore-tests/data/derivation/ia/structuredAttrs_all_set.json +++ b/src/libstore-tests/data/derivation/ia/structuredAttrs_all_set.json @@ -23,7 +23,8 @@ "allowedReferences": null, "allowedRequisites": null, "disallowedReferences": [ - "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar" + "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar", + "dev" ], "disallowedRequisites": [ "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev" @@ -46,7 +47,8 @@ "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" ], "allowedRequisites": [ - "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev" + "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev", + "bin" ], "disallowedReferences": [], "disallowedRequisites": [], diff --git a/src/libstore-tests/derivation-advanced-attrs.cc b/src/libstore-tests/derivation-advanced-attrs.cc index 41538cdcc..f44e96cdd 100644 --- a/src/libstore-tests/derivation-advanced-attrs.cc +++ b/src/libstore-tests/derivation-advanced-attrs.cc @@ -127,6 +127,21 @@ TEST_ATERM_JSON(advancedAttributes_structuredAttrs_defaults, "advanced-attribute #undef TEST_ATERM_JSON +/** + * Since these are both repeated and sensative opaque values, it makes + * sense to give them names in this file. + */ +static std::string pathFoo = "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo", + pathFooDev = "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev", + pathBar = "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar", + pathBarDev = "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev", + pathBarDrvIA = "/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv", + pathBarDrvCA = "/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv", + placeholderFoo = "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9", + placeholderFooDev = "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z", + placeholderBar = "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g", + placeholderBarDev = "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"; + using ExportReferencesMap = decltype(DerivationOptions::exportReferencesGraph); static const DerivationOptions advancedAttributes_defaults = { @@ -216,16 +231,16 @@ DerivationOptions advancedAttributes_ia = { .outputChecks = DerivationOptions::OutputChecks{ .ignoreSelfRefs = true, - .allowedReferences = StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"}, - .disallowedReferences = StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"}, - .allowedRequisites = StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"}, - .disallowedRequisites = StringSet{"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"}, + .allowedReferences = StringSet{pathFoo}, + .disallowedReferences = StringSet{pathBar, "dev"}, + .allowedRequisites = StringSet{pathFooDev, "bin"}, + .disallowedRequisites = StringSet{pathBarDev}, }, .unsafeDiscardReferences = {}, .passAsFile = {}, .exportReferencesGraph{ - {"refs1", {"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"}}, - {"refs2", {"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"}}, + {"refs1", {pathFoo}}, + {"refs2", {pathBarDrvIA}}, }, .additionalSandboxProfile = "sandcastle", .noChroot = true, @@ -246,16 +261,16 @@ DerivationOptions advancedAttributes_ca = { .outputChecks = DerivationOptions::OutputChecks{ .ignoreSelfRefs = true, - .allowedReferences = StringSet{"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"}, - .disallowedReferences = StringSet{"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"}, - .allowedRequisites = StringSet{"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"}, - .disallowedRequisites = StringSet{"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"}, + .allowedReferences = StringSet{placeholderFoo}, + .disallowedReferences = StringSet{placeholderBar, "dev"}, + .allowedRequisites = StringSet{placeholderFooDev, "bin"}, + .disallowedRequisites = StringSet{placeholderBarDev}, }, .unsafeDiscardReferences = {}, .passAsFile = {}, .exportReferencesGraph{ - {"refs1", {"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"}}, - {"refs2", {"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"}}, + {"refs1", {placeholderFoo}}, + {"refs2", {pathBarDrvCA}}, }, .additionalSandboxProfile = "sandcastle", .noChroot = true, @@ -375,13 +390,13 @@ DerivationOptions advancedAttributes_structuredAttrs_ia = { std::map{ {"out", DerivationOptions::OutputChecks{ - .allowedReferences = StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"}, - .allowedRequisites = StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"}, + .allowedReferences = StringSet{pathFoo}, + .allowedRequisites = StringSet{pathFooDev, "bin"}, }}, {"bin", DerivationOptions::OutputChecks{ - .disallowedReferences = StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"}, - .disallowedRequisites = StringSet{"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"}, + .disallowedReferences = StringSet{pathBar, "dev"}, + .disallowedRequisites = StringSet{pathBarDev}, }}, {"dev", DerivationOptions::OutputChecks{ @@ -393,8 +408,8 @@ DerivationOptions advancedAttributes_structuredAttrs_ia = { .passAsFile = {}, .exportReferencesGraph = { - {"refs1", {"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"}}, - {"refs2", {"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"}}, + {"refs1", {pathFoo}}, + {"refs2", {pathBarDrvIA}}, }, .additionalSandboxProfile = "sandcastle", .noChroot = true, @@ -417,13 +432,13 @@ DerivationOptions advancedAttributes_structuredAttrs_ca = { std::map{ {"out", DerivationOptions::OutputChecks{ - .allowedReferences = StringSet{"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"}, - .allowedRequisites = StringSet{"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"}, + .allowedReferences = StringSet{placeholderFoo}, + .allowedRequisites = StringSet{placeholderFooDev, "bin"}, }}, {"bin", DerivationOptions::OutputChecks{ - .disallowedReferences = StringSet{"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"}, - .disallowedRequisites = StringSet{"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"}, + .disallowedReferences = StringSet{placeholderBar, "dev"}, + .disallowedRequisites = StringSet{placeholderBarDev}, }}, {"dev", DerivationOptions::OutputChecks{ @@ -435,8 +450,8 @@ DerivationOptions advancedAttributes_structuredAttrs_ca = { .passAsFile = {}, .exportReferencesGraph = { - {"refs1", {"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"}}, - {"refs2", {"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"}}, + {"refs1", {placeholderFoo}}, + {"refs2", {pathBarDrvCA}}, }, .additionalSandboxProfile = "sandcastle", .noChroot = true, diff --git a/tests/functional/derivation/advanced-attributes-structured-attrs.nix b/tests/functional/derivation/advanced-attributes-structured-attrs.nix index 46f619272..b11041303 100644 --- a/tests/functional/derivation/advanced-attributes-structured-attrs.nix +++ b/tests/functional/derivation/advanced-attributes-structured-attrs.nix @@ -66,10 +66,16 @@ derivation' { outputChecks = { out = { allowedReferences = [ foo ]; - allowedRequisites = [ foo.dev ]; + allowedRequisites = [ + foo.dev + "bin" + ]; }; bin = { - disallowedReferences = [ bar ]; + disallowedReferences = [ + bar + "dev" + ]; disallowedRequisites = [ bar.dev ]; }; dev = { diff --git a/tests/functional/derivation/advanced-attributes.nix b/tests/functional/derivation/advanced-attributes.nix index dd0c09e22..19a80f15d 100644 --- a/tests/functional/derivation/advanced-attributes.nix +++ b/tests/functional/derivation/advanced-attributes.nix @@ -58,8 +58,14 @@ derivation' { impureEnvVars = [ "UNICORN" ]; __darwinAllowLocalNetworking = true; allowedReferences = [ foo ]; - allowedRequisites = [ foo.dev ]; - disallowedReferences = [ bar ]; + allowedRequisites = [ + foo.dev + "bin" + ]; + disallowedReferences = [ + bar + "dev" + ]; disallowedRequisites = [ bar.dev ]; requiredSystemFeatures = [ "rainbow" diff --git a/tests/functional/derivation/ca/advanced-attributes-structured-attrs.drv b/tests/functional/derivation/ca/advanced-attributes-structured-attrs.drv index cd02c2f86..eeaba88e6 100644 --- a/tests/functional/derivation/ca/advanced-attributes-structured-attrs.drv +++ b/tests/functional/derivation/ca/advanced-attributes-structured-attrs.drv @@ -1 +1 @@ -Derive([("bin","","r:sha256",""),("dev","","r:sha256",""),("out","","r:sha256","")],[("/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",["dev","out"]),("/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",["dev","out"])],["/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__json","{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"exportReferencesGraph\":{\"refs1\":[\"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9\"],\"refs2\":[\"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv\"]},\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g\"],\"disallowedRequisites\":[\"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9\"],\"allowedRequisites\":[\"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z\"]}},\"outputHashAlgo\":\"sha256\",\"outputHashMode\":\"recursive\",\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}"),("bin","/04f3da1kmbr67m3gzxikmsl4vjz5zf777sv6m14ahv22r65aac9m"),("dev","/02qcpld1y6xhs5gz9bchpxaw0xdhmsp5dv88lh25r2ss44kh8dxz"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9")]) \ No newline at end of file +Derive([("bin","","r:sha256",""),("dev","","r:sha256",""),("out","","r:sha256","")],[("/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",["dev","out"]),("/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",["dev","out"])],["/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__json","{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"exportReferencesGraph\":{\"refs1\":[\"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9\"],\"refs2\":[\"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv\"]},\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g\",\"dev\"],\"disallowedRequisites\":[\"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9\"],\"allowedRequisites\":[\"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z\",\"bin\"]}},\"outputHashAlgo\":\"sha256\",\"outputHashMode\":\"recursive\",\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}"),("bin","/04f3da1kmbr67m3gzxikmsl4vjz5zf777sv6m14ahv22r65aac9m"),("dev","/02qcpld1y6xhs5gz9bchpxaw0xdhmsp5dv88lh25r2ss44kh8dxz"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9")]) \ No newline at end of file diff --git a/tests/functional/derivation/ca/advanced-attributes.drv b/tests/functional/derivation/ca/advanced-attributes.drv index 068cb593e..ee5968cdc 100644 --- a/tests/functional/derivation/ca/advanced-attributes.drv +++ b/tests/functional/derivation/ca/advanced-attributes.drv @@ -1 +1 @@ -Derive([("out","","r:sha256","")],[("/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",["dev","out"]),("/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",["dev","out"])],["/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__darwinAllowLocalNetworking","1"),("__impureHostDeps","/usr/bin/ditto"),("__noChroot","1"),("__sandboxProfile","sandcastle"),("allowSubstitutes",""),("allowedReferences","/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"),("allowedRequisites","/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"),("builder","/bin/bash"),("disallowedReferences","/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"),("disallowedRequisites","/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"),("exportReferencesGraph","refs1 /164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9 refs2 /nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"),("impureEnvVars","UNICORN"),("name","advanced-attributes"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"),("outputHashAlgo","sha256"),("outputHashMode","recursive"),("preferLocalBuild","1"),("requiredSystemFeatures","rainbow uid-range"),("system","my-system")]) \ No newline at end of file +Derive([("out","","r:sha256","")],[("/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",["dev","out"]),("/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",["dev","out"])],["/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__darwinAllowLocalNetworking","1"),("__impureHostDeps","/usr/bin/ditto"),("__noChroot","1"),("__sandboxProfile","sandcastle"),("allowSubstitutes",""),("allowedReferences","/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"),("allowedRequisites","/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z bin"),("builder","/bin/bash"),("disallowedReferences","/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g dev"),("disallowedRequisites","/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"),("exportReferencesGraph","refs1 /164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9 refs2 /nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"),("impureEnvVars","UNICORN"),("name","advanced-attributes"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"),("outputHashAlgo","sha256"),("outputHashMode","recursive"),("preferLocalBuild","1"),("requiredSystemFeatures","rainbow uid-range"),("system","my-system")]) \ No newline at end of file diff --git a/tests/functional/derivation/ia/advanced-attributes-structured-attrs.drv b/tests/functional/derivation/ia/advanced-attributes-structured-attrs.drv index 1dfcac42d..0aa82e636 100644 --- a/tests/functional/derivation/ia/advanced-attributes-structured-attrs.drv +++ b/tests/functional/derivation/ia/advanced-attributes-structured-attrs.drv @@ -1 +1 @@ -Derive([("bin","/nix/store/33qms3h55wlaspzba3brlzlrm8m2239g-advanced-attributes-structured-attrs-bin","",""),("dev","/nix/store/wyfgwsdi8rs851wmy1xfzdxy7y5vrg5l-advanced-attributes-structured-attrs-dev","",""),("out","/nix/store/7cxy4zx1vqc885r4jl2l64pymqbdmhii-advanced-attributes-structured-attrs","","")],[("/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv",["dev","out"]),("/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv",["dev","out"])],["/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__json","{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"exportReferencesGraph\":{\"refs1\":[\"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo\"],\"refs2\":[\"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv\"]},\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar\"],\"disallowedRequisites\":[\"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo\"],\"allowedRequisites\":[\"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev\"]}},\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}"),("bin","/nix/store/33qms3h55wlaspzba3brlzlrm8m2239g-advanced-attributes-structured-attrs-bin"),("dev","/nix/store/wyfgwsdi8rs851wmy1xfzdxy7y5vrg5l-advanced-attributes-structured-attrs-dev"),("out","/nix/store/7cxy4zx1vqc885r4jl2l64pymqbdmhii-advanced-attributes-structured-attrs")]) \ No newline at end of file +Derive([("bin","/nix/store/cnpasdljgkhnwaf78cf3qygcp4qbki1c-advanced-attributes-structured-attrs-bin","",""),("dev","/nix/store/ijq6mwpa9jbnpnl33qldfqihrr38kprx-advanced-attributes-structured-attrs-dev","",""),("out","/nix/store/h1vh648d3p088kdimy0r8ngpfx7c3nzw-advanced-attributes-structured-attrs","","")],[("/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv",["dev","out"]),("/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv",["dev","out"])],["/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__json","{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"exportReferencesGraph\":{\"refs1\":[\"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo\"],\"refs2\":[\"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv\"]},\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar\",\"dev\"],\"disallowedRequisites\":[\"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo\"],\"allowedRequisites\":[\"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev\",\"bin\"]}},\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}"),("bin","/nix/store/cnpasdljgkhnwaf78cf3qygcp4qbki1c-advanced-attributes-structured-attrs-bin"),("dev","/nix/store/ijq6mwpa9jbnpnl33qldfqihrr38kprx-advanced-attributes-structured-attrs-dev"),("out","/nix/store/h1vh648d3p088kdimy0r8ngpfx7c3nzw-advanced-attributes-structured-attrs")]) \ No newline at end of file diff --git a/tests/functional/derivation/ia/advanced-attributes.drv b/tests/functional/derivation/ia/advanced-attributes.drv index c71a88886..4bc7320f5 100644 --- a/tests/functional/derivation/ia/advanced-attributes.drv +++ b/tests/functional/derivation/ia/advanced-attributes.drv @@ -1 +1 @@ -Derive([("out","/nix/store/wyhpwd748pns4k7svh48wdrc8kvjk0ra-advanced-attributes","","")],[("/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv",["dev","out"]),("/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv",["dev","out"])],["/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__darwinAllowLocalNetworking","1"),("__impureHostDeps","/usr/bin/ditto"),("__noChroot","1"),("__sandboxProfile","sandcastle"),("allowSubstitutes",""),("allowedReferences","/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"),("allowedRequisites","/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"),("builder","/bin/bash"),("disallowedReferences","/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"),("disallowedRequisites","/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"),("exportReferencesGraph","refs1 /nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo refs2 /nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"),("impureEnvVars","UNICORN"),("name","advanced-attributes"),("out","/nix/store/wyhpwd748pns4k7svh48wdrc8kvjk0ra-advanced-attributes"),("preferLocalBuild","1"),("requiredSystemFeatures","rainbow uid-range"),("system","my-system")]) \ No newline at end of file +Derive([("out","/nix/store/ymqmybkq5j4nd1xplw6ccdpbjnfi017v-advanced-attributes","","")],[("/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv",["dev","out"]),("/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv",["dev","out"])],["/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"],"my-system","/bin/bash",["-c","echo hello > $out"],[("__darwinAllowLocalNetworking","1"),("__impureHostDeps","/usr/bin/ditto"),("__noChroot","1"),("__sandboxProfile","sandcastle"),("allowSubstitutes",""),("allowedReferences","/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"),("allowedRequisites","/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev bin"),("builder","/bin/bash"),("disallowedReferences","/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar dev"),("disallowedRequisites","/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"),("exportReferencesGraph","refs1 /nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo refs2 /nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"),("impureEnvVars","UNICORN"),("name","advanced-attributes"),("out","/nix/store/ymqmybkq5j4nd1xplw6ccdpbjnfi017v-advanced-attributes"),("preferLocalBuild","1"),("requiredSystemFeatures","rainbow uid-range"),("system","my-system")]) \ No newline at end of file From 00d2bf91b23caa20197883d76b47dcce49ba0a2f Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 14 Apr 2025 14:26:13 -0400 Subject: [PATCH 2/3] Parse deriving paths in `DerivationOptions` This is an example of "Parse, don't validate" principle [1]. Before, we had a number of `StringSet`s in `DerivationOptions` that were not *actually* allowed to be arbitrary sets of strings. Instead, each set member had to be one of: - a store path - a CA "downstream placeholder" - an output name Only later, in the code that checks outputs, would these strings be further parsed to match these cases. (Actually, only 2 by that point, because the placeholders must be rewritten away by then.) Now, we fully parse everything up front, and have an "honest" data type that reflects these invariants: - store paths are parsed, stored as (opaque) deriving paths - CA "downstream placeholders" are rewritten to the output deriving paths they denote - output names are the only arbitrary strings left Since the first two cases both become deriving paths, that leaves us with a `std::variant` data type, which we use in our sets instead. Getting rid of placeholders is especially nice because we are replacing them with something much more internally-structured / transparent. [1]: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ Co-authored-by: Sergei Zimmerman --- .../data/derivation/ca/all_set.json | 37 +- .../ca/structuredAttrs_all_set.json | 37 +- .../data/derivation/ia/all_set.json | 22 +- .../ia/structuredAttrs_all_set.json | 22 +- .../derivation-advanced-attrs.cc | 165 ++++---- .../build/derivation-building-goal.cc | 17 +- src/libstore/build/derivation-check.cc | 47 ++- src/libstore/build/derivation-check.hh | 2 +- src/libstore/build/derivation-env-desugar.cc | 7 +- src/libstore/build/derivation-goal.cc | 4 +- src/libstore/derivation-options.cc | 387 +++++++++++++++--- src/libstore/downstream-placeholder.cc | 43 ++ .../nix/store/build/derivation-builder.hh | 2 +- .../store/build/derivation-building-goal.hh | 2 +- .../nix/store/build/derivation-env-desugar.hh | 6 +- .../include/nix/store/derivation-options.hh | 99 +++-- .../nix/store/downstream-placeholder.hh | 26 ++ .../include/nix/store/parsed-derivations.hh | 3 +- src/libstore/misc.cc | 5 +- src/libstore/parsed-derivations.cc | 6 +- src/nix/nix-build/nix-build.cc | 4 +- tests/functional/check-refs.sh | 2 +- 22 files changed, 701 insertions(+), 244 deletions(-) diff --git a/src/libstore-tests/data/derivation/ca/all_set.json b/src/libstore-tests/data/derivation/ca/all_set.json index 198356c64..8086c752c 100644 --- a/src/libstore-tests/data/derivation/ca/all_set.json +++ b/src/libstore-tests/data/derivation/ca/all_set.json @@ -4,10 +4,13 @@ "allowSubstitutes": false, "exportReferencesGraph": { "refs1": [ - "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9" + { + "drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv", + "output": "out" + } ], "refs2": [ - "/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv" + "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv" ] }, "impureEnvVars": [ @@ -20,18 +23,36 @@ "outputChecks": { "forAllOutputs": { "allowedReferences": [ - "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9" + { + "drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv", + "output": "out" + } ], "allowedRequisites": [ - "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z", - "bin" + { + "drvPath": "self", + "output": "bin" + }, + { + "drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv", + "output": "dev" + } ], "disallowedReferences": [ - "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g", - "dev" + { + "drvPath": "self", + "output": "dev" + }, + { + "drvPath": "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv", + "output": "out" + } ], "disallowedRequisites": [ - "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8" + { + "drvPath": "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv", + "output": "dev" + } ], "ignoreSelfRefs": true, "maxClosureSize": null, diff --git a/src/libstore-tests/data/derivation/ca/structuredAttrs_all_set.json b/src/libstore-tests/data/derivation/ca/structuredAttrs_all_set.json index f566c48dd..e29447b6a 100644 --- a/src/libstore-tests/data/derivation/ca/structuredAttrs_all_set.json +++ b/src/libstore-tests/data/derivation/ca/structuredAttrs_all_set.json @@ -4,10 +4,13 @@ "allowSubstitutes": false, "exportReferencesGraph": { "refs1": [ - "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9" + { + "drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv", + "output": "out" + } ], "refs2": [ - "/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv" + "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv" ] }, "impureEnvVars": [ @@ -23,11 +26,20 @@ "allowedReferences": null, "allowedRequisites": null, "disallowedReferences": [ - "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g", - "dev" + { + "drvPath": "self", + "output": "dev" + }, + { + "drvPath": "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv", + "output": "out" + } ], "disallowedRequisites": [ - "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8" + { + "drvPath": "qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv", + "output": "dev" + } ], "ignoreSelfRefs": false, "maxClosureSize": null, @@ -44,11 +56,20 @@ }, "out": { "allowedReferences": [ - "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9" + { + "drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv", + "output": "out" + } ], "allowedRequisites": [ - "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z", - "bin" + { + "drvPath": "self", + "output": "bin" + }, + { + "drvPath": "j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv", + "output": "dev" + } ], "disallowedReferences": [], "disallowedRequisites": [], diff --git a/src/libstore-tests/data/derivation/ia/all_set.json b/src/libstore-tests/data/derivation/ia/all_set.json index 8731ca3a2..2e1c848da 100644 --- a/src/libstore-tests/data/derivation/ia/all_set.json +++ b/src/libstore-tests/data/derivation/ia/all_set.json @@ -4,10 +4,10 @@ "allowSubstitutes": false, "exportReferencesGraph": { "refs1": [ - "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" + "p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" ], "refs2": [ - "/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv" + "vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv" ] }, "impureEnvVars": [ @@ -20,18 +20,24 @@ "outputChecks": { "forAllOutputs": { "allowedReferences": [ - "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" + "p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" ], "allowedRequisites": [ - "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev", - "bin" + { + "drvPath": "self", + "output": "bin" + }, + "z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev" ], "disallowedReferences": [ - "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar", - "dev" + { + "drvPath": "self", + "output": "dev" + }, + "r5cff30838majxk5mp3ip2diffi8vpaj-bar" ], "disallowedRequisites": [ - "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev" + "9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev" ], "ignoreSelfRefs": true, "maxClosureSize": null, diff --git a/src/libstore-tests/data/derivation/ia/structuredAttrs_all_set.json b/src/libstore-tests/data/derivation/ia/structuredAttrs_all_set.json index 67fa634cf..a29699b5d 100644 --- a/src/libstore-tests/data/derivation/ia/structuredAttrs_all_set.json +++ b/src/libstore-tests/data/derivation/ia/structuredAttrs_all_set.json @@ -4,10 +4,10 @@ "allowSubstitutes": false, "exportReferencesGraph": { "refs1": [ - "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" + "p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" ], "refs2": [ - "/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv" + "vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv" ] }, "impureEnvVars": [ @@ -23,11 +23,14 @@ "allowedReferences": null, "allowedRequisites": null, "disallowedReferences": [ - "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar", - "dev" + { + "drvPath": "self", + "output": "dev" + }, + "r5cff30838majxk5mp3ip2diffi8vpaj-bar" ], "disallowedRequisites": [ - "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev" + "9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev" ], "ignoreSelfRefs": false, "maxClosureSize": null, @@ -44,11 +47,14 @@ }, "out": { "allowedReferences": [ - "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" + "p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo" ], "allowedRequisites": [ - "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev", - "bin" + { + "drvPath": "self", + "output": "bin" + }, + "z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev" ], "disallowedReferences": [], "disallowedRequisites": [], diff --git a/src/libstore-tests/derivation-advanced-attrs.cc b/src/libstore-tests/derivation-advanced-attrs.cc index f44e96cdd..27b8aba16 100644 --- a/src/libstore-tests/derivation-advanced-attrs.cc +++ b/src/libstore-tests/derivation-advanced-attrs.cc @@ -3,7 +3,7 @@ #include "nix/util/experimental-features.hh" #include "nix/store/derivations.hh" -#include "nix/store/derivations.hh" +#include "nix/store/derived-path.hh" #include "nix/store/derivation-options.hh" #include "nix/store/parsed-derivations.hh" #include "nix/util/types.hh" @@ -17,7 +17,7 @@ namespace nix { using namespace nlohmann; class DerivationAdvancedAttrsTest : public JsonCharacterizationTest, - public JsonCharacterizationTest, + public JsonCharacterizationTest>, public LibStoreTest { protected: @@ -42,7 +42,8 @@ public: { this->readTest(fileName, [&](auto encoded) { auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings); - DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs); + auto options = derivationOptionsFromStructuredAttrs( + *this->store, got.inputDrvs, got.env, got.structuredAttrs, true, this->mockXpSettings); EXPECT_EQ(options.getRequiredSystemFeatures(got), expectedFeatures); }); } @@ -51,11 +52,14 @@ public: * Helper function to test DerivationOptions parsing and comparison */ void testDerivationOptions( - const std::string & fileName, const DerivationOptions & expected, const StringSet & expectedSystemFeatures) + const std::string & fileName, + const DerivationOptions & expected, + const StringSet & expectedSystemFeatures) { this->readTest(fileName, [&](auto encoded) { auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings); - DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs); + auto options = derivationOptionsFromStructuredAttrs( + *this->store, got.inputDrvs, got.env, got.structuredAttrs, true, this->mockXpSettings); EXPECT_EQ(options, expected); EXPECT_EQ(options.getRequiredSystemFeatures(got), expectedSystemFeatures); @@ -131,22 +135,38 @@ TEST_ATERM_JSON(advancedAttributes_structuredAttrs_defaults, "advanced-attribute * Since these are both repeated and sensative opaque values, it makes * sense to give them names in this file. */ -static std::string pathFoo = "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo", - pathFooDev = "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev", - pathBar = "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar", - pathBarDev = "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev", - pathBarDrvIA = "/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv", - pathBarDrvCA = "/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv", - placeholderFoo = "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9", - placeholderFooDev = "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z", - placeholderBar = "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g", - placeholderBarDev = "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"; +static SingleDerivedPath + pathFoo = SingleDerivedPath::Opaque{StorePath{"p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"}}, + pathFooDev = SingleDerivedPath::Opaque{StorePath{"z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"}}, + pathBar = SingleDerivedPath::Opaque{StorePath{"r5cff30838majxk5mp3ip2diffi8vpaj-bar"}}, + pathBarDev = SingleDerivedPath::Opaque{StorePath{"9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"}}, + pathBarDrvIA = SingleDerivedPath::Opaque{StorePath{"vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"}}, + pathBarDrvCA = SingleDerivedPath::Opaque{StorePath{"qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"}}, + placeholderFoo = + SingleDerivedPath::Built{ + .drvPath = makeConstantStorePathRef(StorePath{"j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv"}), + .output = "out", + }, + placeholderFooDev = + SingleDerivedPath::Built{ + .drvPath = makeConstantStorePathRef(StorePath{"j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv"}), + .output = "dev", + }, + placeholderBar = + SingleDerivedPath::Built{ + .drvPath = makeConstantStorePathRef(StorePath{"qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"}), + .output = "out", + }, + placeholderBarDev = SingleDerivedPath::Built{ + .drvPath = makeConstantStorePathRef(StorePath{"qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"}), + .output = "dev", + }; -using ExportReferencesMap = decltype(DerivationOptions::exportReferencesGraph); +using ExportReferencesMap = decltype(DerivationOptions::exportReferencesGraph); -static const DerivationOptions advancedAttributes_defaults = { +static const DerivationOptions advancedAttributes_defaults = { .outputChecks = - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .ignoreSelfRefs = true, }, .unsafeDiscardReferences = {}, @@ -167,7 +187,8 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_defaults) this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) { auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings); - DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs); + auto options = derivationOptionsFromStructuredAttrs( + *this->store, got.inputDrvs, got.env, got.structuredAttrs, true, this->mockXpSettings); EXPECT_TRUE(!got.structuredAttrs); @@ -192,9 +213,9 @@ TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_defaults) TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes) { - DerivationOptions expected = { + DerivationOptions expected = { .outputChecks = - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .ignoreSelfRefs = true, }, .unsafeDiscardReferences = {}, @@ -212,12 +233,13 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes) this->readTest("advanced-attributes.drv", [&](auto encoded) { auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings); - DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs); + auto options = derivationOptionsFromStructuredAttrs( + *this->store, got.inputDrvs, got.env, got.structuredAttrs, true, this->mockXpSettings); EXPECT_TRUE(!got.structuredAttrs); // Reset fields that vary between test cases to enable whole-object comparison - options.outputChecks = DerivationOptions::OutputChecks{.ignoreSelfRefs = true}; + options.outputChecks = DerivationOptions::OutputChecks{.ignoreSelfRefs = true}; options.exportReferencesGraph = {}; EXPECT_EQ(options, expected); @@ -227,14 +249,14 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes) }); }; -DerivationOptions advancedAttributes_ia = { +DerivationOptions advancedAttributes_ia = { .outputChecks = - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .ignoreSelfRefs = true, - .allowedReferences = StringSet{pathFoo}, - .disallowedReferences = StringSet{pathBar, "dev"}, - .allowedRequisites = StringSet{pathFooDev, "bin"}, - .disallowedRequisites = StringSet{pathBarDev}, + .allowedReferences = std::set>{pathFoo}, + .disallowedReferences = std::set>{pathBar, OutputName{"dev"}}, + .allowedRequisites = std::set>{pathFooDev, OutputName{"bin"}}, + .disallowedRequisites = std::set>{pathBarDev}, }, .unsafeDiscardReferences = {}, .passAsFile = {}, @@ -257,14 +279,14 @@ TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_ia) testDerivationOptions("advanced-attributes.drv", advancedAttributes_ia, {"rainbow", "uid-range"}); }; -DerivationOptions advancedAttributes_ca = { +DerivationOptions advancedAttributes_ca = { .outputChecks = - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .ignoreSelfRefs = true, - .allowedReferences = StringSet{placeholderFoo}, - .disallowedReferences = StringSet{placeholderBar, "dev"}, - .allowedRequisites = StringSet{placeholderFooDev, "bin"}, - .disallowedRequisites = StringSet{placeholderBarDev}, + .allowedReferences = std::set>{placeholderFoo}, + .disallowedReferences = std::set>{placeholderBar, OutputName{"dev"}}, + .allowedRequisites = std::set>{placeholderFooDev, OutputName{"bin"}}, + .disallowedRequisites = std::set>{placeholderBarDev}, }, .unsafeDiscardReferences = {}, .passAsFile = {}, @@ -287,8 +309,8 @@ TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes) testDerivationOptions("advanced-attributes.drv", advancedAttributes_ca, {"rainbow", "uid-range", "ca-derivations"}); }; -DerivationOptions advancedAttributes_structuredAttrs_defaults = { - .outputChecks = std::map{}, +DerivationOptions advancedAttributes_structuredAttrs_defaults = { + .outputChecks = std::map::OutputChecks>{}, .unsafeDiscardReferences = {}, .passAsFile = {}, .exportReferencesGraph = {}, @@ -307,7 +329,8 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs_d this->readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) { auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings); - DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs); + auto options = derivationOptionsFromStructuredAttrs( + *this->store, got.inputDrvs, got.env, got.structuredAttrs, true, this->mockXpSettings); EXPECT_TRUE(got.structuredAttrs); @@ -332,11 +355,11 @@ TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs_default TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs) { - DerivationOptions expected = { + DerivationOptions expected = { .outputChecks = - std::map{ + std::map::OutputChecks>{ {"dev", - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .maxSize = 789, .maxClosureSize = 5909, }}, @@ -357,7 +380,8 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs) this->readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) { auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings); - DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs); + auto options = derivationOptionsFromStructuredAttrs( + *this->store, got.inputDrvs, got.env, got.structuredAttrs, true, this->mockXpSettings); EXPECT_TRUE(got.structuredAttrs); @@ -365,7 +389,8 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs) { // Delete all keys but "dev" in options.outputChecks auto * outputChecksMapP = - std::get_if>(&options.outputChecks); + std::get_if::OutputChecks>>( + &options.outputChecks); ASSERT_TRUE(outputChecksMapP); auto & outputChecksMap = *outputChecksMapP; auto devEntry = outputChecksMap.find("dev"); @@ -385,21 +410,21 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs) }); }; -DerivationOptions advancedAttributes_structuredAttrs_ia = { +DerivationOptions advancedAttributes_structuredAttrs_ia = { .outputChecks = - std::map{ + std::map::OutputChecks>{ {"out", - DerivationOptions::OutputChecks{ - .allowedReferences = StringSet{pathFoo}, - .allowedRequisites = StringSet{pathFooDev, "bin"}, + DerivationOptions::OutputChecks{ + .allowedReferences = std::set>{pathFoo}, + .allowedRequisites = std::set>{pathFooDev, OutputName{"bin"}}, }}, {"bin", - DerivationOptions::OutputChecks{ - .disallowedReferences = StringSet{pathBar, "dev"}, - .disallowedRequisites = StringSet{pathBarDev}, + DerivationOptions::OutputChecks{ + .disallowedReferences = std::set>{pathBar, OutputName{"dev"}}, + .disallowedRequisites = std::set>{pathBarDev}, }}, {"dev", - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .maxSize = 789, .maxClosureSize = 5909, }}, @@ -427,21 +452,21 @@ TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs) "advanced-attributes-structured-attrs.drv", advancedAttributes_structuredAttrs_ia, {"rainbow", "uid-range"}); }; -DerivationOptions advancedAttributes_structuredAttrs_ca = { +DerivationOptions advancedAttributes_structuredAttrs_ca = { .outputChecks = - std::map{ + std::map::OutputChecks>{ {"out", - DerivationOptions::OutputChecks{ - .allowedReferences = StringSet{placeholderFoo}, - .allowedRequisites = StringSet{placeholderFooDev, "bin"}, + DerivationOptions::OutputChecks{ + .allowedReferences = std::set>{placeholderFoo}, + .allowedRequisites = std::set>{placeholderFooDev, OutputName{"bin"}}, }}, {"bin", - DerivationOptions::OutputChecks{ - .disallowedReferences = StringSet{placeholderBar, "dev"}, - .disallowedRequisites = StringSet{placeholderBarDev}, + DerivationOptions::OutputChecks{ + .disallowedReferences = std::set>{placeholderBar, OutputName{"dev"}}, + .disallowedRequisites = std::set>{placeholderBarDev}, }}, {"dev", - DerivationOptions::OutputChecks{ + DerivationOptions::OutputChecks{ .maxSize = 789, .maxClosureSize = 5909, }}, @@ -471,14 +496,16 @@ TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs) {"rainbow", "uid-range", "ca-derivations"}); }; -#define TEST_JSON_OPTIONS(FIXUTURE, VAR, VAR2) \ - TEST_F(FIXUTURE, DerivationOptions_##VAR##_from_json) \ - { \ - this->JsonCharacterizationTest::readJsonTest(#VAR, advancedAttributes_##VAR2); \ - } \ - TEST_F(FIXUTURE, DerivationOptions_##VAR##_to_json) \ - { \ - this->JsonCharacterizationTest::writeJsonTest(#VAR, advancedAttributes_##VAR2); \ +#define TEST_JSON_OPTIONS(FIXUTURE, VAR, VAR2) \ + TEST_F(FIXUTURE, DerivationOptions_##VAR##_from_json) \ + { \ + this->JsonCharacterizationTest>::readJsonTest( \ + #VAR, advancedAttributes_##VAR2); \ + } \ + TEST_F(FIXUTURE, DerivationOptions_##VAR##_to_json) \ + { \ + this->JsonCharacterizationTest>::writeJsonTest( \ + #VAR, advancedAttributes_##VAR2); \ } TEST_JSON_OPTIONS(DerivationAdvancedAttrsTest, defaults, defaults) diff --git a/src/libstore/build/derivation-building-goal.cc b/src/libstore/build/derivation-building-goal.cc index c72130142..41d76fbba 100644 --- a/src/libstore/build/derivation-building-goal.cc +++ b/src/libstore/build/derivation-building-goal.cc @@ -32,14 +32,27 @@ DerivationBuildingGoal::DerivationBuildingGoal( , drv{std::make_unique(drv)} , buildMode(buildMode) { + DerivationOptions temp; try { - drvOptions = - std::make_unique(DerivationOptions::fromStructuredAttrs(drv.env, drv.structuredAttrs)); + temp = derivationOptionsFromStructuredAttrs(worker.store, drv.inputDrvs, drv.env, drv.structuredAttrs); } catch (Error & e) { e.addTrace({}, "while parsing derivation '%s'", worker.store.printStorePath(drvPath)); throw; } + auto x = tryResolve( + temp, [&](ref drvPath, const std::string & outputName) -> std::optional { + try { + return resolveDerivedPath( + worker.store, SingleDerivedPath::Built{drvPath, outputName}, &worker.evalStore); + } catch (Error &) { + return std::nullopt; + } + }); + + assert(x); + drvOptions = std::make_unique>(*x); + name = fmt("building derivation '%s'", worker.store.printStorePath(drvPath)); trace("created"); diff --git a/src/libstore/build/derivation-check.cc b/src/libstore/build/derivation-check.cc index 181221ba5..e56b9fe49 100644 --- a/src/libstore/build/derivation-check.cc +++ b/src/libstore/build/derivation-check.cc @@ -11,7 +11,7 @@ void checkOutputs( Store & store, const StorePath & drvPath, const decltype(Derivation::outputs) & drvOutputs, - const decltype(DerivationOptions::outputChecks) & outputChecks, + const decltype(DerivationOptions::outputChecks) & outputChecks, const std::map & outputs) { std::map outputsByPath; @@ -85,7 +85,7 @@ void checkOutputs( return std::make_pair(std::move(pathsDone), closureSize); }; - auto applyChecks = [&](const DerivationOptions::OutputChecks & checks) { + auto applyChecks = [&](const DerivationOptions::OutputChecks & checks) { if (checks.maxSize && info.narSize > *checks.maxSize) throw BuildError( BuildResult::Failure::OutputRejected, @@ -105,28 +105,33 @@ void checkOutputs( *checks.maxClosureSize); } - auto checkRefs = [&](const StringSet & value, bool allowed, bool recursive) { + auto checkRefs = [&](const std::set> & value, bool allowed, bool recursive) { /* Parse a list of reference specifiers. Each element must either be a store path, or the symbolic name of the output of the derivation (such as `out'). */ StorePathSet spec; for (auto & i : value) { - if (store.isStorePath(i)) - spec.insert(store.parseStorePath(i)); - else if (auto output = get(outputs, i)) - spec.insert(output->path); - else { - std::string outputsListing = - concatMapStringsSep(", ", outputs, [](auto & o) { return o.first; }); - throw BuildError( - BuildResult::Failure::OutputRejected, - "derivation '%s' output check for '%s' contains an illegal reference specifier '%s'," - " expected store path or output name (one of [%s])", - store.printStorePath(drvPath), - outputName, - i, - outputsListing); - } + std::visit( + overloaded{ + [&](const StorePath & path) { spec.insert(path); }, + [&](const OutputName & refOutputName) { + if (auto output = get(outputs, refOutputName)) + spec.insert(output->path); + else { + std::string outputsListing = + concatMapStringsSep(", ", outputs, [](auto & o) { return o.first; }); + throw BuildError( + BuildResult::Failure::OutputRejected, + "derivation '%s' output check for '%s' contains output name '%s'," + " but this is not a valid output of this derivation." + " (Valid outputs are [%s].)", + store.printStorePath(drvPath), + outputName, + refOutputName, + outputsListing); + } + }}, + i); } auto used = recursive ? getClosure(info.path).first : info.references; @@ -180,8 +185,8 @@ void checkOutputs( std::visit( overloaded{ - [&](const DerivationOptions::OutputChecks & checks) { applyChecks(checks); }, - [&](const std::map & checksPerOutput) { + [&](const DerivationOptions::OutputChecks & checks) { applyChecks(checks); }, + [&](const std::map::OutputChecks> & checksPerOutput) { if (auto outputChecks = get(checksPerOutput, outputName)) applyChecks(*outputChecks); diff --git a/src/libstore/build/derivation-check.hh b/src/libstore/build/derivation-check.hh index b425c2ac5..01e6c5d56 100644 --- a/src/libstore/build/derivation-check.hh +++ b/src/libstore/build/derivation-check.hh @@ -21,7 +21,7 @@ void checkOutputs( Store & store, const StorePath & drvPath, const decltype(Derivation::outputs) & drvOutputs, - const decltype(DerivationOptions::outputChecks) & drvOptions, + const decltype(DerivationOptions::outputChecks) & drvOptions, const std::map & outputs); } // namespace nix diff --git a/src/libstore/build/derivation-env-desugar.cc b/src/libstore/build/derivation-env-desugar.cc index 8d552fc4d..75b62c116 100644 --- a/src/libstore/build/derivation-env-desugar.cc +++ b/src/libstore/build/derivation-env-desugar.cc @@ -18,7 +18,10 @@ std::string & DesugaredEnv::atFileEnvPair(std::string_view name, std::string fil } DesugaredEnv DesugaredEnv::create( - Store & store, const Derivation & drv, const DerivationOptions & drvOptions, const StorePathSet & inputPaths) + Store & store, + const Derivation & drv, + const DerivationOptions & drvOptions, + const StorePathSet & inputPaths) { DesugaredEnv res; @@ -46,7 +49,7 @@ DesugaredEnv DesugaredEnv::create( } /* Handle exportReferencesGraph(), if set. */ - for (auto & [fileName, storePaths] : drvOptions.getParsedExportReferencesGraph(store)) { + for (auto & [fileName, storePaths] : drvOptions.exportReferencesGraph) { /* Write closure info to . */ res.extraFiles.insert_or_assign( fileName, store.makeValidityRegistration(store.exportReferences(storePaths, inputPaths), false, false)); diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index 14aa044ea..a44b79f57 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -64,9 +64,9 @@ Goal::Co DerivationGoal::haveDerivation(bool storeDerivation) { trace("have derivation"); - auto drvOptions = [&]() -> DerivationOptions { + auto drvOptions = [&]() -> DerivationOptions { try { - return DerivationOptions::fromStructuredAttrs(drv->env, drv->structuredAttrs); + return derivationOptionsFromStructuredAttrs(worker.store, drv->inputDrvs, drv->env, drv->structuredAttrs); } catch (Error & e) { e.addTrace({}, "while parsing derivation '%s'", worker.store.printStorePath(drvPath)); throw; diff --git a/src/libstore/derivation-options.cc b/src/libstore/derivation-options.cc index 75313841c..8c71ef4b1 100644 --- a/src/libstore/derivation-options.cc +++ b/src/libstore/derivation-options.cc @@ -2,15 +2,18 @@ #include "nix/util/json-utils.hh" #include "nix/store/parsed-derivations.hh" #include "nix/store/derivations.hh" +#include "nix/store/derived-path.hh" #include "nix/store/store-api.hh" #include "nix/util/types.hh" #include "nix/util/util.hh" #include "nix/store/globals.hh" +#include "nix/util/variant-wrapper.hh" #include #include #include #include +#include namespace nix { @@ -90,14 +93,60 @@ getStringSetAttr(const StringMap & env, const StructuredAttrs * parsed, const st return ss ? (std::optional{StringSet{ss->begin(), ss->end()}}) : (std::optional{}); } -using OutputChecks = DerivationOptions::OutputChecks; +template +using OutputChecks = DerivationOptions::OutputChecks; -using OutputChecksVariant = std::variant>; +template +using OutputChecksVariant = std::variant, std::map>>; -DerivationOptions DerivationOptions::fromStructuredAttrs( - const StringMap & env, const std::optional & parsed, bool shouldWarn) +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const StringMap & env, + const StructuredAttrs * parsed, + bool shouldWarn, + const ExperimentalFeatureSettings & mockXpSettings) { - return fromStructuredAttrs(env, parsed ? &*parsed : nullptr); + /* Use the SingleDerivedPath version with empty inputDrvs, then + resolve. */ + DerivedPathMap emptyInputDrvs{}; + auto singleDerivedPathOptions = + derivationOptionsFromStructuredAttrs(store, emptyInputDrvs, env, parsed, shouldWarn, mockXpSettings); + + /* "Resolve" all SingleDerivedPath inputs to StorePath. */ + auto resolved = tryResolve( + singleDerivedPathOptions, + [&](ref drvPath, const std::string & outputName) -> std::optional { + // there should be nothing to resolve + assert(false); + }); + + /* Since we should never need to call the call back, there should be + no way it fails. */ + assert(resolved); + + return *resolved; +} + +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const StringMap & env, + const std::optional & parsed, + bool shouldWarn, + const ExperimentalFeatureSettings & mockXpSettings) +{ + return derivationOptionsFromStructuredAttrs(store, env, parsed ? &*parsed : nullptr, shouldWarn, mockXpSettings); +} + +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const DerivedPathMap & inputDrvs, + const StringMap & env, + const std::optional & parsed, + bool shouldWarn, + const ExperimentalFeatureSettings & mockXpSettings) +{ + return derivationOptionsFromStructuredAttrs( + store, inputDrvs, env, parsed ? &*parsed : nullptr, shouldWarn, mockXpSettings); } static void flatten(const nlohmann::json & value, StringSet & res) @@ -111,10 +160,63 @@ static void flatten(const nlohmann::json & value, StringSet & res) throw Error("'exportReferencesGraph' value is not an array or a string"); } -DerivationOptions -DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAttrs * parsed, bool shouldWarn) +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const DerivedPathMap & inputDrvs, + const StringMap & env, + const StructuredAttrs * parsed, + bool shouldWarn, + const ExperimentalFeatureSettings & mockXpSettings) { - DerivationOptions defaults = {}; + DerivationOptions defaults = {}; + + std::map placeholders; + if (mockXpSettings.isEnabled(Xp::CaDerivations)) { + /* Initialize placeholder map from inputDrvs */ + auto initPlaceholders = [&](this const auto & initPlaceholders, + ref basePath, + const DerivedPathMap::ChildNode & node) -> void { + for (const auto & outputName : node.value) { + auto built = SingleDerivedPath::Built{ + .drvPath = basePath, + .output = outputName, + }; + placeholders.insert_or_assign( + DownstreamPlaceholder::fromSingleDerivedPathBuilt(built, mockXpSettings).render(), + std::move(built)); + } + + for (const auto & [outputName, childNode] : node.childMap) { + initPlaceholders( + make_ref(SingleDerivedPath::Built{ + .drvPath = basePath, + .output = outputName, + }), + childNode); + } + }; + + for (const auto & [drvPath, outputs] : inputDrvs.map) { + auto basePath = make_ref(SingleDerivedPath::Opaque{drvPath}); + initPlaceholders(basePath, outputs); + } + } + + auto parseSingleDerivedPath = [&](const std::string & pathS) -> SingleDerivedPath { + if (auto it = placeholders.find(pathS); it != placeholders.end()) + return it->second; + else + return SingleDerivedPath::Opaque{store.toStorePath(pathS).first}; + }; + + auto parseRef = [&](const std::string & pathS) -> DrvRef { + if (auto it = placeholders.find(pathS); it != placeholders.end()) + return it->second; + if (store.isStorePath(pathS)) + return SingleDerivedPath::Opaque{store.toStorePath(pathS).first}; + else + return pathS; + }; if (shouldWarn && parsed) { auto & structuredAttrs = parsed->structuredAttrs; @@ -146,14 +248,14 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt } return { - .outputChecks = [&]() -> OutputChecksVariant { + .outputChecks = [&]() -> OutputChecksVariant { if (parsed) { auto & structuredAttrs = parsed->structuredAttrs; - std::map res; + std::map> res; if (auto * outputChecks = get(structuredAttrs, "outputChecks")) { for (auto & [outputName, output_] : getObject(*outputChecks)) { - OutputChecks checks; + OutputChecks checks; auto & output = getObject(output_); @@ -163,13 +265,14 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt if (auto maxClosureSize = get(output, "maxClosureSize")) checks.maxClosureSize = maxClosureSize->get(); - auto get_ = [&output = output](const std::string & name) -> std::optional { + auto get_ = + [&](const std::string & name) -> std::optional>> { if (auto i = get(output, name)) { - StringSet res; + std::set> res; for (auto j = i->begin(); j != i->end(); ++j) { if (!j->is_string()) throw Error("attribute '%s' must be a list of strings", name); - res.insert(j->get()); + res.insert(parseRef(j->get())); } return res; } @@ -178,7 +281,7 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt res.insert_or_assign( outputName, - OutputChecks{ + OutputChecks{ .maxSize = [&]() -> std::optional { if (auto maxSize = get(output, "maxSize")) return maxSize->get(); @@ -192,21 +295,32 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt return std::nullopt; }(), .allowedReferences = get_("allowedReferences"), - .disallowedReferences = get_("disallowedReferences").value_or(StringSet{}), + .disallowedReferences = + get_("disallowedReferences").value_or(std::set>{}), .allowedRequisites = get_("allowedRequisites"), - .disallowedRequisites = get_("disallowedRequisites").value_or(StringSet{}), + .disallowedRequisites = + get_("disallowedRequisites").value_or(std::set>{}), }); } } return res; } else { - return OutputChecks{ + auto parseRefSet = [&](const std::optional optionalStringSet) + -> std::optional>> { + if (!optionalStringSet) + return std::nullopt; + auto range = *optionalStringSet | std::views::transform(parseRef); + return std::set>(range.begin(), range.end()); + }; + return OutputChecks{ // legacy non-structured-attributes case .ignoreSelfRefs = true, - .allowedReferences = getStringSetAttr(env, parsed, "allowedReferences"), - .disallowedReferences = getStringSetAttr(env, parsed, "disallowedReferences").value_or(StringSet{}), - .allowedRequisites = getStringSetAttr(env, parsed, "allowedRequisites"), - .disallowedRequisites = getStringSetAttr(env, parsed, "disallowedRequisites").value_or(StringSet{}), + .allowedReferences = parseRefSet(getStringSetAttr(env, parsed, "allowedReferences")), + .disallowedReferences = parseRefSet(getStringSetAttr(env, parsed, "disallowedReferences")) + .value_or(std::set>{}), + .allowedRequisites = parseRefSet(getStringSetAttr(env, parsed, "allowedRequisites")), + .disallowedRequisites = parseRefSet(getStringSetAttr(env, parsed, "disallowedRequisites")) + .value_or(std::set>{}), }; } }(), @@ -245,16 +359,19 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt }(), .exportReferencesGraph = [&] { - std::map ret; + std::map> ret; if (parsed) { auto * e = optionalValueAt(parsed->structuredAttrs, "exportReferencesGraph"); if (!e || !e->is_object()) return ret; - for (auto & [key, value] : getObject(*e)) { + for (auto & [key, storePathsJson] : getObject(*e)) { StringSet ss; - flatten(value, ss); - ret.insert_or_assign(key, std::move(ss)); + flatten(storePathsJson, ss); + std::set storePaths; + for (auto & s : ss) + storePaths.insert(parseSingleDerivedPath(s)); + ret.insert_or_assign(key, std::move(storePaths)); } } else { auto s = getOr(env, "exportReferencesGraph", ""); @@ -268,7 +385,7 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt throw Error("invalid file name '%s' in 'exportReferencesGraph'", fileName); auto & storePathS = *i++; - ret.insert_or_assign(std::move(fileName), StringSet{storePathS}); + ret.insert_or_assign(std::move(fileName), std::set{parseSingleDerivedPath(storePathS)}); } } return ret; @@ -286,28 +403,8 @@ DerivationOptions::fromStructuredAttrs(const StringMap & env, const StructuredAt }; } -std::map -DerivationOptions::getParsedExportReferencesGraph(const StoreDirConfig & store) const -{ - std::map res; - - for (auto & [fileName, ss] : exportReferencesGraph) { - StorePathSet storePaths; - for (auto & storePathS : ss) { - if (!store.isInStore(storePathS)) - throw BuildError( - BuildResult::Failure::InputRejected, - "'exportReferencesGraph' contains a non-store path '%1%'", - storePathS); - storePaths.insert(store.toStorePath(storePathS).first); - } - res.insert_or_assign(fileName, storePaths); - } - - return res; -} - -StringSet DerivationOptions::getRequiredSystemFeatures(const BasicDerivation & drv) const +template +StringSet DerivationOptions::getRequiredSystemFeatures(const BasicDerivation & drv) const { // FIXME: cache this? StringSet res; @@ -318,7 +415,8 @@ StringSet DerivationOptions::getRequiredSystemFeatures(const BasicDerivation & d return res; } -bool DerivationOptions::canBuildLocally(Store & localStore, const BasicDerivation & drv) const +template +bool DerivationOptions::canBuildLocally(Store & localStore, const BasicDerivation & drv) const { if (drv.platform != settings.thisSystem.get() && !settings.extraPlatforms.get().count(drv.platform) && !drv.isBuiltin()) @@ -334,42 +432,194 @@ bool DerivationOptions::canBuildLocally(Store & localStore, const BasicDerivatio return true; } -bool DerivationOptions::willBuildLocally(Store & localStore, const BasicDerivation & drv) const +template +bool DerivationOptions::willBuildLocally(Store & localStore, const BasicDerivation & drv) const { return preferLocalBuild && canBuildLocally(localStore, drv); } -bool DerivationOptions::substitutesAllowed() const +template +bool DerivationOptions::substitutesAllowed() const { return settings.alwaysAllowSubstitutes ? true : allowSubstitutes; } -bool DerivationOptions::useUidRange(const BasicDerivation & drv) const +template +bool DerivationOptions::useUidRange(const BasicDerivation & drv) const { return getRequiredSystemFeatures(drv).count("uid-range"); } +std::optional> tryResolve( + const DerivationOptions & drvOptions, + std::function(ref drvPath, const std::string & outputName)> + queryResolutionChain) +{ + auto tryResolvePath = [&](const SingleDerivedPath & input) -> std::optional { + return std::visit( + overloaded{ + [](const SingleDerivedPath::Opaque & p) -> std::optional { return p.path; }, + [&](const SingleDerivedPath::Built & p) -> std::optional { + return queryResolutionChain(p.drvPath, p.output); + }}, + input.raw()); + }; + + auto tryResolveRef = [&](const DrvRef & ref) -> std::optional> { + return std::visit( + overloaded{ + [](const OutputName & outputName) -> std::optional> { return outputName; }, + [&](const SingleDerivedPath & input) -> std::optional> { + return tryResolvePath(input); + }}, + ref); + }; + + auto tryResolveRefSet = + [&](const std::set> & refSet) -> std::optional>> { + std::set> resolvedSet; + for (const auto & ref : refSet) { + auto resolvedRef = tryResolveRef(ref); + if (!resolvedRef) + return std::nullopt; + resolvedSet.insert(*resolvedRef); + } + return resolvedSet; + }; + + // Helper function to try resolving OutputChecks using functional style + auto tryResolveOutputChecks = [&](const DerivationOptions::OutputChecks & checks) + -> std::optional::OutputChecks> { + std::optional>> resolvedAllowedReferences; + if (checks.allowedReferences) { + resolvedAllowedReferences = tryResolveRefSet(*checks.allowedReferences); + if (!resolvedAllowedReferences) + return std::nullopt; + } + + std::optional>> resolvedAllowedRequisites; + if (checks.allowedRequisites) { + resolvedAllowedRequisites = tryResolveRefSet(*checks.allowedRequisites); + if (!resolvedAllowedRequisites) + return std::nullopt; + } + + auto resolvedDisallowedReferences = tryResolveRefSet(checks.disallowedReferences); + if (!resolvedDisallowedReferences) + return std::nullopt; + + auto resolvedDisallowedRequisites = tryResolveRefSet(checks.disallowedRequisites); + if (!resolvedDisallowedRequisites) + return std::nullopt; + + return DerivationOptions::OutputChecks{ + .ignoreSelfRefs = checks.ignoreSelfRefs, + .maxSize = checks.maxSize, + .maxClosureSize = checks.maxClosureSize, + .allowedReferences = resolvedAllowedReferences, + .disallowedReferences = *resolvedDisallowedReferences, + .allowedRequisites = resolvedAllowedRequisites, + .disallowedRequisites = *resolvedDisallowedRequisites, + }; + }; + + // Helper function to resolve exportReferencesGraph using functional style + auto tryResolveExportReferencesGraph = [&](const std::map> & exportGraph) + -> std::optional>> { + std::map> resolved; + for (const auto & [name, inputPaths] : exportGraph) { + std::set resolvedPaths; + for (const auto & inputPath : inputPaths) { + auto resolvedPath = tryResolvePath(inputPath); + if (!resolvedPath) + return std::nullopt; + resolvedPaths.insert(*resolvedPath); + } + resolved.emplace(name, std::move(resolvedPaths)); + } + return resolved; + }; + + // Resolve outputChecks using functional style with std::visit + auto resolvedOutputChecks = std::visit( + overloaded{ + [&](const DerivationOptions::OutputChecks & checks) + -> std::optional::OutputChecks, + std::map::OutputChecks>>> { + auto resolved = tryResolveOutputChecks(checks); + if (!resolved) + return std::nullopt; + return std::variant< + DerivationOptions::OutputChecks, + std::map::OutputChecks>>(*resolved); + }, + [&](const std::map::OutputChecks> & checksMap) + -> std::optional::OutputChecks, + std::map::OutputChecks>>> { + std::map::OutputChecks> resolvedMap; + for (const auto & [outputName, checks] : checksMap) { + auto resolved = tryResolveOutputChecks(checks); + if (!resolved) + return std::nullopt; + resolvedMap.emplace(outputName, *resolved); + } + return std::variant< + DerivationOptions::OutputChecks, + std::map::OutputChecks>>(resolvedMap); + }}, + drvOptions.outputChecks); + + if (!resolvedOutputChecks) + return std::nullopt; + + // Resolve exportReferencesGraph + auto resolvedExportGraph = tryResolveExportReferencesGraph(drvOptions.exportReferencesGraph); + if (!resolvedExportGraph) + return std::nullopt; + + // Return resolved DerivationOptions using designated initializers + return DerivationOptions{ + .outputChecks = *resolvedOutputChecks, + .unsafeDiscardReferences = drvOptions.unsafeDiscardReferences, + .passAsFile = drvOptions.passAsFile, + .exportReferencesGraph = *resolvedExportGraph, + .additionalSandboxProfile = drvOptions.additionalSandboxProfile, + .noChroot = drvOptions.noChroot, + .impureHostDeps = drvOptions.impureHostDeps, + .impureEnvVars = drvOptions.impureEnvVars, + .allowLocalNetworking = drvOptions.allowLocalNetworking, + .requiredSystemFeatures = drvOptions.requiredSystemFeatures, + .preferLocalBuild = drvOptions.preferLocalBuild, + .allowSubstitutes = drvOptions.allowSubstitutes, + }; +} + +template struct DerivationOptions; +template struct DerivationOptions; + } // namespace nix namespace nlohmann { using namespace nix; -DerivationOptions adl_serializer::from_json(const json & json_) +DerivationOptions adl_serializer>::from_json(const json & json_) { auto & json = getObject(json_); return { - .outputChecks = [&]() -> OutputChecksVariant { + .outputChecks = [&]() -> OutputChecksVariant { auto outputChecks = getObject(valueAt(json, "outputChecks")); auto forAllOutputsOpt = optionalValueAt(outputChecks, "forAllOutputs"); auto perOutputOpt = optionalValueAt(outputChecks, "perOutput"); if (forAllOutputsOpt && !perOutputOpt) { - return static_cast(*forAllOutputsOpt); + return static_cast>(*forAllOutputsOpt); } else if (perOutputOpt && !forAllOutputsOpt) { - return static_cast>(*perOutputOpt); + return static_cast>>(*perOutputOpt); } else { throw Error("Exactly one of 'perOutput' or 'forAllOutputs' is required"); } @@ -377,7 +627,7 @@ DerivationOptions adl_serializer::from_json(const json & json .unsafeDiscardReferences = valueAt(json, "unsafeDiscardReferences"), .passAsFile = getStringSet(valueAt(json, "passAsFile")), - .exportReferencesGraph = getMap(getObject(valueAt(json, "exportReferencesGraph")), getStringSet), + .exportReferencesGraph = valueAt(json, "exportReferencesGraph"), .additionalSandboxProfile = getString(valueAt(json, "additionalSandboxProfile")), .noChroot = getBoolean(valueAt(json, "noChroot")), @@ -391,16 +641,17 @@ DerivationOptions adl_serializer::from_json(const json & json }; } -void adl_serializer::to_json(json & json, const DerivationOptions & o) +void adl_serializer>::to_json( + json & json, const DerivationOptions & o) { json["outputChecks"] = std::visit( overloaded{ - [&](const OutputChecks & checks) { + [&](const OutputChecks & checks) { nlohmann::json outputChecks; outputChecks["forAllOutputs"] = checks; return outputChecks; }, - [&](const std::map & checksPerOutput) { + [&](const std::map> & checksPerOutput) { nlohmann::json outputChecks; outputChecks["perOutput"] = checksPerOutput; return outputChecks; @@ -432,7 +683,7 @@ static inline std::optional ptrToOwned(const json * ptr) return std::nullopt; } -DerivationOptions::OutputChecks adl_serializer::from_json(const json & json_) +OutputChecks adl_serializer>::from_json(const json & json_) { auto & json = getObject(json_); @@ -440,14 +691,16 @@ DerivationOptions::OutputChecks adl_serializer: .ignoreSelfRefs = getBoolean(valueAt(json, "ignoreSelfRefs")), .maxSize = ptrToOwned(getNullable(valueAt(json, "maxSize"))), .maxClosureSize = ptrToOwned(getNullable(valueAt(json, "maxClosureSize"))), - .allowedReferences = ptrToOwned(getNullable(valueAt(json, "allowedReferences"))), - .disallowedReferences = getStringSet(valueAt(json, "disallowedReferences")), - .allowedRequisites = ptrToOwned(getNullable(valueAt(json, "allowedRequisites"))), - .disallowedRequisites = getStringSet(valueAt(json, "disallowedRequisites")), + .allowedReferences = + ptrToOwned>>(getNullable(valueAt(json, "allowedReferences"))), + .disallowedReferences = valueAt(json, "disallowedReferences"), + .allowedRequisites = + ptrToOwned>>(getNullable(valueAt(json, "allowedRequisites"))), + .disallowedRequisites = valueAt(json, "disallowedRequisites"), }; } -void adl_serializer::to_json(json & json, const DerivationOptions::OutputChecks & c) +void adl_serializer>::to_json(json & json, const OutputChecks & c) { json["ignoreSelfRefs"] = c.ignoreSelfRefs; json["maxSize"] = c.maxSize; diff --git a/src/libstore/downstream-placeholder.cc b/src/libstore/downstream-placeholder.cc index 780717a62..73ed2b74a 100644 --- a/src/libstore/downstream-placeholder.cc +++ b/src/libstore/downstream-placeholder.cc @@ -1,5 +1,6 @@ #include "nix/store/downstream-placeholder.hh" #include "nix/store/derivations.hh" +#include "nix/util/json-utils.hh" namespace nix { @@ -49,3 +50,45 @@ DownstreamPlaceholder DownstreamPlaceholder::fromSingleDerivedPathBuilt( } } // namespace nix + +namespace nlohmann { + +using namespace nix; + +template +DrvRef adl_serializer>::from_json(const json & json) +{ + // OutputName case: { "drvPath": "self", "output": } + if (json.type() == nlohmann::json::value_t::object) { + auto & obj = getObject(json); + if (auto * drvPath_ = get(obj, "drvPath")) { + auto & drvPath = *drvPath_; + if (drvPath.type() == nlohmann::json::value_t::string && getString(drvPath) == "self") { + return getString(valueAt(obj, "output")); + } + } + } + + // Input case + return adl_serializer::from_json(json); +} + +template +void adl_serializer>::to_json(json & json, const DrvRef & ref) +{ + std::visit( + overloaded{ + [&](const OutputName & outputName) { + json = nlohmann::json::object(); + json["drvPath"] = "self"; + json["output"] = outputName; + }, + [&](const Item & item) { json = item; }, + }, + ref); +} + +template struct adl_serializer>; +template struct adl_serializer>; + +} // namespace nlohmann diff --git a/src/libstore/include/nix/store/build/derivation-builder.hh b/src/libstore/include/nix/store/build/derivation-builder.hh index 5eed38462..af84661e2 100644 --- a/src/libstore/include/nix/store/build/derivation-builder.hh +++ b/src/libstore/include/nix/store/build/derivation-builder.hh @@ -69,7 +69,7 @@ struct DerivationBuilderParams * * @todo this should be part of `Derivation`. */ - const DerivationOptions & drvOptions; + const DerivationOptions & drvOptions; // The remainder is state held during the build. diff --git a/src/libstore/include/nix/store/build/derivation-building-goal.hh b/src/libstore/include/nix/store/build/derivation-building-goal.hh index 547e533e2..8277d6b57 100644 --- a/src/libstore/include/nix/store/build/derivation-building-goal.hh +++ b/src/libstore/include/nix/store/build/derivation-building-goal.hh @@ -52,7 +52,7 @@ private: */ std::unique_ptr drv; - std::unique_ptr drvOptions; + std::unique_ptr> drvOptions; /** * The remainder is state held during the build. diff --git a/src/libstore/include/nix/store/build/derivation-env-desugar.hh b/src/libstore/include/nix/store/build/derivation-env-desugar.hh index 6e2efa6bb..a10ec9fa8 100644 --- a/src/libstore/include/nix/store/build/derivation-env-desugar.hh +++ b/src/libstore/include/nix/store/build/derivation-env-desugar.hh @@ -8,6 +8,7 @@ namespace nix { class Store; struct Derivation; +template struct DerivationOptions; /** @@ -77,7 +78,10 @@ struct DesugaredEnv * just part of `Derivation`. */ static DesugaredEnv create( - Store & store, const Derivation & drv, const DerivationOptions & drvOptions, const StorePathSet & inputPaths); + Store & store, + const Derivation & drv, + const DerivationOptions & drvOptions, + const StorePathSet & inputPaths); }; } // namespace nix diff --git a/src/libstore/include/nix/store/derivation-options.hh b/src/libstore/include/nix/store/derivation-options.hh index 88694f730..0b79af85d 100644 --- a/src/libstore/include/nix/store/derivation-options.hh +++ b/src/libstore/include/nix/store/derivation-options.hh @@ -8,7 +8,8 @@ #include "nix/util/types.hh" #include "nix/util/json-impls.hh" -#include "nix/store/path.hh" +#include "nix/store/store-dir-config.hh" +#include "nix/store/downstream-placeholder.hh" namespace nix { @@ -17,6 +18,9 @@ struct StoreDirConfig; struct BasicDerivation; struct StructuredAttrs; +template +struct DerivedPathMap; + /** * This represents all the special options on a `Derivation`. * @@ -34,6 +38,7 @@ struct StructuredAttrs; * separately. That would be nice to separate concerns, and not make any * environment variable names magical. */ +template struct DerivationOptions { struct OutputChecks @@ -41,13 +46,15 @@ struct DerivationOptions bool ignoreSelfRefs = false; std::optional maxSize, maxClosureSize; + using DrvRef = nix::DrvRef; + /** * env: allowedReferences * * A value of `nullopt` indicates that the check is skipped. * This means that all references are allowed. */ - std::optional allowedReferences; + std::optional> allowedReferences; /** * env: disallowedReferences @@ -55,21 +62,21 @@ struct DerivationOptions * No needed for `std::optional`, because skipping the check is * the same as disallowing the references. */ - StringSet disallowedReferences; + std::set disallowedReferences; /** * env: allowedRequisites * * See `allowedReferences` */ - std::optional allowedRequisites; + std::optional> allowedRequisites; /** * env: disallowedRequisites * * See `disallowedReferences` */ - StringSet disallowedRequisites; + std::set disallowedRequisites; bool operator==(const OutputChecks &) const = default; }; @@ -116,23 +123,7 @@ struct DerivationOptions * attributes give to the builder. The set of paths in the original JSON * is replaced with a list of `PathInfo` in JSON format. */ - std::map exportReferencesGraph; - - /** - * Once a derivations is resolved, the strings in in - * `exportReferencesGraph` should all be store paths (with possible - * suffix paths, but those are discarded). - * - * @return The parsed path set for for each key in the map. - * - * @todo Ideally, `exportReferencesGraph` would just store - * `StorePath`s for this, but we can't just do that, because for CA - * derivations they is actually in general `DerivedPath`s (via - * placeholder strings) until the derivation is resolved and exact - * inputs store paths are known. We can use better types for that - * too, but that is a longer project. - */ - std::map getParsedExportReferencesGraph(const StoreDirConfig & store) const; + std::map> exportReferencesGraph; /** * env: __sandboxProfile @@ -185,18 +176,6 @@ struct DerivationOptions bool operator==(const DerivationOptions &) const = default; - /** - * Parse this information from its legacy encoding as part of the - * environment. This should not be used with nice greenfield formats - * (e.g. JSON) but is necessary for supporting old formats (e.g. - * ATerm). - */ - static DerivationOptions - fromStructuredAttrs(const StringMap & env, const StructuredAttrs * parsed, bool shouldWarn = true); - - static DerivationOptions - fromStructuredAttrs(const StringMap & env, const std::optional & parsed, bool shouldWarn = true); - /** * @param drv Must be the same derivation we parsed this from. In * the future we'll flip things around so a `BasicDerivation` has @@ -222,7 +201,55 @@ struct DerivationOptions bool useUidRange(const BasicDerivation & drv) const; }; +extern template struct DerivationOptions; +extern template struct DerivationOptions; + +struct DerivationOutput; + +/** + * Parse this information from its legacy encoding as part of the + * environment. This should not be used with nice greenfield formats + * (e.g. JSON) but is necessary for supporting old formats (e.g. + * ATerm). + */ +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const DerivedPathMap & inputDrvs, + const StringMap & env, + const StructuredAttrs * parsed, + bool shouldWarn = true, + const ExperimentalFeatureSettings & mockXpSettings = experimentalFeatureSettings); + +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const DerivedPathMap & inputDrvs, + const StringMap & env, + const std::optional & parsed, + bool shouldWarn = true, + const ExperimentalFeatureSettings & mockXpSettings = experimentalFeatureSettings); + +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const StringMap & env, + const StructuredAttrs * parsed, + bool shouldWarn = true, + const ExperimentalFeatureSettings & mockXpSettings = experimentalFeatureSettings); + +DerivationOptions derivationOptionsFromStructuredAttrs( + const StoreDirConfig & store, + const StringMap & env, + const std::optional & parsed, + bool shouldWarn = true, + const ExperimentalFeatureSettings & mockXpSettings = experimentalFeatureSettings); + +std::optional> tryResolve( + const DerivationOptions & drvOptions, + std::function(ref drvPath, const std::string & outputName)> + queryResolutionChain); + }; // namespace nix -JSON_IMPL(DerivationOptions); -JSON_IMPL(DerivationOptions::OutputChecks) +JSON_IMPL(nix::DerivationOptions); +JSON_IMPL(nix::DerivationOptions); +JSON_IMPL(nix::DerivationOptions::OutputChecks) +JSON_IMPL(nix::DerivationOptions::OutputChecks) diff --git a/src/libstore/include/nix/store/downstream-placeholder.hh b/src/libstore/include/nix/store/downstream-placeholder.hh index ee4d9e3c2..ba3e9faef 100644 --- a/src/libstore/include/nix/store/downstream-placeholder.hh +++ b/src/libstore/include/nix/store/downstream-placeholder.hh @@ -2,11 +2,23 @@ ///@file #include "nix/util/hash.hh" +#include "nix/util/json-impls.hh" #include "nix/store/path.hh" #include "nix/store/derived-path.hh" namespace nix { +/** + * A reference is either to a to-be-registered output (by name), + * or to an already-registered store object (by `Input`). + * + * `Ref +using DrvRef = std::variant; + /** * Downstream Placeholders are opaque and almost certainly unique values * used to allow derivations to refer to store objects which are yet to @@ -92,3 +104,17 @@ public: }; } // namespace nix + +namespace nlohmann { + +template +struct adl_serializer> +{ + static nix::DrvRef from_json(const json & json); + static void to_json(json & json, const nix::DrvRef & t); +}; + +extern template struct adl_serializer>; +extern template struct adl_serializer>; + +} // namespace nlohmann diff --git a/src/libstore/include/nix/store/parsed-derivations.hh b/src/libstore/include/nix/store/parsed-derivations.hh index 52e97b0e7..098591310 100644 --- a/src/libstore/include/nix/store/parsed-derivations.hh +++ b/src/libstore/include/nix/store/parsed-derivations.hh @@ -9,6 +9,7 @@ namespace nix { class Store; +template struct DerivationOptions; struct DerivationOutput; @@ -47,7 +48,7 @@ struct StructuredAttrs nlohmann::json::object_t prepareStructuredAttrs( Store & store, - const DerivationOptions & drvOptions, + const DerivationOptions & drvOptions, const StorePathSet & inputPaths, const DerivationOutputs & outputs) const; diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc index 8b2a7287e..642ac0978 100644 --- a/src/libstore/misc.cc +++ b/src/libstore/misc.cc @@ -224,11 +224,12 @@ MissingPaths Store::queryMissing(const std::vector & targets) return; auto drv = make_ref(derivationFromPath(drvPath)); - DerivationOptions drvOptions; + DerivationOptions drvOptions; try { // FIXME: this is a lot of work just to get the value // of `allowSubstitutes`. - drvOptions = DerivationOptions::fromStructuredAttrs(drv->env, drv->structuredAttrs); + drvOptions = + derivationOptionsFromStructuredAttrs(*this, drv->inputDrvs, drv->env, drv->structuredAttrs); } catch (Error & e) { e.addTrace({}, "while parsing derivation '%s'", printStorePath(drvPath)); throw; diff --git a/src/libstore/parsed-derivations.cc b/src/libstore/parsed-derivations.cc index 8d147f65f..95434bd20 100644 --- a/src/libstore/parsed-derivations.cc +++ b/src/libstore/parsed-derivations.cc @@ -100,7 +100,7 @@ static nlohmann::json pathInfoToJSON(Store & store, const StorePathSet & storePa nlohmann::json::object_t StructuredAttrs::prepareStructuredAttrs( Store & store, - const DerivationOptions & drvOptions, + const DerivationOptions & drvOptions, const StorePathSet & inputPaths, const DerivationOutputs & outputs) const { @@ -114,8 +114,8 @@ nlohmann::json::object_t StructuredAttrs::prepareStructuredAttrs( json["outputs"] = std::move(outputsJson); /* Handle exportReferencesGraph. */ - for (auto & [key, storePaths] : drvOptions.getParsedExportReferencesGraph(store)) { - json[key] = pathInfoToJSON(store, store.exportReferences(storePaths, storePaths)); + for (auto & [key, storePaths] : drvOptions.exportReferencesGraph) { + json[key] = pathInfoToJSON(store, store.exportReferences(storePaths, inputPaths)); } return json; diff --git a/src/nix/nix-build/nix-build.cc b/src/nix/nix-build/nix-build.cc index 4d876c9eb..00ef32dfa 100644 --- a/src/nix/nix-build/nix-build.cc +++ b/src/nix/nix-build/nix-build.cc @@ -554,9 +554,9 @@ static void main_nix_build(int argc, char ** argv) env["NIX_STORE"] = store->storeDir; env["NIX_BUILD_CORES"] = fmt("%d", settings.buildCores ? settings.buildCores : settings.getDefaultCores()); - DerivationOptions drvOptions; + DerivationOptions drvOptions; try { - drvOptions = DerivationOptions::fromStructuredAttrs(drv.env, drv.structuredAttrs); + drvOptions = derivationOptionsFromStructuredAttrs(*store, drv.env, drv.structuredAttrs); } catch (Error & e) { e.addTrace({}, "while parsing derivation '%s'", store->printStorePath(packageInfo.requireDrvPath())); throw; diff --git a/tests/functional/check-refs.sh b/tests/functional/check-refs.sh index 590c3fb53..8eb6aaf68 100755 --- a/tests/functional/check-refs.sh +++ b/tests/functional/check-refs.sh @@ -64,5 +64,5 @@ fi if isDaemonNewer "2.28pre20241225"; then # test12 should fail (syntactically invalid). expectStderr 1 nix-build -vvv -o "$RESULT" check-refs.nix -A test12 >"$TEST_ROOT/test12.stderr" - grepQuiet -F "output check for 'lib' contains an illegal reference specifier 'dev', expected store path or output name (one of [lib, out])" < "$TEST_ROOT/test12.stderr" + grepQuiet -F "output check for 'lib' contains output name 'dev', but this is not a valid output of this derivation. (Valid outputs are [lib, out].)" < "$TEST_ROOT/test12.stderr" fi From f34fa2987083a153f4f15aec4e341af849712b88 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 7 Nov 2025 02:02:38 -0500 Subject: [PATCH 3/3] JSON Schema for `DerivationOutputs` Progress on #13570 --- doc/manual/meson.build | 2 +- doc/manual/package.nix | 1 + doc/manual/source/SUMMARY.md.in | 1 + .../protocols/json/derivation-options.md | 49 ++++ doc/manual/source/protocols/json/meson.build | 1 + .../json/schema/derivation-options-v1 | 1 + .../json/schema/derivation-options-v1.yaml | 242 ++++++++++++++++++ src/json-schema-checks/derivation-options | 1 + src/json-schema-checks/meson.build | 13 + 9 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 doc/manual/source/protocols/json/derivation-options.md create mode 120000 doc/manual/source/protocols/json/schema/derivation-options-v1 create mode 100644 doc/manual/source/protocols/json/schema/derivation-options-v1.yaml create mode 120000 src/json-schema-checks/derivation-options diff --git a/doc/manual/meson.build b/doc/manual/meson.build index 231f7b9f8..93c2f24d1 100644 --- a/doc/manual/meson.build +++ b/doc/manual/meson.build @@ -88,7 +88,7 @@ manual = custom_target( @0@ @INPUT0@ @CURRENT_SOURCE_DIR@ > @DEPFILE@ @0@ @INPUT1@ summary @2@ < @CURRENT_SOURCE_DIR@/source/SUMMARY.md.in > @2@/source/SUMMARY.md sed -e 's|@version@|@3@|g' < @INPUT2@ > @2@/book.toml - @4@ -r -L --include='*.md' @CURRENT_SOURCE_DIR@/ @2@/ + @4@ -r -L --exclude='*.drv' --include='*.md' @CURRENT_SOURCE_DIR@/ @2@/ (cd @2@; RUST_LOG=warn @1@ build -d @2@ 3>&2 2>&1 1>&3) | { grep -Fv "because fragment resolution isn't implemented" || :; } 3>&2 2>&1 1>&3 rm -rf @2@/manual mv @2@/html @2@/manual diff --git a/doc/manual/package.nix b/doc/manual/package.nix index 81061b7a1..c140b8fda 100644 --- a/doc/manual/package.nix +++ b/doc/manual/package.nix @@ -41,6 +41,7 @@ mkMesonDerivation (finalAttrs: { ../../src/libstore-tests/data/content-address ../../src/libstore-tests/data/store-path ../../src/libstore-tests/data/realisation + ../../src/libstore-tests/data/derivation ../../src/libstore-tests/data/derived-path ../../src/libstore-tests/data/path-info ../../src/libstore-tests/data/nar-info diff --git a/doc/manual/source/SUMMARY.md.in b/doc/manual/source/SUMMARY.md.in index 5be3d6a90..4d938da8e 100644 --- a/doc/manual/source/SUMMARY.md.in +++ b/doc/manual/source/SUMMARY.md.in @@ -125,6 +125,7 @@ - [Store Path](protocols/json/store-path.md) - [Store Object Info](protocols/json/store-object-info.md) - [Derivation](protocols/json/derivation.md) + - [Derivation Options](protocols/json/derivation-options.md) - [Deriving Path](protocols/json/deriving-path.md) - [Build Trace Entry](protocols/json/build-trace-entry.md) - [Build Result](protocols/json/build-result.md) diff --git a/doc/manual/source/protocols/json/derivation-options.md b/doc/manual/source/protocols/json/derivation-options.md new file mode 100644 index 000000000..1743fb7f6 --- /dev/null +++ b/doc/manual/source/protocols/json/derivation-options.md @@ -0,0 +1,49 @@ +{{#include derivation-options-v1-fixed.md}} + +## Examples + +### Input-addressed derivations + +#### Default options + +```json +{{#include schema/derivation-options-v1/ia/defaults.json}} +``` + +#### All options set + +```json +{{#include schema/derivation-options-v1/ia/all_set.json}} +``` + +#### Default options (structured attributes) + +```json +{{#include schema/derivation-options-v1/ia/structuredAttrs_defaults.json}} +``` + +#### All options set (structured attributes) + +```json +{{#include schema/derivation-options-v1/ia/structuredAttrs_all_set.json}} +``` + +### Content-addressed derivations + +#### All options set + +```json +{{#include schema/derivation-options-v1/ca/all_set.json}} +``` + +#### All options set (structured attributes) + +```json +{{#include schema/derivation-options-v1/ca/structuredAttrs_all_set.json}} +``` + + diff --git a/doc/manual/source/protocols/json/meson.build b/doc/manual/source/protocols/json/meson.build index 4ab94c63b..babf68a93 100644 --- a/doc/manual/source/protocols/json/meson.build +++ b/doc/manual/source/protocols/json/meson.build @@ -14,6 +14,7 @@ schemas = [ 'store-path-v1', 'store-object-info-v2', 'derivation-v4', + 'derivation-options-v1', 'deriving-path-v1', 'build-trace-entry-v1', 'build-result-v1', diff --git a/doc/manual/source/protocols/json/schema/derivation-options-v1 b/doc/manual/source/protocols/json/schema/derivation-options-v1 new file mode 120000 index 000000000..9332a5390 --- /dev/null +++ b/doc/manual/source/protocols/json/schema/derivation-options-v1 @@ -0,0 +1 @@ +../../../../../../src/libstore-tests/data/derivation \ No newline at end of file diff --git a/doc/manual/source/protocols/json/schema/derivation-options-v1.yaml b/doc/manual/source/protocols/json/schema/derivation-options-v1.yaml new file mode 100644 index 000000000..58ff07088 --- /dev/null +++ b/doc/manual/source/protocols/json/schema/derivation-options-v1.yaml @@ -0,0 +1,242 @@ +"$schema": "http://json-schema.org/draft-04/schema" +"$id": "https://nix.dev/manual/nix/latest/protocols/json/schema/derivation-options-v1.json" +title: Derivation Options +description: | + JSON representation of Nix's `DerivationOptions` type. + + This schema describes various build-time options and constraints that can be specified for a derivation. + + > **Warning** + > + > This JSON format is currently + > [**experimental**](@docroot@/development/experimental-features.md#xp-feature-nix-command) + > and subject to change. + +type: object +required: + - outputChecks + - unsafeDiscardReferences + - passAsFile + - exportReferencesGraph + - additionalSandboxProfile + - noChroot + - impureHostDeps + - impureEnvVars + - allowLocalNetworking + - requiredSystemFeatures + - preferLocalBuild + - allowSubstitutes +properties: + outputChecks: + type: object + title: Output Check + description: | + Constraints on what the derivation's outputs can and cannot reference. + Can either apply to all outputs or be specified per output. + oneOf: + - title: Output Checks For All Outputs + description: | + Output checks that apply to all outputs of the derivation. + required: + - forAllOutputs + properties: + forAllOutputs: + "$ref": "#/$defs/outputCheckSpec" + additionalProperties: false + + - title: Output Checks Per Output + description: | + Output checks specified individually for each output. + required: + - perOutput + properties: + perOutput: + type: object + additionalProperties: + "$ref": "#/$defs/outputCheckSpec" + additionalProperties: false + + unsafeDiscardReferences: + type: object + title: Unsafe Discard References + description: | + A map specifying which references should be unsafely discarded from each output. + This is generally not recommended and requires special permissions. + additionalProperties: + type: array + items: + type: string + + passAsFile: + type: array + title: Pass As File + description: | + List of environment variable names whose values should be passed as files rather than directly. + items: + type: string + + exportReferencesGraph: + type: object + title: Export References Graph + description: | + Specify paths whose references graph should be exported to files. + additionalProperties: + type: array + items: + "$ref": "deriving-path-v1.yaml" + + additionalSandboxProfile: + type: string + title: Additional Sandbox Profile + description: | + Additional sandbox profile directives (macOS specific). + + noChroot: + type: boolean + title: No Chroot + description: | + Whether to disable the build sandbox, if allowed. + + impureHostDeps: + type: array + title: Impure Host Dependencies + description: | + List of host paths that the build can access. + items: + type: string + + impureEnvVars: + type: array + title: Impure Environment Variables + description: | + List of environment variable names that should be passed through to the build from the calling environment. + items: + type: string + + allowLocalNetworking: + type: boolean + title: Allow Local Networking + description: | + Whether the build should have access to local network (macOS specific). + + requiredSystemFeatures: + type: array + title: Required System Features + description: | + List of system features required to build this derivation (e.g., "kvm", "nixos-test"). + items: + type: string + + preferLocalBuild: + type: boolean + title: Prefer Local Build + description: | + Whether this derivation should preferably be built locally rather than its outputs substituted. + + allowSubstitutes: + type: boolean + title: Allow Substitutes + description: | + Whether substituting from other stores should be allowed for this derivation's outputs. + +additionalProperties: false + +$defs: + + outputCheckSpec: + type: object + title: Output Check Specification + description: | + Constraints on what a specific output can reference. + required: + - ignoreSelfRefs + - maxSize + - maxClosureSize + - allowedReferences + - allowedRequisites + - disallowedReferences + - disallowedRequisites + properties: + ignoreSelfRefs: + type: boolean + title: Ignore Self References + description: | + Whether references from this output to itself should be ignored when checking references. + + maxSize: + type: ["integer", "null"] + title: Maximum Size + description: | + Maximum allowed size of this output in bytes, or null for no limit. + minimum: 0 + + maxClosureSize: + type: ["integer", "null"] + title: Maximum Closure Size + description: | + Maximum allowed size of this output's closure in bytes, or null for no limit. + minimum: 0 + + allowedReferences: + oneOf: + - type: array + items: + "$ref": "#/$defs/drvRef" + - type: "null" + title: Allowed References + description: | + If set, the output can only reference paths in this list. + If null, no restrictions apply. + + allowedRequisites: + oneOf: + - type: array + items: + "$ref": "#/$defs/drvRef" + - type: "null" + title: Allowed Requisites + description: | + If set, the output's closure can only contain paths in this list. + If null, no restrictions apply. + + disallowedReferences: + type: array + title: Disallowed References + description: | + The output must not reference any paths in this list. + items: + "$ref": "#/$defs/drvRef" + + disallowedRequisites: + type: array + title: Disallowed Requisites + description: | + The output's closure must not contain any paths in this list. + items: + "$ref": "#/$defs/drvRef" + additionalProperties: false + + drvRef: + # TODO fix bug in checker, should be `oneOf` + anyOf: + - type: object + title: Current derivation Output Reference + description: | + A reference to a specific output of the current derivation. + required: + - drvPath + - output + properties: + drvPath: + type: string + const: "self" + title: This derivation + description: | + Won't be confused for a deriving path + output: + type: string + title: Output Name + description: | + The name of the output being referenced. + additionalProperties: false + - "$ref": "deriving-path-v1.yaml" diff --git a/src/json-schema-checks/derivation-options b/src/json-schema-checks/derivation-options new file mode 120000 index 000000000..00c6cde65 --- /dev/null +++ b/src/json-schema-checks/derivation-options @@ -0,0 +1 @@ +../libstore-tests/data/derivation \ No newline at end of file diff --git a/src/json-schema-checks/meson.build b/src/json-schema-checks/meson.build index f72affb0b..991facf12 100644 --- a/src/json-schema-checks/meson.build +++ b/src/json-schema-checks/meson.build @@ -63,6 +63,19 @@ schemas = [ 'with-signature.json', ], }, + # Derivation options + { + 'stem' : 'derivation-options', + 'schema' : schema_dir / 'derivation-options-v1.yaml', + 'files' : [ + 'ia' / 'defaults.json', + 'ia' / 'all_set.json', + 'ia' / 'structuredAttrs_defaults.json', + 'ia' / 'structuredAttrs_all_set.json', + 'ca' / 'all_set.json', + 'ca' / 'structuredAttrs_all_set.json', + ], + }, ] # Derivation and Derivation output