feat: Production readiness improvements for WHOOSH council formation

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>
This commit is contained in:
Claude Code
2025-09-12 20:34:17 +10:00
parent 56ea52b743
commit 131868bdca
1740 changed files with 575904 additions and 171 deletions

View File

@@ -0,0 +1,118 @@
// Package source provides the Source interface.
// All source drivers must implement this interface, register themselves,
// optionally provide a `WithInstance` function and pass the tests
// in package source/testing.
package source
import (
"fmt"
"io"
nurl "net/url"
"sync"
)
var driversMu sync.RWMutex
var drivers = make(map[string]Driver)
// Driver is the interface every source driver must implement.
//
// How to implement a source driver?
// 1. Implement this interface.
// 2. Optionally, add a function named `WithInstance`.
// This function should accept an existing source instance and a Config{} struct
// and return a driver instance.
// 3. Add a test that calls source/testing.go:Test()
// 4. Add own tests for Open(), WithInstance() (when provided) and Close().
// All other functions are tested by tests in source/testing.
// Saves you some time and makes sure all source drivers behave the same way.
// 5. Call Register in init().
//
// Guidelines:
// - All configuration input must come from the URL string in func Open()
// or the Config{} struct in WithInstance. Don't os.Getenv().
// - Drivers are supposed to be read only.
// - Ideally don't load any contents (into memory) in Open or WithInstance.
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 source instance managed by the driver.
// Migrate will call this function only once per instance.
Close() error
// First returns the very first migration version available to the driver.
// Migrate will call this function multiple times.
// If there is no version available, it must return os.ErrNotExist.
First() (version uint, err error)
// Prev returns the previous version for a given version available to the driver.
// Migrate will call this function multiple times.
// If there is no previous version available, it must return os.ErrNotExist.
Prev(version uint) (prevVersion uint, err error)
// Next returns the next version for a given version available to the driver.
// Migrate will call this function multiple times.
// If there is no next version available, it must return os.ErrNotExist.
Next(version uint) (nextVersion uint, err error)
// ReadUp returns the UP migration body and an identifier that helps
// finding this migration in the source for a given version.
// If there is no up migration available for this version,
// it must return os.ErrNotExist.
// Do not start reading, just return the ReadCloser!
ReadUp(version uint) (r io.ReadCloser, identifier string, err error)
// ReadDown returns the DOWN migration body and an identifier that helps
// finding this migration in the source for a given version.
// If there is no down migration available for this version,
// it must return os.ErrNotExist.
// Do not start reading, just return the ReadCloser!
ReadDown(version uint) (r io.ReadCloser, identifier string, err error)
}
// Open returns a new driver instance.
func Open(url string) (Driver, error) {
u, err := nurl.Parse(url)
if err != nil {
return nil, err
}
if u.Scheme == "" {
return nil, fmt.Errorf("source driver: invalid URL scheme")
}
driversMu.RLock()
d, ok := drivers[u.Scheme]
driversMu.RUnlock()
if !ok {
return nil, fmt.Errorf("source driver: unknown driver '%s' (forgotten import?)", u.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
}

View File

@@ -0,0 +1,15 @@
package source
import "os"
// ErrDuplicateMigration is an error type for reporting duplicate migration
// files.
type ErrDuplicateMigration struct {
Migration
os.FileInfo
}
// Error implements error interface.
func (e ErrDuplicateMigration) Error() string {
return "duplicate migration file: " + e.Name()
}

View File

@@ -0,0 +1,4 @@
# file
`file:///absolute/path`
`file://relative/path`

View File

@@ -0,0 +1,66 @@
package file
import (
nurl "net/url"
"os"
"path/filepath"
"github.com/golang-migrate/migrate/v4/source"
"github.com/golang-migrate/migrate/v4/source/iofs"
)
func init() {
source.Register("file", &File{})
}
type File struct {
iofs.PartialDriver
url string
path string
}
func (f *File) Open(url string) (source.Driver, error) {
p, err := parseURL(url)
if err != nil {
return nil, err
}
nf := &File{
url: url,
path: p,
}
if err := nf.Init(os.DirFS(p), "."); err != nil {
return nil, err
}
return nf, nil
}
func parseURL(url string) (string, error) {
u, err := nurl.Parse(url)
if err != nil {
return "", err
}
// concat host and path to restore full path
// host might be `.`
p := u.Opaque
if len(p) == 0 {
p = u.Host + u.Path
}
if len(p) == 0 {
// default to current directory if no path
wd, err := os.Getwd()
if err != nil {
return "", err
}
p = wd
} else if p[0:1] == "." || p[0:1] != "/" {
// make path absolute if relative
abs, err := filepath.Abs(p)
if err != nil {
return "", err
}
p = abs
}
return p, nil
}

View File

@@ -0,0 +1,3 @@
# iofs
https://pkg.go.dev/github.com/golang-migrate/migrate/v4/source/iofs

View File

@@ -0,0 +1,10 @@
/*
Package iofs provides the Go 1.16+ io/fs#FS driver.
It can accept various file systems (like embed.FS, archive/zip#Reader) implementing io/fs#FS.
This driver cannot be used with Go versions 1.15 and below.
Also, Opening with a URL scheme is not supported.
*/
package iofs

View File

@@ -0,0 +1,176 @@
//go:build go1.16
// +build go1.16
package iofs
import (
"errors"
"fmt"
"io"
"io/fs"
"path"
"strconv"
"github.com/golang-migrate/migrate/v4/source"
)
type driver struct {
PartialDriver
}
// New returns a new Driver from io/fs#FS and a relative path.
func New(fsys fs.FS, path string) (source.Driver, error) {
var i driver
if err := i.Init(fsys, path); err != nil {
return nil, fmt.Errorf("failed to init driver with path %s: %w", path, err)
}
return &i, nil
}
// Open is part of source.Driver interface implementation.
// Open cannot be called on the iofs passthrough driver.
func (d *driver) Open(url string) (source.Driver, error) {
return nil, errors.New("Open() cannot be called on the iofs passthrough driver")
}
// PartialDriver is a helper service for creating new source drivers working with
// io/fs.FS instances. It implements all source.Driver interface methods
// except for Open(). New driver could embed this struct and add missing Open()
// method.
//
// To prepare PartialDriver for use Init() function.
type PartialDriver struct {
migrations *source.Migrations
fsys fs.FS
path string
}
// Init prepares not initialized IoFS instance to read migrations from a
// io/fs#FS instance and a relative path.
func (d *PartialDriver) Init(fsys fs.FS, path string) error {
entries, err := fs.ReadDir(fsys, path)
if err != nil {
return err
}
ms := source.NewMigrations()
for _, e := range entries {
if e.IsDir() {
continue
}
m, err := source.DefaultParse(e.Name())
if err != nil {
continue
}
file, err := e.Info()
if err != nil {
return err
}
if !ms.Append(m) {
return source.ErrDuplicateMigration{
Migration: *m,
FileInfo: file,
}
}
}
d.fsys = fsys
d.path = path
d.migrations = ms
return nil
}
// Close is part of source.Driver interface implementation.
// Closes the file system if possible.
func (d *PartialDriver) Close() error {
c, ok := d.fsys.(io.Closer)
if !ok {
return nil
}
return c.Close()
}
// First is part of source.Driver interface implementation.
func (d *PartialDriver) First() (version uint, err error) {
if version, ok := d.migrations.First(); ok {
return version, nil
}
return 0, &fs.PathError{
Op: "first",
Path: d.path,
Err: fs.ErrNotExist,
}
}
// Prev is part of source.Driver interface implementation.
func (d *PartialDriver) Prev(version uint) (prevVersion uint, err error) {
if version, ok := d.migrations.Prev(version); ok {
return version, nil
}
return 0, &fs.PathError{
Op: "prev for version " + strconv.FormatUint(uint64(version), 10),
Path: d.path,
Err: fs.ErrNotExist,
}
}
// Next is part of source.Driver interface implementation.
func (d *PartialDriver) Next(version uint) (nextVersion uint, err error) {
if version, ok := d.migrations.Next(version); ok {
return version, nil
}
return 0, &fs.PathError{
Op: "next for version " + strconv.FormatUint(uint64(version), 10),
Path: d.path,
Err: fs.ErrNotExist,
}
}
// ReadUp is part of source.Driver interface implementation.
func (d *PartialDriver) ReadUp(version uint) (r io.ReadCloser, identifier string, err error) {
if m, ok := d.migrations.Up(version); ok {
body, err := d.open(path.Join(d.path, m.Raw))
if err != nil {
return nil, "", err
}
return body, m.Identifier, nil
}
return nil, "", &fs.PathError{
Op: "read up for version " + strconv.FormatUint(uint64(version), 10),
Path: d.path,
Err: fs.ErrNotExist,
}
}
// ReadDown is part of source.Driver interface implementation.
func (d *PartialDriver) ReadDown(version uint) (r io.ReadCloser, identifier string, err error) {
if m, ok := d.migrations.Down(version); ok {
body, err := d.open(path.Join(d.path, m.Raw))
if err != nil {
return nil, "", err
}
return body, m.Identifier, nil
}
return nil, "", &fs.PathError{
Op: "read down for version " + strconv.FormatUint(uint64(version), 10),
Path: d.path,
Err: fs.ErrNotExist,
}
}
func (d *PartialDriver) open(path string) (fs.File, error) {
f, err := d.fsys.Open(path)
if err == nil {
return f, nil
}
// Some non-standard file systems may return errors that don't include the path, that
// makes debugging harder.
if !errors.As(err, new(*fs.PathError)) {
err = &fs.PathError{
Op: "open",
Path: path,
Err: err,
}
}
return nil, err
}

View File

@@ -0,0 +1,133 @@
package source
import (
"sort"
)
// Direction is either up or down.
type Direction string
const (
Down Direction = "down"
Up Direction = "up"
)
// Migration is a helper struct for source drivers that need to
// build the full directory tree in memory.
// Migration is fully independent from migrate.Migration.
type Migration struct {
// Version is the version of this migration.
Version uint
// Identifier can be any string that helps identifying
// this migration in the source.
Identifier string
// Direction is either Up or Down.
Direction Direction
// Raw holds the raw location path to this migration in source.
// ReadUp and ReadDown will use this.
Raw string
}
// Migrations wraps Migration and has an internal index
// to keep track of Migration order.
type Migrations struct {
index uintSlice
migrations map[uint]map[Direction]*Migration
}
func NewMigrations() *Migrations {
return &Migrations{
index: make(uintSlice, 0),
migrations: make(map[uint]map[Direction]*Migration),
}
}
func (i *Migrations) Append(m *Migration) (ok bool) {
if m == nil {
return false
}
if i.migrations[m.Version] == nil {
i.migrations[m.Version] = make(map[Direction]*Migration)
}
// reject duplicate versions
if _, dup := i.migrations[m.Version][m.Direction]; dup {
return false
}
i.migrations[m.Version][m.Direction] = m
i.buildIndex()
return true
}
func (i *Migrations) buildIndex() {
i.index = make(uintSlice, 0, len(i.migrations))
for version := range i.migrations {
i.index = append(i.index, version)
}
sort.Slice(i.index, func(x, y int) bool {
return i.index[x] < i.index[y]
})
}
func (i *Migrations) First() (version uint, ok bool) {
if len(i.index) == 0 {
return 0, false
}
return i.index[0], true
}
func (i *Migrations) Prev(version uint) (prevVersion uint, ok bool) {
pos := i.findPos(version)
if pos >= 1 && len(i.index) > pos-1 {
return i.index[pos-1], true
}
return 0, false
}
func (i *Migrations) Next(version uint) (nextVersion uint, ok bool) {
pos := i.findPos(version)
if pos >= 0 && len(i.index) > pos+1 {
return i.index[pos+1], true
}
return 0, false
}
func (i *Migrations) Up(version uint) (m *Migration, ok bool) {
if _, ok := i.migrations[version]; ok {
if mx, ok := i.migrations[version][Up]; ok {
return mx, true
}
}
return nil, false
}
func (i *Migrations) Down(version uint) (m *Migration, ok bool) {
if _, ok := i.migrations[version]; ok {
if mx, ok := i.migrations[version][Down]; ok {
return mx, true
}
}
return nil, false
}
func (i *Migrations) findPos(version uint) int {
if len(i.index) > 0 {
ix := i.index.Search(version)
if ix < len(i.index) && i.index[ix] == version {
return ix
}
}
return -1
}
type uintSlice []uint
func (s uintSlice) Search(x uint) int {
return sort.Search(len(s), func(i int) bool { return s[i] >= x })
}

View File

@@ -0,0 +1,40 @@
package source
import (
"fmt"
"regexp"
"strconv"
)
var (
ErrParse = fmt.Errorf("no match")
)
var (
DefaultParse = Parse
DefaultRegex = Regex
)
// Regex matches the following pattern:
//
// 123_name.up.ext
// 123_name.down.ext
var Regex = regexp.MustCompile(`^([0-9]+)_(.*)\.(` + string(Down) + `|` + string(Up) + `)\.(.*)$`)
// Parse returns Migration for matching Regex pattern.
func Parse(raw string) (*Migration, error) {
m := Regex.FindStringSubmatch(raw)
if len(m) == 5 {
versionUint64, err := strconv.ParseUint(m[1], 10, 64)
if err != nil {
return nil, err
}
return &Migration{
Version: uint(versionUint64),
Identifier: m[2],
Direction: Direction(m[3]),
Raw: raw,
}, nil
}
return nil, ErrParse
}