Files
bzzz/pkg/config/config.go
anthonyrawlins d96c931a29 Resolve import cycles and migrate to chorus.services module path
This comprehensive refactoring addresses critical architectural issues:

IMPORT CYCLE RESOLUTION:
• pkg/crypto ↔ pkg/slurp/roles: Created pkg/security/access_levels.go
• pkg/ucxl → pkg/dht: Created pkg/storage/interfaces.go
• pkg/slurp/leader → pkg/election → pkg/slurp/storage: Moved types to pkg/election/interfaces.go

MODULE PATH MIGRATION:
• Changed from github.com/anthonyrawlins/bzzz to chorus.services/bzzz
• Updated all import statements across 115+ files
• Maintains compatibility while removing personal GitHub account dependency

TYPE SYSTEM IMPROVEMENTS:
• Resolved duplicate type declarations in crypto package
• Added missing type definitions (RoleStatus, TimeRestrictions, KeyStatus, KeyRotationResult)
• Proper interface segregation to prevent future cycles

ARCHITECTURAL BENEFITS:
• Build now progresses past structural issues to normal dependency resolution
• Cleaner separation of concerns between packages
• Eliminates circular dependencies that prevented compilation
• Establishes foundation for scalable codebase growth

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-17 10:04:25 +10:00

553 lines
19 KiB
Go

