mirror of
https://github.com/securego/gosec.git
synced 2026-06-20 00:15:59 +02:00
* feat: implement global cache usage in rules * refactor: make global cache generic with local key types - Remove GlobalKey struct from gosec_cache.go - Each use case now defines its own key type (type safety via Go's type system) - Move RegexMatchWithCache to separate regex_cache.go file - Move cache kind constants to rules/hardcoded_credentials.go as local types - Add documentation for cache key requirements
82 lines
2.1 KiB
Go
82 lines
2.1 KiB
Go
package gosec
|
|
|
|
import (
|
|
"container/list"
|
|
"sync"
|
|
)
|
|
|
|
// GlobalCache is a shared LRU cache for expensive operations.
|
|
// Each use case should define its own named key type to avoid collisions.
|
|
//
|
|
// Key type requirements:
|
|
// - The key type must be comparable (no slices, maps, or funcs)
|
|
// - Use type definitions (type MyKey struct{...}), not type aliases (type MyKey = ...)
|
|
// - Avoid anonymous structs - they collide if the structure matches
|
|
var GlobalCache = NewLRUCache[any, any](1 << 16)
|
|
|
|
// LRUCache is a simple thread-safe generic LRU cache.
|
|
type LRUCache[K comparable, V any] struct {
|
|
capacity int
|
|
items map[K]*list.Element
|
|
evictList *list.List
|
|
lock sync.Mutex
|
|
}
|
|
|
|
type entry[K comparable, V any] struct {
|
|
key K
|
|
value V
|
|
}
|
|
|
|
// NewLRUCache creates a new thread-safe LRU cache with the given capacity.
|
|
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
|
|
return &LRUCache[K, V]{
|
|
capacity: capacity,
|
|
items: make(map[K]*list.Element),
|
|
evictList: list.New(),
|
|
}
|
|
}
|
|
|
|
// Get retrieves a value from the cache. Returns the value and true if found,
|
|
// or the zero value and false if not found. Moves the entry to the front of the LRU list.
|
|
func (c *LRUCache[K, V]) Get(key K) (V, bool) {
|
|
c.lock.Lock()
|
|
defer c.lock.Unlock()
|
|
|
|
var zero V
|
|
if ent, ok := c.items[key]; ok {
|
|
c.evictList.MoveToFront(ent)
|
|
return ent.Value.(*entry[K, V]).value, true
|
|
}
|
|
return zero, false
|
|
}
|
|
|
|
// Add inserts or updates a key-value pair in the cache.
|
|
// If the key exists, its value is updated and moved to the front.
|
|
// If the cache is full, the least recently used entry is evicted.
|
|
func (c *LRUCache[K, V]) Add(key K, value V) {
|
|
c.lock.Lock()
|
|
defer c.lock.Unlock()
|
|
|
|
if ent, ok := c.items[key]; ok {
|
|
c.evictList.MoveToFront(ent)
|
|
ent.Value.(*entry[K, V]).value = value
|
|
return
|
|
}
|
|
|
|
ent := &entry[K, V]{key, value}
|
|
element := c.evictList.PushFront(ent)
|
|
c.items[key] = element
|
|
|
|
if c.evictList.Len() > c.capacity {
|
|
c.removeOldest()
|
|
}
|
|
}
|
|
|
|
func (c *LRUCache[K, V]) removeOldest() {
|
|
ent := c.evictList.Back()
|
|
if ent != nil {
|
|
c.evictList.Remove(ent)
|
|
delete(c.items, ent.Value.(*entry[K, V]).key)
|
|
}
|
|
}
|