diff --git a/src/website/shared/listeners/cache_suggestions.py b/src/website/shared/listeners/cache_suggestions.py index a1ac1876..e9197a8b 100644 --- a/src/website/shared/listeners/cache_suggestions.py +++ b/src/website/shared/listeners/cache_suggestions.py @@ -1,5 +1,6 @@ import logging import re +import urllib.parse from itertools import chain from typing import Any @@ -179,6 +180,28 @@ def is_version_affected(version_statuses: list[str]) -> Version.Status: return result +def get_src_position(derivation: NixDerivation) -> str | None: + """ + Get the GitHub URL pointing to the exact source file used for the evaluation of this derivation. + E.g. https://github.com/NixOS/nixpkgs/blob/0e8be3827d0298743ba71b91eea652d43d7dc03d/pkgs/by-name/he/hello/package.nix#L47 + """ + if derivation.metadata and derivation.metadata.position: + rev = urllib.parse.quote(derivation.parent_evaluation.commit_sha1) + # position is something like `/tmp/tmpfh7ff2xs/pkgs/development/python-modules/qemu/default.nix:67` + position_match = re.match( + # FIXME the location of the eval store is going to be configurable in the future. + # https://github.com/Nix-Security-WG/nix-security-tracker/pull/451 + # Ideally the position field is already relative to the location. + r"/tmp/[^/]+/(.+):(\d+)", + derivation.metadata.position, + ) + if position_match: + path = urllib.parse.quote(position_match.group(1)) + linenumber = urllib.parse.quote(position_match.group(2)) + return f"https://github.com/NixOS/nixpkgs/blob/{rev}/{path}#L{linenumber}" + return None + + def channel_structure( version_constraints: list[Version], derivations: list[NixDerivation] ) -> dict: @@ -211,9 +234,17 @@ def channel_structure( "major_version": None, "status": None, "uniform_versions": None, + "src_position": None, "sub_branches": dict(), } - if not branch_name == major_channel: + if branch_name == major_channel: + packages[attribute]["versions"][major_channel]["major_version"] = ( + version + ) + packages[attribute]["versions"][major_channel]["src_position"] = ( + get_src_position(derivation) + ) + else: packages[attribute]["versions"][major_channel]["sub_branches"][ branch_name ] = { @@ -221,11 +252,8 @@ def channel_structure( "status": is_version_affected( [v.is_affected(version) for v in version_constraints] ), + "src_position": get_src_position(derivation), } - else: - packages[attribute]["versions"][major_channel]["major_version"] = ( - version - ) for package_name in packages: for mc in packages[package_name]["versions"].keys(): uniform_versions = True diff --git a/src/website/webview/static/style.css b/src/website/webview/static/style.css index 450f3d51..54f3f2d2 100644 --- a/src/website/webview/static/style.css +++ b/src/website/webview/static/style.css @@ -750,6 +750,10 @@ article .nixpkgs-packages { color: var(--dark-grey); } +.nixpkgs-package .branch-minor .version { + color: var(--dark-grey); +} + .nixpkgs-package .branch-major { display: inline-flex; justify-content: flex-end; @@ -764,6 +768,12 @@ article .nixpkgs-packages { min-width: 5em; display: inline-block; text-align: end; + text-decoration: none; + color: black; +} + +.nixpkgs-package .version:hover { + text-decoration: underline; } .nixpkgs-package .version.affected { diff --git a/src/website/webview/templates/components/nixpkgs_package.html b/src/website/webview/templates/components/nixpkgs_package.html index 6ab3c7ae..a132f030 100644 --- a/src/website/webview/templates/components/nixpkgs_package.html +++ b/src/website/webview/templates/components/nixpkgs_package.html @@ -7,26 +7,31 @@