mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-04-28 03:20:11 +00:00
Fix CodeQL integer and audit findings
This commit is contained in:
parent
29c4d6b5a7
commit
e93c8b40ae
8 changed files with 142 additions and 26 deletions
|
|
@ -929,9 +929,9 @@ func parseSMARTOutput(output []byte, target smartctlTarget) (*DiskSMART, error)
|
|||
} else {
|
||||
for _, attr := range smartData.ATASmartAttributes.Table {
|
||||
if attr.ID == 194 || attr.ID == 190 {
|
||||
temp := int(parseRawValue(attr.Raw.String, attr.Raw.Value))
|
||||
temp := parseRawValue(attr.Raw.String, attr.Raw.Value)
|
||||
if temp > 0 && temp < 150 {
|
||||
result.Temperature = temp
|
||||
result.Temperature = int(temp)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
package audit
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -132,6 +134,7 @@ func NewConsoleLogger() *ConsoleLogger {
|
|||
|
||||
// Log writes an audit event to zerolog.
|
||||
func (c *ConsoleLogger) Log(event Event) error {
|
||||
detailsPresent, detailsLen, detailsDigest := summarizeAuditDetails(event.Details)
|
||||
logEvent := log.With().
|
||||
Str("audit_id", event.ID).
|
||||
Str("event", event.EventType).
|
||||
|
|
@ -139,7 +142,9 @@ func (c *ConsoleLogger) Log(event Event) error {
|
|||
Str("ip", event.IP).
|
||||
Str("path", event.Path).
|
||||
Time("timestamp", event.Timestamp).
|
||||
Str("details", event.Details).
|
||||
Bool("details_present", detailsPresent).
|
||||
Int("details_len", detailsLen).
|
||||
Str("details_sha256", detailsDigest).
|
||||
Logger()
|
||||
|
||||
if event.Success {
|
||||
|
|
@ -151,6 +156,14 @@ func (c *ConsoleLogger) Log(event Event) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func summarizeAuditDetails(details string) (present bool, length int, digest string) {
|
||||
if details == "" {
|
||||
return false, 0, ""
|
||||
}
|
||||
sum := sha256.Sum256([]byte(details))
|
||||
return true, len(details), hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
// Query returns an empty slice for the console logger.
|
||||
// Console logs are not queryable - use enterprise version for persistent storage.
|
||||
func (c *ConsoleLogger) Query(filter QueryFilter) ([]Event, error) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,24 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
func TestSummarizeAuditDetails(t *testing.T) {
|
||||
present, length, digest := summarizeAuditDetails("apiToken=secret-value")
|
||||
if !present {
|
||||
t.Fatal("expected details to be marked present")
|
||||
}
|
||||
if length != len("apiToken=secret-value") {
|
||||
t.Fatalf("length = %d", length)
|
||||
}
|
||||
if digest == "" {
|
||||
t.Fatal("expected non-empty digest")
|
||||
}
|
||||
|
||||
emptyPresent, emptyLength, emptyDigest := summarizeAuditDetails("")
|
||||
if emptyPresent || emptyLength != 0 || emptyDigest != "" {
|
||||
t.Fatalf("unexpected empty summary: %v %d %q", emptyPresent, emptyLength, emptyDigest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConsoleLogger_Log(t *testing.T) {
|
||||
logger := NewConsoleLogger()
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,11 @@ func (f *FlexInt) UnmarshalJSON(data []byte) error {
|
|||
// Try as float (handles cpulimit like 1.5)
|
||||
var fl float64
|
||||
if err := json.Unmarshal(data, &fl); err == nil {
|
||||
*f = FlexInt(int(fl))
|
||||
intVal, ok := intFromFloat64TruncChecked(fl)
|
||||
if !ok {
|
||||
return fmt.Errorf("float value out of range for FlexInt")
|
||||
}
|
||||
*f = FlexInt(intVal)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +53,11 @@ func (f *FlexInt) UnmarshalJSON(data []byte) error {
|
|||
}
|
||||
|
||||
// Convert to int
|
||||
*f = FlexInt(int(floatVal))
|
||||
intVal, ok := intFromFloat64TruncChecked(floatVal)
|
||||
if !ok {
|
||||
return fmt.Errorf("float value out of range for FlexInt")
|
||||
}
|
||||
*f = FlexInt(intVal)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -1581,8 +1589,8 @@ func (a *VMIpAddress) UnmarshalJSON(data []byte) error {
|
|||
if err != nil {
|
||||
prefix = 0
|
||||
}
|
||||
if prefix > math.MaxInt {
|
||||
prefix = math.MaxInt
|
||||
if prefix > 128 {
|
||||
prefix = 128
|
||||
}
|
||||
a.Prefix = int(prefix)
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -581,6 +581,16 @@ func TestFlexIntUnmarshalJSON(t *testing.T) {
|
|||
input: "1000000",
|
||||
want: FlexInt(1000000),
|
||||
},
|
||||
{
|
||||
name: "float overflow",
|
||||
input: "1e309",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "string float overflow",
|
||||
input: `"1e309"`,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid string",
|
||||
input: `"not a number"`,
|
||||
|
|
@ -618,6 +628,19 @@ func TestFlexIntUnmarshalJSON(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestVMIpAddressUnmarshalJSONCapsPrefix(t *testing.T) {
|
||||
var addr VMIpAddress
|
||||
if err := addr.UnmarshalJSON([]byte(`{"ip-address":"2001:db8::1","prefix":"18446744073709551615"}`)); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if addr.Address != "2001:db8::1" {
|
||||
t.Fatalf("Address = %q", addr.Address)
|
||||
}
|
||||
if addr.Prefix != 128 {
|
||||
t.Fatalf("Prefix = %d, want 128", addr.Prefix)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseUint64Flexible(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
|
|||
44
pkg/proxmox/intconv.go
Normal file
44
pkg/proxmox/intconv.go
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package proxmox
|
||||
|
||||
import "math"
|
||||
|
||||
const (
|
||||
maxInt = int(^uint(0) >> 1)
|
||||
minInt = -maxInt - 1
|
||||
)
|
||||
|
||||
func intFromInt64Checked(v int64) (int, bool) {
|
||||
if v > int64(maxInt) || v < int64(minInt) {
|
||||
return 0, false
|
||||
}
|
||||
return int(v), true
|
||||
}
|
||||
|
||||
func intFromUint64Checked(v uint64) (int, bool) {
|
||||
if v > uint64(maxInt) {
|
||||
return 0, false
|
||||
}
|
||||
return int(v), true
|
||||
}
|
||||
|
||||
func intFromFloat64RoundedChecked(v float64) (int, bool) {
|
||||
if math.IsNaN(v) || math.IsInf(v, 0) {
|
||||
return 0, false
|
||||
}
|
||||
rounded := math.Round(v)
|
||||
if rounded > float64(maxInt) || rounded < float64(minInt) {
|
||||
return 0, false
|
||||
}
|
||||
return int(rounded), true
|
||||
}
|
||||
|
||||
func intFromFloat64TruncChecked(v float64) (int, bool) {
|
||||
if math.IsNaN(v) || math.IsInf(v, 0) {
|
||||
return 0, false
|
||||
}
|
||||
truncated := math.Trunc(v)
|
||||
if truncated > float64(maxInt) || truncated < float64(minInt) {
|
||||
return 0, false
|
||||
}
|
||||
return int(truncated), true
|
||||
}
|
||||
|
|
@ -369,33 +369,31 @@ func intFromAny(value interface{}) (int, bool) {
|
|||
case int32:
|
||||
return int(v), true
|
||||
case int64:
|
||||
return int(v), true
|
||||
return intFromInt64Checked(v)
|
||||
case uint:
|
||||
return int(v), true
|
||||
return intFromUint64Checked(uint64(v))
|
||||
case uint8:
|
||||
return int(v), true
|
||||
case uint16:
|
||||
return int(v), true
|
||||
case uint32:
|
||||
return int(v), true
|
||||
return intFromUint64Checked(uint64(v))
|
||||
case uint64:
|
||||
return int(v), true
|
||||
return intFromUint64Checked(v)
|
||||
case float32:
|
||||
if math.IsNaN(float64(v)) || math.IsInf(float64(v), 0) {
|
||||
return 0, false
|
||||
}
|
||||
return int(math.Round(float64(v))), true
|
||||
return intFromFloat64RoundedChecked(float64(v))
|
||||
case float64:
|
||||
if math.IsNaN(v) || math.IsInf(v, 0) {
|
||||
return intFromFloat64RoundedChecked(v)
|
||||
case json.Number:
|
||||
s := strings.TrimSpace(v.String())
|
||||
if i, err := v.Int64(); err == nil {
|
||||
return intFromInt64Checked(i)
|
||||
}
|
||||
if !looksLikeFloatLiteral(s) {
|
||||
return 0, false
|
||||
}
|
||||
return int(math.Round(v)), true
|
||||
case json.Number:
|
||||
if i, err := v.Int64(); err == nil {
|
||||
return int(i), true
|
||||
}
|
||||
if f, err := v.Float64(); err == nil && !math.IsNaN(f) && !math.IsInf(f, 0) {
|
||||
return int(math.Round(f)), true
|
||||
if f, err := v.Float64(); err == nil {
|
||||
return intFromFloat64RoundedChecked(f)
|
||||
}
|
||||
case string:
|
||||
s := strings.TrimSpace(v)
|
||||
|
|
@ -403,15 +401,22 @@ func intFromAny(value interface{}) (int, bool) {
|
|||
return 0, false
|
||||
}
|
||||
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
|
||||
return int(i), true
|
||||
return intFromInt64Checked(i)
|
||||
}
|
||||
if f, err := strconv.ParseFloat(s, 64); err == nil && !math.IsNaN(f) && !math.IsInf(f, 0) {
|
||||
return int(math.Round(f)), true
|
||||
if !looksLikeFloatLiteral(s) {
|
||||
return 0, false
|
||||
}
|
||||
if f, err := strconv.ParseFloat(s, 64); err == nil {
|
||||
return intFromFloat64RoundedChecked(f)
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func looksLikeFloatLiteral(s string) bool {
|
||||
return strings.ContainsAny(s, ".eE")
|
||||
}
|
||||
|
||||
func boolFromAny(value interface{}) (bool, bool) {
|
||||
switch v := value.(type) {
|
||||
case nil:
|
||||
|
|
|
|||
|
|
@ -112,14 +112,19 @@ func TestIntFromAny(t *testing.T) {
|
|||
{"json.Number int", json.Number("42"), 42, true},
|
||||
{"json.Number float", json.Number("42.6"), 43, true},
|
||||
{"json.Number invalid", json.Number("abc"), 0, false},
|
||||
{"json.Number int overflow", json.Number("9223372036854775808"), 0, false},
|
||||
|
||||
// string
|
||||
{"string int", "42", 42, true},
|
||||
{"string negative", "-42", -42, true},
|
||||
{"string float", "42.6", 43, true},
|
||||
{"string int overflow", "9223372036854775808", 0, false},
|
||||
{"string float overflow", "1e309", 0, false},
|
||||
{"string empty", "", 0, false},
|
||||
{"string whitespace", " 42 ", 42, true},
|
||||
{"string invalid", "abc", 0, false},
|
||||
{"uint64 overflow", uint64(maxInt) + 1, 0, false},
|
||||
{"float64 overflow", float64(maxInt) * 2, 0, false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue