From 720cdf4b85bb6a29785858ae21f28f25b26b05f4 Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Thu, 12 Jan 2023 22:56:56 +0100 Subject: [PATCH] [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 4998a3c39c632f8e832e9e3036a2de1dee206c55) (cherry picked from commit 65892751586acaadd157472ff53c98efcee6d6ec) (cherry picked from commit 5eadc6df270e3863c7f58958a61bf1ef3fed518f) --- .forgejo/workflows/testing.yml | 1 + .../environment-to-ini/environment-to-ini.go | 38 ++++++++++++------- .../environment-to-ini_test.go | 21 ++++++++++ modules/setting/config_env.go | 14 ++++--- modules/setting/config_env_test.go | 17 ++++++--- 5 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 contrib/environment-to-ini/environment-to-ini_test.go diff --git a/.forgejo/workflows/testing.yml b/.forgejo/workflows/testing.yml index 22e73f5378..a6509759ff 100644 --- a/.forgejo/workflows/testing.yml +++ b/.forgejo/workflows/testing.yml @@ -50,6 +50,7 @@ jobs: env: TAGS: bindata - run: | + su gitea -c 'go test contrib/environment-to-ini/environment-to-ini.go contrib/environment-to-ini/environment-to-ini_test.go' su gitea -c 'make unit-test-coverage test-check' timeout-minutes: 50 env: diff --git a/contrib/environment-to-ini/environment-to-ini.go b/contrib/environment-to-ini/environment-to-ini.go index 230ed58269..0aa5cb1bef 100644 --- a/contrib/environment-to-ini/environment-to-ini.go +++ b/contrib/environment-to-ini/environment-to-ini.go @@ -5,6 +5,7 @@ package main import ( "os" + "regexp" "strings" "code.gitea.io/gitea/modules/log" @@ -14,21 +15,21 @@ import ( ) // EnvironmentPrefix environment variables prefixed with this represent ini values to write -const EnvironmentPrefix = "GITEA" +const EnvironmentPrefix = "^(FORGEJO|GITEA)" func main() { app := cli.NewApp() app.Name = "environment-to-ini" app.Usage = "Use provided environment to update configuration ini" - app.Description = `As a helper to allow docker users to update the gitea configuration + app.Description = `As a helper to allow docker users to update the Forgejo configuration through the environment, this command allows environment variables to be mapped to values in the ini. - Environment variables of the form "GITEA__SECTION_NAME__KEY_NAME" + Environment variables of the form "FORGEJO__SECTION_NAME__KEY_NAME" will be mapped to the ini section "[section_name]" and the key "KEY_NAME" with the value as provided. - Environment variables of the form "GITEA__SECTION_NAME__KEY_NAME__FILE" + Environment variables of the form "FORGEJO__SECTION_NAME__KEY_NAME__FILE" will be mapped to the ini section "[section_name]" and the key "KEY_NAME" with the value loaded from the specified file. @@ -46,8 +47,8 @@ func main() { ... """ - You would set the environment variables: "GITEA__LOG_0x2E_CONSOLE__COLORIZE=false" - and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found + You would set the environment variables: "FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false" + and "FORGEJO__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found on the configuration cheat sheet.` app.Flags = []cli.Flag{ cli.StringFlag{ @@ -63,7 +64,7 @@ func main() { cli.StringFlag{ Name: "work-path, w", Value: setting.AppWorkPath, - Usage: "Set the gitea working path", + Usage: "Set the forgejo working path", }, cli.StringFlag{ Name: "out, o", @@ -87,6 +88,19 @@ func main() { } } +func splitEnvironmentVariable(prefixRegexp *regexp.Regexp, kv string) (string, string) { + idx := strings.IndexByte(kv, '=') + if idx < 0 { + return "", "" + } + k := kv[:idx] + loc := prefixRegexp.FindStringIndex(k) + if loc == nil { + return "", "" + } + return k[loc[1]:], kv[idx+1:] +} + func runEnvironmentToIni(c *cli.Context) error { setting.InitWorkPathAndCfgProvider(os.Getenv, setting.ArgWorkPathAndCustomConf{ WorkPath: c.String("work-path"), @@ -118,15 +132,13 @@ func runEnvironmentToIni(c *cli.Context) error { // clear Gitea's specific environment variables if requested if c.Bool("clear") { + prefixRegexp := regexp.MustCompile(prefixGitea) for _, kv := range os.Environ() { - idx := strings.IndexByte(kv, '=') - if idx < 0 { + eKey, _ := splitEnvironmentVariable(prefixRegexp, kv) + if eKey == "" { continue } - eKey := kv[:idx] - if strings.HasPrefix(eKey, prefixGitea) { - _ = os.Unsetenv(eKey) - } + _ = os.Unsetenv(eKey) } } diff --git a/contrib/environment-to-ini/environment-to-ini_test.go b/contrib/environment-to-ini/environment-to-ini_test.go new file mode 100644 index 0000000000..5881888fc1 --- /dev/null +++ b/contrib/environment-to-ini/environment-to-ini_test.go @@ -0,0 +1,21 @@ +// Copyright 2023 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package main + +import ( + "regexp" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_splitEnvironmentVariable(t *testing.T) { + prefixRegexp := regexp.MustCompile(EnvironmentPrefix + "__") + k, v := splitEnvironmentVariable(prefixRegexp, "FORGEJO__KEY=VALUE") + assert.Equal(t, k, "KEY") + assert.Equal(t, v, "VALUE") + k, v = splitEnvironmentVariable(prefixRegexp, "nothing=interesting") + assert.Equal(t, k, "") + assert.Equal(t, v, "") +} diff --git a/modules/setting/config_env.go b/modules/setting/config_env.go index 6348803705..4ec2e61289 100644 --- a/modules/setting/config_env.go +++ b/modules/setting/config_env.go @@ -75,19 +75,21 @@ func decodeEnvSectionKey(encoded string) (ok bool, section, key string) { // 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 -func decodeEnvironmentKey(prefixGitea, suffixFile, envKey string) (ok bool, section, key string, useFileValue bool) { - if !strings.HasPrefix(envKey, prefixGitea) { - return false, "", "", false - } +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)] } - ok, section, key = decodeEnvSectionKey(envKey[len(prefixGitea):]) + 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) { + prefixRegexp := regexp.MustCompile(prefixGitea) for _, kv := range envs { idx := strings.IndexByte(kv, '=') if idx < 0 { @@ -97,7 +99,7 @@ func EnvironmentToConfig(cfg ConfigProvider, prefixGitea, suffixFile string, env // parse the environment variable to config section name and key name envKey := kv[:idx] envValue := kv[idx+1:] - ok, sectionName, keyName, useFileValue := decodeEnvironmentKey(prefixGitea, suffixFile, envKey) + ok, sectionName, keyName, useFileValue := decodeEnvironmentKey(prefixRegexp, suffixFile, envKey) if !ok { continue } diff --git a/modules/setting/config_env_test.go b/modules/setting/config_env_test.go index d574554bcc..41c4b4ac2a 100644 --- a/modules/setting/config_env_test.go +++ b/modules/setting/config_env_test.go @@ -5,6 +5,7 @@ package setting import ( "os" + "regexp" "testing" "github.com/stretchr/testify/assert" @@ -33,7 +34,7 @@ func TestDecodeEnvSectionKey(t *testing.T) { } func TestDecodeEnvironmentKey(t *testing.T) { - prefix := "GITEA__" + prefix := regexp.MustCompile("^(FORGEJO|GITEA)__") suffix := "__FILE" ok, section, key, file := decodeEnvironmentKey(prefix, suffix, "SEC__KEY") @@ -54,6 +55,12 @@ func TestDecodeEnvironmentKey(t *testing.T) { assert.Equal(t, "KEY", key) assert.False(t, file) + ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "FORGEJO__SEC__KEY") + assert.True(t, ok) + assert.Equal(t, "sec", section) + assert.Equal(t, "KEY", key) + assert.False(t, file) + // with "__FILE" suffix, it doesn't support to write "[sec].FILE" to config (no such key FILE is used in Gitea) // but it could be fixed in the future by adding a new suffix like "__VALUE" (no such key VALUE is used in Gitea either) ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "GITEA__SEC__FILE") @@ -72,7 +79,7 @@ func TestDecodeEnvironmentKey(t *testing.T) { func TestEnvironmentToConfig(t *testing.T) { cfg, _ := NewConfigProviderFromData("") - changed := EnvironmentToConfig(cfg, "GITEA__", "__FILE", nil) + changed := EnvironmentToConfig(cfg, "^(FORGEJO|GITEA)__", "__FILE", nil) assert.False(t, changed) cfg, err := NewConfigProviderFromData(` @@ -81,16 +88,16 @@ key = old `) assert.NoError(t, err) - changed = EnvironmentToConfig(cfg, "GITEA__", "__FILE", []string{"GITEA__sec__key=new"}) + changed = EnvironmentToConfig(cfg, "^(FORGEJO|GITEA)__", "__FILE", []string{"GITEA__sec__key=new"}) assert.True(t, changed) assert.Equal(t, "new", cfg.Section("sec").Key("key").String()) - changed = EnvironmentToConfig(cfg, "GITEA__", "__FILE", []string{"GITEA__sec__key=new"}) + changed = EnvironmentToConfig(cfg, "^(FORGEJO|GITEA)__", "__FILE", []string{"GITEA__sec__key=new"}) assert.False(t, changed) tmpFile := t.TempDir() + "/the-file" _ = os.WriteFile(tmpFile, []byte("value-from-file"), 0o644) - changed = EnvironmentToConfig(cfg, "GITEA__", "__FILE", []string{"GITEA__sec__key__FILE=" + tmpFile}) + changed = EnvironmentToConfig(cfg, "^(FORGEJO|GITEA)__", "__FILE", []string{"GITEA__sec__key__FILE=" + tmpFile}) assert.True(t, changed) assert.Equal(t, "value-from-file", cfg.Section("sec").Key("key").String()) }