From ed7508735fbc2ad5d99a29fec20b37b154e10789 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:32:55 +0000 Subject: [PATCH 1/3] Initial plan From a0d53415f9bce74cf9f2c0b7fa0d60569f06c89b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:45:13 +0000 Subject: [PATCH 2/3] fix: replace exec base64 command with Go's encoding/base64 for Windows compatibility Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/download_workflow.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/cli/download_workflow.go b/pkg/cli/download_workflow.go index 087e15badc..2d86ead419 100644 --- a/pkg/cli/download_workflow.go +++ b/pkg/cli/download_workflow.go @@ -1,6 +1,7 @@ package cli import ( + "encoding/base64" "fmt" "os" "os/exec" @@ -173,9 +174,9 @@ func downloadWorkflowContent(repo, path, ref string, verbose bool) ([]byte, erro // The content is base64 encoded, decode it contentBase64 := strings.TrimSpace(string(output)) - base64Cmd := exec.Command("base64", "-d") - base64Cmd.Stdin = strings.NewReader(contentBase64) - content, err := base64Cmd.Output() + // Remove newlines that GitHub API embeds in base64 content + contentBase64 = strings.ReplaceAll(contentBase64, "\n", "") + content, err := base64.StdEncoding.DecodeString(contentBase64) if err != nil { return nil, fmt.Errorf("failed to decode file content: %w", err) } From 1aafa81bcefeca40b8c68f8425317c5e7b9b8c6b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:49:43 +0000 Subject: [PATCH 3/3] test: add unit tests for decodeBase64FileContent Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/download_workflow.go | 14 ++++-- pkg/cli/download_workflow_test.go | 77 +++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 pkg/cli/download_workflow_test.go diff --git a/pkg/cli/download_workflow.go b/pkg/cli/download_workflow.go index 2d86ead419..2f8bba1c7a 100644 --- a/pkg/cli/download_workflow.go +++ b/pkg/cli/download_workflow.go @@ -173,13 +173,17 @@ func downloadWorkflowContent(repo, path, ref string, verbose bool) ([]byte, erro } // The content is base64 encoded, decode it - contentBase64 := strings.TrimSpace(string(output)) - // Remove newlines that GitHub API embeds in base64 content - contentBase64 = strings.ReplaceAll(contentBase64, "\n", "") - content, err := base64.StdEncoding.DecodeString(contentBase64) + return decodeBase64FileContent(string(output)) +} + +// decodeBase64FileContent decodes base64-encoded file content returned by the GitHub API. +// The GitHub API wraps lines at 60 characters and may include surrounding whitespace, +// so both are stripped before decoding. +func decodeBase64FileContent(raw string) ([]byte, error) { + cleaned := strings.ReplaceAll(strings.TrimSpace(raw), "\n", "") + content, err := base64.StdEncoding.DecodeString(cleaned) if err != nil { return nil, fmt.Errorf("failed to decode file content: %w", err) } - return content, nil } diff --git a/pkg/cli/download_workflow_test.go b/pkg/cli/download_workflow_test.go new file mode 100644 index 0000000000..b6309fd631 --- /dev/null +++ b/pkg/cli/download_workflow_test.go @@ -0,0 +1,77 @@ +//go:build !integration + +package cli + +import ( + "encoding/base64" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDecodeBase64FileContent(t *testing.T) { + tests := []struct { + name string + input func() string // build the raw API-style input + expected string + wantErr bool + }{ + { + name: "plain base64 without newlines", + input: func() string { + return base64.StdEncoding.EncodeToString([]byte("hello world")) + }, + expected: "hello world", + }, + { + name: "GitHub API style with embedded newlines every 60 chars", + input: func() string { + encoded := base64.StdEncoding.EncodeToString([]byte("hello world")) + // Simulate GitHub API line-wrapping at 60 characters + var sb strings.Builder + for i, c := range encoded { + if i > 0 && i%60 == 0 { + sb.WriteByte('\n') + } + sb.WriteRune(c) + } + return sb.String() + }, + expected: "hello world", + }, + { + name: "leading and trailing whitespace stripped", + input: func() string { + return " " + base64.StdEncoding.EncodeToString([]byte("trim me")) + "\n" + }, + expected: "trim me", + }, + { + name: "binary content round-trips correctly", + input: func() string { + data := []byte{0x00, 0x01, 0x02, 0xFF, 0xFE} + return base64.StdEncoding.EncodeToString(data) + }, + expected: string([]byte{0x00, 0x01, 0x02, 0xFF, 0xFE}), + }, + { + name: "invalid base64 returns error", + input: func() string { return "!!!not-valid-base64!!!" }, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := decodeBase64FileContent(tt.input()) + if tt.wantErr { + assert.Error(t, err, "expected an error for invalid base64 input") + return + } + require.NoError(t, err, "unexpected error decoding base64 content") + assert.Equal(t, tt.expected, string(got), "decoded content should match expected") + }) + } +}