diff --git a/pkg/container/parse_env_file.go b/pkg/container/parse_env_file.go index b1c21f51b9a..b73beb137da 100644 --- a/pkg/container/parse_env_file.go +++ b/pkg/container/parse_env_file.go @@ -27,6 +27,7 @@ func parseEnvFile(e Container, srcPath string, env *map[string]string) common.Ex s := bufio.NewScanner(reader) s.Buffer(nil, 1024*1024*1024) // increase buffer to 1GB to avoid scanner buffer overflow firstLine := true + var lastKey string for s.Scan() { line := s.Text() if firstLine { @@ -39,7 +40,8 @@ func parseEnvFile(e Container, srcPath string, env *map[string]string) common.Ex singleLineEnv := strings.Index(line, "=") multiLineEnv := strings.Index(line, "<<") if singleLineEnv != -1 && (multiLineEnv == -1 || singleLineEnv < multiLineEnv) { - localEnv[line[:singleLineEnv]] = line[singleLineEnv+1:] + lastKey = line[:singleLineEnv] + localEnv[lastKey] = line[singleLineEnv+1:] } else if multiLineEnv != -1 { multiLineEnvContent := "" multiLineEnvDelimiter := line[multiLineEnv+2:] @@ -58,12 +60,14 @@ func parseEnvFile(e Container, srcPath string, env *map[string]string) common.Ex if !delimiterFound { return fmt.Errorf("invalid format delimiter '%v' not found before end of file", multiLineEnvDelimiter) } - localEnv[line[:multiLineEnv]] = multiLineEnvContent - } else { - return fmt.Errorf("invalid format '%v', expected a line with '=' or '<<'", line) + lastKey = line[:multiLineEnv] + localEnv[lastKey] = multiLineEnvContent + } else if lastKey != "" { + localEnv[lastKey] += "\n" + line } } env = &localEnv + return s.Err() } } diff --git a/pkg/container/parse_env_file_test.go b/pkg/container/parse_env_file_test.go new file mode 100644 index 00000000000..418f5e17110 --- /dev/null +++ b/pkg/container/parse_env_file_test.go @@ -0,0 +1,190 @@ +package container + +import ( + "archive/tar" + "bytes" + "context" + "io" + "testing" + + "github.com/nektos/act/pkg/common" + assert "github.com/stretchr/testify/assert" +) + +type mockContainer struct { + content string + err error +} + +func (m *mockContainer) GetContainerArchive(_ context.Context, _ string) (io.ReadCloser, error) { + if m.err != nil { + return nil, m.err + } + + var buf bytes.Buffer + tw := tar.NewWriter(&buf) + hdr := &tar.Header{ + Name: "env", + Size: int64(len(m.content)), + } + _ = tw.WriteHeader(hdr) + _, _ = tw.Write([]byte(m.content)) + _ = tw.Close() + + return io.NopCloser(&buf), nil +} + +func (m *mockContainer) Create([]string, []string) common.Executor { return nil } +func (m *mockContainer) Copy(string, ...*FileEntry) common.Executor { return nil } +func (m *mockContainer) CopyTarStream(context.Context, string, io.Reader) error { return nil } +func (m *mockContainer) CopyDir(string, string, bool) common.Executor { return nil } +func (m *mockContainer) Pull(bool) common.Executor { return nil } +func (m *mockContainer) Start(bool) common.Executor { return nil } +func (m *mockContainer) Exec([]string, map[string]string, string, string) common.Executor { + return nil +} +func (m *mockContainer) UpdateFromEnv(string, *map[string]string) common.Executor { return nil } +func (m *mockContainer) UpdateFromImageEnv(*map[string]string) common.Executor { return nil } +func (m *mockContainer) Remove() common.Executor { return nil } +func (m *mockContainer) Close() common.Executor { return nil } +func (m *mockContainer) ReplaceLogWriter(io.Writer, io.Writer) (io.Writer, io.Writer) { + return nil, nil +} +func (m *mockContainer) GetHealth(context.Context) Health { return HealthHealthy } + +func TestParseEnvFile(t *testing.T) { + tests := []struct { + name string + content string + initial map[string]string + expected map[string]string + }{ + { + name: "single line env var", + content: "FOO=bar", + initial: map[string]string{}, + expected: map[string]string{ + "FOO": "bar", + }, + }, + { + name: "multiple single line env vars", + content: "FOO=bar\nBAZ=qux", + initial: map[string]string{}, + expected: map[string]string{ + "FOO": "bar", + "BAZ": "qux", + }, + }, + { + name: "value containing equals sign", + content: "FOO=bar=baz", + initial: map[string]string{}, + expected: map[string]string{ + "FOO": "bar=baz", + }, + }, + { + name: "multiline env var with heredoc delimiter", + content: "FOO<