Help us shape the future of Go! Take the 2026 Go Developer Survey

handler

package
v1.10.0 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package handler provides the Forge-style HTTP admin API for the Chronicle audit trail library. It uses forge.Router with OpenAPI metadata decorators and typed request DTOs.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type API

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

API wires all Forge-style HTTP handlers together for the Chronicle system.

It starts no spans of its own. Forge already traces every route, and the work a route hands off (verifying a chain, taking a checkpoint, erasing a subject, enforcing retention, building a report) is traced where it runs, so the same spans appear whether the API, the dashboard or your own code called it.

func New

func New(deps Dependencies, router forge.Router) *API

New creates an API from handler dependencies and a Forge router.

func (*API) Handler

func (a *API) Handler() http.Handler

Handler returns the fully assembled http.Handler with all routes. Use this for standalone mode outside Forge.

func (*API) RegisterRoutes

func (a *API) RegisterRoutes(router forge.Router)

RegisterRoutes registers all Chronicle API routes into the given Forge router with full OpenAPI metadata.

type DeletePolicyRequest

type DeletePolicyRequest struct {
	PolicyID string `path:"id" description:"Policy ID"`
}

DeletePolicyRequest is the request for deleting a retention policy.

type Dependencies

type Dependencies struct {
	AuditStore  audit.Store
	VerifyStore verify.Store

	// StreamStore resolves a stream's owning app and tenant so chain
	// verification can confirm the caller owns the stream it names.
	StreamStore stream.Store

	ErasureStore erasure.Store

	// Erasure performs crypto-erasure: destroying the subject's key as well as
	// recording the request and flagging their events. Without it an erasure only
	// flags events, which is all that is possible when nothing encrypted them.
	Erasure *erasure.Service

	RetentionStore retention.Store
	ReportStore    compliance.ReportStore
	Compliance     *compliance.Engine
	Retention      *retention.Enforcer
	Logger         log.Logger

	// CheckpointStore persists signed checkpoints. Optional: when nil, the
	// checkpoint routes report 503 rather than panicking or 500ing, the same
	// way a nil Compliance engine does for the report routes.
	CheckpointStore checkpoint.Store

	// Checkpointer takes a signed checkpoint on demand for POST
	// /v1/checkpoints. Optional for the same reason as CheckpointStore: a
	// deployment that has not configured checkpointing still gets a working
	// API, just not that one write route.
	Checkpointer *checkpoint.Checkpointer

	// CheckpointSigner is what POST /v1/verify checks a covering
	// checkpoint's signature under. It has to be supplied alongside
	// CheckpointStore for the verify route to report checkpoints at all: a
	// store without a signer proves nothing, since anyone who can write the
	// checkpoint row could write a fabricated one.
	//
	// Optional, like the two above. Leave it nil and verification behaves
	// exactly as it did before checkpoints existed, with coverage topping
	// out at keyed.
	CheckpointSigner checkpoint.Signer

	// HashChain is the chain verification recomputes digests under. A
	// nil value here defaults to a zero-value, unkeyed chain, which is what
	// every deployment gets unless tamper_evidence.digest is "hmac". An HMAC
	// deployment that forgets to set this cannot verify anything at all, so
	// callers that have a keyed chain in hand should always pass it.
	HashChain *hash.Chain

	// Guards authenticate and authorise callers per operation class.
	//
	// A zero value leaves every route open to any caller that carries an app
	// scope, which only protects tenants from each other — it does not stop an
	// authenticated caller from purging their own app's audit history. The
	// extension refuses to mount an unguarded API unless the operator opts in.
	Guards Guards
}

Dependencies defines the handler dependencies.

type EventsByUserRequest

type EventsByUserRequest struct {
	UserID string `path:"userId" description:"User ID"`
	After  string `query:"after" optional:"true" description:"Events after this time (RFC3339)"`
	Before string `query:"before" optional:"true" description:"Events before this time (RFC3339)"`
	Limit  int    `query:"limit" optional:"true" description:"Maximum events to return"`
}

EventsByUserRequest is the request for fetching events by user.

type ExportReportRequest

type ExportReportRequest struct {
	ReportID string `path:"id" description:"Report ID"`
	Format   string `path:"format" description:"Export format: json, csv, markdown, html"`
}

ExportReportRequest is the request for exporting a report.

type ForceCheckpointRequest

type ForceCheckpointRequest struct {
	StreamID string `json:"stream_id" optional:"true" description:"Stream to checkpoint"`
}

ForceCheckpointRequest is the JSON request body for taking a checkpoint now.

StreamID is marked optional at the binding level, even though the handler requires it, so a request that omits it entirely still reaches the handler rather than failing forge's own required-field check first. That matters when the Checkpointer dependency itself is unset: the 503 for "checkpointing is not configured" needs to win over a 400 for a missing field the caller was never going to be told about anyway.

type GetCheckpointRequest

type GetCheckpointRequest struct {
	CheckpointID string `path:"id" description:"Checkpoint ID"`
}

GetCheckpointRequest is the request for fetching a single checkpoint.

type GetErasureRequest

type GetErasureRequest struct {
	ErasureID string `path:"id" description:"Erasure record ID"`
}

