mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-10-21 23:01:37 +02:00
fix: validate form edits and enforce task result ownership
This commit is contained in:
1 parent
ab17ffda87
commit
bdefa535b0
19 files changed
+331
-20
No files matched your search
@@ -757,6 +757,9 @@ func batchQueueConcurrencyFromRow(row *database.BatchTaskQueueRow) int {
|
||||
|
||||
// UpdateQueueMetadata 更新队列标题、角色、代理模式和并发数(非 running 时可用)
|
||||
func (m *BatchTaskManager) UpdateQueueMetadata(queueID, title, role, agentMode string, concurrency *int, hitlPolicies ...string) error {
|
||||
if concurrency != nil && (*concurrency < 1 || *concurrency > MaxBatchQueueConcurrency) {
|
||||
return fmt.Errorf("并发数必须为 1–%d", MaxBatchQueueConcurrency)
|
||||
}
|
||||
if utf8.RuneCountInString(title) > MaxBatchQueueTitleLen {
|
||||
return fmt.Errorf("标题不能超过 %d 个字符", MaxBatchQueueTitleLen)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"cyberstrike-ai/internal/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func TestProjectUpdateRejectsBlankNameWithoutPartialSave(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
db, err := database.NewDB(filepath.Join(t.TempDir(), "project.db"), zap.NewNop())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
project, err := db.CreateProject(&database.Project{Name: "original", Description: "old", Status: "active"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r := gin.New()
|
||||
r.PUT("/projects/:id", NewProjectHandler(db, zap.NewNop()).UpdateProject)
|
||||
for _, body := range []string{`{"name":"","description":"new"}`, `{"name":" "}`} {
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodPut, "/projects/"+project.ID, strings.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
r.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusBadRequest {
|
||||
t.Fatalf("status %d: %s", rec.Code, rec.Body)
|
||||
}
|
||||
saved, err := db.GetProject(project.ID)
|
||||
if err != nil || saved.Name != "original" || saved.Description != "old" {
|
||||
t.Fatalf("partial save: %#v %v", saved, err)
|
||||
}
|
||||
}
|
||||
// An omitted name remains a valid partial update.
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodPut, "/projects/"+project.ID, strings.NewReader(`{"description":"updated"}`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
r.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("partial update: %d %s", rec.Code, rec.Body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBatchConcurrencyEditRejectsOutOfRangeWithoutMutation(t *testing.T) {
|
||||
m := NewBatchTaskManager(zap.NewNop())
|
||||
q, err := m.CreateBatchQueue("original", "", "eino_single", "manual", "", "", nil, 3, []string{"hello"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, n := range []int{-1, 0, 9, 99} {
|
||||
if err := m.UpdateQueueMetadata(q.ID, "changed", "", "eino_single", &n); err == nil {
|
||||
t.Fatalf("accepted %d", n)
|
||||
}
|
||||
saved, _ := m.GetBatchQueue(q.ID)
|
||||
if saved.Concurrency != 3 || saved.Title != "original" {
|
||||
t.Fatalf("mutated queue: %#v", saved)
|
||||
}
|
||||
}
|
||||
for _, n := range []int{1, 8} {
|
||||
if err := m.UpdateQueueMetadata(q.ID, "original", "", "eino_single", &n); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
saved, _ := m.GetBatchQueue(q.ID)
|
||||
if saved.Concurrency != n {
|
||||
t.Fatalf("saved %d, want %d", saved.Concurrency, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,9 +198,12 @@ func (h *ProjectHandler) UpdateProject(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
if req.Name != nil {
|
||||
if s := strings.TrimSpace(*req.Name); s != "" {
|
||||
p.Name = s
|
||||
s := strings.TrimSpace(*req.Name)
|
||||
if s == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "项目名称不能为空"})
|
||||
return
|
||||
}
|
||||
p.Name = s
|
||||
}
|
||||
if req.Description != nil {
|
||||
p.Description = clampProjectDescription(*req.Description)
|
||||
|
||||
Reference in new issue
Block a user