From 9716fef8da88e64253c4ad74bf3e982a3fd6c74e Mon Sep 17 00:00:00 2001 From: Sahin Yort Date: Fri, 10 Nov 2023 18:48:56 -0800 Subject: [PATCH] feat: port locale rule (#6) --- WORKSPACE.bazel | 18 +++++++-- distroless/BUILD.bazel | 5 ++- distroless/defs.bzl | 2 + distroless/private/BUILD.bazel | 7 ++++ distroless/private/locale.bzl | 73 ++++++++++++++++++++++++++++++++++ distroless/private/tar.bzl | 24 +++++++---- distroless/tests/asserts.bzl | 2 +- docs/rules.md | 43 ++++++++++++++++++++ examples/cacerts/BUILD.bazel | 27 +++++++------ examples/locale/BUILD.bazel | 71 +++++++++++++++++++++++++++++++++ 10 files changed, 246 insertions(+), 26 deletions(-) create mode 100644 distroless/private/locale.bzl create mode 100644 examples/locale/BUILD.bazel diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index d400e1c..14b7be1 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -3,10 +3,22 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( - name = "ca-certificates", + name = "example-bullseye-ca-certificates", build_file_content = 'exports_files(["data.tar.xz"])', - canonical_id = "test", sha256 = "b2d488ad4d8d8adb3ba319fc9cb2cf9909fc42cb82ad239a26c570a2e749c389", - type = ".deb", urls = ["https://snapshot.debian.org/archive/debian/20231106T210201Z/pool/main/c/ca-certificates/ca-certificates_20210119_all.deb"], ) + +http_archive( + name = "example-bullseye-libc-bin", + build_file_content = 'exports_files(["data.tar.xz"])', + sha256 = "8b048ab5c7e9f5b7444655541230e689631fd9855c384e8c4a802586d9bbc65a", + urls = ["https://snapshot.debian.org/archive/debian-security/20231106T230332Z/pool/updates/main/g/glibc/libc-bin_2.31-13+deb11u7_amd64.deb"], +) + +http_archive( + name = "example-bookworm-libc-bin", + build_file_content = 'exports_files(["data.tar.xz"])', + sha256 = "38c44247c5b3e864d6db2877edd9c9a0555fc4e23ae271b73d7f527802616df5", + urls = ["https://snapshot.debian.org/archive/debian-security/20231106T230332Z/pool/updates/main/g/glibc/libc-bin_2.36-9+deb12u3_armhf.deb"], +) diff --git a/distroless/BUILD.bazel b/distroless/BUILD.bazel index a8a445f..9105891 100644 --- a/distroless/BUILD.bazel +++ b/distroless/BUILD.bazel @@ -17,7 +17,10 @@ bzl_library( name = "defs", srcs = ["defs.bzl"], visibility = ["//visibility:public"], - deps = ["//distroless/private:cacerts"], + deps = [ + "//distroless/private:cacerts", + "//distroless/private:locale", + ], ) bzl_library( diff --git a/distroless/defs.bzl b/distroless/defs.bzl index 7e63f05..2fa63bb 100644 --- a/distroless/defs.bzl +++ b/distroless/defs.bzl @@ -1,5 +1,7 @@ "Public API re-exports" load("//distroless/private:cacerts.bzl", _cacerts = "cacerts") +load("//distroless/private:locale.bzl", _locale = "locale") cacerts = _cacerts +locale = _locale diff --git a/distroless/private/BUILD.bazel b/distroless/private/BUILD.bazel index 19c5083..bcf1328 100644 --- a/distroless/private/BUILD.bazel +++ b/distroless/private/BUILD.bazel @@ -9,6 +9,13 @@ bzl_library( deps = [":tar"], ) +bzl_library( + name = "locale", + srcs = ["locale.bzl"], + visibility = ["//distroless:__subpackages__"], + deps = [":tar"], +) + bzl_library( name = "tar", srcs = ["tar.bzl"], diff --git a/distroless/private/locale.bzl b/distroless/private/locale.bzl new file mode 100644 index 0000000..714091e --- /dev/null +++ b/distroless/private/locale.bzl @@ -0,0 +1,73 @@ +"locale" + +load(":tar.bzl", "tar_lib") + +_DOC = """Create a locale archive from a Debian package. + +An example of this would be + +```starlark +# MODULE.bazel +http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "libc-bin", + build_file_content = 'exports_files(["data.tar.xz"])', + sha256 = "8b048ab5c7e9f5b7444655541230e689631fd9855c384e8c4a802586d9bbc65a", + urls = ["https://snapshot.debian.org/archive/debian-security/20231106T230332Z/pool/updates/main/g/glibc/libc-bin_2.31-13+deb11u7_amd64.deb"], +) + +# BUILD.bazel +load("@rules_distroless//distroless:defs.bzl", "locale") + +locale( + name = "example", + package = "@libc-bin//:data.tar.xz" +) +``` +""" + +def _locale_impl(ctx): + bsdtar = ctx.toolchains[tar_lib.TOOLCHAIN_TYPE] + + output = ctx.actions.declare_file(ctx.attr.name + ".tar.gz") + + args = ctx.actions.args() + args.add("--create") + args.add("--gzip") + args.add("--file", output) + args.add("--include", "^./usr/$") + args.add("--include", "^./usr/lib/$") + args.add("--include", "^./usr/lib/locale/$") + args.add("--include", "./usr/lib/locale/%s" % ctx.attr.charset) + args.add("--include", "^./usr/share/$") + args.add("--include", "^./usr/share/doc/$") + args.add("--include", "^./usr/share/doc/libc-bin/$") + args.add("--include", "^./usr/share/doc/libc-bin/copyright$") + args.add(ctx.file.package, format = "@%s") + + ctx.actions.run( + executable = bsdtar.tarinfo.binary, + inputs = [ctx.file.package], + outputs = [output], + tools = bsdtar.default.files, + arguments = [args], + ) + return [ + DefaultInfo(files = depset([output])), + ] + +locale = rule( + doc = _DOC, + attrs = { + "package": attr.label( + allow_single_file = [".tar.xz", ".tar.gz", ".tar"], + mandatory = True, + ), + "charset": attr.string( + default = "C.utf8", + ), + }, + implementation = _locale_impl, + toolchains = [tar_lib.TOOLCHAIN_TYPE], +) diff --git a/distroless/private/tar.bzl b/distroless/private/tar.bzl index e95bf8e..9160976 100644 --- a/distroless/private/tar.bzl +++ b/distroless/private/tar.bzl @@ -15,7 +15,7 @@ def _mtree_line(file, type, content = None, uid = "0", gid = "0", time = "167256 spec.append("content=" + content) return " ".join(spec) -def _add_file_with_parents(path, file): +def _add_parents(path): lines = [] segments = path.split("/") for i in range(1, len(segments)): @@ -23,24 +23,24 @@ def _add_file_with_parents(path, file): if parent == "": continue lines.append(_mtree_line(parent.lstrip("/"), "dir")) + return lines +def _add_file_with_parents(path, file): + lines = _add_parents(path) lines.append(_mtree_line(path.lstrip("/"), "file", content = file.path)) return lines -def _build_tar(ctx, mtree, output, inputs, compression = "gzip", mnemonic = "Tar"): +def _build_tar(ctx, mtree, output, inputs = [], compression = "gzip", mnemonic = "Tar"): bsdtar = ctx.toolchains[BSDTAR_TOOLCHAIN] - mtree_out = ctx.actions.declare_file(ctx.label.name + ".spec") - ctx.actions.write(mtree_out, content = mtree) - inputs = inputs[:] - inputs.append(mtree_out) + inputs.append(mtree) args = ctx.actions.args() args.add("--create") args.add(compression, format = "--%s") args.add("--file", output) - args.add(mtree_out, format = "@%s") + args.add(mtree, format = "@%s") ctx.actions.run( executable = bsdtar.tarinfo.binary, @@ -51,6 +51,11 @@ def _build_tar(ctx, mtree, output, inputs, compression = "gzip", mnemonic = "Tar mnemonic = mnemonic, ) +def _build_mtree(ctx, content): + mtree_out = ctx.actions.declare_file(ctx.label.name + ".spec") + ctx.actions.write(mtree_out, content = content) + return mtree_out + def _create_mtree(ctx): content = ctx.actions.args() content.set_param_file_format("multiline") @@ -58,12 +63,15 @@ def _create_mtree(ctx): return struct( line = lambda **kwargs: content.add(_mtree_line(**kwargs)), add_file_with_parents = lambda *args, **kwargs: content.add_all(_add_file_with_parents(*args), uniquify = kwargs.pop("uniqify", True)), - build = lambda **kwargs: _build_tar(ctx, content, **kwargs), + add_parents = lambda *args, **kwargs: content.add_all(_add_parents(*args), uniquify = kwargs.pop("uniqify", True)), + build = lambda **kwargs: _build_tar(ctx, _build_mtree(ctx, content), **kwargs), + build_mtree = lambda **kwargs: _build_mtree(ctx, content), ) tar_lib = struct( create_mtree = _create_mtree, line = _mtree_line, + add_directory_with_parents = _add_file_with_parents, add_file_with_parents = _add_file_with_parents, TOOLCHAIN_TYPE = BSDTAR_TOOLCHAIN, ) diff --git a/distroless/tests/asserts.bzl b/distroless/tests/asserts.bzl index bbe4c72..c67139b 100644 --- a/distroless/tests/asserts.bzl +++ b/distroless/tests/asserts.bzl @@ -12,7 +12,7 @@ def assert_tar_listing(name, actual, expected): name = actual_listing, srcs = [actual], outs = ["_{}.listing".format(name)], - cmd = "$(BSDTAR_BIN) -tvf $(execpath {}) >$@".format(actual), + cmd = "cat $(execpath {}) | $(BSDTAR_BIN) -cf $@ --format=mtree --options 'cksum,sha1' @-".format(actual), toolchains = ["@bsd_tar_toolchains//:resolved_toolchain"], ) diff --git a/docs/rules.md b/docs/rules.md index 259a3ed..3677355 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -50,3 +50,46 @@ cacerts( | package | - | Label | required | | + + +## locale + +
+locale(name, charset, package)
+
+ +Create a locale archive from a Debian package. + +An example of this would be + +```starlark +# MODULE.bazel +http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "libc-bin", + build_file_content = 'exports_files(["data.tar.xz"])', + sha256 = "8b048ab5c7e9f5b7444655541230e689631fd9855c384e8c4a802586d9bbc65a", + urls = ["https://snapshot.debian.org/archive/debian-security/20231106T230332Z/pool/updates/main/g/glibc/libc-bin_2.31-13+deb11u7_amd64.deb"], +) + +# BUILD.bazel +load("@rules_distroless//distroless:defs.bzl", "locale") + +locale( + name = "example", + package = "@libc-bin//:data.tar.xz" +) +``` + + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| charset | - | String | optional | "C.utf8" | +| package | - | Label | required | | + + diff --git a/examples/cacerts/BUILD.bazel b/examples/cacerts/BUILD.bazel index 34712c6..b3d3ce3 100644 --- a/examples/cacerts/BUILD.bazel +++ b/examples/cacerts/BUILD.bazel @@ -2,22 +2,23 @@ load("//distroless:defs.bzl", "cacerts") load("//distroless/tests:asserts.bzl", "assert_tar_listing") cacerts( - name = "example", - package = "@ca-certificates//:data.tar.xz", + name = "cacerts", + package = "@example-bullseye-ca-certificates//:data.tar.xz", ) assert_tar_listing( - name = "test_examples", - actual = "example", + name = "test_cacerts", + actual = "cacerts", expected = """\ -drwxr-xr-x 0 0 0 0 Jan 1 2023 etc/ -drwxr-xr-x 0 0 0 0 Jan 1 2023 etc/ssl/ -drwxr-xr-x 0 0 0 0 Jan 1 2023 etc/ssl/certs/ --rwxr-xr-x 0 0 0 200313 Jan 1 2023 etc/ssl/certs/ca-certificates.crt -drwxr-xr-x 0 0 0 0 Jan 1 2023 etc/usr/ -drwxr-xr-x 0 0 0 0 Jan 1 2023 usr/share/ -drwxr-xr-x 0 0 0 0 Jan 1 2023 usr/share/doc/ -drwxr-xr-x 0 0 0 0 Jan 1 2023 usr/share/doc/ca-certificates/ --rwxr-xr-x 0 0 0 18940 Jan 1 2023 usr/share/doc/ca-certificates/copyright +#mtree +./etc time=1672560000.0 mode=755 gid=0 uid=0 type=dir +./etc/ssl time=1672560000.0 mode=755 gid=0 uid=0 type=dir +./etc/ssl/certs time=1672560000.0 mode=755 gid=0 uid=0 type=dir +./etc/ssl/certs/ca-certificates.crt nlink=0 time=1672560000.0 mode=755 gid=0 uid=0 type=file size=200313 cksum=3175436394 sha1digest=01b4ff230afaeeda5cddaf9a002cec9bc9a6d1b4 +./etc/usr time=1672560000.0 mode=755 gid=0 uid=0 type=dir +./usr/share time=1672560000.0 mode=755 gid=0 uid=0 type=dir +./usr/share/doc time=1672560000.0 mode=755 gid=0 uid=0 type=dir +./usr/share/doc/ca-certificates time=1672560000.0 mode=755 gid=0 uid=0 type=dir +./usr/share/doc/ca-certificates/copyright nlink=0 time=1672560000.0 mode=755 gid=0 uid=0 type=file size=18940 cksum=3142022593 sha1digest=4c49e10ddbcfc0f36816df7f9cb503d665621017 """, ) diff --git a/examples/locale/BUILD.bazel b/examples/locale/BUILD.bazel new file mode 100644 index 0000000..7daede0 --- /dev/null +++ b/examples/locale/BUILD.bazel @@ -0,0 +1,71 @@ +load("//distroless:defs.bzl", "locale") +load("//distroless/tests:asserts.bzl", "assert_tar_listing") + +locale( + name = "bullseye", + charset = "C.UTF-8", + package = "@example-bullseye-libc-bin//:data.tar.xz", +) + +assert_tar_listing( + name = "test_bullseye", + actual = "bullseye", + expected = """\ +#mtree +./usr gname=root uname=root time=1696278177.0 mode=755 gid=0 uid=0 type=dir +./usr/lib gname=root uname=root time=1696278177.0 mode=755 gid=0 uid=0 type=dir +./usr/lib/locale gname=root uname=root time=1696278177.0 mode=755 gid=0 uid=0 type=dir +./usr/lib/locale/C.UTF-8 gname=root uname=root time=1696278177.0 mode=755 gid=0 uid=0 type=dir +./usr/lib/locale/C.UTF-8/LC_ADDRESS nlink=0 gname=root uname=root time=1696278177.0 mode=644 gid=0 uid=0 type=file size=131 cksum=1894526643 sha1digest=e17f64601d95342e6977b3fe6779532c8a67a765 +./usr/lib/locale/C.UTF-8/LC_COLLATE nlink=0 gname=root uname=root time=1696278177.0 mode=644 gid=0 uid=0 type=file size=1519554 cksum=1748289584 sha1digest=5e4c048c98c444ac74ee722fc98a5a83b12c53e2 +./usr/lib/locale/C.UTF-8/LC_CTYPE nlink=0 gname=root uname=root time=1696278177.0 mode=644 gid=0 uid=0 type=file size=346132 cksum=1310021308 sha1digest=6a1ad80ed9b5b267137260eceb61ba2377a9d402 +./usr/lib/locale/C.UTF-8/LC_IDENTIFICATION nlink=0 gname=root uname=root time=1696278177.0 mode=644 gid=0 uid=0 type=file size=252 cksum=1126724133 sha1digest=7e5c3b48f452c3bd65d3185db6d568f83bdaa976 +./usr/lib/locale/C.UTF-8/LC_MEASUREMENT nlink=0 gname=root uname=root time=1696278177.0 mode=644 gid=0 uid=0 type=file size=23 cksum=2832611415 sha1digest=0a7d0d264f9ded94057020e807bfaa13a7573821 +./usr/lib/locale/C.UTF-8/LC_MONETARY nlink=0 gname=root uname=root time=1696278177.0 mode=644 gid=0 uid=0 type=file size=270 cksum=2346951072 sha1digest=e15e804a83f37be7902e75fe50b4791a32d8d1c0 +./usr/lib/locale/C.UTF-8/LC_NAME nlink=0 gname=root uname=root time=1696278177.0 mode=644 gid=0 uid=0 type=file size=62 cksum=4205828947 sha1digest=b5d16f1042c3c1c4bef85766aa2c20c1b0d8cff6 +./usr/lib/locale/C.UTF-8/LC_NUMERIC nlink=0 gname=root uname=root time=1696278177.0 mode=644 gid=0 uid=0 type=file size=50 cksum=1826161129 sha1digest=1bd2f3db04022b8cfe5cd7a7f90176f191e19425 +./usr/lib/locale/C.UTF-8/LC_PAPER nlink=0 gname=root uname=root time=1696278177.0 mode=644 gid=0 uid=0 type=file size=34 cksum=1931305775 sha1digest=567aaf639393135b76e22e72aaee1df95764e990 +./usr/lib/locale/C.UTF-8/LC_TELEPHONE nlink=0 gname=root uname=root time=1696278177.0 mode=644 gid=0 uid=0 type=file size=47 cksum=1105692602 sha1digest=3316c99e183186c5cad97a71674ef7431c3da845 +./usr/lib/locale/C.UTF-8/LC_TIME nlink=0 gname=root uname=root time=1696278177.0 mode=644 gid=0 uid=0 type=file size=3360 cksum=1452496685 sha1digest=e619a4db877e0b54fa14b8a3992da2b561b3239b +./usr/lib/locale/C.UTF-8/LC_MESSAGES gname=root uname=root time=1696278177.0 mode=755 gid=0 uid=0 type=dir +./usr/lib/locale/C.UTF-8/LC_MESSAGES/SYS_LC_MESSAGES nlink=0 gname=root uname=root time=1696278177.0 mode=644 gid=0 uid=0 type=file size=48 cksum=1913332552 sha1digest=574d7e92bedf1373ec9506859b0d55ee7babbf20 +./usr/share gname=root uname=root time=1696278177.0 mode=755 gid=0 uid=0 type=dir +./usr/share/doc gname=root uname=root time=1696278177.0 mode=755 gid=0 uid=0 type=dir +./usr/share/doc/libc-bin gname=root uname=root time=1696278177.0 mode=755 gid=0 uid=0 type=dir +./usr/share/doc/libc-bin/copyright nlink=0 gname=root uname=root time=1663877162.0 mode=644 gid=0 uid=0 type=file size=25467 cksum=3366629126 sha1digest=5c4df62d190848821200ce4041d2753bd431a7eb +""", +) + +locale( + name = "bookworm", + package = "@example-bookworm-libc-bin//:data.tar.xz", +) + +assert_tar_listing( + name = "test_bookworm", + actual = "bookworm", + expected = """\ +#mtree +./usr gname=root uname=root time=1696062665.0 mode=755 gid=0 uid=0 type=dir +./usr/lib gname=root uname=root time=1696062665.0 mode=755 gid=0 uid=0 type=dir +./usr/lib/locale gname=root uname=root time=1696062665.0 mode=755 gid=0 uid=0 type=dir +./usr/lib/locale/C.utf8 gname=root uname=root time=1696062665.0 mode=755 gid=0 uid=0 type=dir +./usr/lib/locale/C.utf8/LC_ADDRESS nlink=0 gname=root uname=root time=1696062665.0 mode=644 gid=0 uid=0 type=file size=127 cksum=3322408091 sha1digest=12d0e0600557e0dcb3c64e56894b81230e2eaa72 +./usr/lib/locale/C.utf8/LC_COLLATE nlink=0 gname=root uname=root time=1696062665.0 mode=644 gid=0 uid=0 type=file size=1406 cksum=3234458588 sha1digest=f245e3207984879d0b736c9aa42f4268e27221b9 +./usr/lib/locale/C.utf8/LC_CTYPE nlink=0 gname=root uname=root time=1696062665.0 mode=644 gid=0 uid=0 type=file size=353616 cksum=186081347 sha1digest=86e9c921184546cc60c20c150de13f3da4266304 +./usr/lib/locale/C.utf8/LC_IDENTIFICATION nlink=0 gname=root uname=root time=1696062665.0 mode=644 gid=0 uid=0 type=file size=258 cksum=1453913099 sha1digest=1eeec3b2cb259530d76ef717e24af0fd34d94624 +./usr/lib/locale/C.utf8/LC_MEASUREMENT nlink=0 gname=root uname=root time=1696062665.0 mode=644 gid=0 uid=0 type=file size=23 cksum=2832611415 sha1digest=0a7d0d264f9ded94057020e807bfaa13a7573821 +./usr/lib/locale/C.utf8/LC_MONETARY nlink=0 gname=root uname=root time=1696062665.0 mode=644 gid=0 uid=0 type=file size=270 cksum=3013307797 sha1digest=110ed47e32d65c61ab8240202faa2114d025a009 +./usr/lib/locale/C.utf8/LC_NAME nlink=0 gname=root uname=root time=1696062665.0 mode=644 gid=0 uid=0 type=file size=62 cksum=4205828947 sha1digest=b5d16f1042c3c1c4bef85766aa2c20c1b0d8cff6 +./usr/lib/locale/C.utf8/LC_NUMERIC nlink=0 gname=root uname=root time=1696062665.0 mode=644 gid=0 uid=0 type=file size=50 cksum=1826161129 sha1digest=1bd2f3db04022b8cfe5cd7a7f90176f191e19425 +./usr/lib/locale/C.utf8/LC_PAPER nlink=0 gname=root uname=root time=1696062665.0 mode=644 gid=0 uid=0 type=file size=34 cksum=1931305775 sha1digest=567aaf639393135b76e22e72aaee1df95764e990 +./usr/lib/locale/C.utf8/LC_TELEPHONE nlink=0 gname=root uname=root time=1696062665.0 mode=644 gid=0 uid=0 type=file size=47 cksum=1105692602 sha1digest=3316c99e183186c5cad97a71674ef7431c3da845 +./usr/lib/locale/C.utf8/LC_TIME nlink=0 gname=root uname=root time=1696062665.0 mode=644 gid=0 uid=0 type=file size=3360 cksum=1452496685 sha1digest=e619a4db877e0b54fa14b8a3992da2b561b3239b +./usr/lib/locale/C.utf8/LC_MESSAGES gname=root uname=root time=1696062665.0 mode=755 gid=0 uid=0 type=dir +./usr/lib/locale/C.utf8/LC_MESSAGES/SYS_LC_MESSAGES nlink=0 gname=root uname=root time=1696062665.0 mode=644 gid=0 uid=0 type=file size=48 cksum=1913332552 sha1digest=574d7e92bedf1373ec9506859b0d55ee7babbf20 +./usr/share gname=root uname=root time=1696062665.0 mode=755 gid=0 uid=0 type=dir +./usr/share/doc gname=root uname=root time=1696062665.0 mode=755 gid=0 uid=0 type=dir +./usr/share/doc/libc-bin gname=root uname=root time=1696062665.0 mode=755 gid=0 uid=0 type=dir +./usr/share/doc/libc-bin/copyright nlink=0 gname=root uname=root time=1663877162.0 mode=644 gid=0 uid=0 type=file size=25467 cksum=3366629126 sha1digest=5c4df62d190848821200ce4041d2753bd431a7eb +""", +)