diff --git a/app.go b/app.go index b7c6b22..60c78db 100644 --- a/app.go +++ b/app.go @@ -275,6 +275,16 @@ func Run() { Usage: "secret key value pair eg id=MYSECRET", EnvVar: "PLUGIN_SECRET", }, + cli.BoolFlag{ + Name: "encoded-secrets-from-env", + Usage: "base64 encoded values", + EnvVar: "PLUGIN_ENCODED_ENV_SECRET", + }, + cli.BoolFlag{ + Name: "decode-env-secret", + Usage: "decode env values default-false", + EnvVar: "PLUGIN_DECODE_ENV_SECRET", + }, cli.StringSliceFlag{ Name: "secrets-from-env", Usage: "secret key value pair eg secret_name=secret", @@ -403,6 +413,8 @@ func run(c *cli.Context) error { Platform: c.String("platform"), SSHAgentKey: c.String("ssh-agent-key"), BuildxLoad: c.Bool("buildx-load"), + DecodeEnvSecret: c.Bool("decode-env-secret"), + EncodedSecretEnvs: c.StringSlice("encoded-secrets-from-env"), }, Daemon: Daemon{ Registry: c.String("docker.registry"), diff --git a/docker.go b/docker.go index 7284161..96e836a 100644 --- a/docker.go +++ b/docker.go @@ -1,8 +1,10 @@ package docker import ( + "encoding/base64" "encoding/json" "fmt" + //"log" "os" "os/exec" "path/filepath" @@ -52,34 +54,36 @@ type ( // Build defines Docker build parameters. Build struct { - Remote string // Git remote URL - Name string // Docker build using default named tag - Dockerfile string // Docker build Dockerfile - Context string // Docker build context - Tags []string // Docker build tags - Args []string // Docker build args - ArgsEnv []string // Docker build args from env - Target string // Docker build target - Squash bool // Docker build squash - Pull bool // Docker build pull - CacheFrom []string // Docker buildx cache-from - CacheTo []string // Docker buildx cache-to - Compress bool // Docker build compress - Repo string // Docker build repository - LabelSchema []string // label-schema Label map - AutoLabel bool // auto-label bool - Labels []string // Label map - Link string // Git repo link - NoCache bool // Docker build no-cache - Secret string // secret keypair - SecretEnvs []string // Docker build secrets with env var as source - SecretFiles []string // Docker build secrets with file as source - AddHost []string // Docker build add-host - Quiet bool // Docker build quiet - Platform string // Docker build platform - SSHAgentKey string // Docker build ssh agent key - SSHKeyPath string // Docker build ssh key path - BuildxLoad bool // Docker buildx --load + Remote string // Git remote URL + Name string // Docker build using default named tag + Dockerfile string // Docker build Dockerfile + Context string // Docker build context + Tags []string // Docker build tags + Args []string // Docker build args + ArgsEnv []string // Docker build args from env + Target string // Docker build target + Squash bool // Docker build squash + Pull bool // Docker build pull + CacheFrom []string // Docker buildx cache-from + CacheTo []string // Docker buildx cache-to + Compress bool // Docker build compress + Repo string // Docker build repository + LabelSchema []string // label-schema Label map + AutoLabel bool // auto-label bool + Labels []string // Label map + Link string // Git repo link + NoCache bool // Docker build no-cache + Secret string // secret keypair + SecretEnvs []string // Docker build secrets with env var as source + SecretFiles []string // Docker build secrets with file as source + AddHost []string // Docker build add-host + Quiet bool // Docker build quiet + Platform string // Docker build platform + SSHAgentKey string // Docker build ssh agent key + SSHKeyPath string // Docker build ssh key path + BuildxLoad bool // Docker buildx --load + DecodeEnvSecret bool // Decode the secret value in env + EncodedSecretEnvs []string // Docker build secrets that are encoded using base64 } // Plugin defines the Docker plugin parameters. @@ -164,7 +168,6 @@ func (p Plugin) Exec() error { default: fmt.Println("Registry credentials or Docker config not provided. Guest mode enabled.") } - // create Auth Config File if p.Login.Config != "" { os.MkdirAll(dockerHome, 0600) @@ -507,10 +510,18 @@ func commandBuildx(build Build, builder Builder, dryrun bool, metadataFile strin args = append(args, "--secret", build.Secret) } for _, secret := range build.SecretEnvs { - if arg, err := getSecretStringCmdArg(secret); err == nil { + if arg, err := getSecretStringCmdArg(secret, build.DecodeEnvSecret); err == nil { args = append(args, "--secret", arg) } } + // Handle base64 encoded secrets + if build.DecodeEnvSecret { + for _, encodedSecret := range build.EncodedSecretEnvs { + if arg, err := getSecretStringCmdArg(encodedSecret, build.DecodeEnvSecret); err == nil { + args = append(args, "--secret", arg) + } + } + } for _, secret := range build.SecretFiles { if arg, err := getSecretFileCmdArg(secret); err == nil { args = append(args, "--secret", arg) @@ -555,19 +566,25 @@ func commandBuildx(build Build, builder Builder, dryrun bool, metadataFile strin return exec.Command(dockerExe, args...) } -func getSecretStringCmdArg(kvp string) (string, error) { - return getSecretCmdArg(kvp, false) +func getSecretStringCmdArg(kvp string, decode bool) (string, error) { + if decode { + // Handle base64 encoded secrets + return getSecretCmdArg(kvp, false, true) + } + // Original behavior + return getSecretCmdArg(kvp, false, false) } func getSecretFileCmdArg(kvp string) (string, error) { - return getSecretCmdArg(kvp, true) + return getSecretCmdArg(kvp, true, false) } -func getSecretCmdArg(kvp string, file bool) (string, error) { +func getSecretCmdArg(kvp string, file bool, decode bool) (string, error) { delimIndex := strings.IndexByte(kvp, '=') if delimIndex == -1 { return "", fmt.Errorf("%s is not a valid secret", kvp) } + //log.Printf("kvp string : ", kvp) key := kvp[:delimIndex] value := kvp[delimIndex+1:] @@ -579,6 +596,14 @@ func getSecretCmdArg(kvp string, file bool) (string, error) { if file { return fmt.Sprintf("id=%s,src=%s", key, value), nil } + if decode { + decodedValue, err := base64.StdEncoding.DecodeString(value) + //log.Printf("decoded value of secret : ", decodedValue) + if err != nil { + return "", fmt.Errorf("failed to decode base64 value: %v", err) + } + value = string(decodedValue) + } return fmt.Sprintf("id=%s,env=%s", key, value), nil } diff --git a/docker_test.go b/docker_test.go index b4094aa..5a5ff24 100644 --- a/docker_test.go +++ b/docker_test.go @@ -207,6 +207,38 @@ func TestCommandBuildx(t *testing.T) { "--metadata-file /tmp/metadata.json", ), }, + // Add this new test case + { + name: "decoded secret from env var", + build: Build{ + Name: "plugins/drone-docker:latest", + Dockerfile: "Dockerfile", + Context: ".", + SecretEnvs: []string{ + "foo_secret=FOO_SECRET_ENV_VAR", + }, + EncodedSecretEnvs: []string{ + "encoded_secret=RU5DT0RFRF9TRUNSRVRfRU5WX1ZBUg==", // Base64 for "ENCODED_SECRET_ENV_VAR" + }, + DecodeEnvSecret: true, + Repo: "plugins/drone-docker", + Tags: []string{"latest"}, + }, + want: exec.Command( + dockerExe, + "buildx", + "build", + "--rm=true", + "-f", + "Dockerfile", + "-t", + "plugins/drone-docker:latest", + "--push", + ".", + "--secret", "id=foo_secret,env=FOO_SECRET_ENV_VAR", + "--secret", "id=encoded_secret,env=ENCODED_SECRET_ENV_VAR", + ), + }, } for _, tc := range tcs {