diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index d400e1c..fbc53d0 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 = "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 = "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 = "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..153c5fc --- /dev/null +++ b/distroless/private/locale.bzl @@ -0,0 +1,79 @@ +"locale" + +load(":tar.bzl", "tar_lib") + +_DOC = """Create a ca-certificates.crt bundle from Common CA certificates. + +When provided with the `ca-certificates` Debian package it will create a bundle +of all common CA certificates at `/usr/share/ca-certificates` and bundle them into +a `ca-certificates.crt` file at `/etc/ssl/certs/ca-certificates.crt` + +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 = "ca-certificates", + type = ".deb", + canonical_id = "test", + sha256 = "b2d488ad4d8d8adb3ba319fc9cb2cf9909fc42cb82ad239a26c570a2e749c389", + urls = ["https://snapshot.debian.org/archive/debian/20231106T210201Z/pool/main/c/ca-certificates/ca-certificates_20210119_all.deb"], + build_file_content = "exports_files(["data.tar.xz"])" +) + +# BUILD.bazel +load("@rules_distroless//distroless:defs.bzl", "locale") + +locale( + name = "example", + package = "@ca-certificates//: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/docs/rules.md b/docs/rules.md index 259a3ed..da50da5 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -50,3 +50,52 @@ cacerts( | package | - | Label | required | | + + +## locale + +
+locale(name, charset, package) ++ +Create a ca-certificates.crt bundle from Common CA certificates. + +When provided with the `ca-certificates` Debian package it will create a bundle +of all common CA certificates at `/usr/share/ca-certificates` and bundle them into +a `ca-certificates.crt` file at `/etc/ssl/certs/ca-certificates.crt` + +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 = "ca-certificates", + type = ".deb", + canonical_id = "test", + sha256 = "b2d488ad4d8d8adb3ba319fc9cb2cf9909fc42cb82ad239a26c570a2e749c389", + urls = ["https://snapshot.debian.org/archive/debian/20231106T210201Z/pool/main/c/ca-certificates/ca-certificates_20210119_all.deb"], + build_file_content = "exports_files(["data.tar.xz"])" +) + +# BUILD.bazel +load("@rules_distroless//distroless:defs.bzl", "locale") + +locale( + name = "example", + package = "@ca-certificates//: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..b955762 100644
--- a/examples/cacerts/BUILD.bazel
+++ b/examples/cacerts/BUILD.bazel
@@ -2,13 +2,13 @@ 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 = "@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/
diff --git a/examples/locale/BUILD.bazel b/examples/locale/BUILD.bazel
new file mode 100644
index 0000000..fb2d40c
--- /dev/null
+++ b/examples/locale/BUILD.bazel
@@ -0,0 +1,69 @@
+load("//distroless:defs.bzl", "locale")
+load("//distroless/tests:asserts.bzl", "assert_tar_listing")
+
+locale(
+ name = "bullseye",
+ charset = "C.UTF-8",
+ package = "@bullseye-libc-bin//:data.tar.xz",
+)
+
+assert_tar_listing(
+ name = "test_bullseye",
+ actual = "bullseye",
+ expected = """\
+drwxr-xr-x 0 root root 0 Oct 2 13:22 ./usr/
+drwxr-xr-x 0 root root 0 Oct 2 13:22 ./usr/lib/
+drwxr-xr-x 0 root root 0 Oct 2 13:22 ./usr/lib/locale/
+drwxr-xr-x 0 root root 0 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/
+-rw-r--r-- 0 root root 131 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_ADDRESS
+-rw-r--r-- 0 root root 1519554 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_COLLATE
+-rw-r--r-- 0 root root 346132 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_CTYPE
+-rw-r--r-- 0 root root 252 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_IDENTIFICATION
+-rw-r--r-- 0 root root 23 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_MEASUREMENT
+drwxr-xr-x 0 root root 0 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_MESSAGES/
+-rw-r--r-- 0 root root 48 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_MESSAGES/SYS_LC_MESSAGES
+-rw-r--r-- 0 root root 270 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_MONETARY
+-rw-r--r-- 0 root root 62 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_NAME
+-rw-r--r-- 0 root root 50 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_NUMERIC
+-rw-r--r-- 0 root root 34 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_PAPER
+-rw-r--r-- 0 root root 47 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_TELEPHONE
+-rw-r--r-- 0 root root 3360 Oct 2 13:22 ./usr/lib/locale/C.UTF-8/LC_TIME
+drwxr-xr-x 0 root root 0 Oct 2 13:22 ./usr/share/
+drwxr-xr-x 0 root root 0 Oct 2 13:22 ./usr/share/doc/
+drwxr-xr-x 0 root root 0 Oct 2 13:22 ./usr/share/doc/libc-bin/
+-rw-r--r-- 0 root root 25467 Sep 22 2022 ./usr/share/doc/libc-bin/copyright
+""",
+)
+
+locale(
+ name = "bookworm",
+ package = "@bookworm-libc-bin//:data.tar.xz",
+)
+
+assert_tar_listing(
+ name = "test_bookworm",
+ actual = "bookworm",
+ expected = """\
+drwxr-xr-x 0 root root 0 Sep 30 01:31 ./usr/
+drwxr-xr-x 0 root root 0 Sep 30 01:31 ./usr/lib/
+drwxr-xr-x 0 root root 0 Sep 30 01:31 ./usr/lib/locale/
+drwxr-xr-x 0 root root 0 Sep 30 01:31 ./usr/lib/locale/C.utf8/
+-rw-r--r-- 0 root root 127 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_ADDRESS
+-rw-r--r-- 0 root root 1406 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_COLLATE
+-rw-r--r-- 0 root root 353616 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_CTYPE
+-rw-r--r-- 0 root root 258 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_IDENTIFICATION
+-rw-r--r-- 0 root root 23 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_MEASUREMENT
+drwxr-xr-x 0 root root 0 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_MESSAGES/
+-rw-r--r-- 0 root root 48 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_MESSAGES/SYS_LC_MESSAGES
+-rw-r--r-- 0 root root 270 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_MONETARY
+-rw-r--r-- 0 root root 62 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_NAME
+-rw-r--r-- 0 root root 50 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_NUMERIC
+-rw-r--r-- 0 root root 34 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_PAPER
+-rw-r--r-- 0 root root 47 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_TELEPHONE
+-rw-r--r-- 0 root root 3360 Sep 30 01:31 ./usr/lib/locale/C.utf8/LC_TIME
+drwxr-xr-x 0 root root 0 Sep 30 01:31 ./usr/share/
+drwxr-xr-x 0 root root 0 Sep 30 01:31 ./usr/share/doc/
+drwxr-xr-x 0 root root 0 Sep 30 01:31 ./usr/share/doc/libc-bin/
+-rw-r--r-- 0 root root 25467 Sep 22 2022 ./usr/share/doc/libc-bin/copyright
+""",
+)