diff --git a/TODO.AI.md b/TODO.AI.md index 86f467b..f257a34 100644 --- a/TODO.AI.md +++ b/TODO.AI.md @@ -7,6 +7,27 @@ and the container exits 1 (empty days value passed to `openssl req -days`). The file is generated, so the fix belongs in the upstream gen-dockerfile template, then regenerate. +## Fixed — app.ini migrated for Gitea 28.0.0 (template + startup) + +- Audited against the Gitea source and the 28.0.0 binary's own startup log. Findings: `[security] + ALLOWED_HOST_LIST = *` is rejected (logged `[E]`); `[migration]` is not a section (real name + `[migrations]`, so SKIP_TLS_VERIFY and the host settings under it were silently ignored); + `ALLOWED_DOMAINS`/`BLOCKED_DOMAINS`/`ALLOW_LOCALNETWORKS` deprecated since v28 in favour of + `ALLOWED_HOST_LIST`/`BLOCKED_HOST_LIST`; dead keys `[security] COOKIE_USERNAME`/`COOKIE_SECURE`, + `[server] LETSENCRYPT_ACCEPTTOS`, `[git.timeout] DEFAULT/CLONE/PULL`, `[cors] SCHEME/ALLOW_SUBDOMAIN`; + `[notify.email]` is not a section (`ENABLE_NOTIFY_MAIL` is in `[service]`). +- Template: fixed/removed all of the above; `ALLOWED_HOST_LIST = private,loopback` and explicit + `EGRESS_MODE = lax` in `[security]` and `[migrations]`; added `WORK_PATH`, `LOCAL_ROOT_URL`; matched live + values `DISABLE_REGISTRATION = true`, `ALLOW_LOCALNETWORKS` intent (now via ALLOWED_HOST_LIST). +- `08-gitea.sh` migrates existing configs on start: `*` becomes `private,loopback` (a real value in the + deprecated `[webhook]` key is moved to `[security]`), `[migrations]` host list and `EGRESS_MODE` are + added only when missing. Dead keys are left in place (ignored by Gitea). +- Verified with the real image: a fresh install and an upgrade of a real customised config both start with + zero `[E]` and, for the upgrade, zero warnings. Kept on purpose: `DISABLE_QUERY_AUTH_TOKEN = false` (an + earlier deliberate pin) so a fresh install still logs its one warning. +- Behaviour now actually in effect (was silently ignored before): `[migrations] SKIP_TLS_VERIFY = true` + and migrations/mirrors may reach private and loopback hosts. Needs the owner's confirmation. + ## Fixed — startup overwrote user config when `.initialized` marker was missing (init.d seed copy) - `__run_precopy` in `08-gitea.sh`, `05-dockerd.sh` and `zz-act_runner.sh` did diff --git a/rootfs/tmp/etc/gitea/app.ini b/rootfs/tmp/etc/gitea/app.ini index cf8c46e..99c443d 100644 --- a/rootfs/tmp/etc/gitea/app.ini +++ b/rootfs/tmp/etc/gitea/app.ini @@ -2,6 +2,7 @@ APP_NAME = REPLACE_SERVER_SITE_TITLE RUN_USER = REPLACE_SERVICE_USER RUN_MODE = prod +WORK_PATH = REPLACE_DATA_DIR ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [server] @@ -9,6 +10,7 @@ PROTOCOL = http HTTP_ADDR = 0.0.0.0 HTTP_PORT = 80 ROOT_URL = REPLACE_SERVER_PROTO://REPLACE_SERVER_NAME +LOCAL_ROOT_URL = http://localhost:80/ DOMAIN = REPLACE_SERVER_NAME APP_DATA_PATH = REPLACE_DATA_DIR OFFLINE_MODE = false @@ -19,7 +21,6 @@ ACME_URL = ACME_ACCEPTTOS = true ACME_EMAIL = ssl-admin@REPLACE_SERVER_NAME ACME_DIRECTORY = REPLACE_DATA_DIR/certs -LETSENCRYPT_ACCEPTTOS = true DISABLE_SSH = false START_SSH_SERVER = true SSH_LISTEN_HOST = 0.0.0.0 @@ -167,11 +168,8 @@ MAX_GIT_DIFF_FILES = 100 GC_ARGS = ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [git.timeout] -DEFAULT = 360 MIGRATE = 600 MIRROR = 300 -CLONE = 300 -PULL = 300 GC = 60 ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [picture] @@ -191,8 +189,6 @@ PASSWORD_HASH_ALGO = argon2 MIN_PASSWORD_LENGTH = 8 PASSWORD_COMPLEXITY = on LOGIN_REMEMBER_DAYS = 1825 -COOKIE_USERNAME = git_REPLACE_RANDOM_COOKIE_KEY -COOKIE_SECURE = false CSRF_COOKIE_HTTP_ONLY = true REVERSE_PROXY_LIMIT = 1 REVERSE_PROXY_TRUSTED_PROXIES = * @@ -200,7 +196,8 @@ REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER REVERSE_PROXY_AUTHENTICATION_EMAIL = X-WEBAUTH-EMAIL REVERSE_PROXY_AUTHENTICATION_FULL_NAME = X-WEBAUTH-FULLNAME X_FRAME_OPTIONS = SAMEORIGIN -ALLOWED_HOST_LIST = * +ALLOWED_HOST_LIST = private,loopback +EGRESS_MODE = lax ; explicit: defaults to true starting Gitea 1.23 and deprecates ?token=/?access_token= ; auth entirely in 1.24 — pin false so query-token API calls keep authenticating on ; upgrade instead of silently downgrading to anonymous; migrate callers to @@ -218,11 +215,10 @@ DEFAULT_PAGING_NUM = 50 DEFAULT_GIT_TREES_PER_PAGE = 1000 DEFAULT_MAX_BLOB_SIZE = 10485760 ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -[migration] +[migrations] SKIP_TLS_VERIFY = true -ALLOWED_DOMAINS = -BLOCKED_DOMAINS = -ALLOW_LOCALNETWORKS = false +ALLOWED_HOST_LIST = private,loopback +EGRESS_MODE = lax ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [git.config] http.sslVerify = false @@ -236,7 +232,7 @@ PROXY_URL = PROXY_HOSTS = ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [service] -DISABLE_REGISTRATION = false +DISABLE_REGISTRATION = true REQUIRE_SIGNIN_VIEW = false REGISTER_EMAIL_CONFIRM = REPLACE_GITEA_EMAIL_CONFIRM ENABLE_NOTIFY_MAIL = REPLACE_GITEA_EMAIL_CONFIRM @@ -277,9 +273,6 @@ SEND_AS_PLAIN_TEXT = false [email.incoming] ENABLED = false ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -[notify.email] -ENABLED = REPLACE_GITEA_EMAIL_CONFIRM -; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [openid] ENABLE_OPENID_SIGNIN = true ENABLE_OPENID_SIGNUP = true @@ -327,9 +320,7 @@ TOKEN = ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [cors] ENABLED = true -SCHEME = REPLACE_SERVER_PROTO ALLOW_DOMAIN = * -ALLOW_SUBDOMAIN = true METHODS = GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS MAX_AGE = 10m ALLOW_CREDENTIALS = true diff --git a/rootfs/usr/local/etc/docker/init.d/08-gitea.sh b/rootfs/usr/local/etc/docker/init.d/08-gitea.sh index 432836b..efe588e 100755 --- a/rootfs/usr/local/etc/docker/init.d/08-gitea.sh +++ b/rootfs/usr/local/etc/docker/init.d/08-gitea.sh @@ -137,6 +137,27 @@ __gitea_ini_set() { ' "$ini_file" >"$tmp_file" && cat "$tmp_file" >"$ini_file" rm -f "$tmp_file" } +# Remove KEY from [SECTION] of an ini file, leaving everything else untouched +__gitea_ini_unset() { + local ini_file="$1" section="$2" key="$3" tmp_file + [ -f "$ini_file" ] || return 1 + tmp_file="$(mktemp)" || return 1 + awk -v s="[$section]" -v k="$key" ' + /^\[/ { in_s = ($0 == s) } + in_s && $0 ~ "^" k "[[:space:]]*=" { next } + { print } + ' "$ini_file" >"$tmp_file" && cat "$tmp_file" >"$ini_file" + rm -f "$tmp_file" +} +# Print the value of KEY in [SECTION], empty when absent +__gitea_ini_get() { + local ini_file="$1" section="$2" key="$3" + [ -f "$ini_file" ] || return 1 + awk -v s="[$section]" -v k="$key" ' + /^\[/ { in_s = ($0 == s) } + in_s && $0 ~ "^" k "[[:space:]]*=" { v = substr($0, index($0, "=") + 1); gsub(/^[[:space:]]+|[[:space:]]+$/, "", v); print v; exit } + ' "$ini_file" +} # Set KEY = VALUE inside [SECTION] only when the key is not already present (keeps user choices) __gitea_ini_default() { local ini_file="$1" section="$2" key="$3" value="$4" @@ -478,6 +499,21 @@ __update_conf_files() { __gitea_ini_default "$_ini_file" cron.delete_old_actions OLDER_THAN 8760h __gitea_ini_default "$_ini_file" cron.delete_old_system_notices ENABLED true __gitea_ini_default "$_ini_file" cron.delete_old_system_notices OLDER_THAN 2160h + # Gitea 28 migration: a catch-all "*" host is rejected and logged as an error, so private and + # loopback are listed explicitly. A real value from the deprecated [webhook] key is moved to [security] + _hosts_sec="$(__gitea_ini_get "$_ini_file" security ALLOWED_HOST_LIST)" + _hosts_wh="$(__gitea_ini_get "$_ini_file" webhook ALLOWED_HOST_LIST)" + [ "$_hosts_sec" = "*" ] && _hosts_sec="" + [ "$_hosts_wh" = "*" ] && _hosts_wh="" + _hosts_sec="${_hosts_sec:-${_hosts_wh:-private,loopback}}" + __gitea_ini_set "$_ini_file" security ALLOWED_HOST_LIST "$_hosts_sec" + __gitea_ini_unset "$_ini_file" webhook ALLOWED_HOST_LIST + unset _hosts_sec _hosts_wh + # [migrations] (plural) is the real section; the old [migration] block was ignored by Gitea + __gitea_ini_default "$_ini_file" migrations ALLOWED_HOST_LIST "private,loopback" + # Stating the egress mode explicitly keeps Gitea's default (lax) and silences its startup warning + __gitea_ini_default "$_ini_file" security EGRESS_MODE lax + __gitea_ini_default "$_ini_file" migrations EGRESS_MODE lax sed -i "s|^DOMAIN[[:space:]]*=.*|DOMAIN = ${SERVER_NAME}|" "$_ini_file" sed -i "s|^SSH_DOMAIN[[:space:]]*=.*|SSH_DOMAIN = ${SERVER_NAME}|" "$_ini_file" # Remove deprecated [cors].X_FRAME_OPTIONS (moved to [security] in Gitea v1.26)