From 049899b56b02339ab43062d75a0803a3dfdb40f8 Mon Sep 17 00:00:00 2001 From: Gusted Date: Thu, 10 Jul 2025 17:51:19 +0200 Subject: [PATCH] feat: AGit push options starting with `{base64}` are decoded (#8479) - When specifying push options, tooling like [git-repo-go](https://github.com/alibaba/git-repo-go) encodes pushoption values if they contain newlines or non-ASCII characters as they cannot be easily specified via the CLI otherwise. - Recognize such base64 encoded values in the pushoptions (those that have the `{base64}` prefix), if the base64 decoding fails we return the original value. - Resolves forgejo/forgejo#8161 ## Release notes - Features - [PR](https://codeberg.org/forgejo/forgejo/pulls/8479): AGit push options starting with `{base64}` are decoded Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8479 Reviewed-by: Earl Warren Co-authored-by: Gusted Co-committed-by: Gusted --- modules/git/pushoptions/pushoptions.go | 20 +++++++++++++++++++- modules/git/pushoptions/pushoptions_test.go | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/modules/git/pushoptions/pushoptions.go b/modules/git/pushoptions/pushoptions.go index 9709a8be79..e96ba0a339 100644 --- a/modules/git/pushoptions/pushoptions.go +++ b/modules/git/pushoptions/pushoptions.go @@ -4,6 +4,7 @@ package pushoptions import ( + "encoding/base64" "fmt" "os" "strconv" @@ -109,5 +110,22 @@ func (o gitPushOptions) GetBool(key Key, def bool) bool { func (o gitPushOptions) GetString(key Key) (string, bool) { val, ok := o[string(key)] - return val, ok + if !ok { + return "", false + } + + // If the value is prefixed with `{base64}` then everything after that is very + // likely to be encoded via base64. + base64Value, found := strings.CutPrefix(val, "{base64}") + if !found { + return val, true + } + + value, err := base64.StdEncoding.DecodeString(base64Value) + if err != nil { + // Not valid base64? Return the original value. + return val, true + } + + return string(value), true } diff --git a/modules/git/pushoptions/pushoptions_test.go b/modules/git/pushoptions/pushoptions_test.go index 1cb36d9d1e..d7c50649d0 100644 --- a/modules/git/pushoptions/pushoptions_test.go +++ b/modules/git/pushoptions/pushoptions_test.go @@ -4,6 +4,7 @@ package pushoptions import ( + "encoding/base64" "fmt" "testing" @@ -92,6 +93,23 @@ func TestParse(t *testing.T) { assert.False(t, options.Parse("unknown=value")) assert.True(t, options.Empty()) }) + + t.Run("Base64 values", func(t *testing.T) { + options := New() + + description := `I contain +a +line` + assert.True(t, options.Parse(fmt.Sprintf("%s={base64}%s", AgitDescription, base64.StdEncoding.EncodeToString([]byte(description))))) + val, ok := options.GetString(AgitDescription) + assert.True(t, ok) + assert.Equal(t, description, val) + + assert.True(t, options.Parse(fmt.Sprintf("%s={base64}fooled you", AgitTitle))) + val, ok = options.GetString(AgitTitle) + assert.True(t, ok) + assert.Equal(t, "{base64}fooled you", val) + }) } func TestReadEnv(t *testing.T) {