🔧 Fix Gitea API token auth and container restart/runner races 🔧

Gitea config: `ALLOWED_HOST_LIST` was misplaced under `[webhook]` — the current
config-cheat-sheet places it under `[security]` (default `external`), where it
gates outbound webhook/OAuth2 calls. Left at its `[webhook]` default of unset
(no such key there), `[security] ALLOWED_HOST_LIST` silently fell back to
`external`, blocking internal-facing calls triggered by API actions like org
creation and surfacing as an opaque 502 through the reverse proxy. Also pinned
`DISABLE_QUERY_AUTH_TOKEN=false` explicitly, since Gitea flips its default to
`true` in 1.23 (deprecated in 1.24) and this image always builds against the
latest Gitea release — leaving it unset would silently downgrade `?token=`
API calls to anonymous on the next image rebuild.

Runtime/entrypoint: hardened `grep`/`type -t | grep` calls with `--` across
the entrypoint function library and init.d scripts to stop values starting
with `-` from being parsed as flags; guarded the entrypoint and `__no_exit`
monitor-loop PID-reuse checks with a cmdline marker (PID namespaces reset on
`docker restart` but `/run` persists, so a recorded PID can coincidentally be
reused by an unrelated process and falsely appear "still running"); added a
stale `/tmp/docker.pid` cleanup before each dockerd start attempt for the
same reason; added `NO_COLOR`-aware plain-text fallbacks for emoji status
banners; renamed the `su_cmd` helper to `__su_cmd` for naming consistency
with other private functions; added `fuse-overlayfs` as the Docker-in-Docker
storage driver.

act_runner: removed the legacy single "gitea"-named runner registration and
daemon start in `zz-act_runner.sh` — `start-runners` already owns all runner
registration/count via `RUNNERS_START`, and running both duplicated runners.
Registration now targets `127.0.0.1` instead of the detected external IPv4
address, which is transient/wrong under Docker-in-Docker networking and
caused "no route to host" registration failures. Long-running background
jobs (`cache-server`, `start-runners`) now redirect stdout/stderr to real log
files and are `disown`ed instead of inheriting the `__post_execute` pipe —
otherwise the `tee` reading that pipe never sees EOF and `__run_start_script`
hangs forever waiting on a process that never exits. `start-runners` gained a
version-stamp header and builds `RUNNER_LABELS` from an array instead of one
long string for readability; its `ERR` trap and ports list now respect
`NO_COLOR`.

