first commit
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"browser.local/platform/domain"
|
||||
)
|
||||
|
||||
const (
|
||||
MaxLogBatchEntries = 512
|
||||
MaxLogLineLength = 8192
|
||||
MaxLogQueryLimit = 500
|
||||
)
|
||||
|
||||
func ValidateLogBatchIngest(batch domain.LogBatchIngest) error {
|
||||
var violations []string
|
||||
violations = appendRequired(violations, "runEndpointId", batch.RunEndpointID)
|
||||
violations = appendRequired(violations, "sessionToken", batch.SessionToken)
|
||||
violations = appendRequired(violations, "logStreamId", batch.LogStreamID)
|
||||
violations = appendRequired(violations, "serverInstanceId", batch.ServerInstanceID)
|
||||
violations = appendRequired(violations, "streamKey", batch.StreamKey)
|
||||
violations = appendRequired(violations, "checksum", batch.Checksum)
|
||||
if !validLogStreamSource(batch.Source) {
|
||||
violations = append(violations, "source is invalid")
|
||||
}
|
||||
if batch.FirstSeq == 0 || batch.LastSeq == 0 {
|
||||
violations = append(violations, "sequence range must be positive")
|
||||
}
|
||||
if batch.FirstSeq > batch.LastSeq {
|
||||
violations = append(violations, "firstSeq must not exceed lastSeq")
|
||||
}
|
||||
if batch.Compression != "" && batch.Compression != "none" {
|
||||
violations = append(violations, "compression is invalid")
|
||||
}
|
||||
if len(batch.Entries) == 0 {
|
||||
violations = append(violations, "entries must not be empty")
|
||||
}
|
||||
if len(batch.Entries) > MaxLogBatchEntries {
|
||||
violations = append(violations, fmt.Sprintf("entries must not exceed %d", MaxLogBatchEntries))
|
||||
}
|
||||
if len(batch.Entries) > 0 {
|
||||
expectedCount := int(batch.LastSeq - batch.FirstSeq + 1)
|
||||
if expectedCount != len(batch.Entries) {
|
||||
violations = append(violations, "sequence range must match entry count")
|
||||
}
|
||||
}
|
||||
for i, entry := range batch.Entries {
|
||||
if entry.Seq != batch.FirstSeq+uint64(i) {
|
||||
violations = append(violations, fmt.Sprintf("entries[%d].seq must be contiguous", i))
|
||||
}
|
||||
if strings.TrimSpace(entry.Line) == "" {
|
||||
violations = append(violations, fmt.Sprintf("entries[%d].line is required", i))
|
||||
}
|
||||
if len(entry.Line) > MaxLogLineLength {
|
||||
violations = append(violations, fmt.Sprintf("entries[%d].line is too long", i))
|
||||
}
|
||||
for key := range entry.Fields {
|
||||
if strings.TrimSpace(key) == "" {
|
||||
violations = append(violations, fmt.Sprintf("entries[%d].fields key is required", i))
|
||||
}
|
||||
}
|
||||
}
|
||||
if batch.Checksum != "" {
|
||||
computed, err := LogEntriesChecksum(batch.Entries)
|
||||
if err != nil {
|
||||
violations = append(violations, "checksum cannot be computed")
|
||||
} else if batch.Checksum != computed {
|
||||
violations = append(violations, "checksum does not match entries")
|
||||
}
|
||||
}
|
||||
return finish(violations)
|
||||
}
|
||||
|
||||
func ValidateLogStreamCursorQuery(query domain.LogStreamCursorQuery) error {
|
||||
var violations []string
|
||||
violations = appendRequired(violations, "logStreamId", query.LogStreamID)
|
||||
if query.Limit < 0 {
|
||||
violations = append(violations, "limit must not be negative")
|
||||
}
|
||||
if query.Limit > MaxLogQueryLimit {
|
||||
violations = append(violations, fmt.Sprintf("limit must not exceed %d", MaxLogQueryLimit))
|
||||
}
|
||||
return finish(violations)
|
||||
}
|
||||
|
||||
func LogEntriesChecksum(entries []domain.LogEntry) (string, error) {
|
||||
stable := make([]logEntryChecksumBody, len(entries))
|
||||
for i, entry := range entries {
|
||||
stable[i] = logEntryChecksumBody{
|
||||
Seq: entry.Seq,
|
||||
Timestamp: entry.Timestamp.UTC().Format("2006-01-02T15:04:05.000000000Z07:00"),
|
||||
Level: entry.Level,
|
||||
Line: entry.Line,
|
||||
Fields: entry.Fields,
|
||||
Redacted: entry.Redacted,
|
||||
}
|
||||
}
|
||||
encoded, err := json.Marshal(stable)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sum := sha256.Sum256(encoded)
|
||||
return "sha256:" + hex.EncodeToString(sum[:]), nil
|
||||
}
|
||||
|
||||
type logEntryChecksumBody struct {
|
||||
Seq uint64 `json:"seq"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Level string `json:"level,omitempty"`
|
||||
Line string `json:"line"`
|
||||
Fields map[string]string `json:"fields,omitempty"`
|
||||
Redacted bool `json:"redacted"`
|
||||
}
|
||||
Reference in New Issue
Block a user