Documentation
¶
Overview ¶
Package internal provides audit logging functionality.
Package internal provides shared internal types and utilities.
Package internal provides variable expansion with security limits.
Package internal provides file I/O utilities.
Package internal provides internal interfaces for dependency injection.
Package internal provides JSON flattening utilities.
Package internal provides key validation utilities.
Package internal provides security limits for the env package.
Package internal provides internal struct marshaling utilities.
Package internal provides internal line parsing utilities.
Package internal provides path resolution utilities for dot-notation key access.
Package internal provides path validation utilities for secure file access.
Package internal provides shared resource pools for the env package.
Package internal provides secure io.Reader implementations with security limits.
Package internal provides sensitive key detection and masking utilities.
Package internal provides input validation for environment variable keys and values.
Package internal provides YAML flattening utilities.
Package internal provides YAML lexing utilities.
Package internal provides YAML parsing utilities.
Index ¶
- Constants
- Variables
- func ClearInternCache()
- func DefaultMaskKey(key string) string
- func DetectCycle(vars map[string]string) (string, bool)
- func EscapeValue(value string) string
- func ExtractNumericIndex(path string) (basePath string, index int, ok bool)
- func FlattenJSON(data []byte, cfg JSONFlattenConfig) (map[string]string, error)
- func FlattenYAML(value *Value, cfg YAMLFlattenConfig) (map[string]string, error)
- func GetBuilder() *strings.Builder
- func GetByteSlice() *[]byte
- func HashKey(key string, numShards int) uint32
- func InternKey(key string) string
- func IsASCII(s string) bool
- func IsKey(key string) bool
- func IsValidJSONKey(key string) bool
- func IsYamlNumber(s string) bool
- func IsYamlNumberBytes(s []byte) bool
- func KeysToUpper(m map[string]string) map[string]bool
- func KeysToUpperPooled(m map[string]string) map[string]bool
- func LockMemory(data []byte) error
- func MarshalEnv(m map[string]string, sorted bool) (string, error)
- func MarshalEnvAs(m map[string]string, format MarshalFormat, sorted bool) (string, error)
- func MaskInString(s string) string
- func MaskKey(key string) string
- func MaskValue(key, value string) string
- func MemLockSupported() bool
- func ParseDoubleQuoted(value string) (string, error)
- func ParseDoubleQuotedBytes(value []byte) (string, error)
- func ParseSingleQuoted(value string) (string, error)
- func ParseSingleQuotedBytes(value []byte) (string, error)
- func PutBuilder(sb *strings.Builder)
- func PutByteSlice(buf *[]byte)
- func PutKeysToUpperMap(m map[string]bool)
- func ResolvePath(path string) []string
- func SanitizeForLog(s string) string
- func Struct(v interface{}, prefix string) (map[string]string, error)
- func StructInto(data map[string]string, val reflect.Value, prefix string) error
- func ToUpperASCII(s string) string
- func ToUpperASCIISafe(s string) (string, error)
- func TrimSpace(s string) string
- func TryParseYamlValue(value string) (string, bool)
- func TryParseYamlValueBytes(value []byte) (string, bool)
- func UnlockMemory(data []byte)
- func ValidateFilePath(filename string) error
- func WriteFile(filename string, buf *bytes.Buffer) (err error)
- type Action
- type AuditLogger
- type Auditor
- func (a *Auditor) Close() error
- func (a *Auditor) IsEnabled() bool
- func (a *Auditor) Log(action Action, key, reason string, success bool) error
- func (a *Auditor) LogError(action Action, key, errMsg string) error
- func (a *Auditor) LogSecurity(key, reason string) error
- func (a *Auditor) LogWithDuration(action Action, key, reason string, success bool, duration time.Duration) error
- func (a *Auditor) LogWithFile(action Action, key, file, reason string, success bool) error
- func (a *Auditor) SetEnabled(enabled bool)
- type BufferedHandler
- type BufferedHandlerConfig
- type ChannelHandler
- type CloseableChannelHandler
- type Dependencies
- type Event
- type Expander
- type ExpanderConfig
- type ExpansionError
- type FileError
- type Handler
- type IsSensitiveFunc
- type JSONError
- type JSONFlattenConfig
- type JSONHandler
- type KeyValidator
- type Lexer
- type LineAuditLogger
- type LineExpander
- type LineKeyValidator
- type LineParser
- func (p *LineParser) ExpandAll(vars map[string]string) (map[string]string, error)
- func (p *LineParser) ParseLine(line string) (string, string, error)
- func (p *LineParser) ParseLineBytes(line []byte) (string, string, error)
- func (p *LineParser) ParseValue(value string) (string, error)
- func (p *LineParser) ParseValueBytes(value []byte) (string, error)
- func (p *LineParser) SetValueValidator(v LineValueValidator)
- type LineParserConfig
- type LineParserDependencies
- type LineValueValidator
- type LogHandler
- type MarshalError
- type MarshalFormat
- type MaskerFunc
- type Mode
- type NopHandler
- type ParseError
- type Parser
- type PathValidator
- type PathValidatorConfig
- type SecureReader
- type SecurityError
- type Token
- type TokenType
- type ValidationError
- type Validator
- func (v *Validator) IsSensitive(key string) bool
- func (v *Validator) MaskValue(key, value string) string
- func (v *Validator) ShouldMask(key string) bool
- func (v *Validator) ValidateKey(key string) error
- func (v *Validator) ValidateRequired(keys map[string]bool) error
- func (v *Validator) ValidateValue(value string) error
- type ValidatorConfig
- type Value
- type ValueType
- type ValueValidator
- type VariableExpander
- type YAMLError
- type YAMLFlattenConfig
Constants ¶
const ( DefaultBufferSize = 100 DefaultFlushInterval = 5 * time.Second )
Default values for BufferedHandler.
const ( // DefaultMaxFileSize is the maximum allowed file size (2 MB). DefaultMaxFileSize int64 = 2 * 1024 * 1024 // DefaultMaxLineLength is the maximum allowed line length. DefaultMaxLineLength int = 1024 // DefaultMaxKeyLength is the maximum allowed key length. DefaultMaxKeyLength int = 64 // DefaultMaxValueLength is the maximum allowed value length. DefaultMaxValueLength int = 4096 // DefaultMaxVariables is the maximum number of variables per file. DefaultMaxVariables int = 500 // DefaultMaxExpansionDepth is the maximum variable expansion depth. DefaultMaxExpansionDepth int = 5 )
Default security limits for high-security configurations. These values are intentionally conservative to prevent various attacks.
const ( // HardMaxFileSize is the absolute maximum file size (100 MB). HardMaxFileSize int64 = 100 * 1024 * 1024 // HardMaxLineLength is the absolute maximum line length. HardMaxLineLength int = 64 * 1024 // HardMaxKeyLength is the absolute maximum key length. HardMaxKeyLength int = 1024 // HardMaxValueLength is the absolute maximum value length. HardMaxValueLength int = 1024 * 1024 // HardMaxVariables is the absolute maximum variables per file. HardMaxVariables int = 10000 // HardMaxExpansionDepth is the absolute maximum expansion depth. HardMaxExpansionDepth int = 20 )
Hard security limits that cannot be exceeded. These are absolute maximums for safety and are used across all packages.
const ( // MaxPooledBuilderSize is the maximum capacity for pooled strings.Builder objects. // Builders larger than this are discarded instead of pooled. MaxPooledBuilderSize = 16 * 1024 // 16KB // MaxPooledScannerBufferSize is the maximum capacity for pooled scanner buffers. // Buffers larger than this are discarded instead of pooled. MaxPooledScannerBufferSize = 256 * 1024 // 256KB // MaxPooledByteSliceSize is the maximum capacity for pooled byte slices. // Slices larger than this are discarded instead of pooled. MaxPooledByteSliceSize = 4096 // 4KB // MaxPooledMapSize is the maximum size for pooled map objects. // Maps with more entries than this are discarded instead of pooled. MaxPooledMapSize = 128 )
Pool size limits for sync.Pool objects. Objects larger than these limits are not returned to pools to prevent memory bloat from holding onto large allocations.
Variables ¶
var ( // ErrFileTooLarge indicates the file exceeds the maximum allowed size. ErrFileTooLarge = fmt.Errorf("file exceeds maximum size limit") // ErrLineTooLong indicates a line exceeds the maximum allowed length. ErrLineTooLong = fmt.Errorf("line exceeds maximum length limit") // ErrInvalidValue indicates a value is invalid. ErrInvalidValue = errors.New("invalid value content") // ErrSecurityViolation indicates a security policy violation. ErrSecurityViolation = errors.New("security policy violation") )
Sentinel errors used by internal packages.
var DefaultPathValidator = NewPathValidator(PathValidatorConfig{})
DefaultPathValidator is the default path validator instance. It uses the default key masking function.
var ErrNonASCII = errors.New("string contains non-ASCII characters")
ErrNonASCII is returned when a string contains non-ASCII characters in functions that require ASCII-only input.
var Patterns = []string{
"PASSWORD",
"SECRET",
"TOKEN",
"AUTH",
"CREDENTIAL",
"PASSPHRASE",
"SESSION",
"COOKIE",
"API_KEY",
"APIKEY",
"ACCESS_KEY",
"SECRET_KEY",
"PRIVATE_KEY",
"PUBLIC_KEY",
"PRIVATE",
"ENCRYPTION_KEY",
"ENCRYPT_KEY",
"DECRYPT_KEY",
"SIGNING_KEY",
"SIGN_KEY",
"VERIFY_KEY",
"SSN",
"SOCIAL_SECURITY",
"CREDIT_CARD",
"CARD_NUMBER",
"CVV",
"CVC",
"CCV",
"PAN",
"MNEMONIC",
"SEED",
"RECOVERY",
"WALLET",
"PRIVATE_ADDRESS",
"CONNECTION_STRING",
"CONN_STRING",
"DATABASE_URL",
"DB_PASSWORD",
"AWS_SECRET",
"AZURE_KEY",
"GCP_KEY",
"SERVICE_ACCOUNT",
}
Patterns defines patterns that indicate sensitive data. This is the single source of truth for sensitive key detection. Keys containing these patterns (case-insensitive) will be masked in logs and errors.
Functions ¶
func ClearInternCache ¶
func ClearInternCache()
ClearInternCache clears the key interning cache. This is useful for long-running applications that want to release memory held by cached keys that are no longer needed. This function is safe for concurrent use.
func DefaultMaskKey ¶ added in v1.1.0
DefaultMaskKey masks a key name for safe logging and error reporting. Shows only the first 2 characters followed by "***" for keys longer than 3 characters. This is the default masking function used by validators and path validators.
func DetectCycle ¶
DetectCycle checks if expanding the given variables would cause a cycle. Returns the key that causes the cycle and true if a cycle is detected.
func EscapeValue ¶
EscapeValue escapes a value for .env file format. This function uses pooled builder for efficiency.
func ExtractNumericIndex ¶
ExtractNumericIndex extracts a numeric index from the end of a path. Returns: (basePath, index, true) if path ends with numeric index Returns: ("", -1, false) otherwise
Examples:
"servers.0" -> ("servers", 0, true)
"service.cors.origins.0" -> ("service.cors.origins", 0, true)
"database.host" -> ("", -1, false)
func FlattenJSON ¶
func FlattenJSON(data []byte, cfg JSONFlattenConfig) (map[string]string, error)
FlattenJSON converts nested JSON data to a flat map of string key-value pairs. Keys are converted to uppercase with the configured delimiter.
func FlattenYAML ¶
func FlattenYAML(value *Value, cfg YAMLFlattenConfig) (map[string]string, error)
FlattenYAML converts a YAML Value tree to a flat map of string key-value pairs. Keys are converted to uppercase with the configured delimiter.
func GetBuilder ¶
GetBuilder retrieves a strings.Builder from the shared pool. Returns a fallback builder if the pool returns an unexpected type.
func GetByteSlice ¶
func GetByteSlice() *[]byte
GetByteSlice retrieves a byte slice from the pool. Returns a fallback slice if the pool returns an unexpected type.
func HashKey ¶
HashKey returns a hash value for the given key using an optimized algorithm. For short keys (<=8 chars), uses a simple multiplicative hash. For longer keys, uses FNV-1a with sampling for better performance. The numShards parameter determines the range of the returned hash (0 to numShards-1).
Performance optimizations: - Uses branchless bit manipulation for keys 1-4 chars (most common case) - Avoids conditional branches in the hot path - Single optimization point for numShards==8 at function exit
func InternKey ¶
InternKey returns an interned copy of the key string if available, or stores and returns the input key. This reduces allocations when the same keys are parsed repeatedly. This implementation uses sharded caches with thread-safe access for better concurrency performance.
Optimization: Uses sync.Mutex instead of sync.RWMutex because: 1. The cache is small (128 entries per shard), making lookup very fast 2. RWMutex has higher overhead for the common case of cache hit + small cache 3. Simpler lock management improves cache locality
SECURITY: This function maintains strict consistency between the cache map and order slice to prevent memory leaks and ensure correct FIFO eviction.
func IsASCII ¶ added in v1.1.0
IsASCII checks if a string contains only ASCII characters (bytes < 0x80). This is a fast path function used for input validation.
func IsKey ¶
IsKey determines if a key likely contains sensitive data. Uses byte-level comparison to avoid allocations from strings.ToUpper.
func IsValidJSONKey ¶
IsValidJSONKey checks if a key matches the JSON key pattern ^[A-Za-z0-9_@\-.]+$ This is faster than using regex for the common case. Allowed characters: letters, digits, underscore, at-sign, hyphen, dot. Note: Square brackets are NOT allowed to prevent key name confusion and ambiguity with array index notation.
func IsYamlNumber ¶
IsYamlNumber checks if a string is a valid YAML number.
func IsYamlNumberBytes ¶
IsYamlNumberBytes checks if a byte slice is a valid YAML number.
func KeysToUpper ¶
KeysToUpper converts map keys to uppercase for comparison. This function is optimized to minimize allocations. The caller owns the returned map and does not need to return it to a pool.
func KeysToUpperPooled ¶
KeysToUpperPooled converts map keys to uppercase using a pooled map. The returned map MUST be returned to the pool using PutKeysToUpperMap after use. This reduces allocations when the map is only needed temporarily.
Example:
upperKeys := KeysToUpperPooled(vars) defer PutKeysToUpperMap(upperKeys) // use upperKeys...
func LockMemory ¶
LockMemory locks the specified memory region using mlock. This prevents the memory from being swapped to disk.
func MarshalEnv ¶
MarshalEnv converts a map to .env file format.
func MarshalEnvAs ¶
MarshalEnvAs converts a map to the specified format.
func MaskInString ¶
MaskInString masks potentially sensitive content in a string.
func MaskValue ¶
MaskValue masks a value based on its sensitivity. This is a utility function for general value masking.
func ParseDoubleQuoted ¶
ParseDoubleQuoted handles double-quoted values with escape sequences.
func ParseDoubleQuotedBytes ¶
ParseDoubleQuotedBytes handles double-quoted values from a byte slice with escape sequences.
func ParseSingleQuoted ¶
ParseSingleQuoted handles single-quoted values (no escape processing).
func ParseSingleQuotedBytes ¶
ParseSingleQuotedBytes handles single-quoted values from a byte slice (no escape processing).
func PutBuilder ¶
PutBuilder returns a strings.Builder to the shared pool. Builders with capacity exceeding MaxPooledBuilderSize are discarded to prevent memory bloat. The builder is reset before returning to pool for hygiene and to allow GC to reclaim the previous string data.
SECURITY LIMITATION: strings.Builder does not expose its internal buffer, so we cannot directly clear the contents before pooling. However, the data will be overwritten when the builder is reused. For environments requiring strict data clearing, consider not using the pool for sensitive operations. The Go standard library guarantees that Reset() only sets len to 0, preserving the underlying buffer capacity.
func PutByteSlice ¶
func PutByteSlice(buf *[]byte)
PutByteSlice returns a byte slice to the pool. Slices with capacity exceeding MaxPooledByteSliceSize are discarded.
SECURITY NOTE: This function clears the slice contents before pooling to prevent sensitive data from persisting in pooled buffers. This is important because byte slices may contain parsed environment variable values. The capacity check is performed after clearing to prevent memory bloat.
func PutKeysToUpperMap ¶
PutKeysToUpperMap returns a pooled map obtained from KeysToUpperPooled. It is safe to call with nil.
func ResolvePath ¶
ResolvePath converts a dot-notation path to candidate storage keys. It is used to look up nested values that were flattened during JSON/YAML parsing.
For dot-notation paths (containing "."):
- Returns only the converted uppercase storage keys
- "database.host" -> ["DATABASE_HOST"]
- "servers.0.host" -> ["SERVERS_0_HOST", "SERVERS[0]_HOST"]
For simple keys (no dots):
- Returns both the original key and uppercase version
- "HOST" -> ["HOST", "HOST"] (same key)
- "host" -> ["host", "HOST"] (try original first, then uppercase)
Note: For simple keys, callers should use direct Get() with the key and its uppercase version to avoid this allocation entirely.
SECURITY: Paths exceeding HardMaxKeyLength are rejected to prevent memory exhaustion attacks.
func SanitizeForLog ¶
SanitizeForLog removes potentially sensitive information from a string. It scans for patterns that might indicate sensitive data and masks them.
Performance: Uses single-pass scanning with strings.Builder to avoid O(n*m) complexity from multiple string scans and allocations.
func Struct ¶
Struct converts a struct to environment variables. Struct fields can be tagged with `env:"KEY"` to specify the env variable name. Nested structs are flattened with underscore-separated keys.
func StructInto ¶
StructInto populates a struct from environment variables. Struct fields can be tagged with `env:"KEY"` to specify the env variable name. Optional `envDefault:"value"` sets a default if the key is not found. Also supports inline format: `env:"KEY,envDefault:VALUE"`.
func ToUpperASCII ¶
ToUpperASCII converts an ASCII string to uppercase. This is faster than strings.ToUpper for ASCII-only strings. Uses single-pass algorithm: convert while detecting lowercase. Returns the uppercase string (shares backing array if already uppercase).
SECURITY WARNING: This function is designed for ASCII-only input. Non-ASCII bytes (>= 0x80) are passed through unchanged without validation. Callers must validate input if ASCII-only keys are required for security. For environment variable keys, this is acceptable because: 1. Environment variable names are conventionally ASCII 2. Key validation elsewhere rejects non-ASCII keys 3. Visual spoofing attacks with Unicode are mitigated by key pattern validation
For use cases requiring strict ASCII validation, use ToUpperASCIISafe instead.
func ToUpperASCIISafe ¶ added in v1.1.0
ToUpperASCIISafe converts an ASCII string to uppercase with strict ASCII validation. Returns ErrNonASCII if the input contains any bytes >= 0x80. This is the safe version of ToUpperASCII for use when input validation is required.
Performance: This function has minimal overhead compared to ToUpperASCII (single additional bounds check per character that was already being performed).
func TrimSpace ¶
TrimSpace trims leading and trailing whitespace from a string. This is an optimized version that returns the original string if no trimming is needed, avoiding allocation in the common case where values are already trimmed.
func TryParseYamlValue ¶
TryParseYamlValue attempts to parse YAML-style values.
func TryParseYamlValueBytes ¶
TryParseYamlValueBytes attempts to parse YAML-style values from a byte slice.
func UnlockMemory ¶
func UnlockMemory(data []byte)
UnlockMemory unlocks the specified memory region using munlock.
func ValidateFilePath ¶ added in v1.1.0
ValidateFilePath validates a file path using the default validator. This is a convenience function for backward compatibility.
Types ¶
type Action ¶
type Action string
Action represents the type of action being audited.
const ( ActionLoad Action = "load" ActionParse Action = "parse" ActionGet Action = "get" ActionSet Action = "set" ActionDelete Action = "delete" ActionValidate Action = "validate" ActionExpand Action = "expand" ActionSecurity Action = "security" ActionError Action = "error" ActionFileAccess Action = "file_access" )
Audit action constants.
type AuditLogger ¶ added in v1.1.0
AuditLogger records audit events.
type Auditor ¶
type Auditor struct {
// contains filtered or unexported fields
}
Auditor provides audit logging functionality.
func NewAuditor ¶
func NewAuditor(handler Handler, isSensitive IsSensitiveFunc, masker MaskerFunc, enabled bool) *Auditor
NewAuditor creates a new Auditor with the specified handler.
func (*Auditor) LogSecurity ¶
LogSecurity records a security-related event.
func (*Auditor) LogWithDuration ¶
func (a *Auditor) LogWithDuration(action Action, key, reason string, success bool, duration time.Duration) error
LogWithDuration records an audit event with timing information.
func (*Auditor) LogWithFile ¶
LogWithFile records an audit event with file information.
func (*Auditor) SetEnabled ¶
SetEnabled enables or disables audit logging.
type BufferedHandler ¶
type BufferedHandler struct {
// contains filtered or unexported fields
}
BufferedHandler buffers audit events and writes them in batches. This significantly reduces I/O overhead for high-frequency operations.
Features:
- Batched writes reduce system call overhead
- Time-based auto-flush ensures events are written promptly
- Thread-safe for concurrent use
- Graceful shutdown on Close()
Example:
underlying := NewJSONHandler(file)
buffered := NewBufferedHandler(BufferedHandlerConfig{
Handler: underlying,
BufferSize: 100,
FlushInterval: 5 * time.Second,
})
defer buffered.Close()
func NewBufferedHandler ¶
func NewBufferedHandler(cfg BufferedHandlerConfig) *BufferedHandler
NewBufferedHandler creates a new BufferedHandler with the given configuration.
func (*BufferedHandler) BufferLen ¶
func (h *BufferedHandler) BufferLen() int
BufferLen returns the current number of events in the buffer.
func (*BufferedHandler) Close ¶
func (h *BufferedHandler) Close() error
Close flushes any remaining events and stops the background flush goroutine.
func (*BufferedHandler) Flush ¶
func (h *BufferedHandler) Flush() error
Flush writes all buffered events to the underlying handler. It clears the buffer after successful write. This method is safe for concurrent use.
func (*BufferedHandler) IsFull ¶
func (h *BufferedHandler) IsFull() bool
IsFull returns true if the buffer is at capacity.
func (*BufferedHandler) Log ¶
func (h *BufferedHandler) Log(event Event) error
Log adds an event to the buffer. If the buffer is full, it triggers an automatic flush.
func (*BufferedHandler) RequestFlush ¶
func (h *BufferedHandler) RequestFlush()
RequestFlush signals that a flush should be performed soon. This is useful for triggering a flush from another goroutine without waiting for the flush to complete.
type BufferedHandlerConfig ¶
type BufferedHandlerConfig struct {
// Handler is the underlying handler to write to (required)
Handler Handler
// BufferSize is the maximum number of events to buffer before auto-flush
// Default: 100
BufferSize int
// FlushInterval is the maximum time to wait before auto-flush
// Set to 0 to disable time-based auto-flush
// Default: 5 seconds
FlushInterval time.Duration
// OnError is called when an error occurs during flush
// If nil, errors are silently ignored
OnError func(error)
}
BufferedHandlerConfig holds configuration for BufferedHandler.
type ChannelHandler ¶
type ChannelHandler struct {
// contains filtered or unexported fields
}
ChannelHandler sends audit events to a channel.
Channel Ownership: This handler does NOT own the channel. The caller is responsible for closing the channel when done. The handler's Close() method does nothing because closing a send-only channel (chan<-) would panic if the caller hasn't finished receiving.
Blocking Behavior: This handler blocks if the channel buffer is full. Use a buffered channel if non-blocking behavior is required.
Example:
ch := make(chan Event, 100)
handler := NewChannelHandler(ch)
// Start consumer goroutine
go func() {
for event := range ch {
process(event)
}
}()
// ... use handler ...
handler.Close() // Does NOT close ch
close(ch) // Caller must close the channel to signal EOF to receiver
func NewChannelHandler ¶
func NewChannelHandler(ch chan<- Event) *ChannelHandler
NewChannelHandler creates a new ChannelHandler that sends events to the provided channel. The caller retains ownership of the channel and must close it when finished to signal EOF to receivers.
func (*ChannelHandler) Close ¶
func (h *ChannelHandler) Close() error
Close implements Handler. NOTE: This method does NOT close the underlying channel because the handler does not own it. The caller must close the channel separately.
func (*ChannelHandler) Log ¶
func (h *ChannelHandler) Log(event Event) error
Log sends an audit event to the channel. This method blocks if the channel is full.
type CloseableChannelHandler ¶
type CloseableChannelHandler struct {
// contains filtered or unexported fields
}
CloseableChannelHandler sends audit events to a channel and owns the channel lifecycle. Unlike ChannelHandler, this handler creates its own channel and closes it when Close() is called.
This is useful when you want the handler to manage the complete lifecycle of the channel, ensuring receivers are properly signaled when the handler is closed.
Example:
handler := NewCloseableChannelHandler(100)
// Get the channel for receiving
ch := handler.Channel()
// Start consumer goroutine
go func() {
for event := range ch {
process(event)
}
fmt.Println("Channel closed, consumer exiting")
}()
// ... use handler ...
handler.Close() // Closes the channel, consumer goroutine exits gracefully
func NewCloseableChannelHandler ¶
func NewCloseableChannelHandler(bufferSize int) *CloseableChannelHandler
NewCloseableChannelHandler creates a new CloseableChannelHandler with a buffered channel of the specified size. The handler owns the channel and will close it when Close() is called.
func (*CloseableChannelHandler) Channel ¶
func (h *CloseableChannelHandler) Channel() <-chan Event
Channel returns the underlying channel for receiving events. The returned channel will be closed when Close() is called.
func (*CloseableChannelHandler) Close ¶
func (h *CloseableChannelHandler) Close() error
Close implements Handler. Closes the underlying channel, signaling to any receivers that no more events will be sent. Safe to call multiple times.
func (*CloseableChannelHandler) IsClosed ¶
func (h *CloseableChannelHandler) IsClosed() bool
IsClosed returns true if the handler has been closed.
func (*CloseableChannelHandler) Log ¶
func (h *CloseableChannelHandler) Log(event Event) (err error)
Log sends an audit event to the channel. Returns an error if the handler has been closed. This method blocks if the channel is full. Uses recover to safely handle the race between Log and Close.
type Dependencies ¶ added in v1.1.0
type Dependencies interface {
KeyValidator
ValueValidator
VariableExpander
AuditLogger
}
Dependencies combines all parser dependencies.
type Event ¶
type Event struct {
Timestamp time.Time `json:"timestamp"`
Action Action `json:"action"`
Key string `json:"key,omitempty"`
File string `json:"file,omitempty"`
Reason string `json:"reason,omitempty"`
Success bool `json:"success"`
Masked bool `json:"masked,omitempty"`
Details string `json:"details,omitempty"`
Duration int64 `json:"duration_ns,omitempty"`
}
Event represents a single audit log entry.
type Expander ¶
type Expander struct {
// contains filtered or unexported fields
}
Expander handles variable expansion with security limits.
func NewExpander ¶
func NewExpander(cfg ExpanderConfig) *Expander
NewExpander creates a new Expander with the specified configuration.
func (*Expander) ExpandAllInMap ¶ added in v1.1.0
ExpandAllInMap expands all variables in a map using this expander. This is the primary method for batch expansion, used by parsers.
The method: 1. Checks if any values need expansion (fast path for no variables) 2. Detects cycles to prevent infinite loops 3. Expands all values recursively
Returns the original map if no expansion is needed, avoiding allocations.
type ExpanderConfig ¶
type ExpanderConfig struct {
MaxDepth int
Lookup func(string) (string, bool)
Mode Mode
KeyPattern *regexp.Regexp // For key validation
}
ExpanderConfig holds configuration for creating a new Expander.
type ExpansionError ¶
type ExpansionError struct {
Key string // The key being expanded
Depth int // The current expansion depth
Limit int // The maximum allowed depth
Chain string // The expansion chain (sanitized)
}
ExpansionError provides detailed information about variable expansion failures.
func (*ExpansionError) Error ¶
func (e *ExpansionError) Error() string
Error implements the error interface. SECURITY: Key names are masked to prevent sensitive information leakage. Only the first 2 characters of the key are shown followed by "***".
type FileError ¶
type FileError struct {
Path string // The file path
Op string // The operation that failed (open, read, stat)
Err error // The underlying error
Size int64 // File size if relevant
Limit int64 // The limit that was exceeded if relevant
}
FileError provides detailed information about file-related errors.
type Handler ¶
Handler defines the interface for audit log handlers.
func DefaultHandler ¶
func DefaultHandler() Handler
DefaultHandler returns the default audit handler (writes to stderr).
type IsSensitiveFunc ¶
IsSensitiveFunc is a function type that determines if a key is sensitive.
type JSONFlattenConfig ¶
type JSONFlattenConfig struct {
// KeyDelimiter is the delimiter for nested keys (default: "_").
KeyDelimiter string
// ArrayIndexFormat controls how array indices are formatted.
// "underscore": KEY_0, KEY_1, etc.
ArrayIndexFormat string
// NullAsEmpty converts null values to empty strings (default: true).
NullAsEmpty bool
// NumberAsString converts numbers to strings (default: true).
NumberAsString bool
// BoolAsString converts booleans to strings (default: true).
BoolAsString bool
// MaxDepth limits the maximum nesting depth to prevent stack overflow.
MaxDepth int
}
JSONFlattenConfig holds configuration for JSON flattening.
type JSONHandler ¶
type JSONHandler struct {
// contains filtered or unexported fields
}
JSONHandler writes audit events as JSON to an io.Writer.
func NewJSONHandler ¶
func NewJSONHandler(w io.Writer) *JSONHandler
NewJSONHandler creates a new JSONHandler.
func (*JSONHandler) Log ¶
func (h *JSONHandler) Log(event Event) error
Log writes an audit event as JSON.
type KeyValidator ¶ added in v1.1.0
KeyValidator validates environment variable keys.
type Lexer ¶
type Lexer struct {
// contains filtered or unexported fields
}
Lexer tokenizes YAML input.
type LineAuditLogger ¶ added in v1.1.0
type LineAuditLogger = AuditLogger
Type aliases for backward compatibility with existing internal code.
type LineExpander ¶ added in v1.1.0
type LineExpander = VariableExpander
Type aliases for backward compatibility with existing internal code.
type LineKeyValidator ¶ added in v1.1.0
type LineKeyValidator = KeyValidator
Type aliases for backward compatibility with existing internal code.
type LineParser ¶
type LineParser struct {
// contains filtered or unexported fields
}
LineParser handles parsing of individual lines.
func NewLineParser ¶
func NewLineParser(cfg LineParserConfig, keyValidator LineKeyValidator, auditor LineAuditLogger, expander LineExpander) *LineParser
NewLineParser creates a new LineParser. The validators, auditor, and expander parameters accept interfaces rather than concrete types, allowing for better testability and flexibility. For the keyValidator parameter, you can pass the same object as valueValidator if it implements both interfaces.
func (*LineParser) ExpandAll ¶
ExpandAll expands all variables in the map. Returns the original map if no expansion is needed, avoiding unnecessary allocations. This method delegates to Expander.ExpandAllInMap for the actual expansion logic.
func (*LineParser) ParseLine ¶
func (p *LineParser) ParseLine(line string) (string, string, error)
ParseLine parses a single line and returns the key and value.
func (*LineParser) ParseLineBytes ¶
func (p *LineParser) ParseLineBytes(line []byte) (string, string, error)
ParseLineBytes parses a single line from a byte slice and returns the key and value. This version avoids string allocation by working directly with bytes.
func (*LineParser) ParseValue ¶
func (p *LineParser) ParseValue(value string) (string, error)
ParseValue parses a value handling quotes and escapes.
func (*LineParser) ParseValueBytes ¶
func (p *LineParser) ParseValueBytes(value []byte) (string, error)
ParseValueBytes parses a value from a byte slice handling quotes and escapes. This version avoids string allocation until the final result.
func (*LineParser) SetValueValidator ¶ added in v1.1.0
func (p *LineParser) SetValueValidator(v LineValueValidator)
SetValueValidator sets a separate value validator if needed. This is useful when key and value validation are handled by different objects.
type LineParserConfig ¶
type LineParserConfig struct {
AllowExportPrefix bool
AllowYamlSyntax bool
OverwriteExisting bool
MaxVariables int
ExpandVariables bool
}
LineParserConfig holds the configuration needed for parsing.
type LineParserDependencies ¶ added in v1.1.0
type LineParserDependencies = Dependencies
Type aliases for backward compatibility with existing internal code.
type LineValueValidator ¶ added in v1.1.0
type LineValueValidator = ValueValidator
Type aliases for backward compatibility with existing internal code.
type LogHandler ¶
type LogHandler struct {
// contains filtered or unexported fields
}
LogHandler writes audit events using the standard log package.
func NewLogHandler ¶
func NewLogHandler(logger *log.Logger) *LogHandler
NewLogHandler creates a new LogHandler.
func (*LogHandler) Log ¶
func (h *LogHandler) Log(event Event) error
Log writes an audit event using the logger.
type MarshalError ¶
MarshalError represents a marshaling/unmarshaling error.
func (*MarshalError) Error ¶
func (e *MarshalError) Error() string
Error implements the error interface.
type MarshalFormat ¶
type MarshalFormat int
MarshalFormat represents the output format for marshaling.
const ( // FormatEnv outputs in .env file format. FormatEnv MarshalFormat = iota // FormatJSON outputs in JSON format. FormatJSON // FormatYAML outputs in YAML format. FormatYAML )
type MaskerFunc ¶
MaskerFunc is a function type that masks a key-value pair.
type ParseError ¶
type ParseError struct {
File string // The file being parsed (if applicable)
Line int // The line number where the error occurred
Content string // Sanitized content (sensitive data masked)
Err error // The underlying error
}
ParseError provides detailed information about parsing failures.
func (*ParseError) Error ¶
func (e *ParseError) Error() string
Error implements the error interface.
func (*ParseError) Unwrap ¶
func (e *ParseError) Unwrap() error
Unwrap returns the underlying error for errors.Is() and errors.As().
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser parses YAML tokens into a Value tree.
func NewYAMLParser ¶
NewYAMLParser creates a new YAML parser.
type PathValidator ¶ added in v1.1.0
type PathValidator struct {
// contains filtered or unexported fields
}
PathValidator validates file paths for security. It checks for path traversal attempts, absolute paths, and other dangerous patterns.
func NewPathValidator ¶ added in v1.1.0
func NewPathValidator(cfg PathValidatorConfig) *PathValidator
NewPathValidator creates a new PathValidator with the specified configuration.
func (*PathValidator) Validate ¶ added in v1.1.0
func (v *PathValidator) Validate(filename string) error
Validate validates a file path for security. It checks for path traversal attempts and other potentially dangerous patterns.
Security checks performed:
- Empty filename
- Null bytes (could bypass extension checks)
- URL encoding (could bypass path checks)
- UNC paths (Windows network paths)
- Unix absolute paths
- Windows drive letters
- Path traversal (..)
- Windows reserved device names
- Symlink escape attacks
type PathValidatorConfig ¶ added in v1.1.0
type PathValidatorConfig struct {
// MaskKey is an optional function to mask sensitive key names in errors.
// If nil, a default masking function is used.
MaskKey func(string) string
}
PathValidatorConfig holds configuration for path validation.
type SecureReader ¶
type SecureReader struct {
// contains filtered or unexported fields
}
SecureReader wraps an io.Reader with security limits. It enforces maximum size and line length constraints.
func NewSecureReader ¶
func NewSecureReader(r io.Reader, maxSize int64, maxLineLen int) *SecureReader
NewSecureReader creates a new SecureReader with the specified limits.
type SecurityError ¶
type SecurityError struct {
Action string // The action that was blocked
Reason string // The security reason for blocking
Key string // The key involved (if applicable, sanitized)
Details string // Additional sanitized details
}
SecurityError provides detailed information about security violations.
func (*SecurityError) Error ¶
func (e *SecurityError) Error() string
Error implements the error interface.
func (*SecurityError) Is ¶
func (e *SecurityError) Is(target error) bool
Is implements errors.Is for SecurityError. This allows errors.Is(err, ErrSecurityViolation) to match SecurityError.
type Token ¶
type Token struct {
Type TokenType
Value string
Line int
Column int
Indent int // Indentation level (number of spaces / 2)
IsQuoted bool
}
Token represents a YAML token.
type TokenType ¶
type TokenType int
TokenType represents the type of a YAML token.
const ( // TokenEOF marks the end of input. TokenEOF TokenType = iota // TokenNewline represents a newline character. TokenNewline // TokenDocumentStart represents a document separator (---). TokenDocumentStart // TokenKey represents a key in a key-value pair. TokenKey // TokenValue represents a scalar value. TokenValue // TokenDash represents the start of an array item. TokenDash // TokenColon represents the colon separator. TokenColon // TokenComment represents a comment. TokenComment // TokenIndent represents increased indentation. TokenIndent // TokenDedent represents decreased indentation. TokenDedent )
type ValidationError ¶
type ValidationError struct {
Field string // The field that failed validation
Value string // Sanitized value (sensitive data masked)
Rule string // The validation rule that was violated
Message string // Human-readable explanation
}
ValidationError provides detailed information about validation failures.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
Error implements the error interface.
func (*ValidationError) Is ¶
func (e *ValidationError) Is(target error) bool
Is implements errors.Is for ValidationError. This allows errors.Is(err, ErrInvalidConfig) to match ValidationError.
type Validator ¶
type Validator struct {
// contains filtered or unexported fields
}
Validator provides input validation for environment variable keys and values.
func NewValidator ¶
func NewValidator(cfg ValidatorConfig) *Validator
NewValidator creates a new Validator with the specified configuration.
func (*Validator) IsSensitive ¶
IsSensitive returns true if the key appears to be sensitive.
func (*Validator) ShouldMask ¶
ShouldMask returns true if the key's value should be masked in logs.
func (*Validator) ValidateKey ¶
ValidateKey validates an environment variable key. Returns an error if the key is invalid or forbidden.
func (*Validator) ValidateRequired ¶
ValidateRequired checks that all required keys are present. Returns an error listing any missing required keys.
func (*Validator) ValidateValue ¶
ValidateValue validates an environment variable value. Returns an error if the value contains invalid content.
type ValidatorConfig ¶
type ValidatorConfig struct {
KeyPattern *regexp.Regexp
AllowedKeys []string
ForbiddenKeys []string
RequiredKeys []string
MaxKeyLength int
MaxValueLength int
ValidateUTF8 bool // Validate that values are valid UTF-8
IsSensitive func(string) bool // Injected from root package
MaskKey func(string) string
MaskSensitive func(string) string
}
ValidatorConfig holds configuration for creating a new Validator.
type Value ¶
type Value struct {
Type ValueType
Scalar string
Map map[string]*Value
Array []*Value
Line int
Column int
}
Value represents a YAML value.
func NewArrayValue ¶
NewArrayValue creates a new array value with pre-allocated capacity.
func NewMapValue ¶
NewMapValue creates a new map value with pre-allocated capacity.
func NewScalarValue ¶
NewScalarValue creates a new scalar value.
type ValueValidator ¶ added in v1.1.0
ValueValidator validates environment variable values.
type VariableExpander ¶ added in v1.1.0
VariableExpander performs variable expansion.
type YAMLError ¶
type YAMLError struct {
Path string // YAML path where error occurred
Line int // Line number where error occurred
Column int // Column number where error occurred
Message string
Err error
}
YAMLError represents a YAML parsing error.
type YAMLFlattenConfig ¶
type YAMLFlattenConfig struct {
// KeyDelimiter is the delimiter for nested keys (default: "_").
KeyDelimiter string
// ArrayIndexFormat controls how array indices are formatted.
// "underscore": KEY_0, KEY_1, etc.
// "bracket": KEY[0], KEY[1], etc.
ArrayIndexFormat string
// NullAsEmpty converts null/~ values to empty strings (default: true).
NullAsEmpty bool
// NumberAsString converts numbers to strings (default: true).
NumberAsString bool
// BoolAsString converts booleans to strings (default: true).
BoolAsString bool
// MaxDepth limits the maximum nesting depth to prevent stack overflow.
MaxDepth int
}
YAMLFlattenConfig holds configuration for YAML flattening.