diff --git a/BUILD.bazel b/BUILD.bazel index 50d5a11..894cb59 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,4 +1,16 @@ load("@gazelle//:def.bzl", "gazelle") +load("@package_metadata//purl:purl.bzl", "purl") +load("@package_metadata//rules:package_metadata.bzl", "package_metadata") + +# Package metadata of every target of this module, applied through `REPO.bazel`. +package_metadata( + name = "package_metadata", + purl = purl.bazel( + module_name(), + module_version(), + ), + visibility = ["//visibility:public"], +) alias( name = "buildifier.check", diff --git a/MODULE.bazel b/MODULE.bazel index d6c1df1..316a7a0 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -11,6 +11,7 @@ bazel_dep(name = "bazel_skylib", version = "1.9.2") bazel_dep(name = "rules_go", version = "0.63.0") bazel_dep(name = "gazelle", version = "0.53.0") bazel_dep(name = "bazel_lib", version = "3.0.0") +bazel_dep(name = "package_metadata", version = "0.0.13") bazel_dep(name = "rules_oci", version = "2.3.0", dev_dependency = True) bazel_dep(name = "rules_img", version = "0.3.18", dev_dependency = True) diff --git a/REPO.bazel b/REPO.bazel new file mode 100644 index 0000000..bbbb673 --- /dev/null +++ b/REPO.bazel @@ -0,0 +1,7 @@ +"""File declaring metadata applying to all packages and targets in the Bazel module.""" + +repo( + default_package_metadata = [ + "//:package_metadata", + ], +) diff --git a/docs/src/rules.md b/docs/src/rules.md index 7647ba1..99cf575 100644 --- a/docs/src/rules.md +++ b/docs/src/rules.md @@ -5,6 +5,7 @@ - [helm_chart](./helm_chart.md#helm_chart) - [helm_command](./helm_command.md#helm_command) - [helm_import](./helm_import.md#helm_import) +- [helm_import_package_metadata](./helm_import.md#helm_import_package_metadata) - [helm_install](./helm_install.md#helm_install) - [helm_lint_aspect](./helm_lint.md#helm_lint_aspect) - [helm_lint_test](./helm_lint.md#helm_lint_test) diff --git a/helm/defs.bzl b/helm/defs.bzl index 1dd91b4..44fa458 100644 --- a/helm/defs.bzl +++ b/helm/defs.bzl @@ -16,6 +16,7 @@ load( load( ":helm_import.bzl", _helm_import = "helm_import", + _helm_import_package_metadata = "helm_import_package_metadata", _helm_import_repository = "helm_import_repository", ) load( @@ -67,6 +68,7 @@ chart_file = _chart_file helm_chart = _helm_chart helm_command = _helm_command helm_import = _helm_import +helm_import_package_metadata = _helm_import_package_metadata helm_import_repository = _helm_import_repository helm_install = _helm_install helm_lint_aspect = _helm_lint_aspect diff --git a/helm/helm_import.bzl b/helm/helm_import.bzl index bac17d0..1e58e86 100644 --- a/helm/helm_import.bzl +++ b/helm/helm_import.bzl @@ -3,8 +3,10 @@ load( "//helm/private:import.bzl", _helm_import = "helm_import", + _helm_import_package_metadata = "helm_import_package_metadata", _helm_import_repository = "helm_import_repository", ) helm_import = _helm_import +helm_import_package_metadata = _helm_import_package_metadata helm_import_repository = _helm_import_repository diff --git a/helm/private/BUILD.bazel b/helm/private/BUILD.bazel index 680bd28..1ebb551 100644 --- a/helm/private/BUILD.bazel +++ b/helm/private/BUILD.bazel @@ -19,6 +19,9 @@ bzl_library( deps = [ "@bazel_lib//lib:base64", "@bazel_lib//lib:repo_utils", + "@bazel_skylib//lib:versions", "@bazel_skylib//rules:common_settings", + "@package_metadata//purl:srcs", + "@package_metadata//rules:srcs", ], ) diff --git a/helm/private/import.bzl b/helm/private/import.bzl index d68aede..1ae696c 100644 --- a/helm/private/import.bzl +++ b/helm/private/import.bzl @@ -1,5 +1,8 @@ """Helm rules for managing external dependencies""" +load("@bazel_skylib//lib:versions.bzl", "versions") +load("@package_metadata//purl:purl.bzl", "purl") +load("@package_metadata//rules:package_metadata.bzl", "package_metadata") load(":import_authn.bzl", "authn") load(":providers.bzl", "HelmPackageInfo") @@ -40,6 +43,30 @@ helm_import = rule( provides = [HelmPackageInfo], ) +def helm_import_package_metadata(name, chart_name, version, repository, **kwargs): + """Declares the [`package_metadata`](https://github.com/bazel-contrib/supply-chain/tree/main/metadata) of an imported Helm chart. + + The chart is identified by an `oci` [purl](https://github.com/package-url/purl-spec) carrying + the chart repository and version as `repository_url` and `tag` qualifiers. + + Args: + name (str): The name of the target. + chart_name (str): The name of the chart. + version (str): The version of the chart. + repository (str): The chart repository or OCI registry path the chart was fetched from. + **kwargs (dict): Additional keyword arguments for `package_metadata`. + """ + package_metadata( + name = name, + purl = purl.builder() + .type("oci") + .name(chart_name) + .add_qualifier("repository_url", repository) + .add_qualifier("tag", version) + .build(), + **kwargs + ) + def _find_chart_url(repository_ctx, repo_file, chart_name, chart_version): # HTTP source for `repository_ctx.download`: chart_file = "{}-{}.tgz".format(chart_name, chart_version) @@ -77,11 +104,20 @@ def _find_chart_digest(manifest): fail("could not find chart content layer") _HELM_DEP_BUILD_FILE = """\ -load("@rules_helm//helm:defs.bzl", "helm_import") +load("@rules_helm//helm:defs.bzl", "helm_import", "helm_import_package_metadata") + +helm_import_package_metadata( + name = "package_metadata", + chart_name = "{chart_name}", + repository = "{repository_url}", + version = "{chart_version}", + visibility = ["//visibility:public"], +) helm_import( name = "{chart_name}", chart = "{chart_file}", + {package_metadata_attr} = [":package_metadata"], visibility = ["//visibility:public"], ) @@ -202,10 +238,24 @@ def _helm_import_repository_impl(repository_ctx): chart_name, _, chart_version = chart_file.removesuffix(".tgz").rpartition("-") + if repository_ctx.attr.url: + # The chart's parent path, e.g. `oci://registry-1.docker.io/bitnamicharts`. + repository_url = chart_url.rpartition("/")[0] + else: + repository_url = repository_ctx.attr.repository + + # Bazel 8.0.0 renamed the `applicable_licenses` common attribute to `package_metadata`. + package_metadata_attr = "applicable_licenses" + if not native.bazel_version or versions.is_at_least("8.0.0", native.bazel_version): + package_metadata_attr = "package_metadata" + repository_ctx.file("BUILD.bazel", content = _HELM_DEP_BUILD_FILE.format( chart_name = chart_name, chart_file = chart_file, + chart_version = chart_version, + package_metadata_attr = package_metadata_attr, repository_name = repository_ctx.name, + repository_url = repository_url.rstrip("/"), )) if repository_ctx.attr.url: