|
1 | 1 | package secret |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bufio" |
| 5 | + "bytes" |
4 | 6 | "context" |
5 | | - "io" |
6 | 7 | "os/exec" |
7 | | - "strings" |
8 | | - |
9 | | - "github.com/docker/docker-credential-helpers/client" |
10 | | - "github.com/docker/docker-credential-helpers/credentials" |
11 | | - |
12 | | - "github.com/docker/mcp-gateway/pkg/desktop" |
13 | 8 | ) |
14 | 9 |
|
15 | | -type CredStoreProvider struct { |
16 | | - credentialHelper credentials.Helper |
| 10 | +type CredStoreProvider struct{} |
| 11 | + |
| 12 | +func cmd(ctx context.Context, args ...string) *exec.Cmd { |
| 13 | + return exec.CommandContext(ctx, "docker", append([]string{"pass"}, args...)...) |
17 | 14 | } |
18 | 15 |
|
19 | 16 | func NewCredStoreProvider() *CredStoreProvider { |
20 | | - return &CredStoreProvider{credentialHelper: GetHelper()} |
| 17 | + return &CredStoreProvider{} |
21 | 18 | } |
22 | 19 |
|
23 | 20 | func getSecretKey(secretName string) string { |
24 | | - return "sm_" + secretName |
| 21 | + return "docker/mcp/" + secretName |
25 | 22 | } |
26 | 23 |
|
27 | | -func (store *CredStoreProvider) GetSecret(id string) (string, error) { |
28 | | - _, val, err := store.credentialHelper.Get(getSecretKey(id)) |
| 24 | +func (store *CredStoreProvider) List(ctx context.Context) ([]string, error) { |
| 25 | + c := cmd(ctx, "ls") |
| 26 | + out, err := c.Output() |
29 | 27 | if err != nil { |
30 | | - return "", err |
31 | | - } |
32 | | - return val, nil |
33 | | -} |
34 | | - |
35 | | -func (store *CredStoreProvider) SetSecret(id string, value string) error { |
36 | | - return store.credentialHelper.Add(&credentials.Credentials{ |
37 | | - ServerURL: getSecretKey(id), |
38 | | - Username: "mcp", |
39 | | - Secret: value, |
40 | | - }) |
41 | | -} |
42 | | - |
43 | | -func (store *CredStoreProvider) DeleteSecret(id string) error { |
44 | | - return store.credentialHelper.Delete(getSecretKey(id)) |
45 | | -} |
46 | | - |
47 | | -func GetHelper() credentials.Helper { |
48 | | - credentialHelperPath := desktop.Paths().CredentialHelperPath() |
49 | | - return Helper{ |
50 | | - program: newShellProgramFunc(credentialHelperPath), |
51 | | - } |
52 | | -} |
53 | | - |
54 | | -// newShellProgramFunc creates programs that are executed in a Shell. |
55 | | -func newShellProgramFunc(name string) client.ProgramFunc { |
56 | | - return func(args ...string) client.Program { |
57 | | - return &shell{cmd: exec.CommandContext(context.Background(), name, args...)} |
| 28 | + return nil, err |
| 29 | + } |
| 30 | + scanner := bufio.NewScanner(bytes.NewReader(out)) |
| 31 | + var secrets []string |
| 32 | + for scanner.Scan() { |
| 33 | + secret := scanner.Text() |
| 34 | + if len(secret) == 0 { |
| 35 | + continue |
| 36 | + } |
| 37 | + secrets = append(secrets, secret) |
58 | 38 | } |
| 39 | + return secrets, nil |
59 | 40 | } |
60 | 41 |
|
61 | | -// shell invokes shell commands to talk with a remote credentials-helper. |
62 | | -type shell struct { |
63 | | - cmd *exec.Cmd |
64 | | -} |
65 | | - |
66 | | -// Output returns responses from the remote credentials-helper. |
67 | | -func (s *shell) Output() ([]byte, error) { |
68 | | - return s.cmd.Output() |
69 | | -} |
70 | | - |
71 | | -// Input sets the input to send to a remote credentials-helper. |
72 | | -func (s *shell) Input(in io.Reader) { |
73 | | - s.cmd.Stdin = in |
74 | | -} |
75 | | - |
76 | | -// Helper wraps credential helper program. |
77 | | -type Helper struct { |
78 | | - // name string |
79 | | - program client.ProgramFunc |
80 | | -} |
81 | | - |
82 | | -func (h Helper) List() (map[string]string, error) { |
83 | | - return map[string]string{}, nil |
84 | | -} |
85 | | - |
86 | | -// Add stores new credentials. |
87 | | -func (h Helper) Add(creds *credentials.Credentials) error { |
88 | | - username, secret, err := h.Get(creds.ServerURL) |
89 | | - if err != nil && !credentials.IsErrCredentialsNotFound(err) && !isErrDecryption(err) { |
90 | | - return err |
91 | | - } |
92 | | - if username == creds.Username && secret == creds.Secret { |
93 | | - return nil |
94 | | - } |
95 | | - if err := client.Store(h.program, creds); err != nil { |
| 42 | +func (store *CredStoreProvider) SetSecret(ctx context.Context, id string, value string) error { |
| 43 | + c := cmd(ctx, "set", getSecretKey(id)) |
| 44 | + in, err := c.StdinPipe() |
| 45 | + if err != nil { |
96 | 46 | return err |
97 | 47 | } |
98 | | - return nil |
99 | | -} |
100 | | - |
101 | | -// Delete removes credentials. |
102 | | -func (h Helper) Delete(serverURL string) error { |
103 | | - if _, _, err := h.Get(serverURL); err != nil { |
104 | | - if credentials.IsErrCredentialsNotFound(err) { |
105 | | - return nil |
106 | | - } |
| 48 | + if err := c.Start(); err != nil { |
107 | 49 | return err |
108 | 50 | } |
109 | | - return client.Erase(h.program, serverURL) |
110 | | -} |
111 | | - |
112 | | -// Get returns the username and secret to use for a given registry server URL. |
113 | | -func (h Helper) Get(serverURL string) (string, string, error) { |
114 | | - creds, err := client.Get(h.program, serverURL) |
| 51 | + _, err = in.Write([]byte(value)) |
115 | 52 | if err != nil { |
116 | | - return "", "", err |
| 53 | + return err |
117 | 54 | } |
118 | | - return creds.Username, creds.Secret, nil |
| 55 | + return c.Wait() |
119 | 56 | } |
120 | 57 |
|
121 | | -func isErrDecryption(err error) bool { |
122 | | - return err != nil && strings.Contains(err.Error(), "gpg: decryption failed: No secret key") |
| 58 | +func (store *CredStoreProvider) DeleteSecret(ctx context.Context, id string) error { |
| 59 | + c := cmd(ctx, "rm", getSecretKey(id)) |
| 60 | + return c.Run() |
123 | 61 | } |
124 | | - |
125 | | -var _ credentials.Helper = Helper{} |
0 commit comments