ba919305c2
Features: - Unified Go binary running Task Service, Agent Manager, and Orchestrator - SQLite persistence for boards, columns, and tasks - Docker-based agent execution with ACP message streaming - Augment Agent integration with session resumption support - RESTful API for all operations (port 8080) - In-memory event bus for service communication Architecture: - cmd/kandev: Single entry point for all services - internal/task: Task, board, and column management - internal/agent: Docker container lifecycle and ACP streaming - internal/orchestrator: Agent coordination and monitoring - internal/events: In-memory pub/sub event bus Documentation: - README.md: Project overview and quick start - docs/ARCHITECTURE.md: System architecture (current + planned) - docs/GETTING_STARTED.md: Development setup guide - docs/IMPLEMENTATION_PLAN.md: Original microservices plan - backend/NEXT_STEPS.md: Development roadmap
136 lines
3.0 KiB
Go
136 lines
3.0 KiB
Go
package credentials
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// knownAPIKeyPatterns contains patterns for known API key environment variables
|
|
var knownAPIKeyPatterns = []string{
|
|
"ANTHROPIC_API_KEY",
|
|
"OPENAI_API_KEY",
|
|
"GEMINI_API_KEY",
|
|
"GOOGLE_API_KEY",
|
|
"AZURE_OPENAI_API_KEY",
|
|
"COHERE_API_KEY",
|
|
"HUGGINGFACE_API_KEY",
|
|
"MISTRAL_API_KEY",
|
|
"TOGETHER_API_KEY",
|
|
"REPLICATE_API_TOKEN",
|
|
"AWS_ACCESS_KEY_ID",
|
|
"AWS_SECRET_ACCESS_KEY",
|
|
"GCP_SERVICE_ACCOUNT_KEY",
|
|
"GITHUB_TOKEN",
|
|
"GITLAB_TOKEN",
|
|
"BITBUCKET_TOKEN",
|
|
"NPM_TOKEN",
|
|
"DOCKER_PASSWORD",
|
|
"DOCKER_TOKEN",
|
|
}
|
|
|
|
// EnvProvider provides credentials from environment variables
|
|
type EnvProvider struct {
|
|
prefix string // Optional prefix filter (e.g., "KANDEV_")
|
|
}
|
|
|
|
// NewEnvProvider creates a new environment provider
|
|
func NewEnvProvider(prefix string) *EnvProvider {
|
|
return &EnvProvider{
|
|
prefix: prefix,
|
|
}
|
|
}
|
|
|
|
// Name returns the provider name
|
|
func (p *EnvProvider) Name() string {
|
|
return "environment"
|
|
}
|
|
|
|
// GetCredential retrieves a credential from environment variables
|
|
func (p *EnvProvider) GetCredential(ctx context.Context, key string) (*Credential, error) {
|
|
// First try exact key
|
|
value := os.Getenv(key)
|
|
if value != "" {
|
|
return &Credential{
|
|
Key: key,
|
|
Value: value,
|
|
Source: "environment",
|
|
}, nil
|
|
}
|
|
|
|
// Try with prefix
|
|
if p.prefix != "" {
|
|
prefixedKey := p.prefix + key
|
|
value = os.Getenv(prefixedKey)
|
|
if value != "" {
|
|
return &Credential{
|
|
Key: key,
|
|
Value: value,
|
|
Source: "environment",
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("credential not found: %s", key)
|
|
}
|
|
|
|
// ListAvailable returns list of available credential keys from environment
|
|
func (p *EnvProvider) ListAvailable(ctx context.Context) ([]string, error) {
|
|
available := make([]string, 0)
|
|
|
|
// Check known API key patterns
|
|
for _, pattern := range knownAPIKeyPatterns {
|
|
// Check exact match
|
|
if os.Getenv(pattern) != "" {
|
|
available = append(available, pattern)
|
|
continue
|
|
}
|
|
|
|
// Check with prefix
|
|
if p.prefix != "" && os.Getenv(p.prefix+pattern) != "" {
|
|
available = append(available, pattern)
|
|
}
|
|
}
|
|
|
|
// Also scan environment for any variables ending in common patterns
|
|
for _, env := range os.Environ() {
|
|
parts := strings.SplitN(env, "=", 2)
|
|
if len(parts) != 2 || parts[1] == "" {
|
|
continue
|
|
}
|
|
|
|
key := parts[0]
|
|
|
|
// Skip if already in list
|
|
found := false
|
|
for _, existing := range available {
|
|
if existing == key {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if found {
|
|
continue
|
|
}
|
|
|
|
// Check for API key patterns in environment variable names
|
|
lowerKey := strings.ToLower(key)
|
|
if strings.Contains(lowerKey, "api_key") ||
|
|
strings.Contains(lowerKey, "apikey") ||
|
|
strings.Contains(lowerKey, "api-key") ||
|
|
strings.Contains(lowerKey, "_token") ||
|
|
strings.Contains(lowerKey, "_secret") {
|
|
|
|
// Strip prefix if present
|
|
if p.prefix != "" && strings.HasPrefix(key, p.prefix) {
|
|
key = strings.TrimPrefix(key, p.prefix)
|
|
}
|
|
available = append(available, key)
|
|
}
|
|
}
|
|
|
|
return available, nil
|
|
}
|
|
|