11package commands
22
33import (
4+ "encoding/json"
45 "errors"
56 "fmt"
7+ "slices"
68 "strings"
79
810 "github.com/spf13/cobra"
911
12+ "github.com/docker/mcp-gateway/cmd/docker-mcp/secret-management/formatting"
1013 "github.com/docker/mcp-gateway/cmd/docker-mcp/secret-management/secret"
14+ "github.com/docker/mcp-gateway/pkg/desktop"
1115 "github.com/docker/mcp-gateway/pkg/docker"
1216)
1317
1418const setSecretExample = `
1519### Use secrets for postgres password with default policy
1620
17- > docker mcp secret set POSTGRES_PASSWORD=my-secret-password
18- > docker run -d -l x-secret:POSTGRES_PASSWORD=/pwd.txt -e POSTGRES_PASSWORD_FILE=/pwd.txt -p 5432 postgres
21+ > docker mcp secret set postgres_password=my-secret-password
22+
23+ Inject the secret by querying by ID
24+ > docker run -d -e POSTGRES_PASSWORD=se://docker/mcp/generic/postgres_password -p 5432 postgres
25+
26+ Another way to inject secrets would be to use a pattern.
27+ > docker run -d -e POSTGRES_PASSWORD=se://**/postgres_password -p 5432 postgres
1928
2029### Pass the secret via STDIN
2130
@@ -26,66 +35,105 @@ const setSecretExample = `
2635func secretCommand (docker docker.Client ) * cobra.Command {
2736 cmd := & cobra.Command {
2837 Use : "secret" ,
29- Short : "Manage secrets" ,
38+ Short : "Manage secrets in the local OS Keychain " ,
3039 Example : strings .Trim (setSecretExample , "\n " ),
40+ PersistentPreRunE : func (cmd * cobra.Command , args []string ) error {
41+ err := desktop .CheckHasDockerPass (cmd .Context ())
42+ if err != nil {
43+ return err
44+ }
45+ return nil
46+ },
3147 }
3248 cmd .AddCommand (rmSecretCommand ())
3349 cmd .AddCommand (listSecretCommand ())
3450 cmd .AddCommand (setSecretCommand ())
35- cmd .AddCommand (exportSecretCommand (docker ))
3651 return cmd
3752}
3853
3954func rmSecretCommand () * cobra.Command {
40- var opts secret. RmOpts
55+ var all bool
4156 cmd := & cobra.Command {
4257 Use : "rm name1 name2 ..." ,
43- Short : "Remove secrets from Docker Desktop's secret store " ,
58+ Short : "Remove secrets from the OS Keychain " ,
4459 RunE : func (cmd * cobra.Command , args []string ) error {
45- if err := validateRmArgs (args , opts ); err != nil {
60+ if err := validateRmArgs (args , all ); err != nil {
4661 return err
4762 }
48- return secret .Remove (cmd .Context (), args , opts )
63+
64+ ids := slices .Clone (args )
65+ if all {
66+ var err error
67+ ids , err = secret .List (cmd .Context ())
68+ if err != nil {
69+ return err
70+ }
71+ }
72+
73+ var errs []error
74+ for _ , s := range ids {
75+ errs = append (errs , secret .DeleteSecret (cmd .Context (), s ))
76+ }
77+ return errors .Join (errs ... )
4978 },
5079 }
5180 flags := cmd .Flags ()
52- flags .BoolVar (& opts . All , "all" , false , "Remove all secrets" )
81+ flags .BoolVar (& all , "all" , false , "Remove all secrets" )
5382 return cmd
5483}
5584
56- func validateRmArgs (args []string , opts secret. RmOpts ) error {
57- if len (args ) == 0 && ! opts . All {
85+ func validateRmArgs (args []string , all bool ) error {
86+ if len (args ) == 0 && ! all {
5887 return errors .New ("either provide a secret name or use --all to remove all secrets" )
5988 }
6089 return nil
6190}
6291
6392func listSecretCommand () * cobra.Command {
64- var opts secret. ListOptions
93+ var outJSON bool
6594 cmd := & cobra.Command {
6695 Use : "ls" ,
67- Short : "List all secret names in Docker Desktop's secret store " ,
96+ Short : "List all secrets from the local OS Keychain as well as any active Secrets Engine provider " ,
6897 Args : cobra .NoArgs ,
6998 RunE : func (cmd * cobra.Command , _ []string ) error {
70- return secret .List (cmd .Context (), opts )
99+ // query the Secrets Engine instead to get all the secrets from
100+ // all active providers.
101+ l , err := secret .GetSecrets (cmd .Context ())
102+ if err != nil {
103+ return err
104+ }
105+ if outJSON {
106+ if len (l ) == 0 {
107+ l = []secret.Envelope {} // Guarantee empty list (instead of displaying null)
108+ }
109+ jsonData , err := json .MarshalIndent (l , "" , " " )
110+ if err != nil {
111+ return err
112+ }
113+ fmt .Println (string (jsonData ))
114+ return nil
115+ }
116+ var rows [][]string
117+ for _ , v := range l {
118+ rows = append (rows , []string {v .Id , v .Provider })
119+ }
120+ formatting .PrettyPrintTable (rows , []int {40 , 120 })
121+ return nil
71122 },
72123 }
73124 flags := cmd .Flags ()
74- flags .BoolVar (& opts . JSON , "json" , false , "Print as JSON." )
125+ flags .BoolVar (& outJSON , "json" , false , "Print as JSON." )
75126 return cmd
76127}
77128
78129func setSecretCommand () * cobra.Command {
79130 opts := & secret.SetOpts {}
80131 cmd := & cobra.Command {
81132 Use : "set key[=value]" ,
82- Short : "Set a secret in Docker Desktop's secret store " ,
133+ Short : "Set a secret in the local OS Keychain " ,
83134 Example : strings .Trim (setSecretExample , "\n " ),
84135 Args : cobra .ExactArgs (1 ),
85136 RunE : func (cmd * cobra.Command , args []string ) error {
86- if ! secret .IsValidProvider (opts .Provider ) {
87- return fmt .Errorf ("invalid provider: %s" , opts .Provider )
88- }
89137 var s secret.Secret
90138 if isNotImplicitReadFromStdinSyntax (args , * opts ) {
91139 va , err := secret .ParseArg (args [0 ], * opts )
@@ -105,30 +153,10 @@ func setSecretCommand() *cobra.Command {
105153 }
106154 flags := cmd .Flags ()
107155 flags .StringVar (& opts .Provider , "provider" , "" , "Supported: credstore, oauth/<provider>" )
156+ flags .MarkDeprecated ("provider" , "option will be ignored" )
108157 return cmd
109158}
110159
111160func isNotImplicitReadFromStdinSyntax (args []string , opts secret.SetOpts ) bool {
112- return strings .Contains (args [0 ], "=" ) || len (args ) > 1 || opts .Provider != ""
113- }
114-
115- func exportSecretCommand (docker docker.Client ) * cobra.Command {
116- return & cobra.Command {
117- Use : "export [server1] [server2] ..." ,
118- Short : "Export secrets for the specified servers" ,
119- Hidden : true ,
120- Args : cobra .MinimumNArgs (1 ),
121- RunE : func (cmd * cobra.Command , args []string ) error {
122- secrets , err := secret .Export (cmd .Context (), docker , args )
123- if err != nil {
124- return err
125- }
126-
127- for name , secret := range secrets {
128- _ , _ = fmt .Fprintf (cmd .OutOrStdout (), "%s=%s\n " , name , secret )
129- }
130-
131- return nil
132- },
133- }
161+ return strings .Contains (args [0 ], "=" ) || len (args ) > 1
134162}
0 commit comments