"""Defines a rule for signing the output of a container_push rule using a cosign_key """ load("@aspect_bazel_lib//lib:utils.bzl", "propagate_common_rule_attributes") load("//hack/build/rules/container:push_info.bzl", "OCIPushInfo") load("//hack/build/rules/container/sign:cosign_key.bzl", "CosignKeyInfo") CosignSignInfo = provider( doc = """Contains the cosign push information and executable for signing a container in the artifact registry """, fields = { "repo": "File containing fully qualified OCI repo that was signed", }, ) def _container_sign_impl(ctx): signer = ctx.actions.declare_file("{0}.sh".format(ctx.label.name)) cosign = ctx.toolchains["@rules_oci//cosign:toolchain_type"] crane = ctx.attr._crane_target.files.to_list()[0] crane_path = ctx.attr._crane_target.files.to_list()[0].short_path full_repo_ref_file = ctx.attr.container_push[OCIPushInfo].ref cosign_key = ctx.attr.cosign_key[CosignKeyInfo].key_file runfiles = ctx.runfiles(files = [full_repo_ref_file, cosign_key, crane]) runfiles = runfiles.merge(cosign.default.default_runfiles) substitutions = { "{{cosign_key}}": cosign_key.short_path, "{{cosign_path}}": cosign.cosign_info.binary.short_path, "{{crane_path}}": crane_path, "{{full_repo_ref_file}}": full_repo_ref_file.short_path, "{{skip_confirmation}}": "-y" if ctx.attr.skip_confirmation else "", } ctx.actions.expand_template( template = ctx.file._sign_sh_tpl, output = signer, is_executable = True, substitutions = substitutions, ) return [ DefaultInfo( executable = signer, runfiles = runfiles, ), CosignSignInfo( repo = full_repo_ref_file, ), ] _container_sign = rule( doc = """ A rule for signing container_push targets using a GCP KMS signing key """, implementation = _container_sign_impl, attrs = { "container_push": attr.label( doc = "A container_push target Label", mandatory = True, ), "cosign_key": attr.label( doc = """A cosign_key label flag that can be overwritten at runtime To override a container_sign run/build at run/build time, pass a --key=value pair with the key such as --//hack/build/rules/container/sign:gcp_kms_key and a value as a path to a gcp_kms_key. Ex.: bazel build //hack/tools/build/apko-updater-bot:container_sign \ --//hack/build/rules/container/sign:gcp_kms_key=//hack/build/rules/container/sign:sign-staging This will override the default "sign-dev" key with the "sign-staging" key. To use other keys, add entries into the hack/build/rules/container/sign/BUILD.bazel file """, default = "//hack/build/rules/container/sign:gcp_kms_key", allow_single_file = True, ), "skip_confirmation": attr.bool( doc = "Bool value to skip non-destructive actions for cosign sign - equates to `-y` option for `cosign sign`", mandatory = True, ), "_crane_target": attr.label( default = "@com_github_google_go_containerregistry//cmd/crane", allow_single_file = True, ), "_sign_sh_tpl": attr.label( default = ":sign.sh.tpl", allow_single_file = True, ), }, executable = True, toolchains = [ "@rules_oci//cosign:toolchain_type", ], ) def container_sign( container_push, cosign_key = None, skip_confirmation = True, name = "container_sign", **kwargs): """Creates a standardized container signing mechanism using cosign It creates a container signing rule that borrows much from the rules_oci cosign_sign rule, but implements a attribute for passing signing keys Args: name: the name to pass to the container_sign rule. default: `container_sign` container_push: a container_push Bazel Label to sign cosign_key: a Label to a target providing the CosignKeyInfo provider. Ex: //hack/build/rules/container:f8n-cosign-key skip_confirmation: a flag to use to skip the confirmation step of `cosign sign` to make the the signing non-interactive. default: True **kwargs: additional arguments """ forwarded_args = propagate_common_rule_attributes(kwargs) _container_sign( name = name, container_push = container_push, cosign_key = cosign_key, skip_confirmation = skip_confirmation, **forwarded_args )