删除无用文件
This commit is contained in:
@@ -1,59 +0,0 @@
|
||||
package ingest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"git.apinb.com/ops/logs/internal/config"
|
||||
)
|
||||
|
||||
func TestForwardAlertPostsRawEventIngestPayload(t *testing.T) {
|
||||
var gotPath string
|
||||
var gotBody RawEventIngestBody
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotPath = r.URL.Path
|
||||
if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil {
|
||||
t.Fatalf("decode body: %v", err)
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
config.Spec.AlertForward = &config.AlertForwardConf{
|
||||
Enabled: true,
|
||||
BaseURL: server.URL,
|
||||
InternalKey: "internal-key",
|
||||
}
|
||||
|
||||
err := forwardAlert(AlertReceiveBody{
|
||||
AlertName: "H3C Trap",
|
||||
Summary: "Interface down",
|
||||
Description: "Interface down",
|
||||
SeverityCode: "major",
|
||||
Labels: map[string]string{
|
||||
"source_subtype": "snmp_trap",
|
||||
"ip": "192.168.1.10",
|
||||
},
|
||||
Agent: "logs-trap",
|
||||
RawData: json.RawMessage(`{"trap_oid":"1.3.6.1.4.1"}`),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("forwardAlert returned error: %v", err)
|
||||
}
|
||||
|
||||
if gotPath != "/Alert/v1/raw-events/ingest" {
|
||||
t.Fatalf("expected raw event ingest path, got %q", gotPath)
|
||||
}
|
||||
if gotBody.SourceType != "trap" {
|
||||
t.Fatalf("expected trap source type, got %q", gotBody.SourceType)
|
||||
}
|
||||
if gotBody.ParseStatus != "parsed" {
|
||||
t.Fatalf("expected parsed status, got %q", gotBody.ParseStatus)
|
||||
}
|
||||
if string(gotBody.RawPayload) != `{"trap_oid":"1.3.6.1.4.1"}` {
|
||||
t.Fatalf("raw payload changed: %s", string(gotBody.RawPayload))
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package ingest
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestTruncateError(t *testing.T) {
|
||||
got := truncateError(" abcdef ", 3)
|
||||
if got != "abc" {
|
||||
t.Fatalf("unexpected value: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
package ingest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"git.apinb.com/ops/logs/internal/models"
|
||||
)
|
||||
|
||||
func TestSyslogRuleMatchDetailsExtractsResourceUID(t *testing.T) {
|
||||
rule := models.SyslogRule{
|
||||
Name: "H3C link down",
|
||||
Enabled: true,
|
||||
SourceMatch: "h3c-core",
|
||||
MessageRegex: `Interface (?P<iface>GigabitEthernet[0-9/]+) is down`,
|
||||
ResourceUIDExtractRegex: `Interface (?P<resource_uid>GigabitEthernet[0-9/]+) is down`,
|
||||
}
|
||||
|
||||
match := syslogRuleMatchDetails(&rule, "h3c-core-01", "Interface GigabitEthernet1/0/1 is down", "")
|
||||
if !match.Matched {
|
||||
t.Fatal("expected rule to match")
|
||||
}
|
||||
if match.ResourceUID != "network:GigabitEthernet1/0/1" {
|
||||
t.Fatalf("unexpected resource uid: %q", match.ResourceUID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildReplayRawEventPayloadMarksReplayed(t *testing.T) {
|
||||
ev := models.LogEvent{
|
||||
ID: 12,
|
||||
SourceKind: "syslog",
|
||||
SourceIP: "10.1.2.3",
|
||||
RemoteAddr: "10.1.2.3:514",
|
||||
DeviceName: "h3c-core-01",
|
||||
RawPayload: "<189>Jun 24 10:00:01 h3c-core-01 IFNET/4/LINK_DOWN: Interface GigabitEthernet1/0/1 is down",
|
||||
NormalizedSummary: "h3c-core-01: Interface GigabitEthernet1/0/1 is down",
|
||||
SeverityCode: "warning",
|
||||
DispatchStatus: "pending",
|
||||
}
|
||||
|
||||
body, err := BuildReplayRawEventPayload(ev)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildReplayRawEventPayload returned error: %v", err)
|
||||
}
|
||||
if body.SourceType != "syslog" {
|
||||
t.Fatalf("unexpected source type: %q", body.SourceType)
|
||||
}
|
||||
if body.ParseStatus != "replayed" {
|
||||
t.Fatalf("unexpected parse status: %q", body.ParseStatus)
|
||||
}
|
||||
if body.Labels["replay_of_log_event_id"] != "12" {
|
||||
t.Fatalf("missing replay label: %#v", body.Labels)
|
||||
}
|
||||
var raw map[string]any
|
||||
if err := json.Unmarshal(body.RawPayload, &raw); err != nil {
|
||||
t.Fatalf("raw payload should be json: %v", err)
|
||||
}
|
||||
if raw["raw_packet"] == "" {
|
||||
t.Fatalf("raw packet missing: %#v", raw)
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package ingest
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestResolveResourceByIPFirst(t *testing.T) {
|
||||
e := &Engine{
|
||||
resourceByIP: map[string]resourceRef{
|
||||
"10.0.0.10": {ResourceType: "server", ResourceID: "srv-10", ResourceName: "s10"},
|
||||
},
|
||||
resourceByHN: map[string]resourceRef{
|
||||
"host-a": {ResourceType: "device", ResourceID: "dev-a", ResourceName: "a"},
|
||||
},
|
||||
}
|
||||
ref, method := e.resolveResource("10.0.0.10", "host-a")
|
||||
if method != "ip" {
|
||||
t.Fatalf("method=%s", method)
|
||||
}
|
||||
if ref.ResourceID != "srv-10" {
|
||||
t.Fatalf("resource id=%s", ref.ResourceID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveResourceByHostname(t *testing.T) {
|
||||
e := &Engine{
|
||||
resourceByIP: map[string]resourceRef{},
|
||||
resourceByHN: map[string]resourceRef{
|
||||
"host-a": {ResourceType: "device", ResourceID: "dev-a", ResourceName: "a"},
|
||||
},
|
||||
}
|
||||
ref, method := e.resolveResource("10.0.0.20", "HOST-A")
|
||||
if method != "hostname" {
|
||||
t.Fatalf("method=%s", method)
|
||||
}
|
||||
if ref.ResourceID != "dev-a" {
|
||||
t.Fatalf("resource id=%s", ref.ResourceID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveResourceNoMatch(t *testing.T) {
|
||||
e := &Engine{
|
||||
resourceByIP: map[string]resourceRef{},
|
||||
resourceByHN: map[string]resourceRef{},
|
||||
}
|
||||
_, method := e.resolveResource("10.0.0.20", "host-b")
|
||||
if method != "none" {
|
||||
t.Fatalf("method=%s", method)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
package ingest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.apinb.com/ops/logs/internal/models"
|
||||
"github.com/gosnmp/gosnmp"
|
||||
)
|
||||
|
||||
func TestParseSyslogPayloadPri(t *testing.T) {
|
||||
p := parseSyslogPayload([]byte("<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8"))
|
||||
if p.Priority != 34 {
|
||||
t.Fatalf("priority=%d", p.Priority)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSyslogPayloadRFC3164Hostname(t *testing.T) {
|
||||
p := parseSyslogPayload([]byte("Oct 11 22:14:15 mymachine su: failed"))
|
||||
if p.Hostname != "mymachine" {
|
||||
t.Fatalf("hostname=%q", p.Hostname)
|
||||
}
|
||||
if p.Tag != "su" {
|
||||
t.Fatalf("tag=%q", p.Tag)
|
||||
}
|
||||
if p.Message != "failed" {
|
||||
t.Fatalf("message=%q", p.Message)
|
||||
}
|
||||
}
|
||||
|
||||
func TestForwardAlertBodyIncludesRawData(t *testing.T) {
|
||||
raw := []byte(`{"source":"syslog","parsed":{}}`)
|
||||
b := AlertReceiveBody{
|
||||
AlertName: "a",
|
||||
RawData: raw,
|
||||
}
|
||||
data, err := json.Marshal(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var dec map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &dec); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(dec["raw_data"]) != string(raw) {
|
||||
t.Fatalf("raw_data %s", dec["raw_data"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestInTimeWindowsInvalidJSONReturnsFalse(t *testing.T) {
|
||||
now := time.Date(2026, 1, 1, 10, 0, 0, 0, time.Local)
|
||||
if inTimeWindows(now, "{invalid") {
|
||||
t.Fatal("invalid json should not be treated as always effective")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrapShieldedAllowsEmptySourceIPCIDR(t *testing.T) {
|
||||
e := &Engine{
|
||||
shields: []models.TrapShield{
|
||||
{
|
||||
Enabled: true,
|
||||
SourceIPCIDR: "",
|
||||
OIDPrefix: "1.3.6.1.4.1",
|
||||
InterfaceHint: "",
|
||||
TimeWindowsJSON: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
addr := &net.UDPAddr{IP: net.ParseIP("10.0.0.1"), Port: 162}
|
||||
pkt := &gosnmp.SnmpPacket{}
|
||||
if !trapShielded(e, addr, "1.3.6.1.4.1.999", pkt) {
|
||||
t.Fatal("shield should match when source_ip_cidr is empty and other conditions match")
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package audit
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateRecordRequiresDangerousOperationsToCarryReviewID(t *testing.T) {
|
||||
record := Record{
|
||||
SourceService: "alert",
|
||||
ActorID: "u-1",
|
||||
Action: "policy.update",
|
||||
ObjectType: "notification_policy",
|
||||
ObjectID: "np-1",
|
||||
OperationRisk: RiskDangerous,
|
||||
}
|
||||
|
||||
if err := ValidateRecord(record); err == nil {
|
||||
t.Fatal("expected dangerous operation without approval id to fail")
|
||||
}
|
||||
|
||||
record.ApprovalID = "apr-1"
|
||||
if err := ValidateRecord(record); err != nil {
|
||||
t.Fatalf("expected valid dangerous audit record, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeRecordClassifiesDangerousActions(t *testing.T) {
|
||||
record := NormalizeRecord(Record{
|
||||
SourceService: " alert ",
|
||||
Action: "notification_policy.update",
|
||||
ObjectType: " notification_policy ",
|
||||
ObjectID: " np-1 ",
|
||||
ActorID: " u-1 ",
|
||||
})
|
||||
|
||||
if record.SourceService != "alert" || record.ObjectType != "notification_policy" || record.ObjectID != "np-1" {
|
||||
t.Fatalf("record was not normalized: %#v", record)
|
||||
}
|
||||
if record.OperationRisk != RiskDangerous {
|
||||
t.Fatalf("notification policy changes must be dangerous, got %q", record.OperationRisk)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApprovalTransitionAllowsApproveOnlyFromPending(t *testing.T) {
|
||||
req := ApprovalRequest{Status: ApprovalPending}
|
||||
|
||||
approved, err := Transition(req, ApprovalApproved, "reviewer-1", "ok")
|
||||
if err != nil {
|
||||
t.Fatalf("expected pending approval to approve: %v", err)
|
||||
}
|
||||
if approved.Status != ApprovalApproved {
|
||||
t.Fatalf("unexpected status: %s", approved.Status)
|
||||
}
|
||||
if approved.ReviewerID != "reviewer-1" || approved.ReviewComment != "ok" {
|
||||
t.Fatalf("review metadata not stored: %#v", approved)
|
||||
}
|
||||
|
||||
if _, err := Transition(approved, ApprovalRejected, "reviewer-2", "late"); err == nil {
|
||||
t.Fatal("expected approved request to reject further transition")
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.apinb.com/ops/logs/internal/config"
|
||||
)
|
||||
|
||||
func TestValidateResourceEventRequest(t *testing.T) {
|
||||
req := &resourceEventRequest{
|
||||
EventID: "evt-1",
|
||||
EventTime: "2026-04-27T08:00:00Z",
|
||||
EventType: resourceEventUpsert,
|
||||
ResourceType: "server",
|
||||
ResourceID: "srv-1",
|
||||
ResourceName: "server-1",
|
||||
Version: 1,
|
||||
}
|
||||
if _, err := validateResourceEventRequest(req); err != nil {
|
||||
t.Fatalf("expected valid request, got error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateResourceEventRequestInvalidTime(t *testing.T) {
|
||||
req := &resourceEventRequest{
|
||||
EventID: "evt-1",
|
||||
EventTime: "bad-time",
|
||||
EventType: resourceEventUpsert,
|
||||
ResourceType: "server",
|
||||
ResourceID: "srv-1",
|
||||
Version: 1,
|
||||
}
|
||||
if _, err := validateResourceEventRequest(req); err == nil {
|
||||
t.Fatal("expected invalid time error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonEmptyUnique(t *testing.T) {
|
||||
got := nonEmptyUnique([]string{" 10.0.0.1 ", "", "10.0.0.1", "host-a", "host-a"})
|
||||
if len(got) != 2 {
|
||||
t.Fatalf("unexpected unique size: %d", len(got))
|
||||
}
|
||||
if got[0] != "10.0.0.1" || got[1] != "host-a" {
|
||||
t.Fatalf("unexpected output: %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyResourceEventSignature(t *testing.T) {
|
||||
old := config.Spec.ResourceEvent.HMACSecret
|
||||
config.Spec.ResourceEvent.HMACSecret = "abc123"
|
||||
defer func() {
|
||||
config.Spec.ResourceEvent.HMACSecret = old
|
||||
}()
|
||||
|
||||
body := []byte(`{"event_id":"evt-1"}`)
|
||||
mac := hmac.New(sha256.New, []byte("abc123"))
|
||||
mac.Write(body)
|
||||
signature := fmt.Sprintf("%x", mac.Sum(nil))
|
||||
if err := verifyResourceEventSignature(signature, body); err != nil {
|
||||
t.Fatalf("expected signature to pass: %v", err)
|
||||
}
|
||||
if err := verifyResourceEventSignature("bad", body); err == nil {
|
||||
t.Fatal("expected invalid signature error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateEventTimeSkew(t *testing.T) {
|
||||
old := config.Spec.ResourceEvent.MaxSkewSecs
|
||||
config.Spec.ResourceEvent.MaxSkewSecs = 60
|
||||
defer func() {
|
||||
config.Spec.ResourceEvent.MaxSkewSecs = old
|
||||
}()
|
||||
|
||||
if err := validateEventTimeSkew(time.Now()); err != nil {
|
||||
t.Fatalf("expected current time to pass: %v", err)
|
||||
}
|
||||
if err := validateEventTimeSkew(time.Now().Add(-2 * time.Minute)); err == nil {
|
||||
t.Fatal("expected skew validation to fail for old timestamp")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTrapDictionaryEntryHasBlueprintFields(t *testing.T) {
|
||||
typ := reflect.TypeOf(TrapDictionaryEntry{})
|
||||
for _, name := range []string{"Vendor", "OID", "Name", "SeverityMappingJSON", "ParseExpression"} {
|
||||
if _, ok := typ.FieldByName(name); !ok {
|
||||
t.Fatalf("TrapDictionaryEntry missing blueprint field %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyslogRuleHasBlueprintFields(t *testing.T) {
|
||||
typ := reflect.TypeOf(SyslogRule{})
|
||||
for _, name := range []string{"SourceMatch", "MessageRegex", "SeverityMappingJSON", "ResourceUIDExtractRegex"} {
|
||||
if _, ok := typ.FieldByName(name); !ok {
|
||||
t.Fatalf("SyslogRule missing blueprint field %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user