From 4e2614fc0709ff77e40a8f39e2744239ee371826 Mon Sep 17 00:00:00 2001 From: h0nIg Date: Sun, 29 Jun 2025 21:44:02 +0200 Subject: [PATCH] stdenv: pURL implementation --- doc/redirects.json | 9 ++++ doc/release-notes/rl-2511.section.md | 2 + doc/stdenv/meta.chapter.md | 15 +++++++ pkgs/build-support/fetchgit/default.nix | 10 ++++- pkgs/build-support/fetchgithub/default.nix | 43 +++++++++++++++---- pkgs/build-support/fetchpypi/default.nix | 16 ++++++- .../python/mk-python-derivation.nix | 1 + pkgs/development/ruby-modules/gem/default.nix | 10 +++++ pkgs/stdenv/generic/check-meta.nix | 17 +++++++- 9 files changed, 111 insertions(+), 12 deletions(-) diff --git a/doc/redirects.json b/doc/redirects.json index 1230b6460b54..0ab407db19f3 100644 --- a/doc/redirects.json +++ b/doc/redirects.json @@ -231,6 +231,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" ], @@ -643,6 +646,12 @@ "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-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 018554743449..6d5cf577fb72 100644 --- a/doc/release-notes/rl-2511.section.md +++ b/doc/release-notes/rl-2511.section.md @@ -176,6 +176,8 @@ +- Metadata identifier pURL (https://github.com/package-url/purl-spec) has been added, which enables a SBOM generation. Maintainers are urged to check their `drv.meta.identifiers.v1.purl` for completeness. + - Added `rewriteURL` attribute to the nixpkgs `config`, to allow for rewriting the URLs downloaded by `fetchurl`. - The `dockerTools.streamLayeredImage` builder now uses a better algorithm for generating layered docker images, such that much more sharing is possible when the number of store paths exceeds the layer limit. It gives each of the largest store paths its own layer and adds dependencies to those layers when they aren't used elsewhere. diff --git a/doc/stdenv/meta.chapter.md b/doc/stdenv/meta.chapter.md index 947009869ff1..606d607e04d1 100644 --- a/doc/stdenv/meta.chapter.md +++ b/doc/stdenv/meta.chapter.md @@ -319,3 +319,18 @@ 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. + +#### `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} + +A readonly attribute which is built based on purlParts. diff --git a/pkgs/build-support/fetchgit/default.nix b/pkgs/build-support/fetchgit/default.nix index b2f5f15a309d..ed9daa7ff525 100644 --- a/pkgs/build-support/fetchgit/default.nix +++ b/pkgs/build-support/fetchgit/default.nix @@ -185,7 +185,15 @@ 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)}"; + }; + }; passthru = { gitRepoUrl = url; diff --git a/pkgs/build-support/fetchgithub/default.nix b/pkgs/build-support/fetchgithub/default.nix index 2b3ab060418a..fbbf1dd153b1 100644 --- a/pkgs/build-support/fetchgithub/default.nix +++ b/pkgs/build-support/fetchgithub/default.nix @@ -43,14 +43,36 @@ lib.makeOverridable ( ); baseUrl = "https://${githubBase}/${owner}/${repo}"; newMeta = - meta - // { - homepage = meta.homepage or baseUrl; - } - // lib.optionalAttrs (position != null) { - # to indicate where derivation originates, similar to make-derivation.nix's mkDerivation - position = "${position.file}:${toString position.line}"; - }; + lib.recursiveUpdate + ( + meta + // { + homepage = meta.homepage or baseUrl; + } + // lib.optionalAttrs (position != null) { + # to indicate where derivation originates, similar to make-derivation.nix's mkDerivation + position = "${position.file}:${toString position.line}"; + } + ) + + ( + { + 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)}"; + }; + } + ); + passthruAttrs = removeAttrs args [ "owner" "repo" @@ -153,12 +175,15 @@ lib.makeOverridable ( // passthruAttrs // { inherit name; + } + # fetchurl / fetchzip is not a function, but fetchurlBoot is - ensure that the parameter is accepted and passed through + // lib.optionalAttrs (!builtins.isFunction fetcher || (builtins.functionArgs fetcher) ? meta) { + meta = newMeta; }; in fetcher fetcherArgs // { - meta = newMeta; inherit owner repo tag; rev = revWithTag; } diff --git a/pkgs/build-support/fetchpypi/default.nix b/pkgs/build-support/fetchpypi/default.nix index cb7e443ab7ef..7510582ccf58 100644 --- a/pkgs/build-support/fetchpypi/default.nix +++ b/pkgs/build-support/fetchpypi/default.nix @@ -51,6 +51,8 @@ makeOverridable ( format ? "setuptools", sha256 ? "", hash ? "", + pname, + version, ... }@attrs: let @@ -60,8 +62,20 @@ 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/development/interpreters/python/mk-python-derivation.nix b/pkgs/development/interpreters/python/mk-python-derivation.nix index eb8e76101c49..c7ff2f0dce70 100644 --- a/pkgs/development/interpreters/python/mk-python-derivation.nix +++ b/pkgs/development/interpreters/python/mk-python-derivation.nix @@ -416,6 +416,7 @@ let # default to python's platforms platforms = python.meta.platforms; isBuildPythonPackage = python.meta.platforms; + identifiers.purlParts = attrs.src.meta.identifiers.purlParts or { }; } // meta; } diff --git a/pkgs/development/ruby-modules/gem/default.nix b/pkgs/development/ruby-modules/gem/default.nix index 0e3c1c4187f2..d8b91063ef51 100644 --- a/pkgs/development/ruby-modules/gem/default.nix +++ b/pkgs/development/ruby-modules/gem/default.nix @@ -300,6 +300,16 @@ lib.makeOverridable ( platforms = ruby.meta.platforms; mainProgram = gemName; } + // (lib.optionalAttrs (type == "gem") { + identifiers.purlParts = { + type = "gem"; + # https://github.com/package-url/purl-spec/blob/18fd3e395dda53c00bc8b11fe481666dc7b3807a/types-doc/gem-definition.md + spec = "${gemName}@${version}?platform=${platform}"; + }; + }) + // (lib.optionalAttrs (type == "git") { + identifiers.purlParts = src.meta.identifiers.purlParts or { }; + }) // meta; } ) diff --git a/pkgs/stdenv/generic/check-meta.nix b/pkgs/stdenv/generic/check-meta.nix index d8f519b0f185..4dbc7dd0520a 100644 --- a/pkgs/stdenv/generic/check-meta.nix +++ b/pkgs/stdenv/generic/check-meta.nix @@ -605,6 +605,12 @@ let }) tryCPEPatchVersionInUpdateWithVendor ]; + hasAllPURLParts = + purlParts: + let + values = attrValues purlParts; + in + (length values == 2) && !any isNull values; # The meta attribute is passed in the resulting attribute set, # but it's not part of the actual derivation, i.e., it's not @@ -710,9 +716,18 @@ let cpe = makeCPE guessedParts; } ) possibleCPEPartsFuns; + + purlParts = attrs.meta.identifiers.purlParts or { }; + purl = if hasAllPURLParts purlParts then "pkg:${purlParts.type}/${purlParts.spec}" else null; + v1 = { - inherit cpeParts possibleCPEs; + inherit + cpeParts + possibleCPEs + purlParts + ; ${if cpe != null then "cpe" else null} = cpe; + ${if purl != null then "purl" else null} = purl; }; in v1