- rootfs/tmp/etc/gitea/app.ini: move `ALLOWED_HOST_LIST` to `[security]`; add explicit `DISABLE_QUERY_AUTH_TOKEN=false`
- rootfs/tmp/etc/docker/daemon.json: add `storage-driver: fuse-overlayfs`
- rootfs/usr/local/bin/entrypoint.sh: version bump; `grep --` hardening; cmdline-marker PID-reuse guard; `exit 0` instead of bare `exit`
- rootfs/usr/local/bin/start-runners: add version-stamp header; `NO_COLOR`-aware ERR trap; build `RUNNER_LABELS` from an array
- rootfs/usr/local/etc/docker/functions/entrypoint.sh: version bump; `grep --` hardening across helpers; `__no_exit` monitor-loop cmdline-marker guard; `NO_COLOR`-aware service banners; rename `su_cmd` to `__su_cmd`
- rootfs/usr/local/etc/docker/init.d/05-dockerd.sh: version bump; `NO_COLOR`-aware messages; stale `/tmp/docker.pid` cleanup before start; `symlink`/`su_cmd` calls updated to `__symlink`/`__su_cmd`; `grep --` hardening; add `storage-driver` to both daemon.json heredocs
- rootfs/usr/local/etc/docker/init.d/08-gitea.sh: version bump; `NO_COLOR`-aware messages (including stale-PID-file cleanup); `grep --` hardening; `su_cmd` call updated to `__su_cmd`
- rootfs/usr/local/etc/docker/init.d/zz-act_runner.sh: version bump; remove legacy duplicate runner registration/daemon start; register against `127.0.0.1`; redirect and disown long-running background jobs to prevent pipe hangs; `NO_COLOR`-aware messages
This commit is contained in:
casjay
2026-09-03 18:18:41 -04:00
parent 4a954b0eb3
commit 7e1c90cff6
8 changed files with 253 additions and 102 deletions
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# shellcheck shell=bash
# - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202606261600-git
##@Version : 202609030524-git
# @@Author : Jason Hempstead
# @@Contact : jason@casjaysdev.pro
# @@License : LICENSE.md
@@ -20,6 +20,8 @@
# - - - - - - - - - - - - - - - - - - - - - - - - -
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
# - - - - - - - - - - - - - - - - - - - - - - - - -
VERSION="202609030524-git"
# - - - - - - - - - - - - - - - - - - - - - - - - -
set -e
# - - - - - - - - - - - - - - - - - - - - - - - - -
# run trap command on exit
@@ -43,7 +45,11 @@ __trap_err_handler() {
fi
# Critical error - but only fail if service hasn't started yet
if [ "$SERVICE_IS_RUNNING" != "yes" ]; then
echo "❌ Critical error (exit $retVal): $command" >&2
if [ -z "$NO_COLOR" ]; then
echo "❌ Critical error (exit $retVal): $command" >&2
else
echo "Critical error (exit $retVal): $command" >&2
fi
kill -TERM 1 2>/dev/null || exit $retVal
fi
return 0
@@ -108,7 +114,11 @@ fi
if [ -n "$SERVICE_NAME" ] && [ -f "/run/init.d/$SERVICE_NAME.pid" ]; then
old_pid=$(<"/run/init.d/$SERVICE_NAME.pid") 2>/dev/null
if [ -n "$old_pid" ] && ! kill -0 "$old_pid" 2>/dev/null; then
echo "🧹 Removing stale PID file for $SERVICE_NAME"
if [ -z "$NO_COLOR" ]; then
echo "🧹 Removing stale PID file for $SERVICE_NAME"
else
echo "Removing stale PID file for $SERVICE_NAME"
fi
rm -f "/run/init.d/$SERVICE_NAME.pid"
fi
fi
@@ -275,7 +285,7 @@ __run_precopy() {
ln -sf "$CONF_DIR" "$ETC_DIR"
fi
# allow custom functions
if builtin type -t __run_precopy_local | grep -q 'function'; then __run_precopy_local; fi
if builtin type -t __run_precopy_local | grep -q -- 'function'; then __run_precopy_local; fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Custom prerun functions - IE setup WWW_ROOT_DIR
@@ -285,7 +295,7 @@ __execute_prerun() {
# Define actions/commands
# allow custom functions
if builtin type -t __execute_prerun_local | grep -q 'function'; then __execute_prerun_local; fi
if builtin type -t __execute_prerun_local | grep -q -- 'function'; then __execute_prerun_local; fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Run any pre-execution checks
@@ -370,6 +380,17 @@ __run_pre_execute_checks() {
echo "Warning: cgroup v2 not available, Docker-in-Docker may have limited functionality"
fi
# Remove a stale dockerd pidfile before starting
# /tmp persists across `docker restart` (same container filesystem), but the PID
# namespace is reset on every restart, so a low PID number like the one dockerd
# wrote last time can coincidentally be reused by an unrelated process very early
# in the new namespace. dockerd's own startup check then sees /proc/<pid> exists
# and refuses to start with "process with PID <n> is still running", even though
# it is not actually the previous dockerd. This init script is the sole owner of
# the dockerd lifecycle (enforced separately via SERVICE_PID_FILE), so it is always
# safe to clear docker's own pidfile here before each start attempt.
[ -f "/tmp/docker.pid" ] && rm -f "/tmp/docker.pid"
# Clean up orphaned containers before dockerd starts
# This prevents "failed to load container" errors on restart
if [ -d "/data/docker/containers" ]; then
@@ -392,7 +413,7 @@ __run_pre_execute_checks() {
for get_reg in $DOCKER_REGISTRIES; do
set_reg+="\"$get_reg\" "
done
registry="$(printf '%s\n' "$set_reg" | tr ' ' '\n' | sort -V | grep -v '^$' | tr '\n' ',' | sed 's|,$||g;s| ||g' | grep '^')"
registry="$(printf '%s\n' "$set_reg" | tr ' ' '\n' | sort -V | grep -v -- '^$' | tr '\n' ',' | sed 's|,$||g;s| ||g' | grep -E -- '^')"
export registry
else
unset registry
@@ -425,6 +446,7 @@ EOF
"experimental": true,
"pidfile": "/tmp/docker.pid",
"cgroup-parent": "/docker",
"storage-driver": "fuse-overlayfs",
"default-address-pools": [
{"base": "172.17.0.0/12", "size": 24},
{"base": "192.168.0.0/16", "size": 24},
@@ -442,6 +464,7 @@ EOF
"experimental": true,
"pidfile": "/tmp/docker.pid",
"cgroup-parent": "/docker",
"storage-driver": "fuse-overlayfs",
"default-address-pools": [
{"base": "172.17.0.0/12", "size": 24},
{"base": "192.168.0.0/16", "size": 24},
@@ -463,7 +486,7 @@ EOF
__script_exit 1
fi
# allow custom functions
if builtin type -t __run_pre_execute_checks_local | grep -q 'function'; then __run_pre_execute_checks_local; fi
if builtin type -t __run_pre_execute_checks_local | grep -q -- 'function'; then __run_pre_execute_checks_local; fi
# exit function
return $exitStatus
}
@@ -489,12 +512,12 @@ __update_conf_files() {
# - - - - - - - - - - - - - - - - - - - - - - - - -
# define actions
symlink "$DATA_DIR" "/var/lib/docker"
__symlink "$DATA_DIR" "/var/lib/docker"
chmod 777 "$DATA_DIR" "/var/lib/docker"
# Mark config as fully initialised so __run_precopy skips re-seeding on restart
touch "$CONF_DIR/.initialized" 2>/dev/null || true
# allow custom functions
if builtin type -t __update_conf_files_local | grep -q 'function'; then __update_conf_files_local; fi
if builtin type -t __update_conf_files_local | grep -q -- 'function'; then __update_conf_files_local; fi
# exit function
return $exitCode
}
@@ -516,7 +539,7 @@ __pre_execute() {
# Lets wait a few seconds before continuing
sleep 2
# allow custom functions
if builtin type -t __pre_execute_local | grep -q 'function'; then __pre_execute_local; fi
if builtin type -t __pre_execute_local | grep -q -- 'function'; then __pre_execute_local; fi
# exit function
return $exitCode
}
@@ -549,7 +572,7 @@ __post_execute() {
# fire-and-forget: backgrounded subshell always succeeds at launch
retVal=0
# allow custom functions
if builtin type -t __post_execute_local | grep -q 'function'; then __post_execute_local; fi
if builtin type -t __post_execute_local | grep -q -- 'function'; then __post_execute_local; fi
# exit function
return $retVal
}
@@ -561,7 +584,7 @@ __pre_message() {
# execute commands
# allow custom functions
if builtin type -t __pre_message_local | grep -q 'function'; then __pre_message_local; fi
if builtin type -t __pre_message_local | grep -q -- 'function'; then __pre_message_local; fi
# exit function
return $exitCode
}
@@ -574,7 +597,7 @@ __update_ssl_conf() {
# execute commands
# allow custom functions
if builtin type -t __update_ssl_conf_local | grep -q 'function'; then __update_ssl_conf_local; fi
if builtin type -t __update_ssl_conf_local | grep -q -- 'function'; then __update_ssl_conf_local; fi
# set exitCode
return $exitCode
}
@@ -696,7 +719,7 @@ __run_start_script() {
__log_debug "Using $su_exec" | tee -a -p "/data/logs/init.txt"
fi
__log_info "$message" | tee -a -p "/data/logs/init.txt"
su_cmd touch "$SERVICE_PID_FILE"
__su_cmd touch "$SERVICE_PID_FILE"
# W14: invalidate cached START_SCRIPT if key variables changed
local _script_hash_src="$cmd $args $SERVICE_USER $RESET_ENV $su_exec"
local _script_hash