-
Notifications
You must be signed in to change notification settings - Fork 1
Secrets service experiment #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
aa47ccd
195c287
fc57673
c8d6109
acfd741
6ecc3e8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Secrets Engine Keychain | ||
|
|
||
| Keychain is a standalone library for use to store secrets in a standardized | ||
| format to the OS keychain. |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,119 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| package main | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "context" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "log" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "path" | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/docker/secrets-engine/keychain" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/docker/secrets-engine/keychain/mocks" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "github.com/spf13/cobra" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| func NewCommand() (*cobra.Command, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| kc, err := keychain.New( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| func() *mocks.MockCredential { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return &mocks.MockCredential{} | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| keychain.WithKeyPrefix[*mocks.MockCredential]("cli"), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| list := &cobra.Command{ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Use: "list", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Aliases: []string{"ls"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| RunE: func(cmd *cobra.Command, args []string) error { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| secrets, err := kc.GetAll(cmd.Context()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if len(secrets) == 0 { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fmt.Println("No Secrets found") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| for k, v := range secrets { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| vv, err := v.Marshal() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fmt.Printf("\nID: %s\nValues: %s\n", k, vv) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| var ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| username string | ||||||||||||||||||||||||||||||||||||||||||||||||||
| password string | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| store := &cobra.Command{ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Use: "store", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Aliases: []string{"set"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| RunE: func(cmd *cobra.Command, args []string) error { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| id, err := keychain.ParseID(path.Join("keystore-cli", username)) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| creds := &mocks.MockCredential{ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Username: username, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Password: password, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return kc.Store(cmd.Context(), id, creds) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| store.PersistentFlags().StringVar(&username, "username", "", "The secret key") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| store.PersistentFlags().StringVar(&password, "password", "", "The secret value") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| store.MarkFlagsRequiredTogether("username", "password") | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| retrieve := &cobra.Command{ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Use: "get", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Args: cobra.ExactArgs(1), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| RunE: func(cmd *cobra.Command, args []string) error { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| id, err := keychain.ParseID(path.Join("keystore-cli", args[0])) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| secret, err := kc.Get(cmd.Context(), id) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| val, err := secret.Marshal() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| fmt.Printf("Secret:\nID:%s\nValues:%s\n", id.String(), val) | ||||||||||||||||||||||||||||||||||||||||||||||||||
Check failureCode scanning / CodeQL Clear-text logging of sensitive information High Sensitive data returned by an access to Password Error loading related location Loading
Copilot AutofixAI 9 months ago To fix the issue, we need to ensure that sensitive information (e.g., passwords) is not logged in clear text. Instead of logging the entire output of the In this case, we will modify the
Suggested changeset
2
keychain/cmd/main.go
keychain/mocks/mock_credential.go
Outside changed files
Copilot is powered by AI and may make mistakes. Always verify output.
Refresh and try again.
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| erase := &cobra.Command{ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Use: "erase", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Args: cobra.ExactArgs(1), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Aliases: []string{"rm", "remove"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| RunE: func(cmd *cobra.Command, args []string) error { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| id, err := keychain.ParseID(path.Join("keystore-cli", args[0])) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return err | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return kc.Erase(cmd.Context(), id) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| root := &cobra.Command{} | ||||||||||||||||||||||||||||||||||||||||||||||||||
| root.AddCommand(list, store, retrieve, erase) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| return root, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| func main() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ctx := context.Background() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| cmd, err := NewCommand() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| log.Fatalf("could not create CLI: %v", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| cmd.SetContext(ctx) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if err := cmd.Execute(); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| log.Fatal(err) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| module github.com/docker/secrets-engine/keychain | ||
|
|
||
| go 1.24.3 | ||
|
|
||
| replace github.com/docker/secrets-engine => ../ | ||
|
|
||
| require ( | ||
| github.com/docker/secrets-engine v0.0.0-00010101000000-000000000000 | ||
| github.com/godbus/dbus/v5 v5.1.0 | ||
| github.com/keybase/dbus v0.0.0-20220506165403-5aa21ea2c23a | ||
| github.com/keybase/go-keychain v0.0.1 | ||
| github.com/spf13/cobra v1.9.1 | ||
| ) | ||
|
|
||
| require ( | ||
| github.com/inconshreveable/mousetrap v1.1.0 // indirect | ||
| github.com/spf13/pflag v1.0.6 // indirect | ||
| golang.org/x/crypto v0.32.0 // indirect | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= | ||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
| github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= | ||
| github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= | ||
| github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= | ||
| github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= | ||
| github.com/keybase/dbus v0.0.0-20220506165403-5aa21ea2c23a h1:K0EAzgzEQHW4Y5lxrmvPMltmlRDzlhLfGmots9EHUTI= | ||
| github.com/keybase/dbus v0.0.0-20220506165403-5aa21ea2c23a/go.mod h1:YPNKjjE7Ubp9dTbnWvsP3HT+hYnY6TfXzubYTBeUxc8= | ||
| github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= | ||
| github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= | ||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
| github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||
| github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= | ||
| github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= | ||
| github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= | ||
| github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= | ||
| github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= | ||
| github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= | ||
| golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= | ||
| golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= | ||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| package keychain | ||
|
|
||
| import ( | ||
| "errors" | ||
|
|
||
| "github.com/docker/secrets-engine/pkg/secrets" | ||
| ) | ||
|
|
||
| // We depend on the secrets engine to define how secrets should look like | ||
| // but the caller of keychain does not necessarily need to import secrets engine | ||
| type ( | ||
| Secret = secrets.Secret | ||
| Store = secrets.Store | ||
| ID = secrets.ID | ||
| ) | ||
|
|
||
| var ParseID = secrets.ParseID | ||
|
|
||
| var ( | ||
| ErrCredentialNotFound = secrets.ErrNotFound | ||
| ErrCollectionPathInvalid = errors.New("keychain collection path is invalid") | ||
| ) | ||
|
|
||
| const ( | ||
| // the docker label is the default prefix on all keys stored by the keychain | ||
| // e.g. io.docker.Secrets:encoded(realm/app/username) | ||
| dockerSecretsLabel = "io.docker.Secrets" | ||
| ) | ||
|
|
||
| type keychainStore[T Secret] struct { | ||
| keyPrefix string | ||
| factory func() T | ||
| } | ||
|
|
||
| var _ Store = &keychainStore[Secret]{} | ||
|
|
||
| type Factory[T secrets.Secret] func() T | ||
|
|
||
| type Options[T Secret] func(*keychainStore[T]) error | ||
|
|
||
| func WithKeyPrefix[T Secret](prefix string) Options[T] { | ||
| return func(ks *keychainStore[T]) error { | ||
| if prefix == "" { | ||
| return errors.New("the prefix cannot be empty") | ||
| } | ||
| ks.keyPrefix = prefix | ||
| return nil | ||
| } | ||
| } | ||
|
|
||
| // New creates a new keychain store | ||
| // | ||
| // collectionID is a singular noun indicating the collection name, e.g. "docker" | ||
| // factory is a function used to instantiate new secrets of type T. | ||
| func New[T Secret](factory Factory[T], opts ...Options[T]) (Store, error) { | ||
| k := &keychainStore[T]{ | ||
| factory: factory, | ||
| keyPrefix: dockerSecretsLabel, | ||
| } | ||
| for _, o := range opts { | ||
| if err := o(k); err != nil { | ||
| return nil, err | ||
| } | ||
| } | ||
| return k, nil | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| //go:build darwin && cgo | ||
|
|
||
| package keychain | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| kc "github.com/keybase/go-keychain" | ||
| ) | ||
|
|
||
| const ( | ||
| ServiceName = "DockerAuth" | ||
| ServiceGroup = "com.docker.auth" | ||
| ) | ||
|
|
||
| func getItem(id ID) kc.Item { | ||
| item := kc.NewItem() | ||
| item.SetSecClass(kc.SecClassGenericPassword) | ||
| item.SetService(ServiceName) | ||
| item.SetAccessGroup(ServiceGroup) | ||
| item.SetMatchLimit(kc.MatchLimitOne) | ||
| item.SetAccessible(kc.AccessibleAfterFirstUnlock) | ||
| item.SetReturnData(true) | ||
| item.SetReturnAttributes(true) | ||
| item.SetLabel(id.String()) | ||
| item.SetAccount(id.String()) | ||
| return item | ||
| } | ||
|
|
||
| func (k *keychainStore[T]) Erase(ctx context.Context, id ID) error { | ||
| return mapError(kc.DeleteItem(getItem(id))) | ||
| } | ||
|
|
||
| func (k *keychainStore[T]) Get(ctx context.Context, id ID) (Secret, error) { | ||
| results, err := kc.QueryItem(getItem(id)) | ||
| if err != nil { | ||
| return nil, mapError(err) | ||
| } | ||
| if len(results) == 0 { | ||
| return nil, ErrCredentialsNotFound | ||
| } | ||
|
|
||
| secret := k.factory() | ||
| if err := secret.Unmarshal(results[0].Data); err != nil { | ||
| return nil, err | ||
| } | ||
| return secret, nil | ||
| } | ||
|
|
||
| func (k *keychainStore[T]) GetAll(ctx context.Context) (map[ID]Secret, error) { | ||
| item := getItem(ID("")) | ||
| item.SetMatchLimit(kc.MatchLimitAll) | ||
| results, err := kc.QueryItem(getItem(ID(""))) | ||
| if err != nil { | ||
| return nil, mapError(err) | ||
| } | ||
| creds := make(map[ID]Secret, len(results)) | ||
| for _, result := range results { | ||
| secret := k.factory() | ||
| if err := secret.Unmarshal(result.Data); err != nil { | ||
| return nil, err | ||
| } | ||
| id := ID(result.Label) | ||
| creds[id] = secret | ||
| } | ||
| return creds, nil | ||
| } | ||
|
|
||
| func (k *keychainStore[T]) Store(ctx context.Context, id ID, secret Secret) error { | ||
| data, err := secret.Marshal() | ||
| if err != nil { | ||
| return err | ||
| } | ||
| item := getItem(id) | ||
| item.SetData(data) | ||
| return kc.AddItem(item) | ||
| } | ||
|
|
||
| func mapError(err error) error { | ||
| if err == nil { | ||
| return nil | ||
| } | ||
| switch err.Error() { | ||
| case kc.ErrorInteractionNotAllowed.Error(): | ||
| return ErrInteractionNotAllowed | ||
| case kc.ErrorItemNotFound.Error(): | ||
| return ErrCredentialsNotFound | ||
| case kc.ErrorAuthFailed.Error(): | ||
| return ErrAuthFailed | ||
| } | ||
| return err | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package keychain | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/docker/secrets-engine/pkg/secrets" | ||
| ) | ||
|
|
||
| var _ Store = &keychainStore[Secret]{} | ||
|
|
||
| // Erase implements secrets.Store. | ||
| func (k *keychainStore[T]) Erase(ctx context.Context, id secrets.ID) error { | ||
| panic("unimplemented") | ||
| } | ||
|
|
||
| // Get implements secrets.Store. | ||
| func (k *keychainStore[T]) Get(ctx context.Context, id secrets.ID) (secrets.Secret, error) { | ||
| panic("unimplemented") | ||
| } | ||
|
|
||
| // GetAll implements secrets.Store. | ||
| func (k *keychainStore[T]) GetAll(ctx context.Context) (map[secrets.ID]secrets.Secret, error) { | ||
| panic("unimplemented") | ||
| } | ||
|
|
||
| // Store implements secrets.Store. | ||
| func (k *keychainStore[T]) Store(ctx context.Context, id secrets.ID, secret secrets.Secret) error { | ||
| panic("unimplemented") | ||
| } |
Check failure
Code scanning / CodeQL
Clear-text logging of sensitive information High
Copilot Autofix
AI 9 months ago
To fix the issue, the sensitive information (password) should be excluded from the logs or obfuscated before being logged. The
Marshalmethod inMockCredentialshould be updated to ensure that sensitive data is not exposed. Additionally, the logging statement inkeychain/cmd/main.goshould be modified to avoid printing the password.Steps to fix:
Marshalmethod inkeychain/mocks/mock_credential.goto obfuscate the password (e.g., replace it with a placeholder like***).keychain/cmd/main.goto exclude sensitive data or use the updatedMarshalmethod that obfuscates the password.