summary refs log tree commit diff
diff options
context:
space:
mode:
authorRobert Scott <code@humanleg.org.uk>2022-02-20 19:23:12 +0000
committerAlexander Foremny <aforemny@posteo.de>2022-05-30 16:27:34 +0800
commitda9162f667e5833b885edae3631299c0e7005d2b (patch)
tree6a435bfbd822ad8c133a5b797da1d05fe1d58a15
parent93e6a4b6070a305c7608de120004b3a25f76f796 (diff)
add mechanism for handling meta.sourceProvenance attributes
heavily based on patterns used by licenses infrastructure, so may
appear overengineered for its initial level of use
-rw-r--r--lib/default.nix1
-rw-r--r--lib/source-types.nix25
-rw-r--r--pkgs/stdenv/generic/check-meta.nix46
3 files changed, 68 insertions, 4 deletions
diff --git a/lib/default.nix b/lib/default.nix
index e919509e724a5..791eba8a9301f 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -36,6 +36,7 @@ let
 
     # constants
     licenses = callLibs ./licenses.nix;
+    sourceTypes = callLibs ./source-types.nix;
     systems = callLibs ./systems;
 
     # serialization
diff --git a/lib/source-types.nix b/lib/source-types.nix
new file mode 100644
index 0000000000000..8a4ab540b9da1
--- /dev/null
+++ b/lib/source-types.nix
@@ -0,0 +1,25 @@
+{ lib }:
+
+lib.mapAttrs (tname: tset: let
+  defaultSourceType = {
+    shortName = tname;
+    isSource = false;
+  };
+
+  mkSourceType = sourceTypeDeclaration: let
+    applyDefaults = sourceType: defaultSourceType // sourceType;
+  in lib.pipe sourceTypeDeclaration [
+    applyDefaults
+  ];
+in mkSourceType tset) {
+
+  fromSource = {
+    isSource = true;
+  };
+
+  binaryNativeCode = {};
+
+  binaryBytecode = {};
+
+  binaryFirmware = {};
+}
diff --git a/pkgs/stdenv/generic/check-meta.nix b/pkgs/stdenv/generic/check-meta.nix
index 1da098dabbee1..1be306fd39699 100644
--- a/pkgs/stdenv/generic/check-meta.nix
+++ b/pkgs/stdenv/generic/check-meta.nix
@@ -20,6 +20,9 @@ let
   allowUnfree = config.allowUnfree
     || builtins.getEnv "NIXPKGS_ALLOW_UNFREE" == "1";
 
+  allowNonSource = config.allowNonSource or true
+    || builtins.getEnv "NIXPKGS_ALLOW_NONSOURCE" == "1";
+
   allowlist = config.allowlistedLicenses or config.whitelistedLicenses or [];
   blocklist = config.blocklistedLicenses or config.blacklistedLicenses or [];
 
@@ -86,12 +89,41 @@ let
     allowInsecurePredicate attrs ||
     builtins.getEnv "NIXPKGS_ALLOW_INSECURE" == "1";
 
-  showLicense = license: toString (map (l: l.shortName or "unknown") (lib.lists.toList license));
+  hasSourceProvenance = attrs:
+    attrs ? meta.sourceProvenance;
+
+  isNonSource = sourceTypes: lib.lists.any (t: !t.isSource or true) sourceTypes;
+
+  hasNonSourceProvenance = attrs:
+    hasSourceProvenance attrs &&
+    isNonSource (lib.lists.toList attrs.meta.sourceProvenance);
+
+  # Allow granular checks to allow only some non-source-built packages
+  # Example:
+  # {pkgs, ...}:
+  # {
+  #   allowNonSource = false;
+  #   allowNonSourcePredicate = (x: pkgs.lib.hasPrefix "pulumi" x.name);
+  # }
+  allowNonSourcePredicate = config.allowNonSourcePredicate or (x: false);
+
+  # Check whether non-source packages are allowed and if not, whether the
+  # package has non-source provenance and is not explicitly allowed by the
+  # `allowNonSourcePredicate` function.
+  hasDeniedNonSourceProvenance = attrs:
+    hasNonSourceProvenance attrs &&
+    !allowNonSource &&
+    !allowNonSourcePredicate attrs;
+
+  showLicenseOrSourceType = value: toString (map (v: v.shortName or "unknown") (lib.lists.toList value));
+  showLicense = showLicenseOrSourceType;
+  showSourceType = showLicenseOrSourceType;
 
   pos_str = meta: meta.position or "«unknown-file»";
 
   remediation = {
-    unfree = remediate_allowlist "Unfree" remediate_unfree_predicate;
+    unfree = remediate_allowlist "Unfree" (remediate_predicate "allowUnfreePredicate");
+    non-source = remediate_allowlist "NonSource" (remediate_predicate "allowNonSourcePredicate");
     broken = remediate_allowlist "Broken" (x: "");
     unsupported = remediate_allowlist "UnsupportedSystem" (x: "");
     blocklisted = x: "";
@@ -104,17 +136,19 @@ let
     Unfree = "NIXPKGS_ALLOW_UNFREE";
     Broken = "NIXPKGS_ALLOW_BROKEN";
     UnsupportedSystem = "NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM";
+    NonSource = "NIXPKGS_ALLOW_NONSOURCE";
   }.${allow_attr};
   remediation_phrase = allow_attr: {
     Unfree = "unfree packages";
     Broken = "broken packages";
     UnsupportedSystem = "packages that are unsupported for this system";
+    NonSource = "packages not built from source";
   }.${allow_attr};
-  remediate_unfree_predicate = attrs:
+  remediate_predicate = predicateConfigAttr: attrs:
     ''
 
       Alternatively you can configure a predicate to allow specific packages:
-        { nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
+        { nixpkgs.config.${predicateConfigAttr} = pkg: builtins.elem (lib.getName pkg) [
             "${lib.getName attrs}"
           ];
         }
@@ -226,6 +260,7 @@ let
     downloadPage = str;
     changelog = either (listOf str) str;
     license = either (listOf lib.types.attrs) (either lib.types.attrs str);
+    sourceProvenance = either (listOf lib.types.attrs) (either lib.types.attrs str);
     maintainers = listOf (attrsOf str);
     priority = int;
     platforms = listOf str;
@@ -288,6 +323,7 @@ let
   checkValidity = attrs:
     {
       unfree = hasUnfreeLicense attrs;
+      nonSource = hasNonSourceProvenance attrs;
       broken = isMarkedBroken attrs;
       unsupported = hasUnsupportedPlatform attrs;
       insecure = isMarkedInsecure attrs;
@@ -296,6 +332,8 @@ let
       { valid = "no"; reason = "unfree"; errormsg = "has an unfree license (‘${showLicense attrs.meta.license}’)"; }
     else if hasBlocklistedLicense attrs then
       { valid = "no"; reason = "blocklisted"; errormsg = "has a blocklisted license (‘${showLicense attrs.meta.license}’)"; }
+    else if hasDeniedNonSourceProvenance attrs then
+      { valid = "no"; reason = "non-source"; errormsg = "contains elements not built from source (‘${showSourceType attrs.meta.sourceProvenance}’)"; }
     else if !allowBroken && attrs.meta.broken or false then
       { valid = "no"; reason = "broken"; errormsg = "is marked as broken"; }
     else if !allowUnsupportedSystem && hasUnsupportedPlatform attrs then