package config
import (
"fmt"
"io/ioutil"
"os"
"strings"
"time"
"gopkg.in/yaml.v2"
)
// SecurityConfig holds cluster security and election configuration
type SecurityConfig struct {
// Admin key sharing
AdminKeyShares ShamirShare `yaml:"admin_key_shares" json:"admin_key_shares"`
ElectionConfig ElectionConfig `yaml:"election_config" json:"election_config"`
// Key management
KeyRotationDays int `yaml:"key_rotation_days,omitempty" json:"key_rotation_days,omitempty"`
AuditLogging bool `yaml:"audit_logging" json:"audit_logging"`
AuditPath string `yaml:"audit_path,omitempty" json:"audit_path,omitempty"`
}
// Config represents the complete configuration for a Bzzz agent
type Config struct {
WHOOSHAPI WHOOSHAPIConfig `yaml:"hive_api"`
Agent AgentConfig `yaml:"agent"`
GitHub GitHubConfig `yaml:"github"`
P2P P2PConfig `yaml:"p2p"`
Logging LoggingConfig `yaml:"logging"`
HCFS HCFSConfig `yaml:"hcfs"`
Slurp SlurpConfig `yaml:"slurp"`
V2 V2Config `yaml:"v2"` // BZZZ v2 protocol settings
UCXL UCXLConfig `yaml:"ucxl"` // UCXL protocol settings
Security SecurityConfig `yaml:"security"` // Cluster security and elections
}
// WHOOSHAPIConfig holds WHOOSH system integration settings
type WHOOSHAPIConfig struct {
BaseURL string `yaml:"base_url"`
APIKey string `yaml:"api_key"`
Timeout time.Duration `yaml:"timeout"`
RetryCount int `yaml:"retry_count"`
}
// CollaborationConfig holds role-based collaboration settings
type CollaborationConfig struct {
PreferredMessageTypes []string `yaml:"preferred_message_types"`
AutoSubscribeToRoles []string `yaml:"auto_subscribe_to_roles"`
AutoSubscribeToExpertise []string `yaml:"auto_subscribe_to_expertise"`
ResponseTimeoutSeconds int `yaml:"response_timeout_seconds"`
MaxCollaborationDepth int `yaml:"max_collaboration_depth"`
EscalationThreshold int `yaml:"escalation_threshold"`
CustomTopicSubscriptions []string `yaml:"custom_topic_subscriptions"`
}
// AgentConfig holds agent-specific configuration
type AgentConfig struct {
ID string `yaml:"id"`
Capabilities []string `yaml:"capabilities"`
PollInterval time.Duration `yaml:"poll_interval"`
MaxTasks int `yaml:"max_tasks"`
Models []string `yaml:"models"`
Specialization string `yaml:"specialization"`
ModelSelectionWebhook string `yaml:"model_selection_webhook"`
DefaultReasoningModel string `yaml:"default_reasoning_model"`
SandboxImage string `yaml:"sandbox_image"`
// Role-based configuration from Bees-AgenticWorkers
Role string `yaml:"role"`
SystemPrompt string `yaml:"system_prompt"`
ReportsTo []string `yaml:"reports_to"`
Expertise []string `yaml:"expertise"`
Deliverables []string `yaml:"deliverables"`
// Role-based collaboration settings
CollaborationSettings CollaborationConfig `yaml:"collaboration"`
}
// GitHubConfig holds GitHub integration settings
type GitHubConfig struct {
TokenFile string `yaml:"token_file"`
UserAgent string `yaml:"user_agent"`
Timeout time.Duration `yaml:"timeout"`
RateLimit bool `yaml:"rate_limit"`
Assignee string `yaml:"assignee"`
}
// P2PConfig holds P2P networking configuration
type P2PConfig struct {
ServiceTag string `yaml:"service_tag"`
BzzzTopic string `yaml:"bzzz_topic"`
HmmmTopic string `yaml:"hmmm_topic"`
DiscoveryTimeout time.Duration `yaml:"discovery_timeout"`
// Human escalation settings
EscalationWebhook string `yaml:"escalation_webhook"`
EscalationKeywords []string `yaml:"escalation_keywords"`
ConversationLimit int `yaml:"conversation_limit"`
}
// LoggingConfig holds logging configuration
type LoggingConfig struct {
Level string `yaml:"level"`
Format string `yaml:"format"`
Output string `yaml:"output"`
Structured bool `yaml:"structured"`
}
// V2Config holds BZZZ v2 protocol configuration
type V2Config struct {
// Enable v2 protocol features
Enabled bool `yaml:"enabled" json:"enabled"`
// Protocol version
ProtocolVersion string `yaml:"protocol_version" json:"protocol_version"`
// URI resolution settings
URIResolution URIResolutionConfig `yaml:"uri_resolution" json:"uri_resolution"`
// DHT settings
DHT DHTConfig `yaml:"dht" json:"dht"`
// Semantic addressing
SemanticAddressing SemanticAddressingConfig `yaml:"semantic_addressing" json:"semantic_addressing"`
// Feature flags
FeatureFlags map[string]bool `yaml:"feature_flags" json:"feature_flags"`
}
// URIResolutionConfig holds URI resolution settings
type URIResolutionConfig struct {
CacheTTL time.Duration `yaml:"cache_ttl" json:"cache_ttl"`
MaxPeersPerResult int `yaml:"max_peers_per_result" json:"max_peers_per_result"`
DefaultStrategy string `yaml:"default_strategy" json:"default_strategy"`
ResolutionTimeout time.Duration `yaml:"resolution_timeout" json:"resolution_timeout"`
}
// DHTConfig holds DHT-specific configuration
type DHTConfig struct {
Enabled bool `yaml:"enabled" json:"enabled"`
BootstrapPeers []string `yaml:"bootstrap_peers" json:"bootstrap_peers"`
Mode string `yaml:"mode" json:"mode"` // "client", "server", "auto"
ProtocolPrefix string `yaml:"protocol_prefix" json:"protocol_prefix"`
BootstrapTimeout time.Duration `yaml:"bootstrap_timeout" json:"bootstrap_timeout"`
DiscoveryInterval time.Duration `yaml:"discovery_interval" json:"discovery_interval"`
AutoBootstrap bool `yaml:"auto_bootstrap" json:"auto_bootstrap"`
}
// SemanticAddressingConfig holds semantic addressing settings
type SemanticAddressingConfig struct {
EnableWildcards bool `yaml:"enable_wildcards" json:"enable_wildcards"`
DefaultAgent string `yaml:"default_agent" json:"default_agent"`
DefaultRole string `yaml:"default_role" json:"default_role"`
DefaultProject string `yaml:"default_project" json:"default_project"`
EnableRoleHierarchy bool `yaml:"enable_role_hierarchy" json:"enable_role_hierarchy"`
}
// UCXLConfig holds UCXL protocol configuration
type UCXLConfig struct {
// Enable UCXL protocol
Enabled bool `yaml:"enabled" json:"enabled"`
// UCXI server configuration
Server UCXIServerConfig `yaml:"server" json:"server"`
// Address resolution settings
Resolution UCXLResolutionConfig `yaml:"resolution" json:"resolution"`
// Storage settings
Storage UCXLStorageConfig `yaml:"storage" json:"storage"`
// P2P integration settings
P2PIntegration UCXLP2PConfig `yaml:"p2p_integration" json:"p2p_integration"`
}
// UCXIServerConfig holds UCXI server settings
type UCXIServerConfig struct {
Port int `yaml:"port" json:"port"`
BasePath string `yaml:"base_path" json:"base_path"`
Enabled bool `yaml:"enabled" json:"enabled"`
}
// UCXLResolutionConfig holds address resolution settings
type UCXLResolutionConfig struct {
CacheTTL time.Duration `yaml:"cache_ttl" json:"cache_ttl"`
EnableWildcards bool `yaml:"enable_wildcards" json:"enable_wildcards"`
MaxResults int `yaml:"max_results" json:"max_results"`
}
// UCXLStorageConfig holds storage settings
type UCXLStorageConfig struct {
Type string `yaml:"type" json:"type"` // "filesystem", "memory"
Directory string `yaml:"directory" json:"directory"`
MaxSize int64 `yaml:"max_size" json:"max_size"` // in bytes
}
// UCXLP2PConfig holds P2P integration settings
type UCXLP2PConfig struct {
EnableAnnouncement bool `yaml:"enable_announcement" json:"enable_announcement"`
EnableDiscovery bool `yaml:"enable_discovery" json:"enable_discovery"`
AnnouncementTopic string `yaml:"announcement_topic" json:"announcement_topic"`
DiscoveryTimeout time.Duration `yaml:"discovery_timeout" json:"discovery_timeout"`
}
// HCFSConfig holds HCFS integration configuration
type HCFSConfig struct {
// API settings
APIURL string `yaml:"api_url" json:"api_url"`
APITimeout time.Duration `yaml:"api_timeout" json:"api_timeout"`
// Workspace settings
MountPath string `yaml:"mount_path" json:"mount_path"`
WorkspaceTimeout time.Duration `yaml:"workspace_timeout" json:"workspace_timeout"`
// FUSE settings
FUSEEnabled bool `yaml:"fuse_enabled" json:"fuse_enabled"`
FUSEMountPoint string `yaml:"fuse_mount_point" json:"fuse_mount_point"`
// Cleanup settings
IdleCleanupInterval time.Duration `yaml:"idle_cleanup_interval" json:"idle_cleanup_interval"`
MaxIdleTime time.Duration `yaml:"max_idle_time" json:"max_idle_time"`
// Storage settings
StoreArtifacts bool `yaml:"store_artifacts" json:"store_artifacts"`
CompressArtifacts bool `yaml:"compress_artifacts" json:"compress_artifacts"`
// Enable/disable HCFS integration
Enabled bool `yaml:"enabled" json:"enabled"`
}
// LoadConfig loads configuration from file, environment variables, and defaults
func LoadConfig(configPath string) (*Config, error) {
// Start with defaults
config := getDefaultConfig()
// Load from file if it exists
if configPath != "" && fileExists(configPath) {
if err := loadFromFile(config, configPath); err != nil {
return nil, fmt.Errorf("failed to load config file: %w", err)
}
}
// Override with environment variables
if err := loadFromEnv(config); err != nil {
return nil, fmt.Errorf("failed to load environment variables: %w", err)
}
// Validate configuration
if err := validateConfig(config); err != nil {
return nil, fmt.Errorf("invalid configuration: %w", err)
}
return config, nil
}
// getDefaultConfig returns the default configuration
func getDefaultConfig() *Config {
return &Config{
WHOOSHAPI: WHOOSHAPIConfig{
BaseURL: "https://hive.home.deepblack.cloud",
Timeout: 30 * time.Second,
RetryCount: 3,
},
Agent: AgentConfig{
Capabilities: []string{"general", "reasoning", "task-coordination"},
PollInterval: 30 * time.Second,
MaxTasks: 3,
Models: []string{"phi3", "llama3.1"},
Specialization: "general_developer",
ModelSelectionWebhook: "https://n8n.home.deepblack.cloud/webhook/model-selection",
DefaultReasoningModel: "phi3",
SandboxImage: "registry.home.deepblack.cloud/tony/bzzz-sandbox:latest",
},
GitHub: GitHubConfig{
TokenFile: "/home/tony/chorus/business/secrets/gh-token",
UserAgent: "Bzzz-P2P-Agent/1.0",
Timeout: 30 * time.Second,
RateLimit: true,
Assignee: "anthonyrawlins",
},
P2P: P2PConfig{
ServiceTag: "bzzz-peer-discovery",
BzzzTopic: "bzzz/coordination/v1",
HmmmTopic: "hmmm/meta-discussion/v1",
DiscoveryTimeout: 10 * time.Second,
EscalationWebhook: "https://n8n.home.deepblack.cloud/webhook-test/human-escalation",
EscalationKeywords: []string{"stuck", "help", "human", "escalate", "clarification needed", "manual intervention"},
ConversationLimit: 10,
},
Logging: LoggingConfig{
Level: "info",
Format: "text",
Output: "stdout",
Structured: false,
},
HCFS: HCFSConfig{
APIURL: "http://localhost:8000",
APITimeout: 30 * time.Second,
MountPath: "/tmp/hcfs-workspaces",
WorkspaceTimeout: 2 * time.Hour,
FUSEEnabled: false,
FUSEMountPoint: "/mnt/hcfs",
IdleCleanupInterval: 15 * time.Minute,
MaxIdleTime: 1 * time.Hour,
StoreArtifacts: true,
CompressArtifacts: false,
Enabled: true,
},
Slurp: GetDefaultSlurpConfig(),
UCXL: UCXLConfig{
Enabled: false, // Disabled by default
Server: UCXIServerConfig{
Port: 8081,
BasePath: "/bzzz",
Enabled: true,
},
Resolution: UCXLResolutionConfig{
CacheTTL: 5 * time.Minute,
EnableWildcards: true,
MaxResults: 50,
},
Storage: UCXLStorageConfig{
Type: "filesystem",
Directory: "/tmp/bzzz-ucxl-storage",
MaxSize: 100 * 1024 * 1024, // 100MB
},
P2PIntegration: UCXLP2PConfig{
EnableAnnouncement: true,
EnableDiscovery: true,
AnnouncementTopic: "bzzz/ucxl/announcement/v1",
DiscoveryTimeout: 30 * time.Second,
},
},
Security: SecurityConfig{
AdminKeyShares: ShamirShare{
Threshold: 3,
TotalShares: 5,
},
ElectionConfig: ElectionConfig{
HeartbeatTimeout: 5 * time.Second,
DiscoveryTimeout: 30 * time.Second,
ElectionTimeout: 15 * time.Second,
MaxDiscoveryAttempts: 6,
DiscoveryBackoff: 5 * time.Second,
MinimumQuorum: 3,
ConsensusAlgorithm: "raft",
SplitBrainDetection: true,
ConflictResolution: "highest_uptime",
},
KeyRotationDays: 90,
AuditLogging: true,
AuditPath: ".bzzz/security-audit.log",
},
V2: V2Config{
Enabled: false, // Disabled by default for backward compatibility
ProtocolVersion: "2.0.0",
URIResolution: URIResolutionConfig{
CacheTTL: 5 * time.Minute,
MaxPeersPerResult: 5,
DefaultStrategy: "best_match",
ResolutionTimeout: 30 * time.Second,
},
DHT: DHTConfig{
Enabled: false, // Disabled by default
BootstrapPeers: []string{},
Mode: "auto",
ProtocolPrefix: "/bzzz",
BootstrapTimeout: 30 * time.Second,
DiscoveryInterval: 60 * time.Second,
AutoBootstrap: false,
},
SemanticAddressing: SemanticAddressingConfig{
EnableWildcards: true,
DefaultAgent: "any",
DefaultRole: "any",
DefaultProject: "any",
EnableRoleHierarchy: true,
},
FeatureFlags: map[string]bool{
"uri_protocol": false,
"semantic_addressing": false,
"dht_discovery": false,
"advanced_resolution": false,
},
},
}
}
// loadFromFile loads configuration from a YAML file
func loadFromFile(config *Config, filePath string) error {
data, err := ioutil.ReadFile(filePath)
if err != nil {
return fmt.Errorf("failed to read config file: %w", err)
}
if err := yaml.Unmarshal(data, config); err != nil {
return fmt.Errorf("failed to parse YAML config: %w", err)
}
return nil
}
// loadFromEnv loads configuration from environment variables
func loadFromEnv(config *Config) error {
// WHOOSH API configuration
if url := os.Getenv("BZZZ_HIVE_API_URL"); url != "" {
config.WHOOSHAPI.BaseURL = url
}
if apiKey := os.Getenv("BZZZ_HIVE_API_KEY"); apiKey != "" {
config.WHOOSHAPI.APIKey = apiKey
}
// Agent configuration
if agentID := os.Getenv("BZZZ_AGENT_ID"); agentID != "" {
config.Agent.ID = agentID
}
if capabilities := os.Getenv("BZZZ_AGENT_CAPABILITIES"); capabilities != "" {
config.Agent.Capabilities = strings.Split(capabilities, ",")
}
if specialization := os.Getenv("BZZZ_AGENT_SPECIALIZATION"); specialization != "" {
config.Agent.Specialization = specialization
}
if modelWebhook := os.Getenv("BZZZ_MODEL_SELECTION_WEBHOOK"); modelWebhook != "" {
config.Agent.ModelSelectionWebhook = modelWebhook
}
// GitHub configuration
if tokenFile := os.Getenv("BZZZ_GITHUB_TOKEN_FILE"); tokenFile != "" {
config.GitHub.TokenFile = tokenFile
}
// P2P configuration
if webhook := os.Getenv("BZZZ_ESCALATION_WEBHOOK"); webhook != "" {
config.P2P.EscalationWebhook = webhook
}
// Logging configuration
if level := os.Getenv("BZZZ_LOG_LEVEL"); level != "" {
config.Logging.Level = level
}
// SLURP configuration
if slurpURL := os.Getenv("BZZZ_SLURP_URL"); slurpURL != "" {
config.Slurp.BaseURL = slurpURL
}
if slurpKey := os.Getenv("BZZZ_SLURP_API_KEY"); slurpKey != "" {
config.Slurp.APIKey = slurpKey
}
if slurpEnabled := os.Getenv("BZZZ_SLURP_ENABLED"); slurpEnabled == "true" {
config.Slurp.Enabled = true
}
// UCXL protocol configuration
if ucxlEnabled := os.Getenv("BZZZ_UCXL_ENABLED"); ucxlEnabled == "true" {
config.UCXL.Enabled = true
}
if ucxiPort := os.Getenv("BZZZ_UCXI_PORT"); ucxiPort != "" {
// Would need strconv.Atoi but keeping simple for now
// In production, add proper integer parsing
}
// V2 protocol configuration
if v2Enabled := os.Getenv("BZZZ_V2_ENABLED"); v2Enabled == "true" {
config.V2.Enabled = true
}
if dhtEnabled := os.Getenv("BZZZ_DHT_ENABLED"); dhtEnabled == "true" {
config.V2.DHT.Enabled = true
}
if dhtMode := os.Getenv("BZZZ_DHT_MODE"); dhtMode != "" {
config.V2.DHT.Mode = dhtMode
}
if bootstrapPeers := os.Getenv("BZZZ_DHT_BOOTSTRAP_PEERS"); bootstrapPeers != "" {
config.V2.DHT.BootstrapPeers = strings.Split(bootstrapPeers, ",")
}
return nil
}
// validateConfig validates the configuration values
func validateConfig(config *Config) error {
// Validate required fields
if config.WHOOSHAPI.BaseURL == "" {
return fmt.Errorf("hive_api.base_url is required")
}
// Note: Agent.ID can be empty - it will be auto-generated from node ID in main.go
if len(config.Agent.Capabilities) == 0 {
return fmt.Errorf("agent.capabilities cannot be empty")
}
if config.Agent.PollInterval <= 0 {
return fmt.Errorf("agent.poll_interval must be positive")
}
if config.Agent.MaxTasks <= 0 {
return fmt.Errorf("agent.max_tasks must be positive")
}
// Validate GitHub token file exists if specified
if config.GitHub.TokenFile != "" && !fileExists(config.GitHub.TokenFile) {
return fmt.Errorf("github token file does not exist: %s", config.GitHub.TokenFile)
}
// Validate SLURP configuration
if err := ValidateSlurpConfig(config.Slurp); err != nil {
return fmt.Errorf("slurp configuration invalid: %w", err)
}
return nil
}
// SaveConfig saves the configuration to a YAML file
func SaveConfig(config *Config, filePath string) error {
data, err := yaml.Marshal(config)
if err != nil {
return fmt.Errorf("failed to marshal config to YAML: %w", err)
}
if err := ioutil.WriteFile(filePath, data, 0644); err != nil {
return fmt.Errorf("failed to write config file: %w", err)
}
return nil
}
// GetGitHubToken reads the GitHub token from the configured file
func (c *Config) GetGitHubToken() (string, error) {
if c.GitHub.TokenFile == "" {
return "", fmt.Errorf("no GitHub token file configured")
}
tokenBytes, err := ioutil.ReadFile(c.GitHub.TokenFile)
if err != nil {
return "", fmt.Errorf("failed to read GitHub token: %w", err)
}
return strings.TrimSpace(string(tokenBytes)), nil
}
// fileExists checks if a file exists
func fileExists(filePath string) bool {
_, err := os.Stat(filePath)
return err == nil
}
// GenerateDefaultConfigFile creates a default configuration file
func GenerateDefaultConfigFile(filePath string) error {
config := getDefaultConfig()
return SaveConfig(config, filePath)
}