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

View File

@ -1,14 +1,20 @@
package input
import (
"fmt"
"syscall"
"dagger.io/go/cmd/dagger/logger"
"dagger.io/go/dagger/state"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"golang.org/x/term"
)
var secretCmd = &cobra.Command{
Use: "secret TARGET VALUE",
Use: "secret <TARGET> [-f] [<VALUE|PATH>]",
Short: "Add an encrypted input secret",
Args: cobra.ExactArgs(2),
Args: cobra.RangeArgs(1, 2),
PreRun: func(cmd *cobra.Command, args []string) {
// Fix Viper bug for duplicate flags:
// https://github.com/spf13/viper/issues/233
@ -17,14 +23,35 @@ var secretCmd = &cobra.Command{
}
},
Run: func(cmd *cobra.Command, args []string) {
// lg := logger.New()
// ctx := lg.WithContext(cmd.Context())
lg := logger.New()
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() {
secretCmd.Flags().BoolP("file", "f", false, "Read value from file")
if err := viper.BindPFlags(secretCmd.Flags()); err != nil {
panic(err)
}

View File

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

View File

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

View File

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