From e2e7a72f804ec67b1e3c0eba15eb507f47711806 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) --- .woodpecker/testing-amd64.yml | 8 ++++ .../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, 74 insertions(+), 24 deletions(-) create mode 100644 contrib/environment-to-ini/environment-to-ini_test.go diff --git a/.woodpecker/testing-amd64.yml b/.woodpecker/testing-amd64.yml index 340ee55736..94fd9e1844 100644 --- a/.woodpecker/testing-amd64.yml +++ b/.woodpecker/testing-amd64.yml @@ -75,6 +75,14 @@ pipeline: commands: - ./build/test-env-prepare.sh + environment-to-ini: + image: *golang_image + environment: + GOPROXY_OVERRIDE: *goproxy_override + commands: + - *goproxy_setup + - go test contrib/environment-to-ini/environment-to-ini.go contrib/environment-to-ini/environment-to-ini_test.go + build: image: *test_image environment: diff --git a/contrib/environment-to-ini/environment-to-ini.go b/contrib/environment-to-ini/environment-to-ini.go index ae8535d891..878e3ef018 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" @@ -16,21 +17,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. @@ -48,8 +49,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{ @@ -65,7 +66,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", @@ -91,6 +92,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 { providedCustom := c.String("custom-path") providedConf := c.String("config") @@ -130,15 +144,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 dca9f2bb47..2197d74ed3 100644 --- a/modules/setting/config_env.go +++ b/modules/setting/config_env.go @@ -77,19 +77,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 *ini.File, prefixGitea, suffixFile string, envs []string) (changed bool) { + prefixRegexp := regexp.MustCompile(prefixGitea) for _, kv := range envs { idx := strings.IndexByte(kv, '=') if idx < 0 { @@ -99,7 +101,7 @@ func EnvironmentToConfig(cfg *ini.File, prefixGitea, suffixFile string, envs []s // 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 d49464ecf7..25f00a9f7f 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" @@ -34,7 +35,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") @@ -55,6 +56,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") @@ -73,7 +80,7 @@ func TestDecodeEnvironmentKey(t *testing.T) { func TestEnvironmentToConfig(t *testing.T) { cfg := ini.Empty() - changed := EnvironmentToConfig(cfg, "GITEA__", "__FILE", nil) + changed := EnvironmentToConfig(cfg, "^(FORGEJO|GITEA)__", "__FILE", nil) assert.False(t, changed) cfg, err := ini.Load([]byte(` @@ -82,16 +89,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()) }