Repository: osbuild/osbuild-composer
Pull request #3278 (2023-02-09 12:17:22)

Image info: Update from manifest-db
From https://github.com/osbuild/manifest-db/pull/72

We still have to discuss later on how to/where to move image-info. 
The thing is, Composer needs to have access to image-info when installed as an package, Manifest-DB can't provide this.
So the better place to do it is OSBuild as its packaged, is a dependency of Composer and overall is a good place to host a utility that uses its internals to run.

- [ ] adequate testing for the new functionality or fixed issue
- [ ] adequate documentation informing people about the change such as
  - [ ] submit a PR for the [guides](https://github.com/osbuild/guides) repository if this PR changed any behavior described there: https://www.osbuild.org/guides/


achilleas-k: This is blocked on osbuild `norecovery` support, right?
lavocatt: > This is blocked on osbuild `norecovery` support, right?

Yes.
lavocatt: It's unblocked :partying_face: 

Patch:
diff --git a/Schutzfile b/Schutzfile
index 23692aeb2..bac1da733 100644
--- a/Schutzfile
+++ b/Schutzfile
@@ -2,7 +2,7 @@
   "fedora-36": {
     "dependencies": {
       "osbuild": {
-        "commit": "fdf064b15a1ef42bd13abdfcb7e08f764f596a60"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     },
     "repos": [
@@ -79,7 +79,7 @@
   "fedora-37": {
     "dependencies": {
       "osbuild": {
-        "commit": "fdf064b15a1ef42bd13abdfcb7e08f764f596a60"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     },
     "repos": [
@@ -156,28 +156,28 @@
   "rhel-8.4": {
     "dependencies": {
       "osbuild": {
-        "commit": "ae563ff8962be0ae13e5becd0a3c2c646eeacc24"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     }
   },
   "rhel-8.6": {
     "dependencies": {
       "osbuild": {
-        "commit": "ae563ff8962be0ae13e5becd0a3c2c646eeacc24"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     }
   },
   "rhel-8.7": {
     "dependencies": {
       "osbuild": {
-        "commit": "ae563ff8962be0ae13e5becd0a3c2c646eeacc24"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     }
   },
   "rhel-8.8": {
     "dependencies": {
       "osbuild": {
-        "commit": "cb989f79b110b4b18d372deace94a7c6c7137b93"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     },
     "repos": [
@@ -223,21 +223,21 @@
   "rhel-9.0": {
     "dependencies": {
       "osbuild": {
-        "commit": "ae563ff8962be0ae13e5becd0a3c2c646eeacc24"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     }
   },
   "rhel-9.1": {
     "dependencies": {
       "osbuild": {
-        "commit": "ae563ff8962be0ae13e5becd0a3c2c646eeacc24"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     }
   },
   "rhel-9.2": {
     "dependencies": {
       "osbuild": {
-        "commit": "cb989f79b110b4b18d372deace94a7c6c7137b93"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     },
     "repos": [
@@ -283,21 +283,21 @@
   "centos-8": {
     "dependencies": {
       "osbuild": {
-        "commit": "fdf064b15a1ef42bd13abdfcb7e08f764f596a60"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     }
   },
   "centos-9": {
     "dependencies": {
       "osbuild": {
-        "commit": "fdf064b15a1ef42bd13abdfcb7e08f764f596a60"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     }
   },
   "centos-stream-9": {
     "dependencies": {
       "osbuild": {
-        "commit": "fdf064b15a1ef42bd13abdfcb7e08f764f596a60"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     },
     "repos": [
@@ -343,7 +343,7 @@
   "centos-stream-8": {
     "dependencies": {
       "osbuild": {
-        "commit": "fdf064b15a1ef42bd13abdfcb7e08f764f596a60"
+        "commit": "5eefdc1e9a732a0315c360a3771f1f3ba68a5294"
       }
     },
     "repos": [
diff --git a/internal/distro/rhel8/images.go b/internal/distro/rhel8/images.go
index f2be568ee..9d0d506ed 100644
--- a/internal/distro/rhel8/images.go
+++ b/internal/distro/rhel8/images.go
@@ -394,13 +394,10 @@ func edgeRawImage(workload workload.Workload,
 	img.Users = users.UsersFromBP(customizations.GetUsers())
 	img.Groups = users.GroupsFromBP(customizations.GetGroups())
 
-	// "rw" kernel option is required when /sysroot is mounted read-only to
-	// keep stateful parts of the filesystem writeable (/var/ and /etc)
-	img.KernelOptionsAppend = []string{"modprobe.blacklist=vc4", "rw"}
+	img.KernelOptionsAppend = []string{"modprobe.blacklist=vc4"}
 	// TODO: move to image config
 	img.Keyboard = "us"
 	img.Locale = "C.UTF-8"
-	img.SysrootReadOnly = true
 
 	img.Platform = t.platform
 	img.Workload = workload
@@ -442,12 +439,9 @@ func edgeSimplifiedInstallerImage(workload workload.Workload,
 	rawImg.Users = users.UsersFromBP(customizations.GetUsers())
 	rawImg.Groups = users.GroupsFromBP(customizations.GetGroups())
 
-	// "rw" kernel option is required when /sysroot is mounted read-only to
-	// keep stateful parts of the filesystem writeable (/var/ and /etc)
-	rawImg.KernelOptionsAppend = []string{"modprobe.blacklist=vc4", "rw"}
+	rawImg.KernelOptionsAppend = []string{"modprobe.blacklist=vc4"}
 	rawImg.Keyboard = "us"
 	rawImg.Locale = "C.UTF-8"
-	rawImg.SysrootReadOnly = true
 
 	rawImg.Platform = t.platform
 	rawImg.Workload = workload
diff --git a/internal/distro/rhel9/images.go b/internal/distro/rhel9/images.go
index 04034cbb8..0f32dec51 100644
--- a/internal/distro/rhel9/images.go
+++ b/internal/distro/rhel9/images.go
@@ -340,7 +340,6 @@ func edgeRawImage(workload workload.Workload,
 		Checksum:   options.OSTree.FetchChecksum,
 	}
 	img := image.NewOSTreeRawImage(commit)
-	// TODO: add Fedora once it's ready
 	if !common.VersionLessThan(t.arch.distro.osVersion, "9.2") || t.arch.distro.osVersion == "9-stream" {
 		img.Ignition = true
 	}
@@ -350,10 +349,13 @@ func edgeRawImage(workload workload.Workload,
 
 	// "rw" kernel option is required when /sysroot is mounted read-only to
 	// keep stateful parts of the filesystem writeable (/var/ and /etc)
-	img.KernelOptionsAppend = []string{"modprobe.blacklist=vc4", "rw"}
+	img.KernelOptionsAppend = []string{"modprobe.blacklist=vc4"}
 	img.Keyboard = "us"
 	img.Locale = "C.UTF-8"
-	img.SysrootReadOnly = true
+	if !common.VersionLessThan(t.arch.distro.osVersion, "9.2") || t.arch.distro.osVersion == "9-stream" {
+		img.SysrootReadOnly = true
+		img.KernelOptionsAppend = append(img.KernelOptionsAppend, "rw")
+	}
 
 	img.Platform = t.platform
 	img.Workload = workload
@@ -400,7 +402,6 @@ func edgeSimplifiedInstallerImage(workload workload.Workload,
 		Checksum:   options.OSTree.FetchChecksum,
 	}
 	rawImg := image.NewOSTreeRawImage(commit)
-	// TODO: add Fedora once it's ready
 	if !common.VersionLessThan(t.arch.distro.osVersion, "9.2") || t.arch.distro.osVersion == "9-stream" {
 		rawImg.Ignition = true
 	}
@@ -410,10 +411,13 @@ func edgeSimplifiedInstallerImage(workload workload.Workload,
 
 	// "rw" kernel option is required when /sysroot is mounted read-only to
 	// keep stateful parts of the filesystem writeable (/var/ and /etc)
-	rawImg.KernelOptionsAppend = []string{"modprobe.blacklist=vc4", "rw"}
+	rawImg.KernelOptionsAppend = []string{"modprobe.blacklist=vc4"}
 	rawImg.Keyboard = "us"
 	rawImg.Locale = "C.UTF-8"
-	rawImg.SysrootReadOnly = true
+	if !common.VersionLessThan(t.arch.distro.osVersion, "9.2") || t.arch.distro.osVersion == "9-stream" {
+		rawImg.SysrootReadOnly = true
+		rawImg.KernelOptionsAppend = append(rawImg.KernelOptionsAppend, "rw")
+	}
 
 	rawImg.Platform = t.platform
 	rawImg.Workload = workload
diff --git a/tools/image-info b/tools/image-info
index 376ac53ef..4a3dc1d45 100755
--- a/tools/image-info
+++ b/tools/image-info
@@ -3,7 +3,6 @@
 import argparse
 import configparser
 import contextlib
-import errno
 import functools
 import glob
 import mimetypes
@@ -19,11 +18,16 @@ import time
 import tempfile
 import xml.etree.ElementTree
 import yaml
+import pathlib
+import jsonschema
 
 from collections import OrderedDict
-from typing import Dict
+from typing import Dict, Any
 
-from osbuild import loop
+from osbuild import devices, host, mounts, meta, monitor
+
+index = meta.Index("/usr/lib/osbuild/")
+SECTOR_SIZE = 512
 
 
 def run_ostree(*args, _input=None, _check=True, **kwargs):
@@ -37,40 +41,32 @@ def run_ostree(*args, _input=None, _check=True, **kwargs):
     return res
 
 
-@contextlib.contextmanager
-def loop_create_device(ctl, fd, offset=None, sizelimit=None):
-    while True:
-        lo = loop.Loop(ctl.get_unbound())
-        try:
-            lo.set_fd(fd)
-        except OSError as e:
-            lo.close()
-            if e.errno == errno.EBUSY:
-                continue
-            raise e
-        try:
-            lo.set_status(offset=offset, sizelimit=sizelimit, autoclear=True)
-        except BlockingIOError:
-            lo.clear_fd()
-            lo.close()
-            continue
-        break
-    try:
-        yield lo
-    finally:
-        lo.close()
-
+def loop_open(devmgr: devices.DeviceManager, name: str, image, size, offset=0):
+    """
+    Uses a DeviceManager to open the `name` at `offset`
+    Retuns a Device object and the path onto wich the image was loopback mounted
+    """
+    info = index.get_module_info("Device", "org.osbuild.loopback")
+    fname = os.path.basename(image)
+    options = {
+        "filename": fname,
+        "start": offset // SECTOR_SIZE,
+        "size": size // SECTOR_SIZE
+    }
+    if not info:
+        raise RuntimeError("Can't load org.osbuild.loopback")
 
-@contextlib.contextmanager
-def loop_open(ctl, image, *, offset=None, size=None):
-    with open(image, "rb") as f:
-        fd = f.fileno()
-        with loop_create_device(ctl, fd, offset=offset, sizelimit=size) as lo:
-            yield os.path.join("/dev", lo.devname)
+    jsonschema.validate(options, info.get_schema())
+    dev = devices.Device(name, info, None, options)
+    reply = devmgr.open(dev)
+    return {
+        "Device": dev,
+        "path": os.path.join("/dev", reply["path"])
+    }
 
 
 @contextlib.contextmanager
-def convert_image(ctl, image, fmt):
+def convert_image(image, fmt):
     with tempfile.TemporaryDirectory(dir="/var/tmp") as tmp:
         if fmt["type"] != "raw":
             target = os.path.join(tmp, "image.raw")
@@ -135,6 +131,8 @@ def parse_environment_vars(s):
 def parse_unit_files(s, expected_state):
     r = []
     for line in s.split("\n")[1:]:
+        state = ""
+        unit = ""
         try:
             unit, state, *_ = line.split()
         except ValueError:
@@ -146,7 +144,7 @@ def parse_unit_files(s, expected_state):
     return r
 
 
-def subprocess_check_output(argv, parse_fn=None):
+def subprocess_check_output(argv, parse_fn=None) -> Any:
     try:
         output = subprocess.check_output(argv, encoding="utf-8")
     except subprocess.CalledProcessError as e:
@@ -195,7 +193,7 @@ def read_container_images(tree):
     return images
 
 
-def read_image_format(device):
+def read_image_format(device) -> Dict[str, str]:
     """
     Read image format.
 
@@ -235,7 +233,7 @@ def read_partition(device, partition):
     else:
         blkid = {}
 
-    partition["label"] = blkid.get("LABEL") # doesn't exist for mbr
+    partition["label"] = blkid.get("LABEL")  # doesn't exist for mbr
     partition["uuid"] = blkid.get("UUID")
     partition["fstype"] = blkid.get("TYPE")
     return partition
@@ -289,7 +287,7 @@ def read_partition_table(device):
     ptable = sfdisk["partitiontable"]
     assert ptable["unit"] == "sectors"
     is_dos = ptable["label"] == "dos"
-    ssize = ptable.get("sectorsize", 512)
+    ssize = ptable.get("sectorsize", SECTOR_SIZE)
 
     for i, p in enumerate(ptable["partitions"]):
 
@@ -318,7 +316,7 @@ def read_partition_table(device):
     return info
 
 
-def read_bootloader_type(device):
+def read_bootloader_type(device) -> str:
     """
     Read bootloader type from the provided device.
 
@@ -327,7 +325,7 @@ def read_bootloader_type(device):
     - 'unknown'
     """
     with open(device, "rb") as f:
-        if b"GRUB" in f.read(512):
+        if b"GRUB" in f.read(SECTOR_SIZE):
             return "grub"
         else:
             return "unknown"
@@ -412,20 +410,22 @@ def rpm_verify(tree):
     # verify user and group ownership:
     #   https://github.com/rpm-software-management/rpm/issues/882
     rpm = subprocess.Popen(["chroot", tree, "rpm", "--verify", "--all"],
-            stdout=subprocess.PIPE, encoding="utf-8")
+                           stdout=subprocess.PIPE, encoding="utf-8")
 
     changed = {}
     missing = []
-    for line in rpm.stdout:
-        # format description in rpm(8), under `--verify`
-        attrs = line[:9]
-        if attrs == "missing  ":
-            missing.append(line[12:].rstrip())
-        else:
-            changed[line[13:].rstrip()] = attrs
 
-    # ignore return value, because it returns non-zero when it found changes
-    rpm.wait()
+    if rpm.stdout:
+        for line in rpm.stdout:
+            # format description in rpm(8), under `--verify`
+            attrs = line[:9]
+            if attrs == "missing  ":
+                missing.append(line[12:].rstrip())
+            else:
+                changed[line[13:].rstrip()] = attrs
+
+        # ignore return value, because it returns non-zero when it found changes
+        rpm.wait()
 
     return {
         "missing": sorted(missing),
@@ -433,7 +433,7 @@ def rpm_verify(tree):
     }
 
 
-def rpm_not_installed_docs(tree, is_ostree):
+def rpm_not_installed_docs(tree):
     """
     Gathers information on documentation, which is part of RPM packages,
     but was not installed.
@@ -467,7 +467,7 @@ def rpm_not_installed_docs(tree, is_ostree):
     return sorted(not_installed_docs)
 
 
-def rpm_packages(tree, is_ostree):
+def rpm_packages(tree):
     """
     Read NVRs of RPM packages installed on the system.
 
@@ -494,7 +494,7 @@ def rpm_packages(tree, is_ostree):
         cmd += ["--dbpath", "/usr/share/rpm"]
     elif os.path.exists(os.path.join(tree, "var/lib/rpm")):
         cmd += ["--dbpath", "/var/lib/rpm"]
-    output = subprocess_check_output(cmd)
+    subprocess_check_output(cmd)
     pkgs = subprocess_check_output(cmd, str.split)
     return list(sorted(pkgs))
 
@@ -529,7 +529,8 @@ def read_services(tree, state):
         "chrony-wait.service"
     ]
     """
-    services_state = subprocess_check_output(["systemctl", f"--root={tree}", "list-unit-files"], (lambda s: parse_unit_files(s, state)))
+    services_state = subprocess_check_output(
+        ["systemctl", f"--root={tree}", "list-unit-files"], (lambda s: parse_unit_files(s, state)))
 
     # Since systemd v246, some services previously reported as "enabled" /
     # "disabled" are now reported as "alias". There is no systemd command, that
@@ -539,7 +540,8 @@ def read_services(tree, state):
     # pre/post v246 systemd versions, check all "alias" units and append them
     # to the list, if their target is also listed in 'services_state'.
     if state != "alias":
-        services_alias = subprocess_check_output(["systemctl", f"--root={tree}", "list-unit-files"], (lambda s: parse_unit_files(s, "alias")))
+        services_alias = subprocess_check_output(
+            ["systemctl", f"--root={tree}", "list-unit-files"], (lambda s: parse_unit_files(s, "alias")))
 
         for alias in services_alias:
             # The service may be in one of the following places (output of
@@ -2271,11 +2273,11 @@ def read_resolv_conf(tree):
 
 def append_filesystem(report, tree, *, is_ostree=False):
     if os.path.exists(f"{tree}/etc/os-release"):
-        report["packages"] = rpm_packages(tree, is_ostree)
+        report["packages"] = rpm_packages(tree)
         if not is_ostree:
             report["rpm-verify"] = rpm_verify(tree)
 
-        not_installed_docs = rpm_not_installed_docs(tree, is_ostree)
+        not_installed_docs = rpm_not_installed_docs(tree)
         if not_installed_docs:
             report["rpm_not_installed_docs"] = not_installed_docs
 
@@ -2468,7 +2470,7 @@ def volume_group_for_device(device: str) -> str:
             continue
 
         if res.returncode != 0:
-             raise RuntimeError(res.stderr.strip())
+            raise RuntimeError(res.stderr.strip())
 
         vg_name = res.stdout.strip()
         if vg_name:
@@ -2484,152 +2486,231 @@ def ensure_device_file(path: str, major: int, minor: int):
         os.mknod(path, 0o600 | stat.S_IFBLK, os.makedev(major, minor))
 
 
-@contextlib.contextmanager
-def discover_lvm(dev) -> Dict:
+def discover_lvm(dev: str, parent: devices.Device, devmgr: devices.DeviceManager):
     # find the volume group name for the device file
     vg_name = volume_group_for_device(dev)
 
-    # activate it
-    r = subprocess.run(["vgchange", "-ay", vg_name],
-                       stdout=subprocess.DEVNULL,
-                       stderr=subprocess.PIPE,
-                       check=False)
-    if r.returncode != 0:
-        raise RuntimeError(r.stderr.strip())
+    # activating LVM is done OSBuild side.
+    # However we still have to get OSBuild the name of the VG to open
 
-    try:
-        # Find all logical volumes in the volume group
-        cmd = [
-            "lvdisplay", "-C", "--noheadings",
-            "-o", "lv_name,path,lv_kernel_major,lv_kernel_minor",
-            "--separator", ";",
-            vg_name
-        ]
+    # Find all logical volumes in the volume group
+    cmd = [
+        "lvdisplay", "-C", "--noheadings",
+        "-o", "lv_name,path,lv_kernel_major,lv_kernel_minor",
+        "--separator", ";",
+        vg_name
+    ]
 
-        res = subprocess.run(cmd,
-                             check=False,
-                             stdout=subprocess.PIPE,
-                             stderr=subprocess.PIPE,
-                             encoding="UTF-8")
+    res = subprocess.run(cmd,
+                         check=False,
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.PIPE,
+                         encoding="UTF-8")
 
-        if res.returncode != 0:
-            raise RuntimeError(res.stderr.strip())
+    if res.returncode != 0:
+        raise RuntimeError(res.stderr.strip())
 
-        data = res.stdout.strip()
-        parsed = list(map(lambda l: l.split(";"), data.split("\n")))
-        volumes = OrderedDict()
+    data = res.stdout.strip()
+    parsed = list(map(lambda l: l.split(";"), data.split("\n")))
+    volumes = OrderedDict()
 
-        for vol in parsed:
-            vol = list(map(lambda v: v.strip(), vol))
-            assert len(vol) == 4
-            name, voldev, major, minor = vol
-            info = {
-                "device": voldev
-            }
-            ensure_device_file(voldev, int(major), int(minor))
-
-            read_partition(voldev, info)
-            volumes[name] = info
-            if name.startswith("root"):
-                volumes.move_to_end(name, last=False)
-        res = {
-            "lvm": True,
-            "lvm.vg": vg_name,
-            "lvm.volumes": volumes
-        }
+    # devices_map stores for each device path onto the system the corresponding
+    # OSBuild's Device object
+    devices_map = {}
 
-        yield res
+    for vol in parsed:
+        vol = list(map(lambda v: v.strip(), vol))
+        assert len(vol) == 4
+        name, _, _, _ = vol
 
-    finally:
-        r = subprocess.run(["vgchange", "-an", vg_name],
-                            stdout=subprocess.DEVNULL,
-                            stderr=subprocess.PIPE,
-                            check=False)
-        if r.returncode != 0:
-            raise RuntimeError(r.stderr.strip())
+        options = {
+            "volume": name,
+        }
+
+        # Create an OSBuild device object for the LVM partition
+        info = index.get_module_info("Device", "org.osbuild.lvm2.lv")
+        device = devices.Device(
+            name,
+            info,
+            parent,
+            options)
+        if not info:
+            raise RuntimeError("can't find org.osbuild.lvm2.lv")
+        jsonschema.validate(options, info.get_schema())
+        reply = devmgr.open(device)
+        voldev = reply["path"]  # get the path where is mounted the device
+        minor = reply["node"]["minor"]
+        major = reply["node"]["major"]
+
+        info = {
+            "device": voldev
+        }
+        ensure_device_file(voldev, int(major), int(minor))
+
+        read_partition(voldev, info)
+        volumes[name] = info
+        if name.startswith("root"):
+            volumes.move_to_end(name, last=False)
+
+        # associate the device path with the Device object, we will need it to
+        # mount later on.
+        devices_map[voldev] = device
+    # get back both the device map and the result that'll go in the JSON report
+    return devices_map, {
+        "lvm": True,
+        "lvm.vg": vg_name,
+        "lvm.volumes": volumes
+    }
 
 
 def partition_is_lvm(part: Dict) -> bool:
     return part["type"].upper() in ["E6D6D379-F507-44C2-A23C-238F2A3DF928", "8E"]
 
 
-def append_partitions(report, image, loctl):
+def append_partitions(report, image):
     partitions = report["partitions"]
-
-    with contextlib.ExitStack() as cm:
-        # open each partition as a loop device
-        filesystems = {}
-        for part in partitions:
-            start, size = part["start"], part["size"]
-            dev = cm.enter_context(loop_open(loctl, image, offset=start, size=size))
-            read_partition(dev, part)
-            if partition_is_lvm(part):
-                lvm = cm.enter_context(discover_lvm(dev))
-                for vol in lvm["lvm.volumes"].values():
-                    if vol["fstype"]:
-                        mntopts = []
-                        # we cannot recover since the underlying loopback device is mounted
-                        # read-only but since we are using the it through the device mapper
-                        # the fact might not be communicated and the kernel attempt a to
-                        # a recovery of the filesystem, which will lead to a kernel panic
-                        if vol["fstype"] in ("ext4", "ext3", "xfs"):
-                            mntopts = ["norecovery"]
-                        filesystems[vol["uuid"].upper()] = {
-                            "device": vol["device"],
-                            "mntops": mntopts
-                        }
-                    del vol["device"]
-                part.update(lvm)
-            elif part["uuid"] and part["fstype"]:
-                filesystems[part["uuid"].upper()] = {
-                    "device": dev
-                }
-
-        # find partition with fstab and read it
-        fstab = []
-        for fs in filesystems.values():
-            dev, opts = fs["device"], fs.get("mntops")
-            with mount(dev, opts) as tree:
-                if os.path.exists(f"{tree}/etc/fstab"):
-                    fstab.extend(read_fstab(tree))
-                    break
-        # sort the fstab entries by the mountpoint
-        fstab = sorted(fstab, key=operator.itemgetter(1))
-
-        # mount all partitions to ther respective mount points
-        root_tree = ""
-        for n, fstab_entry in enumerate(fstab):
-            part_uuid = fstab_entry[0].split("=")[1].upper()
-            part_device = filesystems[part_uuid]["device"]
-            part_mountpoint = fstab_entry[1]
-            part_fstype = fstab_entry[2]
-            part_options = fstab_entry[3].split(",")
-            part_options += filesystems[part_uuid].get("mntops", [])
-
-            # the first mount point should be root
-            if n == 0:
-                if part_mountpoint != "/":
-                    raise RuntimeError("The first mountpoint in sorted fstab entries is not '/'")
-                root_tree = cm.enter_context(mount(part_device, part_options))
-                continue
-
-            cm.enter_context(mount_at(part_device, f"{root_tree}{part_mountpoint}", options=part_options, extra=["-t", part_fstype]))
-
-        if not root_tree:
-            raise RuntimeError("The root filesystem tree is not mounted")
-
-        append_filesystem(report, root_tree)
-
-
-def analyse_image(image):
-    loctl = loop.LoopControl()
-
+    with tempfile.TemporaryDirectory() as mountpoint:
+        with host.ServiceManager(monitor=monitor.NullMonitor(1)) as mgr:
+
+            devmgr = devices.DeviceManager(mgr, "/dev", os.path.dirname(image))
+
+            # Device map associate a path onto where the device is mounted with its
+            # corresponding Device object. Mount will require both the path and the
+            # Device object in order to do its job.
+            devices_map = {}
+            filesystems = {}
+            for part in partitions:
+                start, size = part["start"], part["size"]
+                ret = loop_open(
+                    devmgr,
+                    part["partuuid"],
+                    image,
+                    size,
+                    offset=start)
+                dev = ret["path"]
+                devices_map[dev] = ret["Device"]
+                read_partition(dev, part)
+                if partition_is_lvm(part):
+                    dmap, lvm = discover_lvm(dev, ret["Device"], devmgr)
+                    devices_map.update(dmap)
+                    for vol in lvm["lvm.volumes"].values():
+                        if vol["fstype"]:
+                            mntopts = []
+                            # we cannot recover since the underlying loopback device is mounted
+                            # read-only but since we are using the it through the device mapper
+                            # the fact might not be communicated and the kernel attempt a to
+                            # a recovery of the filesystem, which will lead to a kernel panic
+                            if vol["fstype"] in ("ext4", "ext3", "xfs"):
+                                mntopts = ["norecovery"]
+                            filesystems[vol["uuid"].upper()] = {
+                                "device": vol["device"],
+                                "mntops": mntopts
+                            }
+                        del vol["device"]
+                    part.update(lvm)
+                elif part["uuid"] and part["fstype"]:
+                    filesystems[part["uuid"].upper()] = {
+                        "device": dev
+                    }
+
+            # find partition with fstab and read it
+            fstab = []
+            for fs in filesystems.values():
+                dev, opts = fs["device"], fs.get("mntops")
+                with mount(dev, opts) as tree:
+                    if os.path.exists(f"{tree}/etc/fstab"):
+                        fstab.extend(read_fstab(tree))
+                        break
+            # sort the fstab entries by the mountpoint
+            fstab = sorted(fstab, key=operator.itemgetter(1))
+
+            # mount all partitions to ther respective mount points
+            root_tree = ""
+            mmgr = mounts.MountManager(devmgr, mountpoint)
+            for n, fstab_entry in enumerate(fstab):
+                part_uuid = fstab_entry[0].split("=")[1].upper()
+                part_device = filesystems[part_uuid]["device"]
+                part_mountpoint = fstab_entry[1]
+                part_fstype = fstab_entry[2]
+                part_options = fstab_entry[3].split(",")
+                part_options += filesystems[part_uuid].get("mntops", [])
+
+                if "ext4" in part_fstype:
+                    info = index.get_module_info("Mount", "org.osbuild.ext4")
+                elif "vfat" in part_fstype:
+                    info = index.get_module_info("Mount", "org.osbuild.fat")
+                elif "btrfs" in part_fstype:
+                    info = index.get_module_info("Mount", "org.osbuild.btrfs")
+                elif "xfs" in part_fstype:
+                    info = index.get_module_info("Mount", "org.osbuild.xfs")
+                else:
+                    raise RuntimeError("Unknown file system")
+                if not info:
+                    raise RuntimeError(f"Can't find org.osbuild.{part_fstype}")
+
+                # the first mount point should be root
+                if n == 0:
+                    if part_mountpoint != "/":
+                        raise RuntimeError("The first mountpoint in sorted fstab entries is not '/'")
+                    root_tree = mountpoint
+
+                # prepare the options to mount the partition
+                options = {}
+                for option in part_options:
+                    if option == "defaults":  # defaults is not a supported option
+                        continue
+
+                    if "=" in option:
+                        parts = option.split("=")
+                        key = parts[0]
+                        val = parts[1]
+
+                        # uid and gid must be integers
+                        if key == "uid" or key == "gid":
+                            val = int(val)
+
+                        options[key] = val
+                    else:
+                        options[option] = True
+
+                options["readonly"] = True
+
+                # Validate the options
+                #
+                # The mount manager is taking care of opening the file system for us
+                # so we don't have access to the json objects that'll be used to
+                # invoke the mounter. However we're only interested at validating the
+                # options. We can extract these from the schame to validate them
+                # only.
+                jsonschema.validate(options, info.get_schema()["properties"]["options"])
+
+                # Finally mount
+                mmgr.mount(mounts.Mount(
+                    part_device,
+                    info,
+                    devices_map[part_device],  # retrieves the associated Device Object
+                    part_mountpoint,
+                    options))
+
+            if not root_tree:
+                raise RuntimeError("The root filesystem tree is not mounted")
+
+            append_filesystem(report, root_tree)
+
+
+def analyse_image(image) -> Dict[str, Any]:
     imgfmt = read_image_format(image)
-    report = {"image-format": imgfmt}
+    report: Dict[str, Any] = {"image-format": imgfmt}
 
-    with convert_image(loctl, image, imgfmt) as target:
+    with convert_image(image, imgfmt) as target:
         size = os.stat(target).st_size
-        with loop_open(loctl, target, offset=0, size=size) as device:
+        with host.ServiceManager(monitor=monitor.NullMonitor(1)) as mgr:
+            device = loop_open(
+                devices.DeviceManager(mgr, "/dev", os.path.dirname(target)),
+                os.path.basename(target),
+                target,
+                size,
+                offset=0)["path"]
             report["bootloader"] = read_bootloader_type(device)
             report.update(read_partition_table(device))
             if not report["partition-table"]:
@@ -2639,7 +2720,7 @@ def analyse_image(image):
                 return report
 
         # close loop device and descend into partitions on image file
-        append_partitions(report, target, loctl)
+        append_partitions(report, target)
         return report
 
 
@@ -2650,7 +2731,7 @@ def append_directory(report, tree):
         # Make sure that the tools which analyse the directory in-place
         # can not modify its content (e.g. create additional files).
         # mount_at() always mounts the source as read-only!
-        with mount_at(tree, tree_ro, ["bind"]) as mountpoint:
+        with mount_at(tree, tree_ro, ["bind"]) as _:
             if os.path.lexists(f"{tree}/ostree"):
                 os.makedirs(f"{tree}/etc", exist_ok=True)
                 with mount_at(f"{tree}/usr/etc", f"{tree}/etc", extra=["--bind"]):
@@ -2700,7 +2781,7 @@ def analyse_directory(path):
 
 
 def is_tarball(path):
-    mtype, encoding = mimetypes.guess_type(path)
+    mtype, _ = mimetypes.guess_type(path)
     return mtype == "application/x-tar"
 
 
@@ -2759,6 +2840,22 @@ def analyse_compressed(path):
         return analyse_image(image)
 
 
+def is_iso(path):
+    return "iso" in pathlib.Path(path).suffix
+
+
+def analyse_iso(path):
+    with tempfile.TemporaryDirectory(dir="/var/tmp") as tmp:
+        report = None
+        subprocess.run(["mount", "-o", "loop", path, tmp], check=True)
+        try:
+            report = analyse_tarball(os.path.join(tmp, "liveimg.tar.gz"))
+        except Exception as e:
+            print(f"{e}", file=sys.stderr)
+        subprocess.run(["umount", tmp], check=True)
+        return report
+
+
 def main():
     parser = argparse.ArgumentParser(description="Inspect an image")
     parser.add_argument("target", metavar="TARGET",
@@ -2774,6 +2871,8 @@ def main():
         report = analyse_tarball(target)
     elif is_compressed(target):
         report = analyse_compressed(target)
+    elif is_iso(target):
+        report = analyse_iso(target)
     else:
         report = analyse_image(target)
 
@@ -2782,4 +2881,3 @@ def main():
 
 if __name__ == "__main__":
     main()
-


Test patch:
diff --git a/test/data/ansible/check_ostree.yaml b/test/data/ansible/check_ostree.yaml
index 463d8fb49..520199cb1 100644
--- a/test/data/ansible/check_ostree.yaml
+++ b/test/data/ansible/check_ostree.yaml
@@ -259,7 +259,7 @@
     # There are three checks here for /sysroot permission based on pr https://github.com/osbuild/osbuild-composer/pull/3053
     # 1. for edge-commit and edge-installer, check ro when fedora >= 37
     # 2. for edge-commit and edge-installer, check rw for other os.
-    # 3. for edge-simplified-installer and edge-raw-image, check ro for all os.
+    # 3. for edge-simplified-installer and edge-raw-image, check ro for 9.2+ and F37+.
     - name: /sysroot should be mount with ro permission for edge-commit and edge-installer on Fedora >= 37
       block:
         - assert:
@@ -307,7 +307,26 @@
         - name: failed count + 1
           set_fact:
             failed_counter: "{{ failed_counter | int + 1 }}"
-      when: edge_type == "edge-simplified-installer" or edge_type == "edge-raw-image"
+      when: (edge_type == "edge-simplified-installer" or edge_type == "edge-raw-image") and ((ansible_facts['distribution'] == 'Fedora' and ansible_facts['distribution_version'] is version('37', '>=')) or
+            (ansible_facts['distribution'] == 'CentOS' and ansible_facts['distribution_version'] is version('9', '>=')) or (ansible_facts['distribution'] == 'RedHat' and ansible_facts['distribution_version'] is version('9.2', '>=')))
+
+    - name: /sysroot should be mount with rw permission for edge-simplified-installer and edge-raw-image for <9.2 and <F37
+      block:
+        - assert:
+            that:
+              - result_sysroot_mount_status.stdout == "rw"
+            fail_msg: "/sysroot is not mounted with rw permission"
+            success_msg: "/sysroot is mounted with rw permission"
+      always:
+        - set_fact:
+            total_counter: "{{ total_counter | int + 1 }}"
+      rescue:
+        - name: failed count + 1
+          set_fact:
+            failed_counter: "{{ failed_counter | int + 1 }}"
+      when: (edge_type == "edge-simplified-installer" or edge_type == "edge-raw-image") and ((ansible_facts['distribution'] == 'Fedora' and ansible_facts['distribution_version'] is version('37', '<')) or
+            (ansible_facts['distribution'] == 'CentOS' and ansible_facts['distribution_version'] is version('9', '<')) or (ansible_facts['distribution'] == 'RedHat' and ansible_facts['distribution_version'] is version('9.2', '<')))
+
 
     # case: check /var mount point
     - name: check /var mount point
diff --git a/test/data/manifests/centos_8-aarch64-edge_raw_image-boot.json b/test/data/manifests/centos_8-aarch64-edge_raw_image-boot.json
index f79595f43..7631ac963 100644
--- a/test/data/manifests/centos_8-aarch64-edge_raw_image-boot.json
+++ b/test/data/manifests/centos_8-aarch64-edge_raw_image-boot.json
@@ -2102,8 +2102,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -2134,7 +2133,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -2260,7 +2259,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "centos",
                 "install": true,
diff --git a/test/data/manifests/centos_8-aarch64-edge_simplified_installer-boot.json b/test/data/manifests/centos_8-aarch64-edge_simplified_installer-boot.json
index 26a891168..5c980e587 100644
--- a/test/data/manifests/centos_8-aarch64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/centos_8-aarch64-edge_simplified_installer-boot.json
@@ -2454,8 +2454,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -2486,7 +2485,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -2612,7 +2611,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "centos",
                 "install": true,
diff --git a/test/data/manifests/centos_8-x86_64-edge_raw_image-boot.json b/test/data/manifests/centos_8-x86_64-edge_raw_image-boot.json
index 7a6923f30..346ffbfa0 100644
--- a/test/data/manifests/centos_8-x86_64-edge_raw_image-boot.json
+++ b/test/data/manifests/centos_8-x86_64-edge_raw_image-boot.json
@@ -2214,8 +2214,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -2246,7 +2245,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -2372,7 +2371,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "legacy": "i386-pc",
               "uefi": {
                 "vendor": "centos",
diff --git a/test/data/manifests/centos_8-x86_64-edge_simplified_installer-boot.json b/test/data/manifests/centos_8-x86_64-edge_simplified_installer-boot.json
index 5fbd1a17f..bbd8a11e2 100644
--- a/test/data/manifests/centos_8-x86_64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/centos_8-x86_64-edge_simplified_installer-boot.json
@@ -2502,8 +2502,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -2534,7 +2533,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -2660,7 +2659,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "centos",
                 "install": true,
diff --git a/test/data/manifests/rhel_8-aarch64-edge_raw_image-boot.json b/test/data/manifests/rhel_8-aarch64-edge_raw_image-boot.json
index ab60791fc..b28f4c370 100644
--- a/test/data/manifests/rhel_8-aarch64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_8-aarch64-edge_raw_image-boot.json
@@ -857,8 +857,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -889,7 +888,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1015,7 +1014,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_8-aarch64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_8-aarch64-edge_simplified_installer-boot.json
index 5c0da4863..fd39d5fcc 100644
--- a/test/data/manifests/rhel_8-aarch64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_8-aarch64-edge_simplified_installer-boot.json
@@ -994,8 +994,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -1026,7 +1025,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1152,7 +1151,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_8-x86_64-edge_raw_image-boot.json b/test/data/manifests/rhel_8-x86_64-edge_raw_image-boot.json
index 87a08781e..9c6247268 100644
--- a/test/data/manifests/rhel_8-x86_64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_8-x86_64-edge_raw_image-boot.json
@@ -899,8 +899,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -931,7 +930,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1057,7 +1056,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "legacy": "i386-pc",
               "uefi": {
                 "vendor": "redhat",
diff --git a/test/data/manifests/rhel_8-x86_64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_8-x86_64-edge_simplified_installer-boot.json
index 45ccaa45f..003156dfd 100644
--- a/test/data/manifests/rhel_8-x86_64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_8-x86_64-edge_simplified_installer-boot.json
@@ -1012,8 +1012,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -1044,7 +1043,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1170,7 +1169,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_86-aarch64-edge_raw_image-boot.json b/test/data/manifests/rhel_86-aarch64-edge_raw_image-boot.json
index 492f61109..1ac4cbca4 100644
--- a/test/data/manifests/rhel_86-aarch64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_86-aarch64-edge_raw_image-boot.json
@@ -857,8 +857,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -889,7 +888,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1015,7 +1014,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_86-aarch64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_86-aarch64-edge_simplified_installer-boot.json
index e393ee12d..fec2fb986 100644
--- a/test/data/manifests/rhel_86-aarch64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_86-aarch64-edge_simplified_installer-boot.json
@@ -997,8 +997,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -1029,7 +1028,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1155,7 +1154,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_86-x86_64-edge_raw_image-boot.json b/test/data/manifests/rhel_86-x86_64-edge_raw_image-boot.json
index de2f9a3f5..f3e7a7688 100644
--- a/test/data/manifests/rhel_86-x86_64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_86-x86_64-edge_raw_image-boot.json
@@ -899,8 +899,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -931,7 +930,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1057,7 +1056,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "legacy": "i386-pc",
               "uefi": {
                 "vendor": "redhat",
diff --git a/test/data/manifests/rhel_86-x86_64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_86-x86_64-edge_simplified_installer-boot.json
index 6eab9c14e..dd58c65c1 100644
--- a/test/data/manifests/rhel_86-x86_64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_86-x86_64-edge_simplified_installer-boot.json
@@ -1015,8 +1015,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -1047,7 +1046,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1173,7 +1172,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_87-aarch64-edge_raw_image-boot.json b/test/data/manifests/rhel_87-aarch64-edge_raw_image-boot.json
index 7ba963dde..a08243600 100644
--- a/test/data/manifests/rhel_87-aarch64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_87-aarch64-edge_raw_image-boot.json
@@ -857,8 +857,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -889,7 +888,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1015,7 +1014,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_87-aarch64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_87-aarch64-edge_simplified_installer-boot.json
index 50c6e736f..1dc34ad7f 100644
--- a/test/data/manifests/rhel_87-aarch64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_87-aarch64-edge_simplified_installer-boot.json
@@ -994,8 +994,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -1026,7 +1025,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1152,7 +1151,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_87-x86_64-edge_raw_image-boot.json b/test/data/manifests/rhel_87-x86_64-edge_raw_image-boot.json
index e12e29b3c..6e7f0b973 100644
--- a/test/data/manifests/rhel_87-x86_64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_87-x86_64-edge_raw_image-boot.json
@@ -899,8 +899,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -931,7 +930,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1057,7 +1056,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "legacy": "i386-pc",
               "uefi": {
                 "vendor": "redhat",
diff --git a/test/data/manifests/rhel_87-x86_64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_87-x86_64-edge_simplified_installer-boot.json
index ee8f6c8eb..aad826735 100644
--- a/test/data/manifests/rhel_87-x86_64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_87-x86_64-edge_simplified_installer-boot.json
@@ -1012,8 +1012,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -1044,7 +1043,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1170,7 +1169,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_88-aarch64-edge_raw_image-boot.json b/test/data/manifests/rhel_88-aarch64-edge_raw_image-boot.json
index acbb40c4d..3fc775f64 100644
--- a/test/data/manifests/rhel_88-aarch64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_88-aarch64-edge_raw_image-boot.json
@@ -857,8 +857,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -889,7 +888,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1015,7 +1014,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_88-aarch64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_88-aarch64-edge_simplified_installer-boot.json
index 30b024744..8e3749273 100644
--- a/test/data/manifests/rhel_88-aarch64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_88-aarch64-edge_simplified_installer-boot.json
@@ -994,8 +994,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -1026,7 +1025,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1152,7 +1151,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_88-x86_64-edge_raw_image-boot.json b/test/data/manifests/rhel_88-x86_64-edge_raw_image-boot.json
index 02eae1b9a..6d87ddb8b 100644
--- a/test/data/manifests/rhel_88-x86_64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_88-x86_64-edge_raw_image-boot.json
@@ -899,8 +899,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -931,7 +930,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1057,7 +1056,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "legacy": "i386-pc",
               "uefi": {
                 "vendor": "redhat",
diff --git a/test/data/manifests/rhel_88-x86_64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_88-x86_64-edge_simplified_installer-boot.json
index 8bfa83adb..238e80a06 100644
--- a/test/data/manifests/rhel_88-x86_64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_88-x86_64-edge_simplified_installer-boot.json
@@ -1012,8 +1012,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -1044,7 +1043,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1170,7 +1169,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_9-aarch64-edge_raw_image-boot.json b/test/data/manifests/rhel_9-aarch64-edge_raw_image-boot.json
index aeac91f3b..f685f6fdd 100644
--- a/test/data/manifests/rhel_9-aarch64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_9-aarch64-edge_raw_image-boot.json
@@ -2231,8 +2231,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -2263,7 +2262,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -2389,7 +2388,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_9-aarch64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_9-aarch64-edge_simplified_installer-boot.json
index 4e1cad1b5..c9d3b40ed 100644
--- a/test/data/manifests/rhel_9-aarch64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_9-aarch64-edge_simplified_installer-boot.json
@@ -2615,8 +2615,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -2647,7 +2646,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -2773,7 +2772,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_9-x86_64-edge_raw_image-boot.json b/test/data/manifests/rhel_9-x86_64-edge_raw_image-boot.json
index 2dcdee82d..7a7cd90ff 100644
--- a/test/data/manifests/rhel_9-x86_64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_9-x86_64-edge_raw_image-boot.json
@@ -2351,8 +2351,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -2383,7 +2382,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -2509,7 +2508,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "legacy": "i386-pc",
               "uefi": {
                 "vendor": "redhat",
diff --git a/test/data/manifests/rhel_9-x86_64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_9-x86_64-edge_simplified_installer-boot.json
index 8666599a2..1b0ea9073 100644
--- a/test/data/manifests/rhel_9-x86_64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_9-x86_64-edge_simplified_installer-boot.json
@@ -2663,8 +2663,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -2695,7 +2694,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -2821,7 +2820,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_90-aarch64-edge_raw_image-boot.json b/test/data/manifests/rhel_90-aarch64-edge_raw_image-boot.json
index 304bbb931..22ac86d95 100644
--- a/test/data/manifests/rhel_90-aarch64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_90-aarch64-edge_raw_image-boot.json
@@ -836,8 +836,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -868,7 +867,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -994,7 +993,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_90-aarch64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_90-aarch64-edge_simplified_installer-boot.json
index 95f97c2b2..36fc60626 100644
--- a/test/data/manifests/rhel_90-aarch64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_90-aarch64-edge_simplified_installer-boot.json
@@ -985,8 +985,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -1017,7 +1016,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1143,7 +1142,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_90-x86_64-edge_raw_image-boot.json b/test/data/manifests/rhel_90-x86_64-edge_raw_image-boot.json
index d8bcaace9..733feba94 100644
--- a/test/data/manifests/rhel_90-x86_64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_90-x86_64-edge_raw_image-boot.json
@@ -884,8 +884,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -916,7 +915,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1042,7 +1041,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "legacy": "i386-pc",
               "uefi": {
                 "vendor": "redhat",
diff --git a/test/data/manifests/rhel_90-x86_64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_90-x86_64-edge_simplified_installer-boot.json
index dae48d840..70828f36e 100644
--- a/test/data/manifests/rhel_90-x86_64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_90-x86_64-edge_simplified_installer-boot.json
@@ -1006,8 +1006,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -1038,7 +1037,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -1164,7 +1163,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_91-aarch64-edge_raw_image-boot.json b/test/data/manifests/rhel_91-aarch64-edge_raw_image-boot.json
index 253f995ef..90e6eb67e 100644
--- a/test/data/manifests/rhel_91-aarch64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_91-aarch64-edge_raw_image-boot.json
@@ -2231,8 +2231,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -2263,7 +2262,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -2389,7 +2388,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_91-aarch64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_91-aarch64-edge_simplified_installer-boot.json
index ff2ea3e2f..f3000f74f 100644
--- a/test/data/manifests/rhel_91-aarch64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_91-aarch64-edge_simplified_installer-boot.json
@@ -2615,8 +2615,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -2647,7 +2646,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -2773,7 +2772,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,
diff --git a/test/data/manifests/rhel_91-x86_64-edge_raw_image-boot.json b/test/data/manifests/rhel_91-x86_64-edge_raw_image-boot.json
index 6ed58d201..fdda7d85d 100644
--- a/test/data/manifests/rhel_91-x86_64-edge_raw_image-boot.json
+++ b/test/data/manifests/rhel_91-x86_64-edge_raw_image-boot.json
@@ -2351,8 +2351,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -2383,7 +2382,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -2509,7 +2508,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "legacy": "i386-pc",
               "uefi": {
                 "vendor": "redhat",
diff --git a/test/data/manifests/rhel_91-x86_64-edge_simplified_installer-boot.json b/test/data/manifests/rhel_91-x86_64-edge_simplified_installer-boot.json
index 8fd3ccd75..4645facc7 100644
--- a/test/data/manifests/rhel_91-x86_64-edge_simplified_installer-boot.json
+++ b/test/data/manifests/rhel_91-x86_64-edge_simplified_installer-boot.json
@@ -2663,8 +2663,7 @@
               },
               "kernel_opts": [
                 "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75",
-                "modprobe.blacklist=vc4",
-                "rw"
+                "modprobe.blacklist=vc4"
               ]
             }
           },
@@ -2695,7 +2694,7 @@
               "repo": "/ostree/repo",
               "config": {
                 "sysroot": {
-                  "readonly": true,
+                  "readonly": false,
                   "bootloader": "none"
                 }
               }
@@ -2821,7 +2820,7 @@
             "options": {
               "root_fs_uuid": "fb180daf-48a7-4ee0-b10d-394651850fd4",
               "boot_fs_uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8",
-              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4,rw",
+              "kernel_opts": "luks.uuid=6e4ff95f-f662-45ee-a82a-bdf44a2d0b75,modprobe.blacklist=vc4",
               "uefi": {
                 "vendor": "redhat",
                 "install": true,