- DefaultLoginHandler(binaryName) : handler de login Bitwarden prêt à l'emploi avec confirmation. Remplace les réimplémentations identiques dans chaque MCP. - StandardConfigTestHandler(opts) : handler de config test standard sans ManifestCheck. Accepte ConfigCheck, OpenStore, ConnectivityCheck et ExtraChecks. - ManifestCheck dans RunDoctor devient opt-in : inclus uniquement si ManifestDir est fourni (artefact de build, pas de contrainte runtime). - Supprime le handler mort CommandLogin dans bootstrap.Run, désormais remplacé par l'auto-disable et DefaultLoginHandler. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
103 lines
2.5 KiB
Go
103 lines
2.5 KiB
Go
package bootstrap
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"forge.lclr.dev/AI/mcp-framework/secretstore"
|
|
)
|
|
|
|
func withLoginBitwarden(t *testing.T, fn func(secretstore.BitwardenLoginOptions) (string, error)) {
|
|
t.Helper()
|
|
previous := loginBitwarden
|
|
loginBitwarden = fn
|
|
t.Cleanup(func() { loginBitwarden = previous })
|
|
}
|
|
|
|
func TestDefaultLoginHandlerPrintsConfirmation(t *testing.T) {
|
|
var stdout bytes.Buffer
|
|
|
|
withLoginBitwarden(t, func(opts secretstore.BitwardenLoginOptions) (string, error) {
|
|
if opts.ServiceName != "my-mcp" {
|
|
t.Fatalf("ServiceName = %q, want %q", opts.ServiceName, "my-mcp")
|
|
}
|
|
return "session-token", nil
|
|
})
|
|
|
|
handler := DefaultLoginHandler("my-mcp")
|
|
err := handler(context.Background(), Invocation{
|
|
Command: CommandLogin,
|
|
Stdout: &stdout,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("handler returned error: %v", err)
|
|
}
|
|
|
|
out := stdout.String()
|
|
if !strings.Contains(out, `"my-mcp"`) {
|
|
t.Fatalf("stdout = %q, want mention of binary name", out)
|
|
}
|
|
if !strings.Contains(out, "persistée") {
|
|
t.Fatalf("stdout = %q, want confirmation message", out)
|
|
}
|
|
}
|
|
|
|
func TestDefaultLoginHandlerPropagatesError(t *testing.T) {
|
|
var stdout bytes.Buffer
|
|
loginErr := errors.New("vault locked")
|
|
|
|
withLoginBitwarden(t, func(_ secretstore.BitwardenLoginOptions) (string, error) {
|
|
return "", loginErr
|
|
})
|
|
|
|
handler := DefaultLoginHandler("my-mcp")
|
|
err := handler(context.Background(), Invocation{
|
|
Command: CommandLogin,
|
|
Stdout: &stdout,
|
|
})
|
|
if !errors.Is(err, loginErr) {
|
|
t.Fatalf("err = %v, want %v", err, loginErr)
|
|
}
|
|
if stdout.Len() > 0 {
|
|
t.Fatalf("stdout should be empty on error, got %q", stdout.String())
|
|
}
|
|
}
|
|
|
|
func TestRunUsesDefaultLoginHandlerWhenHookSet(t *testing.T) {
|
|
var stdout bytes.Buffer
|
|
|
|
withLoginBitwarden(t, func(_ secretstore.BitwardenLoginOptions) (string, error) {
|
|
return "tok", nil
|
|
})
|
|
|
|
err := Run(context.Background(), Options{
|
|
BinaryName: "my-mcp",
|
|
Args: []string{"login"},
|
|
Stdout: &stdout,
|
|
Hooks: Hooks{
|
|
Login: DefaultLoginHandler("my-mcp"),
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Run error = %v", err)
|
|
}
|
|
if !strings.Contains(stdout.String(), "persistée") {
|
|
t.Fatalf("stdout = %q, want confirmation", stdout.String())
|
|
}
|
|
}
|
|
|
|
func TestRunLoginAutoHiddenWithoutHook(t *testing.T) {
|
|
var stdout bytes.Buffer
|
|
|
|
err := Run(context.Background(), Options{
|
|
BinaryName: "my-mcp",
|
|
Args: []string{"login"},
|
|
Stdout: &stdout,
|
|
})
|
|
if !errors.Is(err, ErrUnknownCommand) {
|
|
t.Fatalf("err = %v, want ErrUnknownCommand", err)
|
|
}
|
|
}
|