Skip to content

Commit

Permalink
support for secrets
Browse files Browse the repository at this point in the history
Signed-off-by: Casey Lee <cplee@nektos.com>
  • Loading branch information
cplee committed Feb 21, 2020
1 parent 9651992 commit 573f78e
Show file tree
Hide file tree
Showing 17 changed files with 715 additions and 17 deletions.
12 changes: 4 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,10 @@ act -v

# Secrets

To run `act` with secrets, you can enter them interactively or supply them as environment variables.
If you have a secret called `FOO` in your workflow, `act` will take whatever you have set as `FOO` in the session from which you are running `act`.
If `FOO` is unset, it will ask you interactively.

You can set environment variables for the current session by running `export FOO="zap"`, or globally in your `.profile`.
You can also set environment variables *per directory* using a tool such as [direnv](https://direnv.net/).
**Be careful not to expose secrets**:
You may want to `.gitignore` any files or folders containing secrets, and/or encrypt secrets.
To run `act` with secrets, you can enter them interactively or supply them as environment variables. The following options are available for providing secrets:

* `act -s MY_SECRET=somevalue` - use `somevalue` as the value for `MY_SECRET`.
* `act -s MY_SECRET` - check for an environment variable named `MY_SECRET` and use it if it exists. If environment variable is not defined, prompt the user for a value.

# Support

Expand Down
1 change: 1 addition & 0 deletions cmd/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type Input struct {
workflowsPath string
eventPath string
reuseContainers bool
secrets []string
dryrun bool
forcePull bool
logOutput bool
Expand Down
4 changes: 3 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ func Execute(ctx context.Context, version string) {
rootCmd.Flags().BoolP("watch", "w", false, "watch the contents of the local repo and run when files change")
rootCmd.Flags().BoolP("list", "l", false, "list workflows")
rootCmd.Flags().StringP("job", "j", "", "run job")
rootCmd.Flags().StringArrayVarP(&input.secrets, "secret", "s", []string{}, "secret to make available to actions with optional value (e.g. -s mysecret=foo or -s mysecret)")
rootCmd.Flags().BoolVarP(&input.reuseContainers, "reuse", "r", false, "reuse action containers to maintain state")
rootCmd.Flags().BoolVarP(&input.forcePull, "pull", "p", false, "pull docker image(s) if already present")
rootCmd.Flags().StringVarP(&input.eventPath, "event", "e", "", "path to event JSON file")
rootCmd.Flags().StringVarP(&input.eventPath, "eventpath", "e", "", "path to event JSON file")
rootCmd.PersistentFlags().StringVarP(&input.workflowsPath, "workflows", "W", "./.github/workflows/", "path to workflow files")
rootCmd.PersistentFlags().StringVarP(&input.workdir, "directory", "C", ".", "working directory")
rootCmd.PersistentFlags().BoolP("verbose", "v", false, "verbose output")
Expand Down Expand Up @@ -96,6 +97,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
ReuseContainers: input.reuseContainers,
Workdir: input.Workdir(),
LogOutput: input.logOutput,
Secrets: newSecrets(input.secrets),
}
runner, err := runner.New(config)
if err != nil {
Expand Down
36 changes: 36 additions & 0 deletions cmd/secrets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cmd

import (
"fmt"
"log"
"os"
"strings"

"github.com/howeyc/gopass"
)

type secrets map[string]string

func newSecrets(secretList []string) secrets {
s := make(map[string]string)
for _, secretPair := range secretList {
secretPairParts := strings.Split(secretPair, "=")
if len(secretPairParts) == 2 {
s[secretPairParts[0]] = secretPairParts[1]
} else if env, ok := os.LookupEnv(secretPairParts[0]); ok && env != "" {
s[secretPairParts[0]] = env
} else {
fmt.Printf("Provide value for '%s': ", secretPairParts[0])
val, err := gopass.GetPasswdMasked()
if err != nil {
log.Fatal("abort")
}
s[secretPairParts[0]] = string(val)
}
}
return s
}

func (s secrets) AsMap() map[string]string {
return s
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
github.com/gogo/protobuf v1.2.0 // indirect
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
github.com/gorilla/mux v1.7.0 // indirect
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jtolds/gls v4.2.1+incompatible // indirect
github.com/mgutz/str v1.2.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U=
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c h1:aY2hhxLhjEAbfXOx2nRJxCXezC6CO2V/yN+OCr1srtk=
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
Expand Down
3 changes: 1 addition & 2 deletions pkg/runner/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,8 @@ func (rc *RunContext) vmRunner() func(*otto.Otto) {
}

func (rc *RunContext) vmSecrets() func(*otto.Otto) {
secrets := make(map[string]string)
return func(vm *otto.Otto) {
_ = vm.Set("secrets", secrets)
_ = vm.Set("secrets", rc.Config.Secrets)
}
}

Expand Down
13 changes: 7 additions & 6 deletions pkg/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ type Runner interface {

// Config contains the config for a new runner
type Config struct {
Workdir string // path to working directory
EventName string // name of event to run
EventPath string // path to JSON file to use for event.json in containers
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
Workdir string // path to working directory
EventName string // name of event to run
EventPath string // path to JSON file to use for event.json in containers
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
Secrets map[string]string // list of secrets
}

type runnerImpl struct {
Expand Down
9 changes: 9 additions & 0 deletions pkg/runner/testdata/secrets/push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: basic
on: push

jobs:
build:
runs-on: ubuntu-latest
steps:
- run: |
echo '${{secrets.MY_SECRET}}' | grep 'top-secret'
11 changes: 11 additions & 0 deletions vendor/github.com/howeyc/gopass/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions vendor/github.com/howeyc/gopass/LICENSE.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 573f78e

Please sign in to comment.