mirror of
https://github.com/casjaysdevdocker/gitea
synced 2026-10-15 14:12:54 -04:00
🔧 Migrate app.ini for Gitea 28 and match live settings 🔧
Audited the template against Gitea 28.0.0 (source plus the binary's own startup log) and fixed everything it flags. Existing configs are migrated on startup without touching user values. - rootfs/tmp/etc/gitea/app.ini: ALLOWED_HOST_LIST "*" -> private,loopback with explicit EGRESS_MODE=lax; [migration] -> [migrations] with ALLOWED_HOST_LIST; drop deprecated/dead keys and the non-existent [notify.email]; add WORK_PATH and LOCAL_ROOT_URL; DISABLE_REGISTRATION=true - rootfs/usr/local/etc/docker/init.d/08-gitea.sh: add __gitea_ini_get/__gitea_ini_unset and migrate existing configs (invalid "*" host list, [webhook] key moved to [security], [migrations] host list, EGRESS_MODE) - TODO.AI.md: record the audit, the verification, and the behaviour changes needing owner confirmation Claude-Session: https://claude.ai/code/session_01Kae22tmhzhmfHyqc34PZbx
This commit is contained in:
3 files changed
+65
-17
No files matched your search
+21
@@ -7,6 +7,27 @@
|
|||||||
and the container exits 1 (empty days value passed to `openssl req -days`). The file is
|
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.
|
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)
|
## 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
|
- `__run_precopy` in `08-gitea.sh`, `05-dockerd.sh` and `zz-act_runner.sh` did
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
APP_NAME = REPLACE_SERVER_SITE_TITLE
|
APP_NAME = REPLACE_SERVER_SITE_TITLE
|
||||||
RUN_USER = REPLACE_SERVICE_USER
|
RUN_USER = REPLACE_SERVICE_USER
|
||||||
RUN_MODE = prod
|
RUN_MODE = prod
|
||||||
|
WORK_PATH = REPLACE_DATA_DIR
|
||||||
|
|
||||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
[server]
|
[server]
|
||||||
@@ -9,6 +10,7 @@ PROTOCOL = http
|
|||||||
HTTP_ADDR = 0.0.0.0
|
HTTP_ADDR = 0.0.0.0
|
||||||
HTTP_PORT = 80
|
HTTP_PORT = 80
|
||||||
ROOT_URL = REPLACE_SERVER_PROTO://REPLACE_SERVER_NAME
|
ROOT_URL = REPLACE_SERVER_PROTO://REPLACE_SERVER_NAME
|
||||||
|
LOCAL_ROOT_URL = http://localhost:80/
|
||||||
DOMAIN = REPLACE_SERVER_NAME
|
DOMAIN = REPLACE_SERVER_NAME
|
||||||
APP_DATA_PATH = REPLACE_DATA_DIR
|
APP_DATA_PATH = REPLACE_DATA_DIR
|
||||||
OFFLINE_MODE = false
|
OFFLINE_MODE = false
|
||||||
@@ -19,7 +21,6 @@ ACME_URL =
|
|||||||
ACME_ACCEPTTOS = true
|
ACME_ACCEPTTOS = true
|
||||||
ACME_EMAIL = ssl-admin@REPLACE_SERVER_NAME
|
ACME_EMAIL = ssl-admin@REPLACE_SERVER_NAME
|
||||||
ACME_DIRECTORY = REPLACE_DATA_DIR/certs
|
ACME_DIRECTORY = REPLACE_DATA_DIR/certs
|
||||||
LETSENCRYPT_ACCEPTTOS = true
|
|
||||||
DISABLE_SSH = false
|
DISABLE_SSH = false
|
||||||
START_SSH_SERVER = true
|
START_SSH_SERVER = true
|
||||||
SSH_LISTEN_HOST = 0.0.0.0
|
SSH_LISTEN_HOST = 0.0.0.0
|
||||||
@@ -167,11 +168,8 @@ MAX_GIT_DIFF_FILES = 100
|
|||||||
GC_ARGS =
|
GC_ARGS =
|
||||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
[git.timeout]
|
[git.timeout]
|
||||||
DEFAULT = 360
|
|
||||||
MIGRATE = 600
|
MIGRATE = 600
|
||||||
MIRROR = 300
|
MIRROR = 300
|
||||||
CLONE = 300
|
|
||||||
PULL = 300
|
|
||||||
GC = 60
|
GC = 60
|
||||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
[picture]
|
[picture]
|
||||||
@@ -191,8 +189,6 @@ PASSWORD_HASH_ALGO = argon2
|
|||||||
MIN_PASSWORD_LENGTH = 8
|
MIN_PASSWORD_LENGTH = 8
|
||||||
PASSWORD_COMPLEXITY = on
|
PASSWORD_COMPLEXITY = on
|
||||||
LOGIN_REMEMBER_DAYS = 1825
|
LOGIN_REMEMBER_DAYS = 1825
|
||||||
COOKIE_USERNAME = git_REPLACE_RANDOM_COOKIE_KEY
|
|
||||||
COOKIE_SECURE = false
|
|
||||||
CSRF_COOKIE_HTTP_ONLY = true
|
CSRF_COOKIE_HTTP_ONLY = true
|
||||||
REVERSE_PROXY_LIMIT = 1
|
REVERSE_PROXY_LIMIT = 1
|
||||||
REVERSE_PROXY_TRUSTED_PROXIES = *
|
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_EMAIL = X-WEBAUTH-EMAIL
|
||||||
REVERSE_PROXY_AUTHENTICATION_FULL_NAME = X-WEBAUTH-FULLNAME
|
REVERSE_PROXY_AUTHENTICATION_FULL_NAME = X-WEBAUTH-FULLNAME
|
||||||
X_FRAME_OPTIONS = SAMEORIGIN
|
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=
|
; 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
|
; 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
|
; 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_GIT_TREES_PER_PAGE = 1000
|
||||||
DEFAULT_MAX_BLOB_SIZE = 10485760
|
DEFAULT_MAX_BLOB_SIZE = 10485760
|
||||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
[migration]
|
[migrations]
|
||||||
SKIP_TLS_VERIFY = true
|
SKIP_TLS_VERIFY = true
|
||||||
ALLOWED_DOMAINS =
|
ALLOWED_HOST_LIST = private,loopback
|
||||||
BLOCKED_DOMAINS =
|
EGRESS_MODE = lax
|
||||||
ALLOW_LOCALNETWORKS = false
|
|
||||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
[git.config]
|
[git.config]
|
||||||
http.sslVerify = false
|
http.sslVerify = false
|
||||||
@@ -236,7 +232,7 @@ PROXY_URL =
|
|||||||
PROXY_HOSTS =
|
PROXY_HOSTS =
|
||||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
[service]
|
[service]
|
||||||
DISABLE_REGISTRATION = false
|
DISABLE_REGISTRATION = true
|
||||||
REQUIRE_SIGNIN_VIEW = false
|
REQUIRE_SIGNIN_VIEW = false
|
||||||
REGISTER_EMAIL_CONFIRM = REPLACE_GITEA_EMAIL_CONFIRM
|
REGISTER_EMAIL_CONFIRM = REPLACE_GITEA_EMAIL_CONFIRM
|
||||||
ENABLE_NOTIFY_MAIL = REPLACE_GITEA_EMAIL_CONFIRM
|
ENABLE_NOTIFY_MAIL = REPLACE_GITEA_EMAIL_CONFIRM
|
||||||
@@ -277,9 +273,6 @@ SEND_AS_PLAIN_TEXT = false
|
|||||||
[email.incoming]
|
[email.incoming]
|
||||||
ENABLED = false
|
ENABLED = false
|
||||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
[notify.email]
|
|
||||||
ENABLED = REPLACE_GITEA_EMAIL_CONFIRM
|
|
||||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
[openid]
|
[openid]
|
||||||
ENABLE_OPENID_SIGNIN = true
|
ENABLE_OPENID_SIGNIN = true
|
||||||
ENABLE_OPENID_SIGNUP = true
|
ENABLE_OPENID_SIGNUP = true
|
||||||
@@ -327,9 +320,7 @@ TOKEN =
|
|||||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
[cors]
|
[cors]
|
||||||
ENABLED = true
|
ENABLED = true
|
||||||
SCHEME = REPLACE_SERVER_PROTO
|
|
||||||
ALLOW_DOMAIN = *
|
ALLOW_DOMAIN = *
|
||||||
ALLOW_SUBDOMAIN = true
|
|
||||||
METHODS = GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS
|
METHODS = GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS
|
||||||
MAX_AGE = 10m
|
MAX_AGE = 10m
|
||||||
ALLOW_CREDENTIALS = true
|
ALLOW_CREDENTIALS = true
|
||||||
|
|||||||
@@ -137,6 +137,27 @@ __gitea_ini_set() {
|
|||||||
' "$ini_file" >"$tmp_file" && cat "$tmp_file" >"$ini_file"
|
' "$ini_file" >"$tmp_file" && cat "$tmp_file" >"$ini_file"
|
||||||
rm -f "$tmp_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)
|
# Set KEY = VALUE inside [SECTION] only when the key is not already present (keeps user choices)
|
||||||
__gitea_ini_default() {
|
__gitea_ini_default() {
|
||||||
local ini_file="$1" section="$2" key="$3" value="$4"
|
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_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 ENABLED true
|
||||||
__gitea_ini_default "$_ini_file" cron.delete_old_system_notices OLDER_THAN 2160h
|
__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|^DOMAIN[[:space:]]*=.*|DOMAIN = ${SERVER_NAME}|" "$_ini_file"
|
||||||
sed -i "s|^SSH_DOMAIN[[:space:]]*=.*|SSH_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)
|
# Remove deprecated [cors].X_FRAME_OPTIONS (moved to [security] in Gitea v1.26)
|
||||||
|
|||||||
Reference in new issue
Block a user