Files
artex/server/task_intercept.go
T
dela 0335d572de
ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
detections / detections (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
First Commit
2026-10-09 08:38:16 +08:00

197 lines
5.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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})
}