Files
Agent-System/internal/swboot/catalog_test.go
T
weichen 83561682eb feat(swboot): wire SWBOOT-10 controlled patch executor (fail-closed)
DB-backed repo_path_allowlist reader (deny-all until admin seeds), per-prefix
admin test_commands (goose 00075), execution evidence table (goose 00074),
isolated git-worktree patch executor with command allowlist/time/output caps
and failure-stops evidence; controlled_patch creation/preview unlocked only
with an allowlisted repo binding (projectworkflow gate + catalog flag);
creator-only server endpoints for bindings/executions; merge/push/deploy stay
behind a typed separate-authorization boundary. Module boundary: app->swboot
composition import registered.
2026-09-26 00:56:59 +00:00

125 lines
4.6 KiB
Go

package swboot
import (
"errors"
"strings"
"testing"
"time"
)
func TestProjectTypesCatalog(t *testing.T) {
items := ProjectTypesCatalog()
if len(items) != 4 {
t.Fatalf("expected 4 project types, got %d", len(items))
}
for _, it := range items {
if it.ProductDomain != DomainNonMedicalSoftware {
t.Fatalf("project type %s polluted domain %q", it.Key, it.ProductDomain)
}
if it.DefaultWorkflowKey != "software_bootstrap" {
t.Fatalf("expected software_bootstrap default for %s", it.Key)
}
blob := strings.ToLower(it.Name + " " + it.Description)
for _, bad := range []string{"临床", "nmpa", "cdmo"} {
if strings.Contains(blob, bad) {
t.Fatalf("medical term in project type %s", it.Key)
}
}
}
}
func TestBuildCreationPreview_SelfBootstrapSolo(t *testing.T) {
res := BuildCreationPreview(CreationPreviewInput{
Name: "Agent-System 自举", ProductDomain: DomainNonMedicalSoftware,
ProjectTypeKey: ProjectTypeExistingSelfBootstrap,
ProblemStatement: "建立可信路线", TargetUsers: "内部团队", TargetOutcome: "可执行发布路线",
GovernanceProfile: GovernanceStandard, TeamMode: TeamModeSolo,
ComplianceProfileKey: "internal_control+security_baseline",
ExecutionMode: ExecutionDocsOnly,
}, time.Date(2026, 9, 16, 12, 0, 0, 0, time.UTC))
if !res.Valid {
t.Fatalf("expected valid preview, issues=%v", res.Issues)
}
if res.ApprovalPolicy != ApprovalCreatorAcknowledgement {
t.Fatalf("expected creator acknowledgement, got %s", res.ApprovalPolicy)
}
if res.RecommendedWorkflow != "software_bootstrap" {
t.Fatalf("expected software_bootstrap, got %s", res.RecommendedWorkflow)
}
if res.CreationToken == "" || res.PlanHash == "" {
t.Fatal("expected token and plan hash")
}
}
func TestBuildCreationPreview_RejectsControlledPatchAndSoloPrivacy(t *testing.T) {
res := BuildCreationPreview(CreationPreviewInput{
Name: "x", ProductDomain: DomainNonMedicalSoftware,
ProjectTypeKey: ProjectTypeGreenfield,
ProblemStatement: "p", TargetUsers: "u", TargetOutcome: "o",
TeamMode: TeamModeSolo, ComplianceProfileKey: "privacy",
ExecutionMode: ExecutionControlledPatch,
}, time.Now().UTC())
if res.Valid {
t.Fatal("expected invalid")
}
joined := strings.Join(res.Issues, ";")
if !strings.Contains(joined, "solo") {
t.Fatalf("expected solo/privacy issue, got %v", res.Issues)
}
if !strings.Contains(joined, "ERR_EXECUTION_MODE_DISABLED") {
t.Fatalf("expected controlled_patch disabled, got %v", res.Issues)
}
}
func TestRepoAllowlistStub(t *testing.T) {
al := NewRepoAllowlist([]string{"/home/weichen/projects/Agent-System"})
if err := al.CheckReadOnlyAccess("/home/weichen/projects/Agent-System/cmd"); err != nil {
t.Fatalf("expected allowlisted path ok: %v", err)
}
if err := al.CheckReadOnlyAccess("/etc/passwd"); !errors.Is(err, ErrRepoPathNotAllowlisted) {
t.Fatalf("expected not allowlisted, got %v", err)
}
if err := al.ExecuteControlledPatch("/home/weichen/projects/Agent-System", nil); !errors.Is(err, ErrPatchExecutionUnimplemented) {
t.Fatalf("expected stub rejection, got %v", err)
}
if err := ApproveMerge("feature/x"); !errors.Is(err, ErrMergeRequiresSeparateAuthorization) {
t.Fatalf("merge must stay behind separate authorization, got %v", err)
}
empty := DefaultRepoAllowlist()
if empty.IsAllowlisted("/home/weichen/projects/Agent-System") {
t.Fatal("empty allowlist must deny all")
}
}
func TestSuggestDeliveryAfterBootstrapNeverActivates(t *testing.T) {
s := SuggestDeliveryAfterBootstrap()
if s.WorkflowKey != "software_delivery" {
t.Fatalf("key=%s", s.WorkflowKey)
}
if s.AutoActivate {
t.Fatal("must not auto-activate delivery")
}
if s.Summary == "" {
t.Fatal("expected operator-facing summary")
}
}
// SWBOOT-10: controlled_patch preview is valid only with an admin-allowlisted
// repo binding; without the flag it stays the fail-closed rejection.
func TestPreview_ControlledPatchRequiresAllowlistedBinding(t *testing.T) {
mk := func(allowlisted bool, repo string) CreationPreviewInput {
return CreationPreviewInput{
Name: "受控补丁预览", ProductDomain: DomainNonMedicalSoftware,
ProjectTypeKey: "greenfield", ProblemStatement: "p", TargetUsers: "u", TargetOutcome: "o",
ExecutionMode: ExecutionControlledPatch, RepoAllowlisted: allowlisted, RepoPath: repo,
}
}
if res := BuildCreationPreview(mk(false, "/repo/x"), time.Now().UTC()); res.Valid {
t.Fatalf("controlled_patch without allowlisted binding must be invalid: %+v", res.Issues)
}
res := BuildCreationPreview(mk(true, "/allow/repo"), time.Now().UTC())
if !res.Valid {
t.Fatalf("controlled_patch with allowlisted binding must preview valid: %+v", res.Issues)
}
}