diff --git a/distroless/BUILD.bazel b/distroless/BUILD.bazel index 9fa2563..2f7d3bd 100644 --- a/distroless/BUILD.bazel +++ b/distroless/BUILD.bazel @@ -20,6 +20,7 @@ bzl_library( deps = [ "//distroless/private:cacerts", "//distroless/private:group", + "//distroless/private:home", "//distroless/private:java_keystore", "//distroless/private:locale", "//distroless/private:os_release", diff --git a/distroless/defs.bzl b/distroless/defs.bzl index face129..f05cfbb 100644 --- a/distroless/defs.bzl +++ b/distroless/defs.bzl @@ -2,6 +2,7 @@ load("//distroless/private:cacerts.bzl", _cacerts = "cacerts") load("//distroless/private:group.bzl", _group = "group") +load("//distroless/private:home.bzl", _home = "home") load("//distroless/private:java_keystore.bzl", _java_keystore = "java_keystore") load("//distroless/private:locale.bzl", _locale = "locale") load("//distroless/private:os_release.bzl", _os_release = "os_release") @@ -13,3 +14,4 @@ os_release = _os_release group = _group passwd = _passwd java_keystore = _java_keystore +home = _home diff --git a/distroless/private/BUILD.bazel b/distroless/private/BUILD.bazel index 5e2ce65..cb02b65 100644 --- a/distroless/private/BUILD.bazel +++ b/distroless/private/BUILD.bazel @@ -71,6 +71,16 @@ bzl_library( deps = [":tar"], ) +bzl_library( + name = "home", + srcs = ["home.bzl"], + visibility = ["//distroless:__subpackages__"], + deps = [ + ":tar", + "@aspect_bazel_lib//lib:tar", + ], +) + bzl_library( name = "tar", srcs = ["tar.bzl"], diff --git a/distroless/private/home.bzl b/distroless/private/home.bzl new file mode 100644 index 0000000..ab8f645 --- /dev/null +++ b/distroless/private/home.bzl @@ -0,0 +1,27 @@ +"home" + +load("@aspect_bazel_lib//lib:tar.bzl", "tar") +load(":tar.bzl", "tar_lib") + +def home(name, dirs, **kwargs): + """ + Create home directories with specific uid and gids. + + Args: + name: name of the target + dirs: array of home directory dicts. + **kwargs: other named arguments to that is passed to tar. see [common rule attributes](https://bazel.build/reference/be/common-definitions#common-attributes). + """ + mtree = [] + + for home in dirs: + mtree.extend( + tar_lib.add_directory_with_parents(home["home"], uid = str(home["uid"]), gid = str(home["gid"])), + ) + + tar( + name = name, + srcs = [], + mtree = mtree, + **kwargs + ) diff --git a/distroless/private/passwd.bzl b/distroless/private/passwd.bzl index 62c6615..229ab56 100644 --- a/distroless/private/passwd.bzl +++ b/distroless/private/passwd.bzl @@ -50,7 +50,7 @@ def passwd(name, passwds, **kwargs): stamp = 0, template = [ "#mtree", - "etc/passwd uid=0 gid=0 mode=0700 time=0 type=file content={content}", + "./etc/passwd uid=0 gid=0 mode=0700 time=0 type=file content={content}", "", ], substitutions = { diff --git a/distroless/private/tar.bzl b/distroless/private/tar.bzl index 9160976..514461f 100644 --- a/distroless/private/tar.bzl +++ b/distroless/private/tar.bzl @@ -2,9 +2,15 @@ BSDTAR_TOOLCHAIN = "@aspect_bazel_lib//lib:tar_toolchain_type" -def _mtree_line(file, type, content = None, uid = "0", gid = "0", time = "1672560000", mode = "0755"): +def _mtree_line(dest, type, content = None, uid = "0", gid = "0", time = "1672560000", mode = "0755"): + # mtree expects paths to start with ./ so normalize paths that starts with + # `/` or relative path (without / and ./) + if not dest.startswith("."): + if not dest.startswith("/"): + dest = "/" + dest + dest = "." + dest spec = [ - file, + dest, "uid=" + uid, "gid=" + gid, "time=" + time, @@ -15,19 +21,27 @@ def _mtree_line(file, type, content = None, uid = "0", gid = "0", time = "167256 spec.append("content=" + content) return " ".join(spec) -def _add_parents(path): +def _add_parents(path, uid = "0", gid = "0", time = "1672560000", mode = "0755"): lines = [] segments = path.split("/") - for i in range(1, len(segments)): - parent = "/".join(segments[:i]) - if parent == "": + segments.pop() + for i in range(0, len(segments)): + parent = "/".join(segments[:i + 1]) + if not parent: continue - lines.append(_mtree_line(parent.lstrip("/"), "dir")) + lines.append( + _mtree_line(parent, "dir", uid = uid, gid = gid, time = time, mode = mode), + ) return lines def _add_file_with_parents(path, file): lines = _add_parents(path) - lines.append(_mtree_line(path.lstrip("/"), "file", content = file.path)) + lines.append(_mtree_line(path, "file", content = file.path)) + return lines + +def _add_directory_with_parents(path, **kwargs): + lines = _add_parents(path) + lines.append(_mtree_line(path, "dir", **kwargs)) return lines def _build_tar(ctx, mtree, output, inputs = [], compression = "gzip", mnemonic = "Tar"): @@ -71,7 +85,7 @@ def _create_mtree(ctx): tar_lib = struct( create_mtree = _create_mtree, line = _mtree_line, - add_directory_with_parents = _add_file_with_parents, + add_directory_with_parents = _add_directory_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 851cdab..6ae8ba4 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -138,6 +138,26 @@ https://www.ibm.com/docs/en/aix/7.2?topic=files-etcgroup-file#group_security__a2 | kwargs | other named arguments to expanded targets. see [common rule attributes](https://bazel.build/reference/be/common-definitions#common-attributes). | none | + + +## home + +
+home(name, dirs, kwargs) ++ + Create home directories with specific uid and gids. + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| name | name of the target | none | +| dirs | array of home directory dicts. | none | +| kwargs | other named arguments to that is passed to tar. see [common rule attributes](https://bazel.build/reference/be/common-definitions#common-attributes). | none | + + ## os_release diff --git a/examples/cacerts/BUILD.bazel b/examples/cacerts/BUILD.bazel index b3d3ce3..03bdd0d 100644 --- a/examples/cacerts/BUILD.bazel +++ b/examples/cacerts/BUILD.bazel @@ -15,7 +15,7 @@ assert_tar_listing( ./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 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 diff --git a/examples/home/BUILD.bazel b/examples/home/BUILD.bazel new file mode 100644 index 0000000..1919573 --- /dev/null +++ b/examples/home/BUILD.bazel @@ -0,0 +1,29 @@ +load("//distroless:defs.bzl", "home") +load("//distroless/tests:asserts.bzl", "assert_tar_listing") + +home( + name = "home", + dirs = [ + { + "home": "/root", + "uid": 0, + "gid": 0, + }, + { + "home": "/home/nonroot", + "uid": 666, + "gid": 666, + }, + ], +) + +assert_tar_listing( + name = "test_home", + actual = "home", + expected = """\ +#mtree +./home time=1672560000.0 mode=755 gid=0 uid=0 type=dir +./home/nonroot time=1672560000.0 mode=755 gid=666 uid=666 type=dir +./root time=1672560000.0 mode=755 gid=0 uid=0 type=dir +""", +)