Major refactoring to hexagonal (ports & adapters) architecture: - Add service layer (apikey_service, project_service) for business logic - Add webhook system with dispatcher and delivery tracking - Add command queue with priority-based processing - Add rate limiting with sliding window algorithm - Add audit logging for command execution - Add OpenTelemetry integration (traces, metrics, spans) - Add circuit breaker for fault tolerance - Add cached repository wrapper for performance - Add comprehensive validation package - Add Kubernetes client integration for pod management - Add database migrations (allowed_ips, audit_log, rate_limiting, queue, webhooks) - Add network policy and PodDisruptionBudget for k8s - Remove legacy executor and projects/registry packages - Untrack secrets.yaml (now managed via envault) - Add coverage.out to .gitignore - Add e2e test infrastructure with docker-compose - Add comprehensive documentation (API, architecture, operations, plans) - Add golangci-lint config and pre-commit hook Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
89 lines
2.4 KiB
Go
89 lines
2.4 KiB
Go
package domain
|
|
|
|
import "time"
|
|
|
|
// Default rate limit values. These must match the defaults in
|
|
// internal/db/migrations/005_rate_limiting.sql
|
|
const (
|
|
DefaultRateLimitPerMinute = 60
|
|
DefaultRateLimitPerHour = 1000
|
|
)
|
|
|
|
// RateLimitConfig holds the rate limit configuration for an API key.
|
|
type RateLimitConfig struct {
|
|
// PerMinute is the maximum number of requests allowed per minute.
|
|
PerMinute int
|
|
|
|
// PerHour is the maximum number of requests allowed per hour.
|
|
PerHour int
|
|
}
|
|
|
|
// DefaultRateLimitConfig returns the default rate limit configuration.
|
|
func DefaultRateLimitConfig() RateLimitConfig {
|
|
return RateLimitConfig{
|
|
PerMinute: DefaultRateLimitPerMinute,
|
|
PerHour: DefaultRateLimitPerHour,
|
|
}
|
|
}
|
|
|
|
// RateLimitState tracks the current usage within a time window.
|
|
type RateLimitState struct {
|
|
// APIKeyID is the identifier of the API key.
|
|
APIKeyID string
|
|
|
|
// WindowStart is the beginning of the current time window.
|
|
WindowStart time.Time
|
|
|
|
// WindowType indicates the type of window ("minute" or "hour").
|
|
WindowType string
|
|
|
|
// RequestCount is the number of requests made in this window.
|
|
RequestCount int
|
|
|
|
// UpdatedAt is when this state was last updated.
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
// WindowTypeMinute is the constant for minute-based windows.
|
|
const WindowTypeMinute = "minute"
|
|
|
|
// WindowTypeHour is the constant for hour-based windows.
|
|
const WindowTypeHour = "hour"
|
|
|
|
// RateLimitResult contains the result of a rate limit check.
|
|
type RateLimitResult struct {
|
|
// Allowed indicates whether the request is allowed.
|
|
Allowed bool
|
|
|
|
// RetryAfter is the duration to wait before retrying (when not allowed).
|
|
RetryAfter time.Duration
|
|
|
|
// RemainingMinute is the number of requests remaining in the current minute.
|
|
RemainingMinute int
|
|
|
|
// RemainingHour is the number of requests remaining in the current hour.
|
|
RemainingHour int
|
|
|
|
// LimitMinute is the per-minute limit for this key.
|
|
LimitMinute int
|
|
|
|
// LimitHour is the per-hour limit for this key.
|
|
LimitHour int
|
|
|
|
// ResetMinute is when the minute window resets.
|
|
ResetMinute time.Time
|
|
|
|
// ResetHour is when the hour window resets.
|
|
ResetHour time.Time
|
|
}
|
|
|
|
// TruncateToMinute truncates a time to the start of the minute.
|
|
func TruncateToMinute(t time.Time) time.Time {
|
|
return t.Truncate(time.Minute)
|
|
}
|
|
|
|
// TruncateToHour truncates a time to the start of the hour.
|
|
func TruncateToHour(t time.Time) time.Time {
|
|
return t.Truncate(time.Hour)
|
|
}
|