diff --git a/plan/task/secretexec.go b/plan/task/secretexec.go new file mode 100644 index 00000000..3f77599f --- /dev/null +++ b/plan/task/secretexec.go @@ -0,0 +1,44 @@ +package task + +import ( + "context" + "os/exec" + "strings" + + "github.com/rs/zerolog/log" + "go.dagger.io/dagger/compiler" + "go.dagger.io/dagger/plancontext" + "go.dagger.io/dagger/solver" +) + +func init() { + Register("SecretExec", func() Task { return &secretExecTask{} }) +} + +type secretExecTask struct { +} + +func (c secretExecTask) Run(ctx context.Context, pctx *plancontext.Context, _ solver.Solver, v *compiler.Value) (*compiler.Value, error) { + var secretExec struct { + Command struct { + Name string + Args []string + } + } + + if err := v.Decode(&secretExec); err != nil { + return nil, err + } + lg := log.Ctx(ctx) + + lg.Debug().Str("name", secretExec.Command.Name).Str("args", strings.Join(secretExec.Command.Args, " ")).Msg("executing secret command") + + out, err := exec.CommandContext(ctx, secretExec.Command.Name, secretExec.Command.Args...).Output() + if err != nil { + return nil, err + } + secret := pctx.Secrets.New(string(out)) + return compiler.NewValue().FillFields(map[string]interface{}{ + "contents": secret.MarshalCUE(), + }) +} diff --git a/stdlib/europa/dagger/engine/plan.cue b/stdlib/europa/dagger/engine/plan.cue index 923614bf..5fed2aa5 100644 --- a/stdlib/europa/dagger/engine/plan.cue +++ b/stdlib/europa/dagger/engine/plan.cue @@ -78,6 +78,13 @@ _#inputSecret: { // Read secret from an environment variable ON THE CLIENT MACHINE _type: "SecretEnv" envvar: string + } | { + // Get secret by executing a command ON THE CLIENT MACHINE + _type: "SecretExec" + command: { + name: string + args: [...string] + } } } diff --git a/tests/plan.bats b/tests/plan.bats index 58bb7f21..41f0e920 100644 --- a/tests/plan.bats +++ b/tests/plan.bats @@ -56,4 +56,16 @@ setup() { run "$DAGGER" --europa up ./plan/inputs/directories/conflicting_values.cue assert_failure assert_output --partial 'failed to up environment: actions.verify.contents: conflicting values "local directory" and "local dfsadf"' -} \ No newline at end of file +} + +@test "plan/inputs/secrets exec" { + cd "$TESTDIR" + "$DAGGER" --europa up ./plan/inputs/secrets/exec.cue +} + +@test "plan/inputs/secrets invalid command" { + cd "$TESTDIR" + run "$DAGGER" --europa up ./plan/inputs/secrets/invalid_command.cue + assert_failure + assert_output --partial 'failed: exec: "rtyet": executable file not found in $PATH' +} diff --git a/tests/plan/inputs/secrets/exec.cue b/tests/plan/inputs/secrets/exec.cue new file mode 100644 index 00000000..b8aa8fd9 --- /dev/null +++ b/tests/plan/inputs/secrets/exec.cue @@ -0,0 +1,34 @@ +package main + +import ( + "alpha.dagger.io/europa/dagger/engine" +) + +engine.#Plan & { + inputs: secrets: echo: command: { + name: "echo" + args: ["hello europa"] + } + + actions: { + + image: engine.#Pull & { + source: "alpine:3.15.0@sha256:e7d88de73db3d3fd9b2d63aa7f447a10fd0220b7cbf39803c803f2af9ba256b3" + } + + verify: engine.#Exec & { + input: image.output + mounts: secret: { + dest: "/run/secrets/test" + contents: inputs.secrets.echo.contents + } + args: [ + "sh", "-c", + #""" + test "$(cat /run/secrets/test)" = "hello europa" + ls -l /run/secrets/test | grep -- "-r--------" + """#, + ] + } + } +} diff --git a/tests/plan/inputs/secrets/invalid_command.cue b/tests/plan/inputs/secrets/invalid_command.cue new file mode 100644 index 00000000..87a133a0 --- /dev/null +++ b/tests/plan/inputs/secrets/invalid_command.cue @@ -0,0 +1,34 @@ +package main + +import ( + "alpha.dagger.io/europa/dagger/engine" +) + +engine.#Plan & { + inputs: secrets: echo: command: { + name: "rtyet" // should fail because command doesnt exist + args: ["hello europa"] + } + + actions: { + + image: engine.#Pull & { + source: "alpine:3.15.0@sha256:e7d88de73db3d3fd9b2d63aa7f447a10fd0220b7cbf39803c803f2af9ba256b3" + } + + verify: engine.#Exec & { + input: image.output + mounts: secret: { + dest: "/run/secrets/test" + contents: inputs.secrets.echo.contents + } + args: [ + "sh", "-c", + #""" + test "$(cat /run/secrets/test)" = "hello europa" + ls -l /run/secrets/test | grep -- "-r--------" + """#, + ] + } + } +}