Adding a Provider
Guide for implementing a new SecretProvider backend.
1. Implement the Interface
Section titled “1. Implement the Interface”Create a new package under internal/provider/<name>/:
internal/provider/gcp/ gcp.go -- Provider implementation auth.go -- Credential helpers (if needed) errors.go -- Error translation (if needed)Implement the SecretProvider interface from internal/provider/provider.go:
package gcp
import ( "context" "github.com/n24q02m/skret/internal/config" "github.com/n24q02m/skret/internal/provider")
type Provider struct { // Client, config, etc.}
func New(cfg *config.ResolvedConfig) (*Provider, error) { // Initialize the provider using cfg.Path, cfg.Region, etc. return &Provider{}, nil}
func (p *Provider) Name() string { return "gcp" }func (p *Provider) Capabilities() provider.Capabilities { /* ... */ }func (p *Provider) Get(ctx context.Context, key string) (*provider.Secret, error) { /* ... */ }func (p *Provider) List(ctx context.Context, prefix string) ([]*provider.Secret, error) { /* ... */ }func (p *Provider) Set(ctx context.Context, key, value string, meta provider.SecretMeta) error { /* ... */ }func (p *Provider) Delete(ctx context.Context, key string) error { /* ... */ }func (p *Provider) GetHistory(ctx context.Context, key string) ([]*provider.Secret, error) { /* ... */ }func (p *Provider) Rollback(ctx context.Context, key string, version int64) error { /* ... */ }func (p *Provider) Close() error { /* ... */ }2. Register in the Registry
Section titled “2. Register in the Registry”Add the provider factory in two places:
internal/cli/root.go (CLI usage):
import "github.com/n24q02m/skret/internal/provider/gcp"
reg.Register("gcp", func(c *config.ResolvedConfig) (provider.SecretProvider, error) { return gcp.New(c)})pkg/skret/client.go (library usage):
import "github.com/n24q02m/skret/internal/provider/gcp"
reg.Register("gcp", func(c *config.ResolvedConfig) (provider.SecretProvider, error) { return gcp.New(c)})3. Add Config Validation
Section titled “3. Add Config Validation”Update internal/config/schema.go to validate provider-specific fields:
case "gcp": if e.Path == "" { return fmt.Errorf("config: environment %q: path is required for gcp provider", name) }Add any new fields to the Environment struct if the provider needs them.
4. Write Tests
Section titled “4. Write Tests”Unit tests
Section titled “Unit tests”Test each method with mocked SDK calls:
func TestGet(t *testing.T) { /* ... */ }func TestList(t *testing.T) { /* ... */ }func TestSet(t *testing.T) { /* ... */ }func TestDelete(t *testing.T) { /* ... */ }func TestGetHistory(t *testing.T) { /* ... */ }Integration tests
Section titled “Integration tests”Env-gated tests against the real service:
func TestGCPIntegration(t *testing.T) { if os.Getenv("SKRET_E2E_GCP") == "" { t.Skip("SKRET_E2E_GCP not set") } // Test against real GCP Secret Manager}Target coverage: >=95% on the provider package.
5. Translate Errors
Section titled “5. Translate Errors”Map provider-specific errors to skret’s standard error codes:
import "github.com/n24q02m/skret/internal/provider"
// Map GCP "NOT_FOUND" to provider.ErrNotFoundif status.Code(err) == codes.NotFound { return nil, provider.ErrNotFound}6. Document
Section titled “6. Document”Create docs/providers/<name>.md with:
- Prerequisites and setup
- IAM / permission requirements
.skret.yamlconfiguration example- Provider-specific quotas and limits
- Capabilities table (read, write, versioning, tagging, etc.)
7. Update Config Documentation
Section titled “7. Update Config Documentation”Add the new provider to docs/reference/config-schema.md and docs/guide/configuration.md.
Checklist
Section titled “Checklist”-
SecretProviderinterface fully implemented - Factory registered in CLI and library
- Config validation for provider-specific fields
- Unit tests (>=95% coverage)
- Integration tests (env-gated)
- Error translation to standard codes
- Provider documentation page
- Config docs updated