Skip to content

Add new PURL type: 'nix' [old] - #314

Draft
RaitoBezarius wants to merge 1 commit into
package-url:mainfrom
RaitoBezarius:master
Draft

Add new PURL type: 'nix' [old]#314
RaitoBezarius wants to merge 1 commit into
package-url:mainfrom
RaitoBezarius:master

Conversation

@RaitoBezarius

Copy link
Copy Markdown

This adds a first version of the Nix package type.

This adds a first version of the Nix package type.

Signed-off-by: Raito Bezarius <masterancpp@gmail.com>
Comment thread PURL-TYPES.rst
pkg:nix/glibc@2.39-52?drvpath=/nix/store/3nxf8kw3vgghz2y72b9qwi01sz62nhyk-glibc-2.39-52.drv&output=out&repository=github:user/nixpkgs
pkg:nix/systemd@255.6?drvpath=/nix/store/r34i4md1cmc19392zbbp9ya5nmd0av0k-systemd-255.6.drv&output=dev


Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably want to remove "nix" from the old list below.

Comment thread PURL-TYPES.rst
nix
---

``nix`` for Nix derivations:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
``nix`` for Nix derivations:
``nix`` for Nix store paths:

The PURL is for each store path, and we may have multiple PURL for different output paths in the same derivation.

Comment thread PURL-TYPES.rst
``nix`` for Nix derivations:

- The default package repository is <https://github.com/NixOS/nixpkgs> but the ``repository`` qualifier can override the package repository.
- The ``name`` is the package ``pname`` field of the given derivation. It is case sensitive.

@flokli flokli Sep 17, 2024

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't always have the pname / version separate. Deep down pname and version are concatenated into a single string. Should something creating a PURL try to split this off? (Probably fine, but in that case, see the comment on the version field).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the current state of name, pname, and versioning standards was part of why I didn't expect there to be a PURL standard yet for nix. (TBH I haven't checked on the current-state of discussions for a while so maybe it's settled lol)
Although it'd be great if this spec discussion helps push things forwards

Comment thread PURL-TYPES.rst

- The default package repository is <https://github.com/NixOS/nixpkgs> but the ``repository`` qualifier can override the package repository.
- The ``name`` is the package ``pname`` field of the given derivation. It is case sensitive.
- The ``version`` is the ``version`` field of the given derivation.

@flokli flokli Sep 17, 2024

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do PURL look like for store paths where the version cannot be extracted? Is this field (and other fields) optional or required? The spec for other PURLs in this file do explicitly say what's required and what not.

Comment thread PURL-TYPES.rst
- The default package repository is <https://github.com/NixOS/nixpkgs> but the ``repository`` qualifier can override the package repository.
- The ``name`` is the package ``pname`` field of the given derivation. It is case sensitive.
- The ``version`` is the ``version`` field of the given derivation.
- The ``drvpath`` qualifier is the derivation path (``.drvPath``).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to have an outpath here too, or are PURL always for individual output paths, so this information would be redundant?

Is drvpath optional or required?

Comment thread PURL-TYPES.rst
- The ``name`` is the package ``pname`` field of the given derivation. It is case sensitive.
- The ``version`` is the ``version`` field of the given derivation.
- The ``drvpath`` qualifier is the derivation path (``.drvPath``).
- The ``output`` qualifier is the output field, by default: ``out``

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- The ``output`` qualifier is the output field, by default: ``out``
- The ``output`` qualifier is the name of the output, which helps to distinguish in the case of multi-output derivations

The "default" behavior is confusing. It doesn't describe if it should always be set, or if it is "out" in case the field is not present.

Or should it always be set to something, and the fact it's "out" in single-output derivations is an implementation detail of Nix that should be left out of the spec? I prefer this one, which is my the suggestion uses this variant.

I don't think it should be omitted in case of single-output derivations, it'd be odd if it suddenly would appear if an expression is refactored to multiple outputs.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

including the output field also accounts for if the default is changed in the future and shouldn't be very painful to just include

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should just map this to outputName of the drv. Then this works with lib.getLib etc

Comment thread PURL-TYPES.rst

``nix`` for Nix derivations:

