Skip to content

Commit

Permalink
feat: improve password management (#58)
Browse files Browse the repository at this point in the history
Co-authored-by: Giulio <giuliocalzolari@users.noreply.github.com>
  • Loading branch information
giuliocalzolari and giuliocalzolari authored Jan 9, 2025
1 parent 272e749 commit adc0532
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 10 deletions.
25 changes: 20 additions & 5 deletions cmd/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,21 @@ Example:
$ helm datarobot load images.tgz -r registry.example.com -u reg_username -p reg_password
Successfully pushed image: registry.example.com/test-image1:1.0.0
'''`, "'", "`", -1),
'''
Authentication can be provided in various ways, including:
'''sh
export REGISTRY_USERNAME=reg_username
export REGISTRY_PASSWORD=reg_password
$ helm datarobot load images.tgz -r registry.example.com
'''
'''sh
$ echo "reg_password" | helm datarobot load images.tgz -r registry.example.com -u reg_username --password-stdin
'''
`, "'", "`", -1),
Args: cobra.MinimumNArgs(1), // Requires at least one argument (file path)
RunE: func(cmd *cobra.Command, args []string) error {

Expand Down Expand Up @@ -118,13 +132,13 @@ Successfully pushed image: registry.example.com/test-image1:1.0.0

if loadToken != "" {
auth = &authn.Bearer{
Token: loadToken,
Token: GetSecret(loadPasswordStdin, "REGISTRY_TOKEN", loadToken),
}

} else if loadUsername != "" && loadPassword != "" {
auth = &authn.Basic{
Username: loadUsername,
Password: loadPassword,
Username: GetSecret(false, "REGISTRY_USERNAME", loadUsername),
Password: GetSecret(loadPasswordStdin, "REGISTRY_PASSWORD", loadPassword),
}

} else {
Expand All @@ -143,12 +157,13 @@ Successfully pushed image: registry.example.com/test-image1:1.0.0
}

var loadReg, loadUsername, loadPassword, loadToken, loadImagePrefix, loadImageSuffix, loadImageRepo string
var loadDryRun bool
var loadDryRun, loadPasswordStdin bool

func init() {
rootCmd.AddCommand(loadCmd)
loadCmd.Flags().StringVarP(&loadUsername, "username", "u", "", "username to auth")
loadCmd.Flags().StringVarP(&loadPassword, "password", "p", "", "pass to auth")
loadCmd.Flags().BoolVar(&loadPasswordStdin, "password-stdin", false, "Read password from stdin")
loadCmd.Flags().StringVarP(&loadToken, "token", "t", "", "pass to auth")
loadCmd.Flags().StringVarP(&loadReg, "registry", "r", "", "registry to auth")
loadCmd.Flags().StringVarP(&loadImagePrefix, "prefix", "", "", "append prefix on repo name")
Expand Down
24 changes: 19 additions & 5 deletions cmd/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,21 @@ $ helm datarobot sync testdata/test-chart1/ -r registry.example.com -u reg_usern
Pulling image: docker.io/datarobot/test-image1:1.0.0
Pushing image: registry.example.com/datarobot/test-image1:1.0.0
'''
'''`, "'", "`", -1),
Authentication can be provided in various ways, including:
'''sh
export REGISTRY_USERNAME=reg_username
export REGISTRY_PASSWORD=reg_password
$ helm datarobot sync testdata/test-chart1/ -r registry.example.com
'''
'''sh
$ echo "reg_password" | helm datarobot sync testdata/test-chart1/ -r registry.example.com -u reg_username --password-stdin
'''
`, "'", "`", -1),
RunE: func(cmd *cobra.Command, args []string) error {
images, err := ExtractImagesFromCharts(args)
if err != nil {
Expand Down Expand Up @@ -74,13 +87,13 @@ Pushing image: registry.example.com/datarobot/test-image1:1.0.0

if syncToken != "" {
auth = &authn.Bearer{
Token: syncToken,
Token: GetSecret(syncPasswordStdin, "REGISTRY_TOKEN", syncToken),
}

} else if syncUsername != "" && syncPassword != "" {
auth = &authn.Basic{
Username: syncUsername,
Password: syncPassword,
Username: GetSecret(false, "REGISTRY_USERNAME", syncUsername),
Password: GetSecret(syncPasswordStdin, "REGISTRY_PASSWORD", syncPassword),
}

} else {
Expand All @@ -97,13 +110,14 @@ Pushing image: registry.example.com/datarobot/test-image1:1.0.0
}

var syncReg, syncUsername, syncPassword, syncToken, syncImagePrefix, syncImageSuffix, syncImageRepo, syncTransform, caCertPath, certPath, keyPath string
var syncDryRun, skipTlsVerify bool
var syncDryRun, skipTlsVerify, syncPasswordStdin bool

func init() {
rootCmd.AddCommand(syncCmd)
syncCmd.Flags().StringVarP(&annotation, "annotation", "a", "datarobot.com/images", "annotation to lookup")
syncCmd.Flags().StringVarP(&syncUsername, "username", "u", "", "username to auth")
syncCmd.Flags().StringVarP(&syncPassword, "password", "p", "", "pass to auth")
syncCmd.Flags().BoolVar(&syncPasswordStdin, "password-stdin", false, "Read password from stdin")
syncCmd.Flags().StringVarP(&syncToken, "token", "t", "", "pass to auth")
syncCmd.Flags().StringVarP(&syncReg, "registry", "r", "", "registry to auth")
syncCmd.Flags().StringVarP(&syncImagePrefix, "prefix", "", "", "append prefix on repo name")
Expand Down
21 changes: 21 additions & 0 deletions cmd/utils.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package cmd

import (
"bufio"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
"os"
"sort"
"strings"

Expand Down Expand Up @@ -121,3 +123,22 @@ func ExtractImagesFromManifest(manifest string) ([]string, error) {
sort.Strings(manifestImages)
return manifestImages, nil
}

func GetSecret(stdin bool, envVar string, argv string) string {
secret := ""
if stdin {
scanner := bufio.NewScanner(os.Stdin)
if scanner.Scan() {
secret = scanner.Text()
}
}
if secret == "" {
value, exists := os.LookupEnv(envVar)
if !exists {
secret = argv
} else {
secret = value
}
}
return secret
}
43 changes: 43 additions & 0 deletions cmd/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"io/ioutil"
"os"
"testing"

"github.com/stretchr/testify/assert"
)

func TestGetTransport(t *testing.T) {
Expand Down Expand Up @@ -94,3 +96,44 @@ E4bmYvhnmO/hlPwDN02OSWHYm6m0yIzWXw==
t.Fatal("Expected InsecureSkipVerify to be true")
}
}

func TestGetSecret(t *testing.T) {
t.Run("direct", func(t *testing.T) {
output := GetSecret(false, "TEST_SEC", "test")
expectedOutput := `test`
assert.Equal(t, expectedOutput, output)
})
t.Run("env", func(t *testing.T) {
os.Setenv("TEST_SEC", "test")
output := GetSecret(false, "TEST_SEC", "")
expectedOutput := `test`
assert.Equal(t, expectedOutput, output)
})
t.Run("sdtin", func(t *testing.T) {
input := "test\n"
// Save the original os.Stdin
originalStdin := os.Stdin
defer func() { os.Stdin = originalStdin }()

// Create a temporary os.Stdin
r, w, err := os.Pipe()
if err != nil {
t.Fatalf("Failed to create pipe: %v", err)
}

// Write the mock input to the pipe
_, err = w.Write([]byte(input))
if err != nil {
t.Fatalf("Failed to write to pipe: %v", err)
}
// Close the pipe write to simulate end of input
w.Close()

// Redirect os.Stdin to read from the pipe
os.Stdin = r
output := GetSecret(true, "", "")
expectedOutput := `test`
assert.Equal(t, expectedOutput, output)
})

}
15 changes: 15 additions & 0 deletions docs/helm-datarobot_load.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ Successfully pushed image: registry.example.com/test-image1:1.0.0

```

Authentication can be provided in various ways, including:

```sh
export REGISTRY_USERNAME=reg_username
export REGISTRY_PASSWORD=reg_password
$ helm datarobot load images.tgz -r registry.example.com
```

```sh
$ echo "reg_password" | helm datarobot load images.tgz -r registry.example.com -u reg_username --password-stdin
```



```
helm-datarobot load [flags]
```
Expand All @@ -29,6 +43,7 @@ helm-datarobot load [flags]
-i, --insecure Skip server certificate verification
-K, --key string Path to the client key
-p, --password string pass to auth
--password-stdin Read password from stdin
--prefix string append prefix on repo name
-r, --registry string registry to auth
--repo string rewrite the target repository name
Expand Down
14 changes: 14 additions & 0 deletions docs/helm-datarobot_sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,22 @@ $ helm datarobot sync testdata/test-chart1/ -r registry.example.com -u reg_usern

Pulling image: docker.io/datarobot/test-image1:1.0.0
Pushing image: registry.example.com/datarobot/test-image1:1.0.0
```

Authentication can be provided in various ways, including:

```sh
export REGISTRY_USERNAME=reg_username
export REGISTRY_PASSWORD=reg_password
$ helm datarobot sync testdata/test-chart1/ -r registry.example.com
```

```sh
$ echo "reg_password" | helm datarobot sync testdata/test-chart1/ -r registry.example.com -u reg_username --password-stdin
```



```
helm-datarobot sync [flags]
```
Expand All @@ -32,6 +45,7 @@ helm-datarobot sync [flags]
-i, --insecure Skip server certificate verification
-K, --key string Path to the client key
-p, --password string pass to auth
--password-stdin Read password from stdin
--prefix string append prefix on repo name
-r, --registry string registry to auth
--repo string rewrite the target repository name
Expand Down

0 comments on commit adc0532

Please sign in to comment.