audit

package
v1.0.54 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Index

Constants

View Source
const (
	EnvAudit         = "DWS_AUDIT"
	EnvAuditDir      = "DWS_AUDIT_DIR"
	EnvRetentionDays = "DWS_AUDIT_RETENTION_DAYS"
	EnvForwardURL    = "DWS_AUDIT_FORWARD_URL"
	EnvForwardToken  = "DWS_AUDIT_FORWARD_TOKEN"
	EnvForwardRedact = "DWS_AUDIT_FORWARD_REDACT"
	EnvAuditDebug    = "DWS_AUDIT_DEBUG"
)

Variables

This section is empty.

Functions

func AuditFilesInRange

func AuditFilesInRange(dir, since, until string) ([]string, error)

func ComputeHash

func ComputeHash(prevHash string, eventJSON []byte) string

func DebugEnabled

func DebugEnabled() bool

DebugEnabled reports whether audit-subsystem diagnostics should be surfaced to stderr. Failures are always eligible for the structured log; this gates the noisier stderr channel.

func IsEnabled

func IsEnabled() bool

func LatestAuditFile

func LatestAuditFile(dir string) (string, error)

func RedactEventJSON

func RedactEventJSON(evt Event, level RedactLevel) ([]byte, error)

func VerifyFile

func VerifyFile(path string) (valid bool, brokenAt int, err error)

Types

type Actor

type Actor struct {
	UserID   string `json:"user_id"`
	Name     string `json:"name,omitempty"`
	CorpID   string `json:"corp_id"`
	CorpName string `json:"corp_name,omitempty"`
}

type Chain

type Chain struct{}

Chain computes the L1 sha256 tamper-evidence chain. It is deliberately stateless: every seal derives prev_hash from the last record already present in the current day's file rather than from an in-memory or sidecar cursor.

This makes the chain correct in two cases the previous global-sidecar design broke:

  • cross-date: each day rotates to a fresh file whose first record chains from "", so every file is independently verifiable by VerifyFile.
  • cross-process: because the caller holds an exclusive inter-process lock on the file while sealing, the tail read reflects records written by any other dws process, so concurrent writers cannot fork the chain.

func NewChain

func NewChain(string) *Chain

NewChain keeps the historical constructor signature. The directory argument is no longer needed because prev_hash is derived from the target file.

func (*Chain) SealFromFile

func (c *Chain) SealFromFile(f *os.File, body []byte) (prevHash, hash string, err error)

SealFromFile reads the hash of the last record in f (the current day's audit file) and returns the prev_hash / hash pair for the event whose hash-free body is provided. The caller must hold the file lock.

type DateRotatingWriter

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

func NewDateRotatingWriter

func NewDateRotatingWriter(dir string, retentionDays int) (*DateRotatingWriter, error)

func (*DateRotatingWriter) Close

func (w *DateRotatingWriter) Close() error

func (*DateRotatingWriter) Dir

func (w *DateRotatingWriter) Dir() string

type Event

type Event struct {
	Timestamp     time.Time `json:"ts"`
	ExecutionID   string    `json:"execution_id"`
	AgentID       string    `json:"agent_id,omitempty"`
	Actor         Actor     `json:"actor"`
	Product       string    `json:"product"`
	Command       string    `json:"command"`
	Endpoint      string    `json:"endpoint"`
	ParamsSummary string    `json:"params_summary,omitempty"`
	Result        string    `json:"result"`
	ErrCategory   string    `json:"error_category,omitempty"`
	ErrReason     string    `json:"error_reason,omitempty"`
	DurationMs    int64     `json:"duration_ms"`
	CLIVersion    string    `json:"cli_version"`
	OS            string    `json:"os"`
	Arch          string    `json:"arch"`
	PrevHash      string    `json:"prev_hash"`
	Hash          string    `json:"hash"`
}

func RedactEvent

func RedactEvent(evt Event, level RedactLevel) Event

type FileSink

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

func NewFileSink

func NewFileSink(writer *DateRotatingWriter, chain *Chain, forwarder *HTTPForwarder) *FileSink

func (*FileSink) Close

func (s *FileSink) Close() error

Close flushes in-flight remote forwards (bounded) before closing the writer, so events are not silently dropped when the CLI process exits right after emitting.

func (*FileSink) Emit

func (s *FileSink) Emit(evt *Event) error

type HTTPForwarder

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

func NewHTTPForwarder

func NewHTTPForwarder(url, token string, redact RedactLevel, report func(string, ...any)) *HTTPForwarder

func (*HTTPForwarder) Close

func (f *HTTPForwarder) Close(ctx context.Context) error

Close waits for in-flight forwards to finish, bounded by ctx (and, if ctx has no deadline, by a small internal timeout) so shutdown never blocks forever.

func (*HTTPForwarder) Forward

func (f *HTTPForwarder) Forward(evt Event)

Forward dispatches the event asynchronously while tracking the goroutine so Close can wait for delivery instead of the CLI dropping it on exit.

type NopSink

type NopSink struct{}

func (NopSink) Close

func (NopSink) Close() error

func (NopSink) Emit

func (NopSink) Emit(*Event) error

type RedactLevel

type RedactLevel string
const (
	RedactNone    RedactLevel = "none"
	RedactHashed  RedactLevel = "hashed"
	RedactMinimal RedactLevel = "minimal"
)

type Sink

type Sink interface {
	Emit(event *Event) error
	Close() error
}

func BuildSink

func BuildSink(configDir string, report func(format string, args ...any)) (Sink, error)

BuildSink constructs the audit sink for configDir. It returns an error when the audit subsystem is enabled but cannot initialize (e.g. the log directory is not writable) so the caller can surface the failure instead of silently degrading. report receives non-fatal forwarder diagnostics; it may be nil.

Jump to

Keyboard shortcuts

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