package server import ( "errors" "net/http" "github.com/Autumn-27/artex/db" ) // validateTaskInterceptRuleReq 의 action 검증 오류다. 이 검증기와 buildTaskInterceptRules // 의 호출처는 작업 수준 규칙 CRUD 핸들러(taskInterceptCreateRule·taskInterceptUpdateRule) // 와 작업·템플릿 생성/수정 핸들러(createTask·pgCreateTaskTemplate·pgUpdateTaskTemplate)뿐이고, // 전부 writeErr 로 HTTP 400 을 돌려주는 사용자 전용 경로다(에이전트 도구를 거치지 않는다). // action 열거값(block·allow)은 클라이언트가 그대로 주고받는 와이어 식별자라 원문을 유지한다. const errTaskInterceptInvalidAction = "action 은 block 또는 allow 여야 합니다" // 任务级资产拦截/允许规则的 CRUD。规则按 task_id 归属,仅对该任务生效: // action=block 拦截(禁止测试),action=allow 允许(白名单)。执行判定见 db.EvaluateAssetGate。 type taskInterceptRuleReq struct { Enabled bool `json:"enabled"` Action string `json:"action"` // block | allow Kind string `json:"kind"` Pattern string `json:"pattern"` Note string `json:"note"` } // validateTaskInterceptRuleReq 归一并校验;复用全局规则的 kind/pattern 校验器。 func validateTaskInterceptRuleReq(req *taskInterceptRuleReq) error { if req.Action == "" { req.Action = "block" } if req.Action != "block" && req.Action != "allow" { return errors.New(errTaskInterceptInvalidAction) } v := assetInterceptRuleReq{Enabled: req.Enabled, Kind: req.Kind, Pattern: req.Pattern, Note: req.Note} if err := validateAssetInterceptRuleReq(&v); err != nil { return err } req.Pattern = v.Pattern // 已 trim return nil } // buildTaskInterceptRules 校验创建任务时录入的任务级规则并转换为 db 输入形态。 func buildTaskInterceptRules(reqs []taskInterceptRuleReq) ([]db.TaskInterceptRuleInput, error) { if len(reqs) == 0 { return nil, nil } out := make([]db.TaskInterceptRuleInput, 0, len(reqs)) for i := range reqs { rq := reqs[i] if err := validateTaskInterceptRuleReq(&rq); err != nil { return nil, err } out = append(out, db.TaskInterceptRuleInput{ Enabled: rq.Enabled, Action: rq.Action, Kind: rq.Kind, Pattern: rq.Pattern, Note: rq.Note, }) } return out, nil } func (s *Server) taskInterceptListRules(w http.ResponseWriter, r *http.Request) { pg := s.pg(w) if pg == nil { return } taskID, ok := pathInt(r, "id") if !ok || taskID <= 0 { writeErr(w, 400, "bad task id") return } rules, err := pg.Assets().ListTaskInterceptRules(taskID) if err != nil { writeErr(w, 500, err.Error()) return } if rules == nil { rules = []db.AssetInterceptRule{} } writeJSON(w, 200, map[string]any{"rules": rules}) } func (s *Server) taskInterceptCreateRule(w http.ResponseWriter, r *http.Request) { pg := s.pg(w) if pg == nil { return } taskID, ok := pathInt(r, "id") if !ok || taskID <= 0 { writeErr(w, 400, "bad task id") return } var req taskInterceptRuleReq if err := decode(r, &req); err != nil { writeErr(w, 400, err.Error()) return } if err := validateTaskInterceptRuleReq(&req); err != nil { writeErr(w, 400, err.Error()) return } rule, err := pg.Assets().CreateTaskInterceptRule(taskID, req.Action, req.Kind, req.Pattern, req.Note, req.Enabled) if err != nil { writeErr(w, 500, err.Error()) return } writeJSON(w, 200, rule) } func (s *Server) taskInterceptUpdateRule(w http.ResponseWriter, r *http.Request) { pg := s.pg(w) if pg == nil { return } taskID, ok := pathInt(r, "id") if !ok || taskID <= 0 { writeErr(w, 400, "bad task id") return } ruleID, ok := pathInt(r, "rid") if !ok || ruleID <= 0 { writeErr(w, 400, "bad rule id") return } var req taskInterceptRuleReq if err := decode(r, &req); err != nil { writeErr(w, 400, err.Error()) return } if err := validateTaskInterceptRuleReq(&req); err != nil { writeErr(w, 400, err.Error()) return } rule, err := pg.Assets().UpdateTaskInterceptRule(taskID, ruleID, req.Action, req.Kind, req.Pattern, req.Note, req.Enabled) if err != nil { writeErr(w, 500, err.Error()) return } writeJSON(w, 200, rule) } func (s *Server) taskInterceptDeleteRule(w http.ResponseWriter, r *http.Request) { pg := s.pg(w) if pg == nil { return } taskID, ok := pathInt(r, "id") if !ok || taskID <= 0 { writeErr(w, 400, "bad task id") return } ruleID, ok := pathInt(r, "rid") if !ok || ruleID <= 0 { writeErr(w, 400, "bad rule id") return } deleted, err := pg.Assets().DeleteTaskInterceptRule(taskID, ruleID) if err != nil { writeErr(w, 500, err.Error()) return } writeJSON(w, 200, map[string]any{"deleted": deleted}) } func (s *Server) taskInterceptToggleRule(w http.ResponseWriter, r *http.Request) { pg := s.pg(w) if pg == nil { return } taskID, ok := pathInt(r, "id") if !ok || taskID <= 0 { writeErr(w, 400, "bad task id") return } ruleID, ok := pathInt(r, "rid") if !ok || ruleID <= 0 { writeErr(w, 400, "bad rule id") return } var req struct { Enabled bool `json:"enabled"` } if err := decode(r, &req); err != nil { writeErr(w, 400, err.Error()) return } if err := pg.Assets().ToggleTaskInterceptRule(taskID, ruleID, req.Enabled); err != nil { writeErr(w, 500, err.Error()) return } writeJSON(w, 200, map[string]any{"ok": true, "enabled": req.Enabled}) }