package secretstore import ( "errors" "os" "path/filepath" "strings" "testing" "github.com/99designs/keyring" "forge.lclr.dev/AI/mcp-framework/manifest" ) func TestOpenFromManifestUsesPolicyFromManifest(t *testing.T) { var gotStartDir string store, err := OpenFromManifest(OpenFromManifestOptions{ ServiceName: "email-mcp", LookupEnv: func(name string) (string, bool) { if name == "EMAIL_TOKEN" { return "from-env", true } return "", false }, ExecutableResolver: func() (string, error) { return filepath.Join(string(filepath.Separator), "opt", "email-mcp", "bin", "email-mcp"), nil }, ManifestLoader: func(startDir string) (manifest.File, string, error) { gotStartDir = startDir return manifest.File{ SecretStore: manifest.SecretStore{BackendPolicy: string(BackendEnvOnly)}, }, filepath.Join(startDir, manifest.DefaultFile), nil }, }) if err != nil { t.Fatalf("OpenFromManifest returned error: %v", err) } wantDir := filepath.Join(string(filepath.Separator), "opt", "email-mcp", "bin") if gotStartDir != wantDir { t.Fatalf("manifest loader startDir = %q, want %q", gotStartDir, wantDir) } value, err := store.GetSecret("EMAIL_TOKEN") if err != nil { t.Fatalf("GetSecret returned error: %v", err) } if value != "from-env" { t.Fatalf("GetSecret = %q, want from-env", value) } } func TestOpenFromManifestFallsBackToAutoWhenManifestIsMissing(t *testing.T) { withKeyringHooks(t, nil, func(cfg keyring.Config) (keyring.Keyring, error) { t.Fatal("unexpected keyring open call") return nil, nil }) store, err := OpenFromManifest(OpenFromManifestOptions{ ServiceName: "email-mcp", LookupEnv: func(name string) (string, bool) { if name == "EMAIL_TOKEN" { return "env-token", true } return "", false }, ExecutableResolver: func() (string, error) { return filepath.Join(string(filepath.Separator), "opt", "email-mcp", "bin", "email-mcp"), nil }, ManifestLoader: func(string) (manifest.File, string, error) { return manifest.File{}, "", os.ErrNotExist }, }) if err != nil { t.Fatalf("OpenFromManifest returned error: %v", err) } value, err := store.GetSecret("EMAIL_TOKEN") if err != nil { t.Fatalf("GetSecret returned error: %v", err) } if value != "env-token" { t.Fatalf("GetSecret = %q, want env-token", value) } } func TestOpenFromManifestReturnsExplicitErrorForInvalidManifestPolicy(t *testing.T) { _, err := OpenFromManifest(OpenFromManifestOptions{ ServiceName: "email-mcp", ExecutableResolver: func() (string, error) { return filepath.Join(string(filepath.Separator), "opt", "email-mcp", "bin", "email-mcp"), nil }, ManifestLoader: func(startDir string) (manifest.File, string, error) { return manifest.File{ SecretStore: manifest.SecretStore{BackendPolicy: "totally-invalid"}, }, filepath.Join(startDir, manifest.DefaultFile), nil }, }) if err == nil { t.Fatal("expected error") } if !errors.Is(err, ErrInvalidBackendPolicy) { t.Fatalf("error = %v, want ErrInvalidBackendPolicy", err) } if !strings.Contains(err.Error(), "secret_store.backend_policy") { t.Fatalf("error = %v, want manifest policy context", err) } if !strings.Contains(err.Error(), manifest.DefaultFile) { t.Fatalf("error = %v, want manifest path", err) } } func TestResolveManifestPolicyPreservesBitwardenCacheDisable(t *testing.T) { cacheDisabled := false resolution, err := resolveManifestPolicy(OpenFromManifestOptions{ ServiceName: "email-mcp", ExecutableResolver: func() (string, error) { return filepath.Join(string(filepath.Separator), "opt", "email-mcp", "bin", "email-mcp"), nil }, ManifestLoader: func(startDir string) (manifest.File, string, error) { return manifest.File{ SecretStore: manifest.SecretStore{ BackendPolicy: string(BackendBitwardenCLI), BitwardenCache: &cacheDisabled, }, }, filepath.Join(startDir, manifest.DefaultFile), nil }, }) if err != nil { t.Fatalf("resolveManifestPolicy returned error: %v", err) } if resolution.BitwardenCache { t.Fatal("resolution BitwardenCache = true, want false") } if resolution.Policy != BackendBitwardenCLI { t.Fatalf("resolution policy = %q, want %q", resolution.Policy, BackendBitwardenCLI) } } func TestOpenFromManifestAppliesBitwardenCacheDisable(t *testing.T) { withBitwardenSession(t) fakeCLI := newFakeBitwardenCLI("bw") fakeCLI.itemsByID["item-1"] = fakeBitwardenItem{ ID: "item-1", Name: "email-mcp/api-token", Secret: "secret-v1", MarkerService: "email-mcp", MarkerSecretName: "api-token", } withBitwardenRunner(t, fakeCLI.run) cacheDisabled := false store, err := OpenFromManifest(OpenFromManifestOptions{ ServiceName: "email-mcp", ExecutableResolver: func() (string, error) { return filepath.Join(string(filepath.Separator), "opt", "email-mcp", "bin", "email-mcp"), nil }, ManifestLoader: func(startDir string) (manifest.File, string, error) { return manifest.File{ SecretStore: manifest.SecretStore{ BackendPolicy: string(BackendBitwardenCLI), BitwardenCache: &cacheDisabled, }, }, filepath.Join(startDir, manifest.DefaultFile), nil }, }) if err != nil { t.Fatalf("OpenFromManifest returned error: %v", err) } for i := 0; i < 2; i++ { value, err := store.GetSecret("api-token") if err != nil { t.Fatalf("GetSecret #%d returned error: %v", i+1, err) } if value != "secret-v1" { t.Fatalf("GetSecret #%d = %q, want secret-v1", i+1, value) } } if fakeCLI.getItemCalls != 2 { t.Fatalf("bw get item count = %d, want 2 when manifest disables cache", fakeCLI.getItemCalls) } } func TestOpenFromManifestReturnsExecutableResolutionError(t *testing.T) { execErr := errors.New("boom") _, err := OpenFromManifest(OpenFromManifestOptions{ ExecutableResolver: func() (string, error) { return "", execErr }, }) if !errors.Is(err, execErr) { t.Fatalf("error = %v, want wrapped executable resolver error", err) } } func TestOpenFromManifestReturnsManifestLoaderError(t *testing.T) { loadErr := errors.New("cannot parse manifest") _, err := OpenFromManifest(OpenFromManifestOptions{ ExecutableResolver: func() (string, error) { return filepath.Join(string(filepath.Separator), "opt", "email-mcp", "bin", "email-mcp"), nil }, ManifestLoader: func(string) (manifest.File, string, error) { return manifest.File{}, "", loadErr }, }) if !errors.Is(err, loadErr) { t.Fatalf("error = %v, want wrapped manifest loader error", err) } }