From: Jakub Jirutka <jakub@jirutka.cz>
Date: Wed, 12 Jul 2023 17:04:03 +0200
Date: Sun, 28 Jul 2024 01:34:54 +0200
Subject: Allow to run on readonly /usr/share

Workaround for https://github.com/keycloak/keycloak/issues/11286.

We split Keycloak installation into four directories:

* /usr/share/keycloak
  * the installation directory
  * owned by root, read-only for "ǩeycloak"
* /etc/keycloak
  * configuration files
  * directory is owned by root and "keycloak" group, files are owned and
    writable by "keycloak", but can be also read-only
* /var/lib/keycloak
  * the keycloak home directory (kc.home.dir)
  * owned by "keycloak"
* /var/lib/keycloak/conf
  * symlink to /etc/keycloak
  * created by `kc` script
* /var/lib/keycloak/data
  * site data
  * chmod 750
* /var/lib/keycloak/lib/{app,lib,quarkus-run.jar}
  * symlinks to /usr/share/keycloak/lib/
  * created by `kc` script
* /var/lib/keycloak/lib/quarkus
  * output directory for Quarkus optimised build to speed-up startup - this is
    generated by `kc build` (or `rc-service keycloak rebuild` or on the first
    start of the service) based on the current configuration
  * symlinked to /usr/share/keycloak/lib/quarkus
* /var/lib/keycloak/{providers,themes}
  * symlinks to /usr/share/keycloak/
  * created by `kc` script
* /var/lib/keycloak/version.txt
  * copy of /usr/share/keycloak/version.txt created by `kc build`

Note: /usr/share/keycloak/lib/quarkus.dist is a readonly copy of the lib/quarkus
directory from the distribution package; we use it as a seed for the new
installation, because `kc build` fails when the quarkus directory is empty.

--- a/quarkus/dist/src/main/content/bin/kc.sh
+++ b/quarkus/dist/src/main/content/bin/kc.sh
@@ -34,12 +34,17 @@
   fi
 }
 
-SERVER_OPTS="-Dkc.home.dir='$(abs_path '..')'"
-SERVER_OPTS="$SERVER_OPTS -Djboss.server.config.dir='$(abs_path '../conf')'"
+# XXX: Alpine-specific variables.
+KCSH_DIST_DIR="$(realpath "$(abs_path '..')")"
+: ${KCSH_HOME_DIR:="/var/lib/keycloak"}
+: ${KCSH_CONFIG_DIR:="/etc/keycloak"}
+
+SERVER_OPTS="-Dkc.home.dir='$KCSH_HOME_DIR'"
+SERVER_OPTS="$SERVER_OPTS -Djboss.server.config.dir='$KCSH_CONFIG_DIR'"
 SERVER_OPTS="$SERVER_OPTS -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
 SERVER_OPTS="$SERVER_OPTS -Dpicocli.disable.closures=true"
 SERVER_OPTS="$SERVER_OPTS -Dquarkus-log-max-startup-records=10000"
-CLASSPATH_OPTS="'$(abs_path "../lib/quarkus-run.jar")'"
+CLASSPATH_OPTS="'$KCSH_HOME_DIR/lib/quarkus-run.jar'"
 
 DEBUG_MODE="${DEBUG:-false}"
 DEBUG_PORT="${DEBUG_PORT:-8787}"
@@ -49,6 +54,7 @@
     printf '%s\n' "$1" | sed "s/'/'\\\\''/g; 1 s/^/'/; $ s/$/'/"
 }
 
+BUILD=false
 PRE_BUILD=true
 while [ "$#" -gt 0 ]
 do
@@ -71,8 +77,8 @@
             -D*) SERVER_OPTS="$SERVER_OPTS ${OPT}";;
             *) case "$1" in
                  --optimized | --help | --help-all | -h) PRE_BUILD=false;;
-                 build) if [ -z "$CONFIG_ARGS" ]; then PRE_BUILD=false; fi;;
-               esac 
+                 build) BUILD=true; if [ -z "$CONFIG_ARGS" ]; then PRE_BUILD=false; fi;;
+               esac
                CONFIG_ARGS="$CONFIG_ARGS ${OPT}"
                ;;
           esac
@@ -155,6 +161,25 @@
 if [ "$PRINT_ENV" = "true" ]; then
   echo "Using JAVA_OPTS: $JAVA_OPTS"
   echo "Using JAVA_RUN_OPTS: $JAVA_RUN_OPTS"
+fi
+
+# XXX-Patched: Added by Alpine Linux aport to allow running Keycloak
+# from read-only /usr/share.
+mkdir -p "$KCSH_HOME_DIR"/lib/quarkus
+for path in lib/app lib/lib lib/quarkus-run.jar providers themes; do
+  if ! [ -e "$KCSH_HOME_DIR/$path" ]; then
+    ln -s "$KCSH_DIST_DIR/$path" "$KCSH_HOME_DIR/$path"
+  fi
+done
+if ! [ "$KCSH_CONFIG_DIR" -ef "$KCSH_HOME_DIR"/conf ]; then
+  ln -sf "$KCSH_CONFIG_DIR" "$KCSH_HOME_DIR"/conf
+fi
+if [ "$BUILD" = "true" ] || ! [ -e "$KCSH_HOME_DIR"/lib/quarkus/build-system.properties ]; then
+  rm -f "$KCSH_HOME_DIR"/lib/quarkus/*
+  # Copy the distribution quarkus files. They will be overwritten by
+  # `kc build`, but this command fails when the directory is empty.
+  cp "$KCSH_DIST_DIR"/lib/quarkus.dist/* "$KCSH_HOME_DIR"/lib/quarkus/
+  cp "$KCSH_DIST_DIR"/version.txt "$KCSH_HOME_DIR"/
 fi
 
 if [ "$PRE_BUILD" = "true" ]; then
