-
Notifications
You must be signed in to change notification settings - Fork 164
Remove JFS references + secrets engine injection #247
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
base: release/4.54
Are you sure you want to change the base?
Changes from 13 commits
bc38cfe
9154242
49d560d
51295fb
5854556
1a546dd
d2602e1
527a07f
d888b86
baae072
e890cf7
312e404
c90a282
724f259
6cd8aa8
5939775
261cd00
5b06909
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 |
|---|---|---|
| @@ -1,13 +1,9 @@ | ||
| package backup | ||
|
|
||
| import "github.com/docker/mcp-gateway/pkg/desktop" | ||
|
|
||
| type Backup struct { | ||
| Config string `json:"config"` | ||
| Registry string `json:"registry"` | ||
| Catalog string `json:"catalog"` | ||
| CatalogFiles map[string]string `json:"catalogFiles"` | ||
| Tools string `json:"tools"` | ||
| Secrets []desktop.Secret `json:"secrets"` | ||
| Policy string `json:"policy"` | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,91 +1,149 @@ | ||
| package commands | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "errors" | ||
| "fmt" | ||
| "slices" | ||
| "strings" | ||
|
|
||
| "github.com/spf13/cobra" | ||
|
|
||
| "github.com/docker/mcp-gateway/cmd/docker-mcp/secret-management/formatting" | ||
| "github.com/docker/mcp-gateway/cmd/docker-mcp/secret-management/secret" | ||
| "github.com/docker/mcp-gateway/pkg/docker" | ||
| "github.com/docker/mcp-gateway/pkg/desktop" | ||
| ) | ||
|
|
||
| const setSecretExample = ` | ||
| ### Use secrets for postgres password with default policy | ||
|
|
||
| > docker mcp secret set POSTGRES_PASSWORD=my-secret-password | ||
| > docker run -d -l x-secret:POSTGRES_PASSWORD=/pwd.txt -e POSTGRES_PASSWORD_FILE=/pwd.txt -p 5432 postgres | ||
| > docker mcp secret set postgres_password=my-secret-password | ||
|
|
||
| Inject the secret by querying by ID | ||
| > docker run -d -e POSTGRES_PASSWORD=se://docker/mcp/generic/postgres_password -p 5432 postgres | ||
|
|
||
| Another way to inject secrets would be to use a pattern. | ||
| > docker run -d -e POSTGRES_PASSWORD=se://**/postgres_password -p 5432 postgres | ||
|
|
||
| ### Pass the secret via STDIN | ||
|
|
||
| > echo my-secret-password > pwd.txt | ||
| > cat pwd.txt | docker mcp secret set POSTGRES_PASSWORD | ||
| ` | ||
|
|
||
| func secretCommand(docker docker.Client) *cobra.Command { | ||
| func secretCommand() *cobra.Command { | ||
| cmd := &cobra.Command{ | ||
| Use: "secret", | ||
| Short: "Manage secrets", | ||
| Short: "Manage secrets in the local OS Keychain", | ||
| Example: strings.Trim(setSecretExample, "\n"), | ||
| PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { | ||
|
||
| err := desktop.CheckHasDockerPass(cmd.Context()) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| return nil | ||
| }, | ||
| } | ||
| cmd.AddCommand(rmSecretCommand()) | ||
| cmd.AddCommand(listSecretCommand()) | ||
| cmd.AddCommand(setSecretCommand()) | ||
| cmd.AddCommand(exportSecretCommand(docker)) | ||
| return cmd | ||
| } | ||
|
|
||
| func rmSecretCommand() *cobra.Command { | ||
| var opts secret.RmOpts | ||
| var all bool | ||
| cmd := &cobra.Command{ | ||
| Use: "rm name1 name2 ...", | ||
| Short: "Remove secrets from Docker Desktop's secret store", | ||
| Short: "Remove secrets from the local OS Keychain", | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| if err := validateRmArgs(args, opts); err != nil { | ||
| if err := validateRmArgs(args, all); err != nil { | ||
| return err | ||
| } | ||
| return secret.Remove(cmd.Context(), args, opts) | ||
|
|
||
| ids := slices.Clone(args) | ||
| if all { | ||
| var err error | ||
| ids, err = secret.List(cmd.Context()) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| var errs []error | ||
| for _, s := range ids { | ||
| errs = append(errs, secret.DeleteSecret(cmd.Context(), s)) | ||
| } | ||
| return errors.Join(errs...) | ||
| }, | ||
| } | ||
| flags := cmd.Flags() | ||
| flags.BoolVar(&opts.All, "all", false, "Remove all secrets") | ||
| flags.BoolVar(&all, "all", false, "Remove all secrets") | ||
| return cmd | ||
| } | ||
|
|
||
| func validateRmArgs(args []string, opts secret.RmOpts) error { | ||
| if len(args) == 0 && !opts.All { | ||
| func validateRmArgs(args []string, all bool) error { | ||
| if len(args) == 0 && !all { | ||
| return errors.New("either provide a secret name or use --all to remove all secrets") | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func listSecretCommand() *cobra.Command { | ||
| var opts secret.ListOptions | ||
| var outJSON bool | ||
| cmd := &cobra.Command{ | ||
| Use: "ls", | ||
| Short: "List all secret names in Docker Desktop's secret store", | ||
| Short: "List all secrets from the local OS Keychain as well as any active Secrets Engine provider", | ||
| Args: cobra.NoArgs, | ||
| RunE: func(cmd *cobra.Command, _ []string) error { | ||
| return secret.List(cmd.Context(), opts) | ||
| // query the Secrets Engine instead to get all the secrets from | ||
| // all active providers. | ||
| l, err := secret.GetSecrets(cmd.Context()) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if outJSON { | ||
| type secretListItem struct { | ||
| Name string `json:"name"` | ||
| Provider string `json:"provider,omitempty"` | ||
| } | ||
| output := make([]secretListItem, 0, len(l)) | ||
| for _, env := range l { | ||
| output = append(output, secretListItem{ | ||
| Name: secret.StripNamespace(env.ID), | ||
| Provider: env.Provider, | ||
| }) | ||
| } | ||
| if len(output) == 0 { | ||
| output = []secretListItem{} // Guarantee empty list (instead of displaying null) | ||
| } | ||
| jsonData, err := json.MarshalIndent(output, "", " ") | ||
| if err != nil { | ||
| return err | ||
| } | ||
| fmt.Println(string(jsonData)) | ||
| return nil | ||
| } | ||
| var rows [][]string | ||
| for _, v := range l { | ||
| rows = append(rows, []string{v.ID, v.Provider}) | ||
| } | ||
| formatting.PrettyPrintTable(rows, []int{40, 120}) | ||
| return nil | ||
| }, | ||
| } | ||
| flags := cmd.Flags() | ||
| flags.BoolVar(&opts.JSON, "json", false, "Print as JSON.") | ||
| flags.BoolVar(&outJSON, "json", false, "Print as JSON.") | ||
| return cmd | ||
| } | ||
|
|
||
| func setSecretCommand() *cobra.Command { | ||
| opts := &secret.SetOpts{} | ||
| cmd := &cobra.Command{ | ||
| Use: "set key[=value]", | ||
| Short: "Set a secret in Docker Desktop's secret store", | ||
| Short: "Set a secret in the local OS Keychain", | ||
| Example: strings.Trim(setSecretExample, "\n"), | ||
| Args: cobra.ExactArgs(1), | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| if !secret.IsValidProvider(opts.Provider) { | ||
| return fmt.Errorf("invalid provider: %s", opts.Provider) | ||
| } | ||
| var s secret.Secret | ||
| if isNotImplicitReadFromStdinSyntax(args, *opts) { | ||
| va, err := secret.ParseArg(args[0], *opts) | ||
|
|
@@ -105,30 +163,10 @@ func setSecretCommand() *cobra.Command { | |
| } | ||
| flags := cmd.Flags() | ||
| flags.StringVar(&opts.Provider, "provider", "", "Supported: credstore, oauth/<provider>") | ||
| _ = flags.MarkDeprecated("provider", "all secrets now stored via docker pass in OS Keychain") | ||
| return cmd | ||
| } | ||
|
|
||
| func isNotImplicitReadFromStdinSyntax(args []string, opts secret.SetOpts) bool { | ||
| return strings.Contains(args[0], "=") || len(args) > 1 || opts.Provider != "" | ||
| } | ||
|
|
||
| func exportSecretCommand(docker docker.Client) *cobra.Command { | ||
| return &cobra.Command{ | ||
| Use: "export [server1] [server2] ...", | ||
| Short: "Export secrets for the specified servers", | ||
| Hidden: true, | ||
| Args: cobra.MinimumNArgs(1), | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| secrets, err := secret.Export(cmd.Context(), docker, args) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| for name, secret := range secrets { | ||
| _, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s=%s\n", name, secret) | ||
| } | ||
|
|
||
| return nil | ||
| }, | ||
| } | ||
| func isNotImplicitReadFromStdinSyntax(args []string, _ secret.SetOpts) bool { | ||
| return strings.Contains(args[0], "=") || len(args) > 1 | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get rid of the entire backup package. It's superseded by profiles and secrets and now that the policy dump and set commands are gone, can we verify whether this entire package can be removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, I think we are safe to remove it. Could be another PR though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good, will address in a follow-up PR