about summary refs log tree commit diff
path: root/pkgs/build-support/docker
diff options
context:
space:
mode:
authorWxNzEMof <143541718+WxNzEMof@users.noreply.github.com>2024-01-22 11:48:36 +0000
committerWxNzEMof <143541718+WxNzEMof@users.noreply.github.com>2024-02-26 18:10:51 +0000
commit0ec13cdb905f4428d9f008f2d99b4bd62e6fff67 (patch)
tree68834dcdf33fd16ffa22910bdc444b5e49ac4505 /pkgs/build-support/docker
parentfcea2b6260dd566c28c894b4207a5f2b56c2cba3 (diff)
streamLayeredImage: Allow customizing ownership
This opens the way towards building images where Nix can be used as an
unprivileged user (in single-user mode).
Diffstat (limited to 'pkgs/build-support/docker')
-rw-r--r--pkgs/build-support/docker/default.nix19
-rw-r--r--pkgs/build-support/docker/stream_layered_image.py25
2 files changed, 32 insertions, 12 deletions
diff --git a/pkgs/build-support/docker/default.nix b/pkgs/build-support/docker/default.nix
index 6c13a379f9346..5a57a3f80c7c0 100644
--- a/pkgs/build-support/docker/default.nix
+++ b/pkgs/build-support/docker/default.nix
@@ -907,6 +907,11 @@ rec {
     , # Time of creation of the image. Passing "now" will make the
       # created date be the time of building.
       created ? "1970-01-01T00:00:01Z"
+    , # Credentials for file ownership.
+      uid ? 0
+    , gid ? 0
+    , uname ? "root"
+    , gname ? "root"
     , # Optional bash script to run on the files prior to fixturizing the layer.
       extraCommands ? ""
     , # Optional bash script to run inside fakeroot environment.
@@ -1007,7 +1012,7 @@ rec {
 
         conf = runCommand "${baseName}-conf.json"
           {
-            inherit fromImage maxLayers created;
+            inherit fromImage maxLayers created uid gid uname gname;
             imageName = lib.toLower name;
             preferLocalBuild = true;
             passthru.imageTag =
@@ -1086,14 +1091,22 @@ rec {
               "store_layers": $store_layers[0],
               "customisation_layer", $customisation_layer,
               "repo_tag": $repo_tag,
-              "created": $created
+              "created": $created,
+              "uid": $uid,
+              "gid": $gid,
+              "uname": $uname,
+              "gname": $gname
             }
             ' --arg store_dir "${storeDir}" \
               --argjson from_image ${if fromImage == null then "null" else "'\"${fromImage}\"'"} \
               --slurpfile store_layers store_layers.json \
               --arg customisation_layer ${customisationLayer} \
               --arg repo_tag "$imageName:$imageTag" \
-              --arg created "$created" |
+              --arg created "$created" \
+              --arg uid "$uid" \
+              --arg gid "$gid" \
+              --arg uname "$uname" \
+              --arg gname "$gname" |
             tee $out
         '';
 
diff --git a/pkgs/build-support/docker/stream_layered_image.py b/pkgs/build-support/docker/stream_layered_image.py
index d7c63eb43a78f..b7e68fe322852 100644
--- a/pkgs/build-support/docker/stream_layered_image.py
+++ b/pkgs/build-support/docker/stream_layered_image.py
@@ -9,6 +9,8 @@ image as an uncompressed tarball to stdout:
   the fields with the same name on the image spec [2].
 * "created" can be "now".
 * "created" is also used as mtime for files added to the image.
+* "uid", "gid", "uname", "gname" is the file ownership, for example,
+  0, 0, "root", "root".
 * "store_layers" is a list of layers in ascending order, where each
   layer is the list of store paths to include in that layer.
 
@@ -45,7 +47,7 @@ from datetime import datetime, timezone
 from collections import namedtuple
 
 
-def archive_paths_to(obj, paths, mtime):
+def archive_paths_to(obj, paths, mtime, uid, gid, uname, gname):
     """
     Writes the given store paths as a tar file to the given stream.
 
@@ -61,10 +63,10 @@ def archive_paths_to(obj, paths, mtime):
 
     def apply_filters(ti):
         ti.mtime = mtime
-        ti.uid = 0
-        ti.gid = 0
-        ti.uname = "root"
-        ti.gname = "root"
+        ti.uid = uid
+        ti.gid = gid
+        ti.uname = uname
+        ti.gname = gname
         return ti
 
     def nix_root(ti):
@@ -208,7 +210,7 @@ def overlay_base_config(from_image, final_config):
     return final_config
 
 
-def add_layer_dir(tar, paths, store_dir, mtime):
+def add_layer_dir(tar, paths, store_dir, mtime, uid, gid, uname, gname):
     """
     Appends given store paths to a TarFile object as a new layer.
 
@@ -231,7 +233,7 @@ def add_layer_dir(tar, paths, store_dir, mtime):
     archive_paths_to(
         extract_checksum,
         paths,
-        mtime=mtime,
+        mtime, uid, gid, uname, gname
     )
     (checksum, size) = extract_checksum.extract()
 
@@ -247,7 +249,7 @@ def add_layer_dir(tar, paths, store_dir, mtime):
             archive_paths_to(
                 write,
                 paths,
-                mtime=mtime,
+                mtime, uid, gid, uname, gname
             )
             write.close()
 
@@ -324,6 +326,10 @@ def main():
       else datetime.fromisoformat(conf["created"])
     )
     mtime = int(created.timestamp())
+    uid = int(conf["uid"])
+    gid = int(conf["gid"])
+    uname = conf["uname"]
+    gname = conf["gname"]
     store_dir = conf["store_dir"]
 
     from_image = load_from_image(conf["from_image"])
@@ -336,7 +342,8 @@ def main():
         for num, store_layer in enumerate(conf["store_layers"], start=start):
             print("Creating layer", num, "from paths:", store_layer,
                   file=sys.stderr)
-            info = add_layer_dir(tar, store_layer, store_dir, mtime=mtime)
+            info = add_layer_dir(tar, store_layer, store_dir,
+                                 mtime, uid, gid, uname, gname)
             layers.append(info)
 
         print("Creating layer", len(layers) + 1, "with customisation...",