From ea7bb2b2301ab67725b541085dc2f5715d677d7b Mon Sep 17 00:00:00 2001 From: Steve Barrau <98589981+stevebarrau@users.noreply.github.com> Date: Thu, 22 Jan 2026 10:28:36 +0000 Subject: [PATCH] feat: add package metadata for wheel libraries Add package_metadata rule to generated BUILD files for wheel libraries to track package provenance using PURL (Package URL) format. --- MODULE.bazel | 3 ++- .../pypi/generate_whl_library_build_bazel.bzl | 13 ++++++++++++- python/private/pypi/whl_library.bzl | 14 +++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 6486634370..4584a9307b 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -6,8 +6,9 @@ module( bazel_dep(name = "bazel_features", version = "1.21.0") bazel_dep(name = "bazel_skylib", version = "1.8.2") -bazel_dep(name = "rules_cc", version = "0.1.5") +bazel_dep(name = "package_metadata", version = "0.0.6") bazel_dep(name = "platforms", version = "0.0.11") +bazel_dep(name = "rules_cc", version = "0.1.5") # Those are loaded only when using py_proto_library # Use py_proto_library directly from protobuf repository diff --git a/python/private/pypi/generate_whl_library_build_bazel.bzl b/python/private/pypi/generate_whl_library_build_bazel.bzl index fbabe2ede3..0557c408a8 100644 --- a/python/private/pypi/generate_whl_library_build_bazel.bzl +++ b/python/private/pypi/generate_whl_library_build_bazel.bzl @@ -41,6 +41,12 @@ _TEMPLATE = """\ package(default_visibility = ["//visibility:public"]) +package_metadata( + name = "package_metadata", + purl = {purl}, + visibility = ["//:__subpackages__"], +) + {fn}( {kwargs} ) @@ -50,6 +56,7 @@ def generate_whl_library_build_bazel( *, annotation = None, default_python_version = None, + purl = None, **kwargs): """Generate a BUILD file for an unzipped Wheel @@ -63,7 +70,10 @@ def generate_whl_library_build_bazel( A complete BUILD file as a string """ - loads = [] + loads = [ + """load("@package_metadata//rules:package_metadata.bzl", "package_metadata")""", + ] + if kwargs.get("tags"): fn = "whl_library_targets" @@ -132,6 +142,7 @@ def generate_whl_library_build_bazel( "{} = {},".format(k, _RENDER.get(k, repr)(v)) for k, v in sorted(kwargs.items()) ])), + purl = repr(purl), ), ] + additional_content, ) diff --git a/python/private/pypi/whl_library.bzl b/python/private/pypi/whl_library.bzl index db2b6bc770..ab82c6e4dc 100644 --- a/python/private/pypi/whl_library.bzl +++ b/python/private/pypi/whl_library.bzl @@ -506,6 +506,11 @@ def _whl_library_impl(rctx): entry_points[entry_point_without_py] = entry_point_script_name namespace_package_files = pypi_repo_utils.find_namespace_package_files(rctx, rctx.path("site-packages")) + purl = "pkg:pypi/{}@{}".format( + # https://github.com/package-url/purl-spec/blob/main/types-doc/pypi-definition.md#name-definition + metadata["name"].replace("_", "-").lower(), + metadata["version"], + ) build_file_contents = generate_whl_library_build_bazel( name = whl_path.basename, @@ -526,6 +531,7 @@ def _whl_library_impl(rctx): "pypi_version={}".format(metadata["version"]), ], namespace_package_files = namespace_package_files, + purl = purl, ) # Delete these in case the wheel had them. They generally don't cause @@ -533,7 +539,13 @@ def _whl_library_impl(rctx): rctx.file("WORKSPACE") rctx.file("WORKSPACE.bazel") rctx.file("MODULE.bazel") - rctx.file("REPO.bazel") + rctx.file("REPO.bazel", """\ +repo( + default_package_metadata = [ + "//:package_metadata", + ], +) +""") paths = list(rctx.path(".").readdir()) for _ in range(10000000):