GetErasureRequest is the request for fetching a single erasure.

type GetEventRequest

type GetEventRequest struct {
	EventID string `path:"id" description:"Audit event ID"`
}

GetEventRequest is the request for fetching a single event.

type GetReportRequest

type GetReportRequest struct {
	ReportID string `path:"id" description:"Report ID"`
}

GetReportRequest is the request for fetching a single report.

type Guard

type Guard struct {
	// Middleware authenticates the caller and rejects insufficient permissions.
	// Nil means the route class is unprotected.
	Middleware forge.Middleware

	// Provider names the OpenAPI security scheme this guard authenticates with.
	Provider string

	// Scopes are the permissions Middleware enforces, recorded for documentation.
	Scopes []string
}

Guard protects one class of routes.

Middleware does the enforcing; Provider and Scopes exist so the generated OpenAPI spec describes the same requirement. A zero Guard leaves its routes unprotected, which is why [Guards.Validate] exists — the extension refuses to mount an unguarded API unless the operator opts in explicitly.

func (Guard) IsZero

func (g Guard) IsZero() bool

IsZero reports whether the guard enforces nothing.

type Guards

type Guards struct {
	Read  Guard
	Write Guard
	Admin Guard
}

Guards holds one guard per operation class, graded by blast radius.

  • Read covers everything that only observes: listing and fetching events, stats, reports, policies, archives, and chain verification.
  • Write covers creating records that do not destroy anything: saving a retention policy, generating a compliance report.
  • Admin covers the irreversible operations: enforcing retention (which purges events), deleting a policy, and requesting an erasure.

func (Guards) IsZero

func (g Guards) IsZero() bool

IsZero reports whether no class is protected at all.

func (Guards) Unprotected

func (g Guards) Unprotected() []string

Unprotected returns the names of the route classes that enforce nothing. The extension uses this to decide whether it may mount the API.

type ListArchivesRequest

type ListArchivesRequest struct {
	Limit  int `query:"limit" optional:"true" description:"Maximum results (default: 50)"`
	Offset int `query:"offset" optional:"true" description:"Number of results to skip"`
}

ListArchivesRequest is the request for listing archive records.

type ListErasuresRequest

type ListErasuresRequest struct {
	Limit  int `query:"limit" optional:"true" description:"Maximum results (default: 50)"`
	Offset int `query:"offset" optional:"true" description:"Number of results to skip"`
}

ListErasuresRequest is the request for listing erasure records.

type ListEventsRequest

type ListEventsRequest struct {
	Category string `query:"category" optional:"true" description:"Filter by category (comma-separated)"`
	Action   string `query:"action" optional:"true" description:"Filter by action (comma-separated)"`
	Severity string `query:"severity" optional:"true" description:"Filter by severity (comma-separated)"`
	Outcome  string `query:"outcome" optional:"true" description:"Filter by outcome (comma-separated)"`
	After    string `query:"after" optional:"true" description:"Events after this time (RFC3339)"`
	Before   string `query:"before" optional:"true" description:"Events before this time (RFC3339)"`
	Limit    int    `query:"limit" optional:"true" description:"Maximum results (default: 50, max: 1000)"`
	Offset   int    `query:"offset" optional:"true" description:"Number of results to skip"`
	Order    string `query:"order" optional:"true" description:"Sort order: asc or desc (default: desc)"`
}

ListEventsRequest is the request for listing audit events.

type ListReportsRequest

type ListReportsRequest struct {
	Limit  int `query:"limit" optional:"true" description:"Maximum results (default: 50)"`
	Offset int `query:"offset" optional:"true" description:"Number of results to skip"`
}

ListReportsRequest is the request for listing compliance reports.

type RequestErasureRequest

type RequestErasureRequest struct {
	SubjectID   string `json:"subject_id" description:"Subject ID to erase"`
	Reason      string `json:"reason" description:"Reason for erasure"`
	RequestedBy string `json:"requested_by" description:"Who requested the erasure"`
}

RequestErasureRequest is the JSON request body for creating an erasure.

type SavePolicyRequest

type SavePolicyRequest struct {
	Category string `json:"category" description:"Event category to apply retention to"`
	Duration string `json:"duration" description:"Retention duration (Go duration string, e.g. 720h)"`
	Archive  bool   `json:"archive" description:"Whether to archive events before purging"`
}

SavePolicyRequest is the JSON request body for saving a retention policy.

type StatsResponse

type StatsResponse struct {
	TotalEvents  int64                  `json:"total_events"`
	Categories   []audit.AggregateGroup `json:"categories"`
	Severities   []audit.AggregateGroup `json:"severities"`
	Outcomes     []audit.AggregateGroup `json:"outcomes"`
	RecentEvents []*audit.Event         `json:"recent_events"`
}

StatsResponse contains aggregate audit event statistics.

type VerifyChainRequest

type VerifyChainRequest struct {
	StreamID string `json:"stream_id" description:"Stream ID to verify"`
	FromSeq  uint64 `json:"from_seq" description:"Starting sequence number"`
	ToSeq    uint64 `json:"to_seq" description:"Ending sequence number"`
}

VerifyChainRequest is the JSON request body for chain verification.

Jump to

Keyboard shortcuts

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