forgejo/modules/setting/config_env.go

143 lines
4 KiB
Go
Raw Normal View History

// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package setting
import (
"os"
"regexp"
"strconv"
"strings"
"code.gitea.io/gitea/modules/log"
)
const escapeRegexpString = "_0[xX](([0-9a-fA-F][0-9a-fA-F])+)_"
var escapeRegex = regexp.MustCompile(escapeRegexpString)
// decodeEnvSectionKey will decode a portable string encoded Section__Key pair
// Portable strings are considered to be of the form [A-Z0-9_]*
// We will encode a disallowed value as the UTF8 byte string preceded by _0X and
// followed by _. E.g. _0X2C_ for a '-' and _0X2E_ for '.'
// Section and Key are separated by a plain '__'.
// The entire section can be encoded as a UTF8 byte string
func decodeEnvSectionKey(encoded string) (ok bool, section, key string) {
inKey := false
last := 0
escapeStringIndices := escapeRegex.FindAllStringIndex(encoded, -1)
for _, unescapeIdx := range escapeStringIndices {
preceding := encoded[last:unescapeIdx[0]]
if !inKey {
if splitter := strings.Index(preceding, "__"); splitter > -1 {
section += preceding[:splitter]
inKey = true
key += preceding[splitter+2:]
} else {
section += preceding
}
} else {
key += preceding
}
toDecode := encoded[unescapeIdx[0]+3 : unescapeIdx[1]-1]
decodedBytes := make([]byte, len(toDecode)/2)
for i := 0; i < len(toDecode)/2; i++ {
// Can ignore error here as we know these should be hexadecimal from the regexp
byteInt, _ := strconv.ParseInt(toDecode[2*i:2*i+2], 16, 0)
decodedBytes[i] = byte(byteInt)
}
if inKey {
key += string(decodedBytes)
} else {
section += string(decodedBytes)
}
last = unescapeIdx[1]
}
remaining := encoded[last:]
if !inKey {
if splitter := strings.Index(remaining, "__"); splitter > -1 {
section += remaining[:splitter]
key += remaining[splitter+2:]
} else {
section += remaining
}
} else {
key += remaining
}
section = strings.ToLower(section)
ok = section != "" && key != ""
if !ok {
section = ""
key = ""
}
return ok, section, key
}
// decodeEnvironmentKey decode the environment key to section and key
// The environment key is in the form of GITEA__SECTION__KEY or GITEA__SECTION__KEY__FILE
[BRANDING] parse FORGEJO__* in the container environment Add the FORGEJO__ prefix as equivalent to GITEA__ when interpreted by environment-to-ini. It is used when running the Forgejo container like so: docker run --name forgejo -e FORGEJO__security__INSTALL_LOCK=true \ -d codeberg.org/forgejo/forgejo:1.19 (cherry picked from commit 6cd61e2ab701ae9236ff9a68520ee1e2d03e6193) (cherry picked from commit 62cae8cc6a6ddc9e5bb066c81834b75cef3be29f) (cherry picked from commit aee1afc5097531b2740b2aa8ef4aef745e7a1be0) (cherry picked from commit 6ba563cd9b09d012a804f3f438c5ae4e38ca6ced) (cherry picked from commit 6429b20f4a1561480a4a0c214cc571f79c313be0) (cherry picked from commit dd545aa077e21616b406d765b19a75df643a9695) (cherry picked from commit 63a00e573e2d6b6bfb75d28a816327435bace02d) (cherry picked from commit 8e35a50b91fcec0b27b6b5458facb12e9bda8505) (cherry picked from commit 26e8fb6cd953a6c9dfae89b430856895c7253a7c) (cherry picked from commit 56bbf644beb25f62964b2c0c847d7b9d711ed56e) (cherry picked from commit 4d0a8c8640fee94ddffad2250ce5619d4894d3d3) (cherry picked from commit b58f775fa22116334d5e0d7114c5d37d96693471) (cherry picked from commit f4b6fa7a937cb4bfcb3623d4e13fce76e76c069e) (cherry picked from commit 4eca3630826d5cbf9e11156f84434ad7fad1c88b) (cherry picked from commit e2e7a72f804ec67b1e3c0eba15eb507f47711806) (cherry picked from commit 00ce992957a6797124310826675db2dde0f450af) (cherry picked from commit 971b26ec1c1e8cda6eef44d27eb33dbb0982e77c) (cherry picked from commit dd2f0046bdf68e4f8cd14001e4f1fc82d720b080)
2023-01-12 22:56:56 +01:00
func decodeEnvironmentKey(prefixRegexp *regexp.Regexp, suffixFile, envKey string) (ok bool, section, key string, useFileValue bool) {
if strings.HasSuffix(envKey, suffixFile) {
useFileValue = true
envKey = envKey[:len(envKey)-len(suffixFile)]
}
[BRANDING] parse FORGEJO__* in the container environment Add the FORGEJO__ prefix as equivalent to GITEA__ when interpreted by environment-to-ini. It is used when running the Forgejo container like so: docker run --name forgejo -e FORGEJO__security__INSTALL_LOCK=true \ -d codeberg.org/forgejo/forgejo:1.19 (cherry picked from commit 6cd61e2ab701ae9236ff9a68520ee1e2d03e6193) (cherry picked from commit 62cae8cc6a6ddc9e5bb066c81834b75cef3be29f) (cherry picked from commit aee1afc5097531b2740b2aa8ef4aef745e7a1be0) (cherry picked from commit 6ba563cd9b09d012a804f3f438c5ae4e38ca6ced) (cherry picked from commit 6429b20f4a1561480a4a0c214cc571f79c313be0) (cherry picked from commit dd545aa077e21616b406d765b19a75df643a9695) (cherry picked from commit 63a00e573e2d6b6bfb75d28a816327435bace02d) (cherry picked from commit 8e35a50b91fcec0b27b6b5458facb12e9bda8505) (cherry picked from commit 26e8fb6cd953a6c9dfae89b430856895c7253a7c) (cherry picked from commit 56bbf644beb25f62964b2c0c847d7b9d711ed56e) (cherry picked from commit 4d0a8c8640fee94ddffad2250ce5619d4894d3d3) (cherry picked from commit b58f775fa22116334d5e0d7114c5d37d96693471) (cherry picked from commit f4b6fa7a937cb4bfcb3623d4e13fce76e76c069e) (cherry picked from commit 4eca3630826d5cbf9e11156f84434ad7fad1c88b) (cherry picked from commit e2e7a72f804ec67b1e3c0eba15eb507f47711806) (cherry picked from commit 00ce992957a6797124310826675db2dde0f450af) (cherry picked from commit 971b26ec1c1e8cda6eef44d27eb33dbb0982e77c) (cherry picked from commit dd2f0046bdf68e4f8cd14001e4f1fc82d720b080)
2023-01-12 22:56:56 +01:00
loc := prefixRegexp.FindStringIndex(envKey)
if loc == nil {
return false, "", "", false
}
ok, section, key = decodeEnvSectionKey(envKey[loc[1]:])
return ok, section, key, useFileValue
}
func EnvironmentToConfig(cfg ConfigProvider, prefixGitea, suffixFile string, envs []string) (changed bool) {
[BRANDING] parse FORGEJO__* in the container environment Add the FORGEJO__ prefix as equivalent to GITEA__ when interpreted by environment-to-ini. It is used when running the Forgejo container like so: docker run --name forgejo -e FORGEJO__security__INSTALL_LOCK=true \ -d codeberg.org/forgejo/forgejo:1.19 (cherry picked from commit 6cd61e2ab701ae9236ff9a68520ee1e2d03e6193) (cherry picked from commit 62cae8cc6a6ddc9e5bb066c81834b75cef3be29f) (cherry picked from commit aee1afc5097531b2740b2aa8ef4aef745e7a1be0) (cherry picked from commit 6ba563cd9b09d012a804f3f438c5ae4e38ca6ced) (cherry picked from commit 6429b20f4a1561480a4a0c214cc571f79c313be0) (cherry picked from commit dd545aa077e21616b406d765b19a75df643a9695) (cherry picked from commit 63a00e573e2d6b6bfb75d28a816327435bace02d) (cherry picked from commit 8e35a50b91fcec0b27b6b5458facb12e9bda8505) (cherry picked from commit 26e8fb6cd953a6c9dfae89b430856895c7253a7c) (cherry picked from commit 56bbf644beb25f62964b2c0c847d7b9d711ed56e) (cherry picked from commit 4d0a8c8640fee94ddffad2250ce5619d4894d3d3) (cherry picked from commit b58f775fa22116334d5e0d7114c5d37d96693471) (cherry picked from commit f4b6fa7a937cb4bfcb3623d4e13fce76e76c069e) (cherry picked from commit 4eca3630826d5cbf9e11156f84434ad7fad1c88b) (cherry picked from commit e2e7a72f804ec67b1e3c0eba15eb507f47711806) (cherry picked from commit 00ce992957a6797124310826675db2dde0f450af) (cherry picked from commit 971b26ec1c1e8cda6eef44d27eb33dbb0982e77c) (cherry picked from commit dd2f0046bdf68e4f8cd14001e4f1fc82d720b080)
2023-01-12 22:56:56 +01:00
prefixRegexp := regexp.MustCompile(prefixGitea)
for _, kv := range envs {
idx := strings.IndexByte(kv, '=')
if idx < 0 {
continue
}
// parse the environment variable to config section name and key name
envKey := kv[:idx]
envValue := kv[idx+1:]
[BRANDING] parse FORGEJO__* in the container environment Add the FORGEJO__ prefix as equivalent to GITEA__ when interpreted by environment-to-ini. It is used when running the Forgejo container like so: docker run --name forgejo -e FORGEJO__security__INSTALL_LOCK=true \ -d codeberg.org/forgejo/forgejo:1.19 (cherry picked from commit 6cd61e2ab701ae9236ff9a68520ee1e2d03e6193) (cherry picked from commit 62cae8cc6a6ddc9e5bb066c81834b75cef3be29f) (cherry picked from commit aee1afc5097531b2740b2aa8ef4aef745e7a1be0) (cherry picked from commit 6ba563cd9b09d012a804f3f438c5ae4e38ca6ced) (cherry picked from commit 6429b20f4a1561480a4a0c214cc571f79c313be0) (cherry picked from commit dd545aa077e21616b406d765b19a75df643a9695) (cherry picked from commit 63a00e573e2d6b6bfb75d28a816327435bace02d) (cherry picked from commit 8e35a50b91fcec0b27b6b5458facb12e9bda8505) (cherry picked from commit 26e8fb6cd953a6c9dfae89b430856895c7253a7c) (cherry picked from commit 56bbf644beb25f62964b2c0c847d7b9d711ed56e) (cherry picked from commit 4d0a8c8640fee94ddffad2250ce5619d4894d3d3) (cherry picked from commit b58f775fa22116334d5e0d7114c5d37d96693471) (cherry picked from commit f4b6fa7a937cb4bfcb3623d4e13fce76e76c069e) (cherry picked from commit 4eca3630826d5cbf9e11156f84434ad7fad1c88b) (cherry picked from commit e2e7a72f804ec67b1e3c0eba15eb507f47711806) (cherry picked from commit 00ce992957a6797124310826675db2dde0f450af) (cherry picked from commit 971b26ec1c1e8cda6eef44d27eb33dbb0982e77c) (cherry picked from commit dd2f0046bdf68e4f8cd14001e4f1fc82d720b080)
2023-01-12 22:56:56 +01:00
ok, sectionName, keyName, useFileValue := decodeEnvironmentKey(prefixRegexp, suffixFile, envKey)
if !ok {
continue
}
// use environment value as config value, or read the file content as value if the key indicates a file
keyValue := envValue
if useFileValue {
fileContent, err := os.ReadFile(envValue)
if err != nil {
log.Error("Error reading file for %s : %v", envKey, envValue, err)
continue
}
keyValue = string(fileContent)
}
// try to set the config value if necessary
section, err := cfg.GetSection(sectionName)
if err != nil {
section, err = cfg.NewSection(sectionName)
if err != nil {
log.Error("Error creating section: %s : %v", sectionName, err)
continue
}
}
key := section.Key(keyName)
if key == nil {
key, err = section.NewKey(keyName, keyValue)
if err != nil {
log.Error("Error creating key: %s in section: %s with value: %s : %v", keyName, sectionName, keyValue, err)
continue
}
}
oldValue := key.Value()
if !changed && oldValue != keyValue {
changed = true
}
key.SetValue(keyValue)
}
return changed
}