 131868bdca
			
		
	
	131868bdca
	
	
	
		
			
			Major security, observability, and configuration improvements:
## Security Hardening
- Implemented configurable CORS (no more wildcards)
- Added comprehensive auth middleware for admin endpoints
- Enhanced webhook HMAC validation
- Added input validation and rate limiting
- Security headers and CSP policies
## Configuration Management
- Made N8N webhook URL configurable (WHOOSH_N8N_BASE_URL)
- Replaced all hardcoded endpoints with environment variables
- Added feature flags for LLM vs heuristic composition
- Gitea fetch hardening with EAGER_FILTER and FULL_RESCAN options
## API Completeness
- Implemented GetCouncilComposition function
- Added GET /api/v1/councils/{id} endpoint
- Council artifacts API (POST/GET /api/v1/councils/{id}/artifacts)
- /admin/health/details endpoint with component status
- Database lookup for repository URLs (no hardcoded fallbacks)
## Observability & Performance
- Added OpenTelemetry distributed tracing with goal/pulse correlation
- Performance optimization database indexes
- Comprehensive health monitoring
- Enhanced logging and error handling
## Infrastructure
- Production-ready P2P discovery (replaces mock implementation)
- Removed unused Redis configuration
- Enhanced Docker Swarm integration
- Added migration files for performance indexes
## Code Quality
- Comprehensive input validation
- Graceful error handling and failsafe fallbacks
- Backwards compatibility maintained
- Following security best practices
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
		
	
		
			
				
	
	
		
			124 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			124 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Package database provides the Driver interface.
 | |
| // All database drivers must implement this interface, register themselves,
 | |
| // optionally provide a `WithInstance` function and pass the tests
 | |
| // in package database/testing.
 | |
| package database
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"sync"
 | |
| 
 | |
| 	iurl "github.com/golang-migrate/migrate/v4/internal/url"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	ErrLocked    = fmt.Errorf("can't acquire lock")
 | |
| 	ErrNotLocked = fmt.Errorf("can't unlock, as not currently locked")
 | |
| )
 | |
| 
 | |
| const NilVersion int = -1
 | |
| 
 | |
| var driversMu sync.RWMutex
 | |
| var drivers = make(map[string]Driver)
 | |
| 
 | |
| // Driver is the interface every database driver must implement.
 | |
| //
 | |
| // How to implement a database driver?
 | |
| //  1. Implement this interface.
 | |
| //  2. Optionally, add a function named `WithInstance`.
 | |
| //     This function should accept an existing DB instance and a Config{} struct
 | |
| //     and return a driver instance.
 | |
| //  3. Add a test that calls database/testing.go:Test()
 | |
| //  4. Add own tests for Open(), WithInstance() (when provided) and Close().
 | |
| //     All other functions are tested by tests in database/testing.
 | |
| //     Saves you some time and makes sure all database drivers behave the same way.
 | |
| //  5. Call Register in init().
 | |
| //  6. Create a internal/cli/build_<driver-name>.go file
 | |
| //  7. Add driver name in 'DATABASE' variable in Makefile
 | |
| //
 | |
| // Guidelines:
 | |
| //   - Don't try to correct user input. Don't assume things.
 | |
| //     When in doubt, return an error and explain the situation to the user.
 | |
| //   - All configuration input must come from the URL string in func Open()
 | |
| //     or the Config{} struct in WithInstance. Don't os.Getenv().
 | |
| type Driver interface {
 | |
| 	// Open returns a new driver instance configured with parameters
 | |
| 	// coming from the URL string. Migrate will call this function
 | |
| 	// only once per instance.
 | |
| 	Open(url string) (Driver, error)
 | |
| 
 | |
| 	// Close closes the underlying database instance managed by the driver.
 | |
| 	// Migrate will call this function only once per instance.
 | |
| 	Close() error
 | |
| 
 | |
| 	// Lock should acquire a database lock so that only one migration process
 | |
| 	// can run at a time. Migrate will call this function before Run is called.
 | |
| 	// If the implementation can't provide this functionality, return nil.
 | |
| 	// Return database.ErrLocked if database is already locked.
 | |
| 	Lock() error
 | |
| 
 | |
| 	// Unlock should release the lock. Migrate will call this function after
 | |
| 	// all migrations have been run.
 | |
| 	Unlock() error
 | |
| 
 | |
| 	// Run applies a migration to the database. migration is guaranteed to be not nil.
 | |
| 	Run(migration io.Reader) error
 | |
| 
 | |
| 	// SetVersion saves version and dirty state.
 | |
| 	// Migrate will call this function before and after each call to Run.
 | |
| 	// version must be >= -1. -1 means NilVersion.
 | |
| 	SetVersion(version int, dirty bool) error
 | |
| 
 | |
| 	// Version returns the currently active version and if the database is dirty.
 | |
| 	// When no migration has been applied, it must return version -1.
 | |
| 	// Dirty means, a previous migration failed and user interaction is required.
 | |
| 	Version() (version int, dirty bool, err error)
 | |
| 
 | |
| 	// Drop deletes everything in the database.
 | |
| 	// Note that this is a breaking action, a new call to Open() is necessary to
 | |
| 	// ensure subsequent calls work as expected.
 | |
| 	Drop() error
 | |
| }
 | |
| 
 | |
| // Open returns a new driver instance.
 | |
| func Open(url string) (Driver, error) {
 | |
| 	scheme, err := iurl.SchemeFromURL(url)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	driversMu.RLock()
 | |
| 	d, ok := drivers[scheme]
 | |
| 	driversMu.RUnlock()
 | |
| 	if !ok {
 | |
| 		return nil, fmt.Errorf("database driver: unknown driver %v (forgotten import?)", scheme)
 | |
| 	}
 | |
| 
 | |
| 	return d.Open(url)
 | |
| }
 | |
| 
 | |
| // Register globally registers a driver.
 | |
| func Register(name string, driver Driver) {
 | |
| 	driversMu.Lock()
 | |
| 	defer driversMu.Unlock()
 | |
| 	if driver == nil {
 | |
| 		panic("Register driver is nil")
 | |
| 	}
 | |
| 	if _, dup := drivers[name]; dup {
 | |
| 		panic("Register called twice for driver " + name)
 | |
| 	}
 | |
| 	drivers[name] = driver
 | |
| }
 | |
| 
 | |
| // List lists the registered drivers
 | |
| func List() []string {
 | |
| 	driversMu.RLock()
 | |
| 	defer driversMu.RUnlock()
 | |
| 	names := make([]string, 0, len(drivers))
 | |
| 	for n := range drivers {
 | |
| 		names = append(names, n)
 | |
| 	}
 | |
| 	return names
 | |
| }
 |