- The default package repository is <https://github.com/NixOS/nixpkgs> but the ``repository`` qualifier can override the package repository.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this field even matter at all? With just the PURL we cannot reproduce the drv path anyways, there's a lot of other details (like rev, system, ...) we'd need. Also, the line gets blurry if you have a repo that imports nixpkgs, but overrides an expression, what should this be set to?

Inclined to remove this, this can only be a hint at most.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this field being mostly informative I feel we'd want a nar package type or at least a nar field to better identify where you got the package from if using a cache like cache.nixos.org. ommitted or something for if you built it locally?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not identifying the package. If you have a nar sha256 hash, you can fetch it from any content-addressed store.

@06kellyjac 06kellyjac Sep 26, 2024

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"what" being covered by the hash, but "where" can also useful for some governance.
Also if you can find that hash in your content-addressed store then great, but if you can't you might at least want a possible alternative location to check to find the same artifact described by the PURL.

Also lightning quick response! ⚡

@06kellyjac 06kellyjac left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General thanks for kicking this off.
Added some comments :)

Comment thread PURL-TYPES.rst
- The ``name`` is the package ``pname`` field of the given derivation. It is case sensitive.
- The ``version`` is the ``version`` field of the given derivation.
- The ``drvpath`` qualifier is the derivation path (``.drvPath``).
- The ``output`` qualifier is the output field, by default: ``out``

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

including the output field also accounts for if the default is changed in the future and shouldn't be very painful to just include

Comment thread PURL-TYPES.rst

``nix`` for Nix derivations:

- The default package repository is <https://github.com/NixOS/nixpkgs> but the ``repository`` qualifier can override the package repository.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this field being mostly informative I feel we'd want a nar package type or at least a nar field to better identify where you got the package from if using a cache like cache.nixos.org. ommitted or something for if you built it locally?

Comment thread PURL-TYPES.rst
``nix`` for Nix derivations:

- The default package repository is <https://github.com/NixOS/nixpkgs> but the ``repository`` qualifier can override the package repository.
- The ``name`` is the package ``pname`` field of the given derivation. It is case sensitive.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the current state of name, pname, and versioning standards was part of why I didn't expect there to be a PURL standard yet for nix. (TBH I haven't checked on the current-state of discussions for a while so maybe it's settled lol)
Although it'd be great if this spec discussion helps push things forwards

@jkowalleck jkowalleck added the PURL type new Register a new PURL type label Oct 17, 2024
@jkowalleck

jkowalleck commented Oct 17, 2024

Copy link
Copy Markdown
Member

see:

@jkowalleck jkowalleck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • please also add examples to the test suite
  • please also remove nix from the list of "Other candidate types to define"

@jkowalleck jkowalleck added PURL type change Change(s) to a registered PURL type and removed PURL type new Register a new PURL type labels Oct 17, 2024
@johnmhoran johnmhoran added PURL type new Register a new PURL type nix labels Oct 18, 2024
@jkowalleck jkowalleck removed the PURL type new Register a new PURL type label Oct 19, 2024

@jkowalleck jkowalleck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rebase onto latest master branch, and then remove nix from the Other candidate types to define

@johnmhoran johnmhoran added the PURL type new Register a new PURL type label Oct 22, 2024
@RaitoBezarius

Copy link
Copy Markdown
Author

Thanks for the review, and sorry for the delay, this PR was opened to spark discussions and discussions are still continuing in the Nix ecosystem on what is the best format as we have some special challenges.

In terms of expectations, I'd like to ensure that most stakeholders are willing to carry on this, if so, I will apply the changes and add some examples whenever I have time (the other stakeholders are of course welcome to send me patches :P). If we are not to continue this path, we will probably close this PR and document why we cannot continue on this path.

Sorry again for the delay and thanks to flokli to pester me.

@johnmhoran johnmhoran added this to the 1.1 milestone Apr 4, 2025
@pombredanne

Copy link
Copy Markdown
Member

So if you think this is the way to go, after the merge of PR #514, PURL tests and defs are now defined in new JSON schemas 👼 😇 😁 :

... therefore with the new approach... this PR would need to be updated. Sorry for the churn. ❤️

@britter

britter commented Aug 5, 2025

Copy link
Copy Markdown

@RaitoBezarius any update on this? 😃

