diff --git a/.gitignore b/.gitignore index 2fbedf41..b326214e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ dist/ .todo *.nupkg +.vscode/ diff --git a/cmd/input.go b/cmd/input.go index b785009d..23eaa5cd 100644 --- a/cmd/input.go +++ b/cmd/input.go @@ -18,6 +18,7 @@ type Input struct { forcePull bool noOutput bool envfile string + secretfile string } func (i *Input) resolve(path string) string { @@ -39,6 +40,11 @@ func (i *Input) Envfile() string { return i.resolve(i.envfile) } +// Secretfile returns path to secrets +func (i *Input) Secretfile() string { + return i.resolve(i.secretfile) +} + // Workdir returns path to workdir func (i *Input) Workdir() string { return i.resolve(".") diff --git a/cmd/root.go b/cmd/root.go index e54e5a6b..9a7446be 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -46,7 +46,8 @@ func Execute(ctx context.Context, version string) { rootCmd.PersistentFlags().BoolP("verbose", "v", false, "verbose output") rootCmd.PersistentFlags().BoolVarP(&input.noOutput, "quiet", "q", false, "disable logging of output from steps") rootCmd.PersistentFlags().BoolVarP(&input.dryrun, "dryrun", "n", false, "dryrun mode") - rootCmd.PersistentFlags().StringVarP(&input.envfile, "env-file", "", ".env", "environment file to read") + rootCmd.PersistentFlags().StringVarP(&input.secretfile, "secret-file", "", "", "file with list of secrets to read from") + rootCmd.PersistentFlags().StringVarP(&input.envfile, "env-file", "", ".env", "environment file to read and use as env in the containers") rootCmd.SetArgs(args()) if err := rootCmd.Execute(); err != nil { @@ -92,16 +93,29 @@ func setupLogging(cmd *cobra.Command, args []string) { } } +func readEnvs(path string, envs map[string]string) bool { + if _, err := os.Stat(path); err == nil { + env, err := godotenv.Read(path) + if err != nil { + log.Fatalf("Error loading from %s: %v", path, err) + } + for k, v := range env { + envs[k] = v + } + return true + } + return false +} + func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []string) error { return func(cmd *cobra.Command, args []string) error { - envfile := input.Envfile() - if _, err := os.Stat(envfile); err == nil { - log.Debugf("Loading environment from %s", envfile) - err := godotenv.Load(envfile) - if err != nil { - log.Fatalf("Error loading environment from %s: %v", envfile, err) - } - } + log.Debugf("Loading environment from %s", input.Envfile()) + envs := make(map[string]string) + _ = readEnvs(input.Envfile(), envs) + + log.Debugf("Loading secrets from %s", input.Secretfile()) + secrets := newSecrets(input.secrets) + _ = readEnvs(input.Secretfile(), secrets) planner, err := model.NewWorkflowPlanner(input.WorkflowsPath()) if err != nil { @@ -149,7 +163,8 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str Workdir: input.Workdir(), BindWorkdir: input.bindWorkdir, LogOutput: !input.noOutput, - Secrets: newSecrets(input.secrets), + Env: envs, + Secrets: secrets, Platforms: input.newPlatforms(), } runner, err := runner.New(config) diff --git a/pkg/runner/run_context.go b/pkg/runner/run_context.go index 980a98e1..034aaf23 100644 --- a/pkg/runner/run_context.go +++ b/pkg/runner/run_context.go @@ -45,7 +45,7 @@ type stepResult struct { // GetEnv returns the env for the context func (rc *RunContext) GetEnv() map[string]string { if rc.Env == nil { - rc.Env = mergeMaps(rc.Run.Workflow.Env, rc.Run.Job().Env) + rc.Env = mergeMaps(rc.Config.Env, rc.Run.Workflow.Env, rc.Run.Job().Env) } return rc.Env } diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 2d14018a..6cc0073b 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -24,6 +24,7 @@ type Config struct { ReuseContainers bool // reuse containers to maintain state ForcePull bool // force pulling of the image, if already present LogOutput bool // log the output from docker run + Env map[string]string // env for containers Secrets map[string]string // list of secrets Platforms map[string]string // list of platforms } diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index 8b9e1be1..94ea3277 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -3,7 +3,6 @@ package runner import ( "context" "fmt" - "os" "path/filepath" "testing" @@ -110,18 +109,8 @@ func TestRunEventSecrets(t *testing.T) { workdir, err := filepath.Abs("testdata") assert.NilError(t, err, workflowPath) - _ = godotenv.Load(filepath.Join(workdir, workflowPath, ".env")) - - secrets := make(map[string]string) - for _, secret := range []string{ - "MY_SECRET", - "MULTILINE_SECRET", - "JSON_SECRET", - } { - if env, ok := os.LookupEnv(secret); ok && env != "" { - secrets[secret] = env - } - } + env, _ := godotenv.Read(filepath.Join(workdir, workflowPath, ".env")) + secrets, _ := godotenv.Read(filepath.Join(workdir, workflowPath, ".secrets")) runnerConfig := &Config{ Workdir: workdir, @@ -129,6 +118,7 @@ func TestRunEventSecrets(t *testing.T) { Platforms: platforms, ReuseContainers: false, Secrets: secrets, + Env: env, } runner, err := New(runnerConfig) assert.NilError(t, err, workflowPath) diff --git a/pkg/runner/testdata/secrets/.actrc b/pkg/runner/testdata/secrets/.actrc index 7679ca66..98e7f403 100644 --- a/pkg/runner/testdata/secrets/.actrc +++ b/pkg/runner/testdata/secrets/.actrc @@ -1,4 +1,2 @@ -W . --s MY_SECRET --s MULTILINE_SECRET --s JSON_SECRET +--secret-file .secrets diff --git a/pkg/runner/testdata/secrets/.env b/pkg/runner/testdata/secrets/.env index 6c5b217c..3b66cf2a 100644 --- a/pkg/runner/testdata/secrets/.env +++ b/pkg/runner/testdata/secrets/.env @@ -1,3 +1,2 @@ -MY_SECRET=top-secret -MULTILINE_SECRET="foo\nbar\nbaz" -JSON_SECRET={"foo": "bar"} +HELLO=WORLD +MULTILINE_ENV="foo\nbar\nbaz" diff --git a/pkg/runner/testdata/secrets/.secrets b/pkg/runner/testdata/secrets/.secrets new file mode 100644 index 00000000..6c5b217c --- /dev/null +++ b/pkg/runner/testdata/secrets/.secrets @@ -0,0 +1,3 @@ +MY_SECRET=top-secret +MULTILINE_SECRET="foo\nbar\nbaz" +JSON_SECRET={"foo": "bar"} diff --git a/pkg/runner/testdata/secrets/push.yml b/pkg/runner/testdata/secrets/push.yml index b99a5273..e9161974 100644 --- a/pkg/runner/testdata/secrets/push.yml +++ b/pkg/runner/testdata/secrets/push.yml @@ -11,3 +11,7 @@ jobs: echo "${{secrets.MULTILINE_SECRET}}" | wc -l | grep 3 - run: | echo '${{secrets.JSON_SECRET}}' | grep "{\"foo\": \"bar\"}" + - run: | + echo '${{env.HELLO}}' | grep "WORLD" + - run: | + echo "${{env.MULTILINE_ENV}}" | wc -l | grep 3