control

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 13, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package control defines the JSON shapes shared between the daemon's unix-socket HTTP server and goban-client.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Audit

type Audit struct {
	// contains filtered or unexported fields
}

Audit is an append-only JSON-lines logger for administrative actions performed against the control plane (manual ban / unban). Writes are serialized by a mutex; the underlying writer is `*os.File` in production or a `*bytes.Buffer` in tests.

Format example (one line, pretty-printed for readability):

{
  "time":   "2026-05-11T12:34:56.789Z",
  "action": "ban",
  "ip":     "192.0.2.99",
  "rule":   "manual",
  "ttl":    "5m0s",
  "source": "manual"
}

The control server appends a line only on the SUCCESS path of /ban and /unban — failed attempts are deliberately not audited so the file stays useful as a "what was applied" timeline.

func NewAuditFile

func NewAuditFile(path string) (*Audit, func() error, error)

NewAuditFile opens (or creates) path in append mode with mode 0640. Parents are created with 0755. Returns a closer for callers to defer.

func NewAuditWriter

func NewAuditWriter(w io.Writer) *Audit

NewAuditWriter wraps an arbitrary io.Writer (used by tests).

func (*Audit) Log

func (a *Audit) Log(ev AuditEvent)

Log appends one event as a JSON line. If the underlying writer fails the error is silently swallowed — audit logging must not break the control plane.

type AuditEvent

type AuditEvent struct {
	Time   time.Time `json:"time"`
	Action string    `json:"action"`
	IP     string    `json:"ip"`
	Rule   string    `json:"rule,omitempty"`
	TTL    string    `json:"ttl,omitempty"`
	Source string    `json:"source"`
}

AuditEvent is one entry in the audit log.

type BanInfo

type BanInfo struct {
	IP        string        `json:"ip"`
	Rule      string        `json:"rule,omitempty"`
	TTL       time.Duration `json:"ttl,omitempty"`
	ExpiresAt time.Time     `json:"expires_at,omitempty"`
}

BanInfo is one entry in GET /banned.

type BanReq

type BanReq struct {
	IP   string        `json:"ip"`
	Rule string        `json:"rule"`
	TTL  time.Duration `json:"ttl"`
}

BanReq is the body of POST /ban.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client talks to a goban daemon over its unix socket.

func NewClient

func NewClient(socketPath string) *Client

NewClient constructs a Client that dials the given unix socket on every request. The underlying http.Client uses a 10s default timeout.

func (*Client) Ban

func (c *Client) Ban(ctx context.Context, ip, rule string, ttl time.Duration) error

Ban posts to /ban.

func (*Client) Banned

func (c *Client) Banned(ctx context.Context) ([]BanInfo, error)

Banned retrieves /banned.

func (*Client) Reload

func (c *Client) Reload(ctx context.Context) error

Reload triggers a hot config reload on the daemon. Errors from validation, immutable-field checks, or runtime failures are returned verbatim from the daemon for the operator to see.

func (*Client) Rules

func (c *Client) Rules(ctx context.Context) ([]RuleInfo, error)

Rules retrieves /rules.

func (*Client) Status

func (c *Client) Status(ctx context.Context) (StatusResp, error)

Status retrieves /status.

func (*Client) Unban

func (c *Client) Unban(ctx context.Context, ip string) error

Unban posts to /unban.

type ErrorResp

type ErrorResp struct {
	Error string `json:"error"`
}

ErrorResp wraps an error message in a uniform shape.

type RuleInfo

type RuleInfo struct {
	Name      string         `json:"name"`
	Source    string         `json:"source"`
	Regex     string         `json:"regex,omitempty"`
	Threshold int            `json:"threshold"`
	FindTime  time.Duration  `json:"findtime"`
	BanTime   time.Duration  `json:"bantime"`
	Tracked   int            `json:"tracked"`
	Hits      uint64         `json:"hits"`
	Bans      uint64         `json:"bans"`
	Misses    uint64         `json:"misses"`
	Strikes   map[string]int `json:"strikes,omitempty"`
}

RuleInfo is one entry in GET /rules.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the unix-socket HTTP server.

func New

func New(state State, socketPath string, socketMode os.FileMode, log zerolog.Logger, audit *Audit) *Server

New constructs a Server. The socket file is created on Start. audit may be nil; when non-nil, successful /ban and /unban requests append a JSON line to the audit log.

func (*Server) Start

func (s *Server) Start(_ context.Context) error

Start listens on the unix socket and serves HTTP in a goroutine.

func (*Server) Stop

func (s *Server) Stop(ctx context.Context) error

Stop shuts the server down, closes the listener and removes the socket file.

type State

type State interface {
	Status() StatusResp
	Rules() []RuleInfo
	Banned(ctx context.Context) ([]BanInfo, error)
	Unban(ctx context.Context, ip netip.Addr) error
	BanManual(ctx context.Context, ip netip.Addr, rule string, ttl time.Duration) error
	// Reload re-reads config from disk and applies the diff atomically.
	// On any failure the running daemon is unchanged and the error is
	// returned for the operator to see.
	Reload(ctx context.Context) error
}

State is the read-only view of the daemon that the control server exposes.

type StatusResp

type StatusResp struct {
	Version    string    `json:"version"`
	Uptime     string    `json:"uptime"`
	StartedAt  time.Time `json:"started_at"`
	Watchers   int       `json:"watchers"`
	TotalBans  int       `json:"total_bans"`
	NumRules   int       `json:"num_rules"`
	NumSources int       `json:"num_sources"`
}

StatusResp is returned by GET /status.

type UnbanReq

type UnbanReq struct {
	IP string `json:"ip"`
}

UnbanReq is the body of POST /unban.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL