- Bump github.com/rabbitmq/amqp091-go 1.12.0 -> 1.13.0 (3 Critical, 7 High,
reachable via rabbitmq.Connect) and golang.org/x/{text,net,crypto},
klauspost/compress; toolchain go1.26.8, builder image pinned to
golang:1.26.8-alpine3.24.
- Build Content-Disposition per RFC 6266/8187 (ASCII fallback +
filename*=UTF-8''), stripping CR/LF, quotes and backslashes (CWE-113).
- Cap request bodies with MaxBytesReader (HTTP_MAX_UPLOAD_BYTES, default
2 GiB); multipart uploads over the limit return 413 (CWE-400).
- /readyz reports "unavailable" instead of raw backend errors (CWE-209).
- Drop deprecated middleware.RealIP; add X-Content-Type-Options: nosniff.
- docker-compose credentials come from ${VAR:-default}.
- Check the RegisterValidation error; annotate verified gosec false
positives with #nosec and a reason.
Re-scan: govulncheck 0 reachable, trivy fs/image 0 High/Critical,
gosec High 0. go test -race passes against PostGIS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
90 lines
3.3 KiB
Go
90 lines
3.3 KiB
Go
// Package config loads application configuration from the environment.
|
|
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/caarlos0/env/v11"
|
|
"github.com/joho/godotenv"
|
|
)
|
|
|
|
// Config holds all configuration for the application. Values are read from
|
|
// environment variables; a local .env file (if present) is loaded first.
|
|
type Config struct {
|
|
HTTP HTTPConfig
|
|
DB DBConfig
|
|
S3 S3Config
|
|
RabbitMQ RabbitMQConfig
|
|
Landscape LandscapeConfig
|
|
}
|
|
|
|
// HTTPConfig configures the HTTP server.
|
|
type HTTPConfig struct {
|
|
Port int `env:"PORT" envDefault:"8080"`
|
|
ReadHeaderTimeout time.Duration `env:"HTTP_READ_HEADER_TIMEOUT" envDefault:"5s"`
|
|
ReadTimeout time.Duration `env:"HTTP_READ_TIMEOUT" envDefault:"120s"`
|
|
WriteTimeout time.Duration `env:"HTTP_WRITE_TIMEOUT" envDefault:"120s"`
|
|
IdleTimeout time.Duration `env:"HTTP_IDLE_TIMEOUT" envDefault:"60s"`
|
|
ShutdownTimeout time.Duration `env:"HTTP_SHUTDOWN_TIMEOUT" envDefault:"10s"`
|
|
// MaxUploadBytes caps the size of any request body, multipart uploads
|
|
// included (default 2 GiB); larger requests get 413. 0 disables the cap.
|
|
MaxUploadBytes int64 `env:"HTTP_MAX_UPLOAD_BYTES" envDefault:"2147483648"`
|
|
}
|
|
|
|
// Addr returns the listen address for the HTTP server.
|
|
func (c HTTPConfig) Addr() string {
|
|
return fmt.Sprintf(":%d", c.Port)
|
|
}
|
|
|
|
// DBConfig configures the Postgres connection.
|
|
type DBConfig struct {
|
|
URL string `env:"DB_URL,required"`
|
|
// Schema is the Postgres schema migrations operate on. It is used by
|
|
// `migrate fresh` to know which schema to drop and recreate; in production
|
|
// this may be something other than "public".
|
|
Schema string `env:"DB_SCHEMA" envDefault:"public"`
|
|
}
|
|
|
|
// S3Config configures the S3/MinIO object store.
|
|
type S3Config struct {
|
|
Endpoint string `env:"S3_ENDPOINT,required"`
|
|
AccessKey string `env:"S3_ACCESS_KEY,required"`
|
|
SecretKey string `env:"S3_SECRET_KEY,required"`
|
|
Bucket string `env:"S3_BUCKET" envDefault:"geofiles"`
|
|
UseSSL bool `env:"S3_USE_SSL" envDefault:"false"`
|
|
}
|
|
|
|
// RabbitMQConfig configures the RabbitMQ connection and example topology.
|
|
type RabbitMQConfig struct {
|
|
URL string `env:"RABBITMQ_URL,required"`
|
|
Exchange string `env:"RABBITMQ_EXCHANGE" envDefault:"gis.events"`
|
|
Queue string `env:"RABBITMQ_QUEUE" envDefault:"gis.events.example"`
|
|
}
|
|
|
|
// LandscapeConfig bounds the Landscape Program's parallelism, and with it the
|
|
// worker's peak memory: a run holds up to MaxConcurrentNodes nodes in flight,
|
|
// each running a pool of MaxWorkers/MaxConcurrentNodes goroutines that own one
|
|
// window buffer per input and output. The defaults (8 total workers spread
|
|
// over 2 nodes) keep that product bounded regardless of how many cores the
|
|
// host has.
|
|
type LandscapeConfig struct {
|
|
// MaxWorkers is the total window-worker budget shared by all nodes of a run.
|
|
MaxWorkers int `env:"LP_MAX_WORKERS" envDefault:"8"`
|
|
// MaxConcurrentNodes is how many graph nodes of one stage run at a time.
|
|
MaxConcurrentNodes int `env:"LP_MAX_NODES" envDefault:"2"`
|
|
}
|
|
|
|
// Load reads configuration from the environment, loading an optional .env file
|
|
// from the current working directory first.
|
|
func Load() (*Config, error) {
|
|
// A missing .env file is not an error: in production we rely on real env vars.
|
|
_ = godotenv.Load()
|
|
|
|
cfg := &Config{}
|
|
if err := env.Parse(cfg); err != nil {
|
|
return nil, fmt.Errorf("parse config: %w", err)
|
|
}
|
|
return cfg, nil
|
|
}
|