From 5bbc1401338af3b3f952d892022c35707dd09308 Mon Sep 17 00:00:00 2001
From: Timothée Ravier <tim@siosm.fr>
Date: Aug 19 2022 09:35:46 +0000
Subject: [PATCH 1/2] Revert "Revert "common: Add readonly sysroot migration unit and script""


Updated to fix indentation/syntax issue

This reverts commit 30f2880cfcc311a4358779910d63c813ec09b43e.

---

diff --git a/fedora-common-ostree.yaml b/fedora-common-ostree.yaml
index 0b48095..d95fa2c 100644
--- a/fedora-common-ostree.yaml
+++ b/fedora-common-ostree.yaml
@@ -111,3 +111,113 @@ postprocess:
             ln -srf /usr/bin/true ${x}
         fi
     done
+  - |
+    #!/usr/bin/env bash
+    set -xeuo pipefail
+
+    # Setup unit & script for readonly sysroot migration:
+    # - https://fedoraproject.org/wiki/Changes/Silverblue_Kinoite_readonly_sysroot
+    # - https://bugzilla.redhat.com/show_bug.cgi?id=2060976
+
+    cat > /usr/lib/systemd/system/fedora-silverblue-readonly-sysroot.service <<'EOF'
+    [Unit]
+    Description=Fedora Silverblue Read-Only Sysroot Migration
+    Documentation=https://fedoraproject.org/wiki/Changes/Silverblue_Kinoite_readonly_sysroot
+    ConditionPathExists=!/var/lib/.fedora_silverblue_readonly_sysroot
+    RequiresMountsFor=/sysroot /boot
+    ConditionPathIsReadWrite=/sysroot
+
+    [Service]
+    Type=oneshot
+    ExecStart=/usr/libexec/fedora-silverblue-readonly-sysroot
+    RemainAfterExit=yes
+
+    [Install]
+    WantedBy=multi-user.target
+    'EOF'
+
+    chmod 644 /usr/lib/systemd/system/fedora-silverblue-readonly-sysroot.service
+
+    cat > /usr/libexec/fedora-silverblue-readonly-sysroot <<'EOF'
+    #!/bin/bash
+
+    # Update an existing system to use a read only sysroot
+    # See https://fedoraproject.org/wiki/Changes/Silverblue_Kinoite_readonly_sysroot
+    # and https://bugzilla.redhat.com/show_bug.cgi?id=2060976
+
+    set -euo pipefail
+
+    main() {
+        # Used to condition execution of this unit at the systemd level
+        local -r stamp_file="/var/lib/.fedora_silverblue_readonly_sysroot
+
+        if [[ -f "${stamp_file}" ]]; then
+            exit 0
+        fi
+
+        local -r ostree_sysroot_readonly="$(ostree config --repo=/sysroot/ostree/repo get "sysroot.readonly" &> /dev/null || echo "false")"
+        if [[ "${ostree_sysroot_readonly}" == "true" ]]; then
+            # Nothing to do
+            touch "${stamp_file}"
+            exit 0
+        fi
+
+        local -r boot_entries="$(ls -A /boot/loader/entries/ | wc -l)"
+
+        # Ensure that we can read BLS entries to avoid touching systems where /boot
+        # is not mounted
+        if [[ "${boot_entries}" -eq 0 ]]; then
+            echo "No BLS entry found: Maybe /boot is not mounted?" 1>&2
+            echo "This is unexpected thus no migration will be performed" 1>&2
+            touch "${stamp_file}"
+            exit 0
+        fi
+
+        # Check if any existing deployment is still missing the rw karg
+        local rw_kargs_found=0
+        local count=0
+        for f in "/boot/loader/entries/"*; do
+            count="$(grep -c "^options .* rw" "${f}" || true)"
+            if [[ "${count}" -ge 1 ]]; then
+                rw_kargs_found=$((rw_kargs_found + 1))
+            fi
+        done
+
+        # Some deployments are still missing the rw karg. Let's try to update them
+        if [[ "${boot_entries}" -ne "${rw_kargs_found}" ]]; then
+            ostree admin kargs edit-in-place --append-if-missing=rw || \
+                echo "Failed to edit kargs in place with ostree" 1>&2
+        fi
+
+        # Re-check if any existing deployment is still missing the rw karg
+        rw_kargs_found=0
+        count=0
+        for f in "/boot/loader/entries/"*; do
+            count="$(grep -c "^options .* rw" "${f}" || true)"
+            if [[ "${count}" -ge 1 ]]; then
+                rw_kargs_found=$((rw_kargs_found + 1))
+            fi
+        done
+        unset count
+
+        # If all deployments are good, then we can set the sysroot.readonly option
+        # in the ostree repo config
+        if [[ "${boot_entries}" -eq "${rw_kargs_found}" ]]; then
+            echo "Setting up the sysroot.readonly option in the ostree repo config"
+            ostree config --repo=/sysroot/ostree/repo set "sysroot.readonly" "true"
+            touch "${stamp_file}"
+            exit 0
+        fi
+
+        # If anything else before failed, we will retry on next boot
+        echo "Will retry next boot" 1>&2
+        exit 0
+    }
+
+    main "${@}"
+    'EOF'
+
+    chmod 755 /usr/libexec/fedora-silverblue-readonly-sysroot
+
+    # Enable the corresponding unit
+    systemctl enable fedora-silverblue-readonly-sysroot.service

From f6457f06f04327c9d8fb0c19dfc89bd6b503a4da Mon Sep 17 00:00:00 2001
From: Timothée Ravier <tim@siosm.fr>
Date: Aug 19 2022 09:35:46 +0000
Subject: [PATCH 2/2] Add script to validate manifests syntax


---

diff --git a/ci/validate b/ci/validate
new file mode 100755
index 0000000..a78b4f7
--- /dev/null
+++ b/ci/validate
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+# Validate basic syntax of shell script and yaml.
+
+import os
+import stat
+import subprocess
+import yaml
+
+validated=0
+
+def openat(dirfd, name, mode='r'):
+    def opener(path, flags):
+        return os.open(path, flags, dir_fd=dirfd)
+    return open(name, mode, opener=opener)
+
+
+def validate_shell(rootfd, name):
+    subprocess.check_call(['bash', '-n', name], preexec_fn=lambda: os.fchdir(rootfd))
+    global validated
+    validated +=1
+
+
+for root, dirs, files, rootfd in os.fwalk('.'):
+    # Skip .git
+    if '.git' in dirs:
+        dirs.remove('.git')
+    for name in files:
+        if name.endswith(('.yaml', '.yml')):
+            print("Validating:", name)
+            with open(os.open(name, dir_fd=rootfd, flags=os.O_RDONLY)) as f:
+                yaml.safe_load(f)
+                validated +=1
+            continue
+        elif name.endswith('.sh'):
+            print("Validating:", name)
+            validate_shell(rootfd, name)
+            continue
+        stbuf = os.lstat(name, dir_fd=rootfd)
+        if not stat.S_ISREG(stbuf.st_mode):
+            continue
+        if not stbuf.st_mode & stat.S_IXUSR:
+            continue
+        mimetype = subprocess.check_output(['file', '-b', '--mime-type', name], encoding='UTF-8',
+                                        preexec_fn=lambda: os.fchdir(rootfd)).strip()
+        if mimetype == 'text/x-shellscript':
+            print("Validating:", name)
+            validate_shell(rootfd, name)
+
+print(f"Validated {validated} files")