@mjherzog mjherzog removed this from the PURL-TBD milestone Sep 18, 2025
@mjherzog mjherzog changed the title Add nix package type Add new PURL type: nix Mar 27, 2026
@mjherzog mjherzog removed the PURL type change Change(s) to a registered PURL type label Mar 27, 2026
@mjherzog mjherzog removed the type: nix label Apr 4, 2026
@mjherzog mjherzog changed the title Add new PURL type: nix Add new PURL type: 'nix' Apr 4, 2026
@chinyeungli

Copy link
Copy Markdown

any update on this?

@mjherzog

Copy link
Copy Markdown
Member

No update - we do not have a candidate PR work because the minimum is a candidate PURL type definition in JSON Schema format. Plus tests for anything unique about the candidate PURL type

@chinyeungli

Copy link
Copy Markdown

Based on NixOS/nixpkgs#454333 , it seems the nix type will not be used?

@matt-phylum

Copy link
Copy Markdown
Contributor

Based on NixOS/nixpkgs#454333 , it seems the nix type will not be used?

You mean because Nixpkgs will use non-nix PURLs to refer to non-nix packages that it downloads? I think it's an unrelated issue. If a package in Nixpkg contains a pkg:github PURL, that's a reference to the package's source. A pkg:nix PURL as currently defined by this PR describes package binaries in a Nix store. pkg:nix is more specific.

But I don't know if this pkg:nix would ever be used for anything besides trying to resolve an upstream pkg:github pkg:git etc. The problem is that for the given example pkg:nix/systemd@255.6?drvpath=/nix/store/r34i4md1cmc19392zbbp9ya5nmd0av0k-systemd-255.6.drv&output=dev, the PURL is simultaneously too specific and not specific enough. That drvpath qualifier is for a specific derivation with a specific set of patches for a specific nix store path for a specific processor architecture for a specific operating system with a specific build system (eg when cross compiling) with a specific set of options (eg if CUDA is enabled for a package, that's a different derivation), and it's all recursive so if any of those parameters are changed for any dependency then that would also change this qualifier. It's infeasible to enumerate all the possible values for drvpath, and it's not possible to derive meaningful comparisons between drvpath values without having a database of known values. This makes drvpath effectively useless for vulnerability matching (and potentially license matching?) unless you are limited to packages that are produced by Hydra or some other well known source, and even then its usage for vulnerability matching would require maintaining long lists of hashes. But without the drvpath qualifier, this PURL specifies just a name and a version without specifying any information about where to find the definition for that name and version, and the version is not specific enough because it's typically the upstream package version and not the Nixpkgs package version.

On the other hand, if you just wanted to identify or locate the package instead of match vulnerabilities against it, drvpath on its own is sufficient, and no combination of the other options currently defined is sufficient. I think normally software that is expecting Nix derivation paths as input will only be expecting Nix derivation paths, and it wouldn't make sense to accept PURLs that could be something besides a derivation path in that case.

