任务执行1-19

This commit is contained in:
zxr
2026-06-26 12:51:50 +08:00
parent 175d9f8f94
commit 19908230f2
19 changed files with 2615 additions and 1260 deletions

View File

@@ -0,0 +1,219 @@
package audit
import (
"errors"
"strings"
"time"
"git.apinb.com/ops/logs/internal/impl"
"git.apinb.com/ops/logs/internal/models"
)
const (
RiskNormal = "normal"
RiskDangerous = "dangerous"
ApprovalPending = "pending"
ApprovalApproved = "approved"
ApprovalRejected = "rejected"
)
type Record struct {
TraceID string `json:"trace_id,omitempty"`
SourceService string `json:"source_service,omitempty"`
ActorID string `json:"actor_id,omitempty"`
ActorName string `json:"actor_name,omitempty"`
Action string `json:"action,omitempty"`
ObjectType string `json:"object_type,omitempty"`
ObjectID string `json:"object_id,omitempty"`
OperationRisk string `json:"operation_risk,omitempty"`
ApprovalID string `json:"approval_id,omitempty"`
RequestMethod string `json:"request_method,omitempty"`
RequestPath string `json:"request_path,omitempty"`
ClientIP string `json:"client_ip,omitempty"`
BeforeJSON string `json:"before_json,omitempty"`
AfterJSON string `json:"after_json,omitempty"`
Result string `json:"result,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
}
type ApprovalRequest struct {
RequestID string `json:"request_id,omitempty"`
SourceService string `json:"source_service,omitempty"`
Action string `json:"action,omitempty"`
ObjectType string `json:"object_type,omitempty"`
ObjectID string `json:"object_id,omitempty"`
RequesterID string `json:"requester_id,omitempty"`
RequesterName string `json:"requester_name,omitempty"`
Reason string `json:"reason,omitempty"`
BeforeJSON string `json:"before_json,omitempty"`
AfterJSON string `json:"after_json,omitempty"`
Status string `json:"status,omitempty"`
ReviewerID string `json:"reviewer_id,omitempty"`
ReviewerName string `json:"reviewer_name,omitempty"`
ReviewComment string `json:"review_comment,omitempty"`
ReviewedAt *time.Time `json:"reviewed_at,omitempty"`
}
func NormalizeRecord(record Record) Record {
record.TraceID = strings.TrimSpace(record.TraceID)
record.SourceService = strings.TrimSpace(record.SourceService)
record.ActorID = strings.TrimSpace(record.ActorID)
record.ActorName = strings.TrimSpace(record.ActorName)
record.Action = strings.TrimSpace(record.Action)
record.ObjectType = strings.TrimSpace(record.ObjectType)
record.ObjectID = strings.TrimSpace(record.ObjectID)
record.OperationRisk = strings.TrimSpace(strings.ToLower(record.OperationRisk))
record.ApprovalID = strings.TrimSpace(record.ApprovalID)
record.RequestMethod = strings.TrimSpace(strings.ToUpper(record.RequestMethod))
record.RequestPath = strings.TrimSpace(record.RequestPath)
record.ClientIP = strings.TrimSpace(record.ClientIP)
record.Result = strings.TrimSpace(record.Result)
if record.Result == "" {
record.Result = "success"
}
if record.OperationRisk == "" {
if IsDangerousOperation(record.Action, record.ObjectType) {
record.OperationRisk = RiskDangerous
} else {
record.OperationRisk = RiskNormal
}
}
return record
}
func ValidateRecord(record Record) error {
record = NormalizeRecord(record)
if record.SourceService == "" {
return errors.New("source_service is required")
}
if record.ActorID == "" {
return errors.New("actor_id is required")
}
if record.Action == "" {
return errors.New("action is required")
}
if record.ObjectType == "" {
return errors.New("object_type is required")
}
if record.ObjectID == "" {
return errors.New("object_id is required")
}
if record.OperationRisk != RiskNormal && record.OperationRisk != RiskDangerous {
return errors.New("operation_risk must be normal or dangerous")
}
if record.OperationRisk == RiskDangerous && record.ApprovalID == "" {
return errors.New("approval_id is required for dangerous operation")
}
return nil
}
func IsDangerousOperation(action, objectType string) bool {
key := strings.ToLower(strings.TrimSpace(action) + " " + strings.TrimSpace(objectType))
dangerWords := []string{
"notification_policy",
"notification policy",
"silence_policy",
"suppression",
"escalation_policy",
"automation_script",
"script.execute",
"script.rollback",
}
for _, word := range dangerWords {
if strings.Contains(key, word) {
return true
}
}
return false
}
func SaveRecord(record Record) (models.AuditLog, error) {
record = NormalizeRecord(record)
if err := ValidateRecord(record); err != nil {
return models.AuditLog{}, err
}
row := models.AuditLog{
TraceID: record.TraceID,
SourceService: record.SourceService,
ActorID: record.ActorID,
ActorName: record.ActorName,
Action: record.Action,
ObjectType: record.ObjectType,
ObjectID: record.ObjectID,
OperationRisk: record.OperationRisk,
ApprovalID: record.ApprovalID,
RequestMethod: record.RequestMethod,
RequestPath: record.RequestPath,
ClientIP: record.ClientIP,
BeforeJSON: record.BeforeJSON,
AfterJSON: record.AfterJSON,
Result: record.Result,
ErrorMessage: record.ErrorMessage,
}
if err := impl.DBService.Create(&row).Error; err != nil {
return models.AuditLog{}, err
}
return row, nil
}
func NormalizeApproval(req ApprovalRequest) ApprovalRequest {
req.RequestID = strings.TrimSpace(req.RequestID)
req.SourceService = strings.TrimSpace(req.SourceService)
req.Action = strings.TrimSpace(req.Action)
req.ObjectType = strings.TrimSpace(req.ObjectType)
req.ObjectID = strings.TrimSpace(req.ObjectID)
req.RequesterID = strings.TrimSpace(req.RequesterID)
req.RequesterName = strings.TrimSpace(req.RequesterName)
req.Status = strings.TrimSpace(strings.ToLower(req.Status))
req.ReviewerID = strings.TrimSpace(req.ReviewerID)
req.ReviewerName = strings.TrimSpace(req.ReviewerName)
if req.Status == "" {
req.Status = ApprovalPending
}
return req
}
func ValidateApprovalRequest(req ApprovalRequest) error {
req = NormalizeApproval(req)
if req.SourceService == "" {
return errors.New("source_service is required")
}
if req.Action == "" {
return errors.New("action is required")
}
if req.ObjectType == "" {
return errors.New("object_type is required")
}
if req.ObjectID == "" {
return errors.New("object_id is required")
}
if req.RequesterID == "" {
return errors.New("requester_id is required")
}
if !IsDangerousOperation(req.Action, req.ObjectType) {
return errors.New("operation is not classified as dangerous")
}
return nil
}
func Transition(req ApprovalRequest, nextStatus, reviewerID, comment string) (ApprovalRequest, error) {
req = NormalizeApproval(req)
nextStatus = strings.TrimSpace(strings.ToLower(nextStatus))
reviewerID = strings.TrimSpace(reviewerID)
if req.Status != ApprovalPending {
return ApprovalRequest{}, errors.New("only pending approval can be reviewed")
}
if nextStatus != ApprovalApproved && nextStatus != ApprovalRejected {
return ApprovalRequest{}, errors.New("next status must be approved or rejected")
}
if reviewerID == "" {
return ApprovalRequest{}, errors.New("reviewer_id is required")
}
now := time.Now()
req.Status = nextStatus
req.ReviewerID = reviewerID
req.ReviewComment = strings.TrimSpace(comment)
req.ReviewedAt = &now
return req, nil
}