Close P0 auth gaps for lineage/runs, stage ABAC fail-closed, and project:create; add IAM migrations 00021-23, me settings APIs, schema v2 manifests, orchestrator skeleton, and gate A regression coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
85 lines
2.2 KiB
Go
85 lines
2.2 KiB
Go
package squad
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// ValidateQualityGateV2 按 quality_gate_key 执行结构化门禁。
|
|
func ValidateQualityGateV2(gateKey, wsDir string) []string {
|
|
switch gateKey {
|
|
case "quality.system_reqs.v2":
|
|
return validateRequirementsJSON(wsDir)
|
|
case "quality.test_manager.v2":
|
|
return validateTestCasesJSON(wsDir)
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func validateRequirementsJSON(wsDir string) []string {
|
|
path := filepath.Join(wsDir, "artifacts", "requirements.json")
|
|
raw, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return []string{"requirements.json 为必需产物"}
|
|
}
|
|
var reqs []map[string]any
|
|
if err := json.Unmarshal(raw, &reqs); err != nil {
|
|
return []string{"requirements.json 格式无效"}
|
|
}
|
|
ids := map[string]bool{}
|
|
issues := make([]string, 0)
|
|
for _, r := range reqs {
|
|
id, _ := r["id"].(string)
|
|
if id == "" {
|
|
issues = append(issues, "需求缺少 id")
|
|
continue
|
|
}
|
|
if ids[id] {
|
|
issues = append(issues, "重复需求 id: "+id)
|
|
}
|
|
ids[id] = true
|
|
for _, field := range []string{"verification_method", "acceptance_criteria"} {
|
|
if v, _ := r[field].(string); strings.TrimSpace(v) == "" {
|
|
issues = append(issues, id+": 缺少 "+field)
|
|
}
|
|
}
|
|
}
|
|
return issues
|
|
}
|
|
|
|
func validateTestCasesJSON(wsDir string) []string {
|
|
path := filepath.Join(wsDir, "artifacts", "test_cases.json")
|
|
raw, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return []string{"test_cases.json 为必需产物"}
|
|
}
|
|
var cases []map[string]any
|
|
if err := json.Unmarshal(raw, &cases); err != nil {
|
|
return []string{"test_cases.json 格式无效"}
|
|
}
|
|
reqPath := filepath.Join(wsDir, "artifacts", "requirements.json")
|
|
reqRaw, err := os.ReadFile(reqPath)
|
|
if err != nil {
|
|
return []string{"缺少上游 requirements.json 无法验证覆盖率"}
|
|
}
|
|
var reqs []map[string]any
|
|
_ = json.Unmarshal(reqRaw, &reqs)
|
|
covered := map[string]bool{}
|
|
for _, tc := range cases {
|
|
if rid, _ := tc["requirement_id"].(string); rid != "" {
|
|
covered[rid] = true
|
|
}
|
|
}
|
|
issues := make([]string, 0)
|
|
for _, r := range reqs {
|
|
id, _ := r["id"].(string)
|
|
if id != "" && !covered[id] {
|
|
issues = append(issues, "需求未覆盖: "+id)
|
|
}
|
|
}
|
|
return issues
|
|
}
|