I think it would be much more useful to describe the source of the derivation, eg pkg:nix/systemd@255.6?drvpath=/nix/store/r34i4md1cmc19392zbbp9ya5nmd0av0k-systemd-255.6.drv&output=dev is actually the output of executing Nix code within another derivation, which will typically be the result of extracting from Git, either explicitly or via Flakes. A PURL like pkg:nix/systemd@260.1?path=legacyPackages.linux-x86_64.systemd&repository=github:nixos/nixpkgs&ref=nixos-26.05&rev=b51242d7d43689db2f3be91bd05d5b24fbb469c4&timestamp=1779683686 discards a lot of specificity to the point where you may not be able to produce the same derivation given this information and introduces some complexities around the definition of the repository and especially path qualifier, but repository+ref+timestamp should normally be sufficient for vulnerability matching supporting patches without having to maintain a database of known hashes. I'm not happy with this path qualifier and I don't know if timestamp is really the right thing to do (it's similar to what is stored in flake.lock), but it seems more useful to go at it this way than focusing on the derivation path. I guess you could even include the derivation path in the PURL as another qualifier to not lose it if it's available.

I don't know if it's possible to work backwards from installed Nix derivations to this kind of information, which would be a significant barrier to adoption. I've never tried it. I don't know what the Nixpkgs team does for tracking vulnerabilities or if there is a Nixpkgs way to determine what vulnerabilities affect a system configuration, which would be good to align with here. It's interesting that the glibc package (and only the glibc package) has a patch suffix appended to the version number.

@chinyeungli

Copy link
Copy Markdown

this PURL specifies just a name and a version without specifying any information about where to find the definition for that name and version, and the version is not specific enough because it's typically the upstream package version and not the Nixpkgs package version.

Isn't that also the case if we use pkg:github or pkg:pypi since they refer to the upstream package version instead of the Nixpkgs version?

I am thinking something like this:
pkg:nix/systemd@255.6?repository=https://github.com/NixOS/nixpkgs&commit_hash=038fb464fcfa79b4f08131b07f2d8c9a6bcc4160&attribute_path=systemd

where commit_hash is the unique git commit hash, meaning we do not need to worry about the differences in the cryptographic hash in the store path that generated by different systems.

See https://www.nixhub.io/packages/systemd
or
https://search.devbox.sh/v2/pkg?name=systemd

    {
      "version": "255.6",
      "last_updated": "2024-07-28T04:39:20Z",
      "platforms": [
        {
          "arch": "arm64",
          "os": "Linux",
          "system": "aarch64-linux",
          "attribute_path": "systemd",
          "commit_hash": "038fb464fcfa79b4f08131b07f2d8c9a6bcc4160",
          "date": "2024-07-28T04:39:20Z",
          "outputs": [
            {
              "name": "out",
              "path": "/nix/store/6j800imqpvg8g4801lkn4xc784gp41s6-systemd-255.6",
              "default": true,
              "nar": "nar/0rx8c2ffxdvgxllx0mn76lc131c5d29wq6sfhi8hkp8fz5db9f8q.nar.xz"
            },
            {
              "name": "man",
              "path": "/nix/store/ylfa0gk5ysk53axdky96lwi2qhydp7i2-systemd-255.6-man",
              "default": true,
              "nar": "nar/0wh5np0p653yzlgaxir32ga2n735zz7n6nsazcwpqgs0sb806w3z.nar.xz"
            },
            {
              "name": "debug",
              "path": "/nix/store/hwmb0f5yjrh55gljinf3in2yd03nwhjh-systemd-255.6-debug",
              "nar": "nar/1z90hl852ghzzk5wzsyz2ns71yik2bxf6b6sfigsfzp1s5p26c9g.nar.xz"
            },
            {
              "name": "dev",
              "path": "/nix/store/63ip78x5hsx7zg6df9cc4xahj6aqp7l2-systemd-255.6-dev",
              "nar": "nar/19zx108bzypc3h63w8qy68ci6yy7r2fzfym86imjvd075y0sd344.nar.xz"
            }
          ]
        },
        {
          "arch": "x86-64",
          "os": "Linux",
          "system": "x86_64-linux",
          "attribute_path": "systemd",
          "commit_hash": "038fb464fcfa79b4f08131b07f2d8c9a6bcc4160",
          "date": "2024-07-28T04:39:20Z",
          "outputs": [
            {
              "name": "out",
              "path": "/nix/store/sbqf71kqhlgaff1ajd8zak09g4wn8ymd-systemd-255.6",
              "default": true,
              "nar": "nar/15p78cisgb58f1b04lcm50qwpv9jd02gcblma9jhv24k5d33pcg0.nar.xz"
            },
            {
              "name": "man",
              "path": "/nix/store/fj4a9lnwilfz4n7ywh0g94lsizy03kd0-systemd-255.6-man",
              "default": true,
              "nar": "nar/15zih7jcmqrynb7c38ycz9fnisbs8v05vmswmy7nagq4zff2byzv.nar.xz"
            },
            {
              "name": "dev",
              "path": "/nix/store/kfdrhijk8gfcwnw3nck3vjnr969yh7zd-systemd-255.6-dev",
              "nar": "nar/0vw53zax6rf1gqs6sq6y36cg75bz1zcl3mgn53fm3scx05ilqz5v.nar.xz"
            },
            {
              "name": "debug",
              "path": "/nix/store/vadhb5lv5pd0vp821vrw64v0n8nb9q02-systemd-255.6-debug",
              "nar": "nar/13789jfr1g8cf40dll20r718vsydw0lmam0gma47yscawc96xdnq.nar.xz"
            }
          ]
        }
      ],
      "platforms_summary": "Linux",
      "outputs_summary": "man (Linux only), out (Linux only), debug (Linux only), dev (Linux only)"
    },

In this case, we have the version and the commit hash to pin down the exact commit that was used. Would this be a potential solution?

@matt-phylum

Copy link
Copy Markdown
Contributor

I like the level of specificity from commit hashes, but I don't like that commit hashes aren't comparable without additional information. If you wanted to know if a vulnerability had been patched or not in a particular commit ID of the nixpkgs repository, you would need to have a copy of the commit graph of the nixpkgs repository containing both the fixed commit and the question commit, and I'd imagine for most tools that would need to do that kind of query that would involve adding special support for nixpkgs. Including the commit hash might still be the right thing to do anyway.

@chinyeungli

Copy link
Copy Markdown

@matt-phylum I think there is a way to avoid downloading or managing a full local commit graph.
what about using this github compare API?

https://api.github.com/repos/NixOS/nixpkgs/compare/<commit_B>...<commit_A>

Using "imlib2" as a sample:

Using the compare API:

"status": "ahead",
"status": "behind",

The status field indicates ea04e1fdd523987348c468e8cb53cc36c575d629 is behind of 36a53087406df82c50b95babe3fa27667a151763

This might resolve the comparison issue. In other words, once we identify the first commit that introduced the fix for a vulnerability, then every commit after that point can be considered free of that vulnerability, and every commit before it should be considered still affected.

However, this commit_hash approach may not work well if in different branches?

@matt-phylum

Copy link
Copy Markdown
Contributor

I don't think relying on internet access and GitHub's API for every comparison is really great either. It requires an active internet connection and managing third party API tokens, it's subject to GitHub outages and rate limiting, and it would require separate implementations and possibly separate API token management for other hosts like Codeberg. NUR has GitHub and git.catgirl.cloud and codeberg.org and git.kruemmelspalter.org etc.

Another complicating factor is that packages are usually defined in Git repositories, but AFAIK this information is only available for Flakes. If somebody isn't using Flakes, they're probably just downloading a tarball. I'm not sure how that would work with timestamps either.

@jkowalleck

jkowalleck commented Jun 8, 2026

Copy link
Copy Markdown
Member

RE: #314 (comment)

I don't think relying on internet access and GitHub's API for every comparison is really great either. ...

there is no GitHub needed here.
this <from>...<to> and <from>..<to> notation is a feature of git. see for example

@chinyeungli

Copy link
Copy Markdown

@matt-phylum Thanks. All your points are spot on and completely valid.

@jkowalleck Thanks, but to use the native git commands, you'd have to download/clone the entire multi-gigabyte commit graph locally. I think that's exactly what we want to avoid doing here.

@mjherzog

mjherzog commented Jun 9, 2026

Copy link
Copy Markdown
Member

@chinyeungli Are you up for drafting a candidate PURL type definition JSON file following the PURL Type schema?

@chinyeungli

Copy link
Copy Markdown

Are you up for drafting a candidate PURL type definition JSON file following the PURL Type schema?

Sure. Let me think about it and draft something.

This was referenced Jun 9, 2026
@arianvp

arianvp commented Jun 9, 2026

Copy link
Copy Markdown

If somebody isn't using Flakes, they're probably just downloading a tarball. I'm not sure how that would work with timestamps either.

Nixpkgs channel tarballs embed the version information in the tarball as .git-revision and .version and .version-suffix

and are accessible through lib.trivial.{version,release,versionSuffix,revisionWithDefault} functions

https://github.com/NixOS/nixpkgs/blob/2a5f1b8429b586a70033f92fc9045db1705c088c/lib/trivial.nix#L455

@chinyeungli

Copy link
Copy Markdown

I created another PR with the new json schemas at #877
I think we can keep the discussion there.

navayla777-dotcom referenced this pull request Jun 10, 2026
Removed draft from name in metadata

Signed-off-by: Michael Herzog <mjherzog@aboutcode.org>
@mjherzog mjherzog linked an issue Jun 10, 2026 that may be closed by this pull request
@mjherzog

Copy link
Copy Markdown
Member

keeping open until we complete

@mjherzog mjherzog changed the title Add new PURL type: 'nix' Add new PURL type: 'nix' [old] Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PURL type new Register a new PURL type

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add PURL type: nix