diff --git a/doc/redirects.json b/doc/redirects.json index 4ba879f51d2bf6..8c42fbc9fb9e5b 100644 --- a/doc/redirects.json +++ b/doc/redirects.json @@ -268,6 +268,9 @@ "sec-meta-identifiers-cpe": [ "index.html#sec-meta-identifiers-cpe" ], + "sec-meta-identifiers-purl": [ + "index.html#sec-meta-identifiers-purl" + ], "sec-modify-via-packageOverrides": [ "index.html#sec-modify-via-packageOverrides" ], @@ -692,6 +695,15 @@ "var-meta-identifiers-possibleCPEs": [ "index.html#var-meta-identifiers-possibleCPEs" ], + "var-meta-identifiers-purl": [ + "index.html#var-meta-identifiers-purl" + ], + "var-meta-identifiers-purlParts": [ + "index.html#var-meta-identifiers-purlParts" + ], + "var-meta-identifiers-purls": [ + "index.html#var-meta-identifiers-purls" + ], "var-meta-teams": [ "index.html#var-meta-teams" ], diff --git a/doc/release-notes/rl-2511.section.md b/doc/release-notes/rl-2511.section.md index 21a9b41636e58e..4626c1a583d492 100644 --- a/doc/release-notes/rl-2511.section.md +++ b/doc/release-notes/rl-2511.section.md @@ -264,6 +264,8 @@ +- Metadata identifier purl (Package URL, https://github.com/package-url/purl-spec) has been added for fetchgit, fetchpypi and fetchFromGithub fetchers and mkDerivation has been adjusted to reuse these informations. Package URL's enables a reliable identification and locatization of software packages. Maintainers of derivations using the adopted fetchers should rely on the `drv.src.meta.identifiers.v1.purl` default identifier and can enhance their `drv.meta.identifiers.v1.purls` list once they would like to have additional identifiers. Maintainers using fetchurl for `drv.src` are urged to adopt their `drv.meta.identifiers.purlParts` for proper identification. Maintainers should check that their `drv.src` / `drv.srcs` either evaluate properly or that they throw an UnsupportedPlatform statement instead of a missing attribute error. The inheritance feature of `drv.src(s).meta.identifiers.purl(s)` for `drv.meta.identifiers.purl(s)` can get activated via `config.derivationPURLInheritance`. + - Added `rewriteURL` attribute to the nixpkgs `config`, to allow for rewriting the URLs downloaded by `fetchurl`. - Added `hashedMirrors` attribute to the nixpkgs `config`, to allow for customization of the hashed mirrors used by `fetchurl`. diff --git a/doc/stdenv/meta.chapter.md b/doc/stdenv/meta.chapter.md index 947009869ff152..c5973ade1c7e0e 100644 --- a/doc/stdenv/meta.chapter.md +++ b/doc/stdenv/meta.chapter.md @@ -319,3 +319,22 @@ A readonly attribute that concatenates all CPE parts in one string. #### `meta.identifiers.possibleCPEs` {#var-meta-identifiers-possibleCPEs} A readonly attribute containing the list of guesses for what CPE for this package can look like. It includes all variants of version handling mentioned above. Each item is an attrset with attributes `cpeParts` and `cpe` for each guess. + +### Package URL {#sec-meta-identifiers-purl} + +[Package-URL](https://github.com/package-url/purl-spec) (PURL) is a specification to reliably identify and locate software packages. Through identification of software packages, additional (non-major) use cases are e.g. software license cross-verification via third party databases or initial vulnerability response management. Package URL's shall default to the mkDerivation.src, as the original consumed software package is the single point of truth. The default inheritance must get enabled explicitly through the nixpkgs config paramter `derivationPURLInheritance`. + +#### `meta.identifiers.purlParts` {#var-meta-identifiers-purlParts} + +This attribute contains an attribute set of all parts of the PURL for this package. + +* `type` mandatory [type](https://github.com/package-url/purl-spec/blob/18fd3e395dda53c00bc8b11fe481666dc7b3807a/docs/standard/summary.md) which needs to be provided +* `spec` specify the PURL in accordance with the [purl-spec](https://github.com/package-url/purl-spec/blob/18fd3e395dda53c00bc8b11fe481666dc7b3807a/purl-specification.md) + +#### `meta.identifiers.purl` {#var-meta-identifiers-purl} + +An extendable attribute which is built based on purlParts. It is the main identifier, consumers should consider using the PURL's list interface to be prepared for edge cases. + +#### `meta.identifiers.purls` {#var-meta-identifiers-purls} + +An extendable attribute list which defaults to a single element equal to the main PURL. It provides an interface for additional identifiers of mkDerivation.src and / or vendored dependencies inside mkDerivation.src, which maintainers can conciously decide to use on top. Identifiers different to the default src identifier are not recommended by default as they might cause maintenance overhead or may diverge (e.g. differences between source distribution pkg:github and binary distribution like pkg:pypi). diff --git a/pkgs/build-support/fetchgit/default.nix b/pkgs/build-support/fetchgit/default.nix index 5a8ea3cf048802..8262e092709f72 100644 --- a/pkgs/build-support/fetchgit/default.nix +++ b/pkgs/build-support/fetchgit/default.nix @@ -214,7 +214,18 @@ lib.makeOverridable ( "FETCHGIT_HTTP_PROXIES" ]; - inherit preferLocalBuild meta allowedRequisites; + inherit preferLocalBuild allowedRequisites; + + meta = meta // { + identifiers = { + purlParts = { + type = "generic"; + # https://github.com/package-url/purl-spec/blob/18fd3e395dda53c00bc8b11fe481666dc7b3807a/types-doc/generic-definition.md + spec = "${name}?vcs_url=${url}@${(lib.revOrTag rev tag)}"; + }; + } + // meta.identifiers or { }; + }; passthru = { gitRepoUrl = url; diff --git a/pkgs/build-support/fetchgithub/default.nix b/pkgs/build-support/fetchgithub/default.nix index ae5ff338264a22..18a82cf7211ce7 100644 --- a/pkgs/build-support/fetchgithub/default.nix +++ b/pkgs/build-support/fetchgithub/default.nix @@ -49,11 +49,28 @@ lib.makeOverridable ( meta // { homepage = meta.homepage or baseUrl; + identifiers = { + purlParts = + if githubBase == "github.com" then + { + type = "github"; + # https://github.com/package-url/purl-spec/blob/18fd3e395dda53c00bc8b11fe481666dc7b3807a/types-doc/github-definition.md + spec = "${owner}/${repo}@${(lib.revOrTag rev tag)}"; + } + else + { + type = "generic"; + # https://github.com/package-url/purl-spec/blob/18fd3e395dda53c00bc8b11fe481666dc7b3807a/types-doc/generic-definition.md + spec = "${repo}?vcs_url=https://${githubBase}/${owner}/${repo}@${(lib.revOrTag rev tag)}"; + }; + } + // meta.identifiers or { }; } // lib.optionalAttrs (position != null) { # to indicate where derivation originates, similar to make-derivation.nix's mkDerivation position = "${position.file}:${toString position.line}"; }; + passthruAttrs = removeAttrs args [ "owner" "repo" diff --git a/pkgs/build-support/fetchpypi/default.nix b/pkgs/build-support/fetchpypi/default.nix index 71530bddff377f..453883ac13f2ec 100644 --- a/pkgs/build-support/fetchpypi/default.nix +++ b/pkgs/build-support/fetchpypi/default.nix @@ -51,6 +51,8 @@ lib.makeOverridable ( format ? "setuptools", sha256 ? "", hash ? "", + pname, + version, ... }@attrs: let @@ -60,8 +62,20 @@ lib.makeOverridable ( "hash" ] ); + meta = { + identifiers.purlParts = { + type = "pypi"; + # https://github.com/package-url/purl-spec/blob/18fd3e395dda53c00bc8b11fe481666dc7b3807a/types-doc/pypi-definition.md + spec = "${pname}@${version}"; + }; + }; in fetchurl { - inherit url sha256 hash; + inherit + url + sha256 + hash + meta + ; } ) diff --git a/pkgs/by-name/jq/jq/package.nix b/pkgs/by-name/jq/jq/package.nix index b2a0941a79fe4f..5ad75de67faf0d 100644 --- a/pkgs/by-name/jq/jq/package.nix +++ b/pkgs/by-name/jq/jq/package.nix @@ -134,5 +134,9 @@ stdenv.mkDerivation (finalAttrs: { ]; platforms = lib.platforms.unix; mainProgram = "jq"; + identifiers.purlParts = { + type = "github"; + spec = "jqlang/jq@jq-${finalAttrs.version}"; + }; }; }) diff --git a/pkgs/by-name/po/popt/package.nix b/pkgs/by-name/po/popt/package.nix index eb9e4f3685ed48..c40e17228f54ae 100644 --- a/pkgs/by-name/po/popt/package.nix +++ b/pkgs/by-name/po/popt/package.nix @@ -49,5 +49,9 @@ stdenv.mkDerivation rec { maintainers = with maintainers; [ qyliss ]; license = licenses.mit; platforms = platforms.unix; + identifiers.purlParts = { + type = "github"; + spec = "rpm-software-management/popt@popt-${version}-release"; + }; }; } diff --git a/pkgs/development/ruby-modules/gem/default.nix b/pkgs/development/ruby-modules/gem/default.nix index 10ea06c415bd3b..f6a9e25bf042a3 100644 --- a/pkgs/development/ruby-modules/gem/default.nix +++ b/pkgs/development/ruby-modules/gem/default.nix @@ -77,6 +77,13 @@ lib.makeOverridable ( attrs.source.remotes or [ "https://rubygems.org" ] ); inherit (attrs.source) sha256; + meta = { + identifiers.purlParts = { + type = "gem"; + # https://github.com/package-url/purl-spec/blob/18fd3e395dda53c00bc8b11fe481666dc7b3807a/types-doc/gem-definition.md + spec = "${gemName}@${version}?platform=${platform}"; + }; + }; } else if type == "git" then fetchgit { diff --git a/pkgs/stdenv/generic/check-meta.nix b/pkgs/stdenv/generic/check-meta.nix index b99f2531831c51..465f58ffca441b 100644 --- a/pkgs/stdenv/generic/check-meta.nix +++ b/pkgs/stdenv/generic/check-meta.nix @@ -35,6 +35,8 @@ let isList elem unique + flatten + filter ; inherit (lib.meta) @@ -68,6 +70,8 @@ let allowlist = config.allowlistedLicenses or config.whitelistedLicenses or [ ]; blocklist = config.blocklistedLicenses or config.blacklistedLicenses or [ ]; + allowSrcEvalForDrvMeta = config.allowSrcEvalForDrvMeta; + areLicenseListsValid = if mutuallyExclusive allowlist blocklist then true @@ -300,7 +304,7 @@ let let expectedOutputs = attrs.meta.outputsToInstall or [ ]; actualOutputs = attrs.outputs or [ "out" ]; - missingOutputs = builtins.filter (output: !builtins.elem output actualOutputs) expectedOutputs; + missingOutputs = filter (output: !builtins.elem output actualOutputs) expectedOutputs; in '' The package ${getNameWithVersion attrs} has set meta.outputsToInstall to: ${builtins.concatStringsSep ", " expectedOutputs} @@ -476,7 +480,7 @@ let let expectedOutputs = attrs.meta.outputsToInstall or [ ]; actualOutputs = attrs.outputs or [ "out" ]; - missingOutputs = builtins.filter (output: !builtins.elem output actualOutputs) expectedOutputs; + missingOutputs = filter (output: !builtins.elem output actualOutputs) expectedOutputs; in if config.checkMeta then builtins.length missingOutputs > 0 else false; @@ -712,14 +716,59 @@ let cpe = makeCPE guessedParts; } ) possibleCPEPartsFuns; + + evaluateSrc = allowSrcEvalForDrvMeta && !isMarkedBroken attrs && !hasUnsupportedPlatform attrs; + purlParts = attrs.meta.identifiers.purlParts or { }; + purlPartsFormatted = + if purlParts ? type && purlParts ? spec then "pkg:${purlParts.type}/${purlParts.spec}" else null; + + # search for a PURL in the following order: + purl = + # 1) locally set through API + if purlPartsFormatted != null then + purlPartsFormatted + else if !evaluateSrc then + null + else + # 2) locally overwritten through meta.identifiers.purl + (attrs.src.meta.identifiers.purl or null); + + # search for a PURL in the following order: + purls = + # 1) locally overwritten through meta.identifiers.purls (e.g. extension of list) + attrs.meta.identifiers.purls or ( + # 2) locally set through API + if purlPartsFormatted != null then + [ purlPartsFormatted ] + else if !evaluateSrc then + [ ] + else + # 3) src.meta.PURL + (attrs.src.meta.identifiers.purls or ( + # 4) srcs.meta.PURL + if !attrs ? srcs then + [ ] + else if isList attrs.srcs then + concatMap (drv: drv.meta.identifiers.purls or [ ]) attrs.srcs + else + attrs.srcs.meta.identifiers.purls or [ ] + ) + ) + ); + v1 = { - inherit cpeParts possibleCPEs; + inherit + cpeParts + possibleCPEs + purls + ; ${if cpe != null then "cpe" else null} = cpe; + ${if purl != null then "purl" else null} = purl; }; in v1 // { - inherit v1; + inherit v1 purlParts; }; # Expose the result of the checks for everyone to see. diff --git a/pkgs/top-level/config.nix b/pkgs/top-level/config.nix index 09d31a2d117c08..e07861e9b4592d 100644 --- a/pkgs/top-level/config.nix +++ b/pkgs/top-level/config.nix @@ -333,6 +333,17 @@ let Please read https://www.visualstudio.com/license-terms/mt644918/ and enable this config if you accept. ''; }; + + allowSrcEvalForDrvMeta = mkOption { + type = types.bool; + default = false; + description = '' + Enables evaluation of drv.src or drv.srcs, in order to generate parts of drv.meta. Most of the nixpkgs derivations have a drv.src or drv.srcs which properly evaluate, but there are some corner cases. + + Background: Commonly PURL identifiers are based on the source of software. For example software distributed through github.com can get identified via pkg:github/org/repo. + This feature flag should get activated, once an SBOM tool is in use and where drv.meta.identifiers.purl(s) should inherit the informations from drv.src(s).meta.identifiers.purl(s). + ''; + }; }; in