secret input type, simplify state format

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
This commit is contained in:
Andrea Luzzardi 2021-05-17 11:12:46 -07:00
parent 5442d6b261
commit 9d416d65f7
5 changed files with 83 additions and 91 deletions

View File

@ -10,6 +10,7 @@ import (
"dagger.io/go/cmd/dagger/logger" "dagger.io/go/cmd/dagger/logger"
"dagger.io/go/dagger" "dagger.io/go/dagger"
"dagger.io/go/dagger/compiler" "dagger.io/go/dagger/compiler"
"dagger.io/go/dagger/state"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -84,9 +85,9 @@ var listCmd = &cobra.Command{
}, },
} }
func isUserSet(env *dagger.EnvironmentState, val *compiler.Value) bool { func isUserSet(env *state.State, val *compiler.Value) bool {
for _, i := range env.Inputs { for key := range env.Inputs {
if val.Path().String() == i.Key { if val.Path().String() == key {
return true return true
} }
} }

View File

@ -1,14 +1,20 @@
package input package input
import ( import (
"fmt"
"syscall"
"dagger.io/go/cmd/dagger/logger"
"dagger.io/go/dagger/state"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"golang.org/x/term"
) )
var secretCmd = &cobra.Command{ var secretCmd = &cobra.Command{
Use: "secret TARGET VALUE", Use: "secret <TARGET> [-f] [<VALUE|PATH>]",
Short: "Add an encrypted input secret", Short: "Add an encrypted input secret",
Args: cobra.ExactArgs(2), Args: cobra.RangeArgs(1, 2),
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
// Fix Viper bug for duplicate flags: // Fix Viper bug for duplicate flags:
// https://github.com/spf13/viper/issues/233 // https://github.com/spf13/viper/issues/233
@ -17,14 +23,35 @@ var secretCmd = &cobra.Command{
} }
}, },
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
// lg := logger.New() lg := logger.New()
// ctx := lg.WithContext(cmd.Context()) ctx := lg.WithContext(cmd.Context())
panic("not implemented") var secret string
if len(args) == 1 {
// No value specified: prompt terminal
fmt.Print("Secret: ")
data, err := term.ReadPassword(syscall.Stdin)
if err != nil {
lg.Fatal().Err(err).Msg("unable to read secret from terminal")
}
fmt.Println("")
secret = string(data)
} else {
// value specified: read it
secret = readInput(ctx, args[1])
}
updateEnvironmentInput(
ctx,
args[0],
state.SecretInput(secret),
)
}, },
} }
func init() { func init() {
secretCmd.Flags().BoolP("file", "f", false, "Read value from file")
if err := viper.BindPFlags(secretCmd.Flags()); err != nil { if err := viper.BindPFlags(secretCmd.Flags()); err != nil {
panic(err) panic(err)
} }

View File

@ -11,7 +11,6 @@ import (
cueflow "cuelang.org/go/tools/flow" cueflow "cuelang.org/go/tools/flow"
"dagger.io/go/dagger/compiler" "dagger.io/go/dagger/compiler"
"dagger.io/go/dagger/state" "dagger.io/go/dagger/state"
"dagger.io/go/pkg/cuetils"
"dagger.io/go/stdlib" "dagger.io/go/stdlib"
"github.com/opentracing/opentracing-go" "github.com/opentracing/opentracing-go"
@ -43,15 +42,15 @@ func NewEnvironment(st *state.State) (*Environment, error) {
} }
// Prepare inputs // Prepare inputs
for _, input := range st.Inputs { for key, input := range st.Inputs {
v, err := input.Value.Compile(st) v, err := input.Compile(st)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if input.Key == "" { if key == "" {
err = e.input.FillPath(cue.MakePath(), v) err = e.input.FillPath(cue.MakePath(), v)
} else { } else {
err = e.input.FillPath(cue.ParsePath(input.Key), v) err = e.input.FillPath(cue.ParsePath(key), v)
} }
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -24,25 +24,12 @@ import (
// Under the hood, an artifact is encoded as a LLB pipeline, and // Under the hood, an artifact is encoded as a LLB pipeline, and
// attached to the cue configuration as a // attached to the cue configuration as a
// //
type InputType string
const (
InputTypeDir InputType = "dir"
InputTypeGit InputType = "git"
InputTypeDocker InputType = "docker"
InputTypeText InputType = "text"
InputTypeJSON InputType = "json"
InputTypeYAML InputType = "yaml"
InputTypeFile InputType = "file"
InputTypeEmpty InputType = ""
)
type Input struct { type Input struct {
Type InputType `yaml:"type,omitempty"`
Dir *dirInput `yaml:"dir,omitempty"` Dir *dirInput `yaml:"dir,omitempty"`
Git *gitInput `yaml:"git,omitempty"` Git *gitInput `yaml:"git,omitempty"`
Docker *dockerInput `yaml:"docker,omitempty"` Docker *dockerInput `yaml:"docker,omitempty"`
Secret *secretInput `yaml:"secret,omitempty"`
Text *textInput `yaml:"text,omitempty"` Text *textInput `yaml:"text,omitempty"`
JSON *jsonInput `yaml:"json,omitempty"` JSON *jsonInput `yaml:"json,omitempty"`
YAML *yamlInput `yaml:"yaml,omitempty"` YAML *yamlInput `yaml:"yaml,omitempty"`
@ -50,32 +37,31 @@ type Input struct {
} }
func (i Input) Compile(state *State) (*compiler.Value, error) { func (i Input) Compile(state *State) (*compiler.Value, error) {
switch i.Type { switch {
case InputTypeDir: case i.Dir != nil:
return i.Dir.Compile(state) return i.Dir.Compile(state)
case InputTypeGit: case i.Git != nil:
return i.Git.Compile(state) return i.Git.Compile(state)
case InputTypeDocker: case i.Docker != nil:
return i.Docker.Compile(state) return i.Docker.Compile(state)
case InputTypeText: case i.Text != nil:
return i.Text.Compile(state) return i.Text.Compile(state)
case InputTypeJSON: case i.Secret != nil:
return i.Secret.Compile(state)
case i.JSON != nil:
return i.JSON.Compile(state) return i.JSON.Compile(state)
case InputTypeYAML: case i.YAML != nil:
return i.YAML.Compile(state) return i.YAML.Compile(state)
case InputTypeFile: case i.File != nil:
return i.File.Compile(state) return i.File.Compile(state)
case "":
return nil, fmt.Errorf("input has not been set")
default: default:
return nil, fmt.Errorf("unsupported input type: %s", i.Type) return nil, fmt.Errorf("input has not been set")
} }
} }
// An input artifact loaded from a local directory // An input artifact loaded from a local directory
func DirInput(path string, include []string) Input { func DirInput(path string, include []string) Input {
return Input{ return Input{
Type: InputTypeDir,
Dir: &dirInput{ Dir: &dirInput{
Path: path, Path: path,
Include: include, Include: include,
@ -124,7 +110,6 @@ type gitInput struct {
func GitInput(remote, ref, dir string) Input { func GitInput(remote, ref, dir string) Input {
return Input{ return Input{
Type: InputTypeGit,
Git: &gitInput{ Git: &gitInput{
Remote: remote, Remote: remote,
Ref: ref, Ref: ref,
@ -149,7 +134,6 @@ func (git gitInput) Compile(_ *State) (*compiler.Value, error) {
// An input artifact loaded from a docker container // An input artifact loaded from a docker container
func DockerInput(ref string) Input { func DockerInput(ref string) Input {
return Input{ return Input{
Type: InputTypeDocker,
Docker: &dockerInput{ Docker: &dockerInput{
Ref: ref, Ref: ref,
}, },
@ -166,63 +150,62 @@ func (i dockerInput) Compile(_ *State) (*compiler.Value, error) {
// An input value encoded as text // An input value encoded as text
func TextInput(data string) Input { func TextInput(data string) Input {
i := textInput(data)
return Input{ return Input{
Type: InputTypeText, Text: &i,
Text: &textInput{
Data: data,
},
} }
} }
type textInput struct { type textInput string
Data string `json:"data,omitempty"`
}
func (i textInput) Compile(_ *State) (*compiler.Value, error) { func (i textInput) Compile(_ *State) (*compiler.Value, error) {
return compiler.Compile("", fmt.Sprintf("%q", i.Data)) return compiler.Compile("", fmt.Sprintf("%q", i))
}
// A secret input value
func SecretInput(data string) Input {
i := secretInput(data)
return Input{
Secret: &i,
}
}
type secretInput string
func (i secretInput) Compile(_ *State) (*compiler.Value, error) {
return compiler.Compile("", fmt.Sprintf("%q", i))
} }
// An input value encoded as JSON // An input value encoded as JSON
func JSONInput(data string) Input { func JSONInput(data string) Input {
i := jsonInput(data)
return Input{ return Input{
Type: InputTypeJSON, JSON: &i,
JSON: &jsonInput{
Data: data,
},
} }
} }
type jsonInput struct { type jsonInput string
// Marshalled JSON data
Data string `json:"data,omitempty"`
}
func (i jsonInput) Compile(_ *State) (*compiler.Value, error) { func (i jsonInput) Compile(_ *State) (*compiler.Value, error) {
return compiler.DecodeJSON("", []byte(i.Data)) return compiler.DecodeJSON("", []byte(i))
} }
// An input value encoded as YAML // An input value encoded as YAML
func YAMLInput(data string) Input { func YAMLInput(data string) Input {
i := yamlInput(data)
return Input{ return Input{
Type: InputTypeYAML, YAML: &i,
YAML: &yamlInput{
Data: data,
},
} }
} }
type yamlInput struct { type yamlInput string
// Marshalled YAML data
Data string `json:"data,omitempty"`
}
func (i yamlInput) Compile(_ *State) (*compiler.Value, error) { func (i yamlInput) Compile(_ *State) (*compiler.Value, error) {
return compiler.DecodeYAML("", []byte(i.Data)) return compiler.DecodeYAML("", []byte(i))
} }
func FileInput(data string) Input { func FileInput(data string) Input {
return Input{ return Input{
Type: InputTypeFile,
File: &fileInput{ File: &fileInput{
Path: data, Path: data,
}, },

View File

@ -11,17 +11,12 @@ type State struct {
Name string `yaml:"name,omitempty"` Name string `yaml:"name,omitempty"`
// User Inputs // User Inputs
Inputs []inputKV `yaml:"inputs,omitempty"` Inputs map[string]Input `yaml:"inputs,omitempty"`
// Computed values // Computed values
Computed string `yaml:"-"` Computed string `yaml:"-"`
} }
type inputKV struct {
Key string `yaml:"key,omitempty"`
Value Input `yaml:"value,omitempty"`
}
// Cue module containing the environment plan // Cue module containing the environment plan
// The input's top-level artifact is used as a module directory. // The input's top-level artifact is used as a module directory.
func (s *State) PlanSource() Input { func (s *State) PlanSource() Input {
@ -29,15 +24,10 @@ func (s *State) PlanSource() Input {
} }
func (s *State) SetInput(key string, value Input) error { func (s *State) SetInput(key string, value Input) error {
for i, inp := range s.Inputs { if s.Inputs == nil {
if inp.Key != key { s.Inputs = make(map[string]Input)
continue
}
// Remove existing inputs with the same key
s.Inputs = append(s.Inputs[:i], s.Inputs[i+1:]...)
} }
s.Inputs[key] = value
s.Inputs = append(s.Inputs, inputKV{Key: key, Value: value})
return nil return nil
} }
@ -45,14 +35,6 @@ func (s *State) SetInput(key string, value Input) error {
// For example RemoveInputs("foo.bar") will remove all inputs // For example RemoveInputs("foo.bar") will remove all inputs
// at foo.bar, foo.bar.baz, etc. // at foo.bar, foo.bar.baz, etc.
func (s *State) RemoveInputs(key string) error { func (s *State) RemoveInputs(key string) error {
newInputs := make([]inputKV, 0, len(s.Inputs)) delete(s.Inputs, key)
for _, i := range s.Inputs {
if i.Key == key {
continue
}
newInputs = append(newInputs, i)
}
s.Inputs = newInputs
return nil return nil
} }