Files

110 lines
2.6 KiB
Go
Raw Permalink Normal View History

package audit
import (
"crypto/sha256"
"fmt"
"sync"
"time"
)
// ImmutableLogEntry represents a tamper-proof audit entry
type ImmutableLogEntry struct {
Sequence int64 `json:"sequence"`
PrevHash string `json:"prev_hash"`
Content string `json:"content"`
Hash string `json:"hash"`
Timestamp time.Time `json:"timestamp"`
Signature string `json:"signature,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
// ImmutableLog maintains a tamper-proof audit trail
type ImmutableLog struct {
mu sync.RWMutex
entries []*ImmutableLogEntry
logPath string
sequence int64
prevHash string
workflowKey string
}
// NewImmutableLog creates a new immutable log
func NewImmutableLog(logPath string, workflowKey string) *ImmutableLog {
return &ImmutableLog{
entries: make([]*ImmutableLogEntry, 0),
logPath: logPath,
sequence: 0,
prevHash: "genesis",
workflowKey: workflowKey,
}
}
// Append adds an entry to the immutable log
func (il *ImmutableLog) Append(content string, metadata map[string]interface{}) (*ImmutableLogEntry, error) {
il.mu.Lock()
defer il.mu.Unlock()
il.sequence++
hash := il.computeHash(il.sequence, il.prevHash, content)
entry := &ImmutableLogEntry{
Sequence: il.sequence,
PrevHash: il.prevHash,
Content: content,
Hash: hash,
Timestamp: time.Now(),
Metadata: metadata,
}
il.entries = append(il.entries, entry)
il.prevHash = hash
return entry, nil
}
// Verify verifies the integrity of the log
func (il *ImmutableLog) Verify() (bool, error) {
il.mu.RLock()
defer il.mu.RUnlock()
prevHash := "genesis"
for _, entry := range il.entries {
expectedHash := il.computeHash(entry.Sequence, entry.PrevHash, entry.Content)
if entry.Hash != expectedHash || entry.PrevHash != prevHash {
return false, fmt.Errorf("integrity check failed at sequence %d", entry.Sequence)
}
prevHash = entry.Hash
}
return true, nil
}
// GetEntries returns all entries
func (il *ImmutableLog) GetEntries() []*ImmutableLogEntry {
il.mu.RLock()
defer il.mu.RUnlock()
result := make([]*ImmutableLogEntry, len(il.entries))
copy(result, il.entries)
return result
}
// GetLastHash returns the last hash
func (il *ImmutableLog) GetLastHash() string {
il.mu.RLock()
defer il.mu.RUnlock()
return il.prevHash
}
// computeHash computes SHA256 hash
func (il *ImmutableLog) computeHash(seq int64, prevHash, content string) string {
data := fmt.Sprintf("%d:%s:%s:%s", seq, prevHash, content, il.workflowKey)
hash := sha256.Sum256([]byte(data))
return fmt.Sprintf("%x", hash)
}