Files
Agent-System/internal/projectinstance/rdev_pg_test.go
T
weichenandCursor c767a99807 fix(authz): close project-context ABAC gap and repair CI PG fixtures
enforceChatProjectAccess before allowAnyStageAccess on GET /context/project
so activated projects are no longer readable by arbitrary authenticated users.

Align failing gate fixtures with official workflow keys, isolated TEST_DATABASE_URL,
unique project names (00057), duty membership, and in-memory bizdev-cli envs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 18:12:26 +08:00

124 lines
4.0 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 projectinstance_test
import (
"context"
"testing"
"time"
"chat-agent-system/internal/projectinstance"
"chat-agent-system/internal/projectworkflow"
"chat-agent-system/internal/workflowdef"
)
// TestPG_RDevActivateWithNAClose 激活 rdev(60 任务)并将 rd_sw_plan 规划关闭。
func TestPG_RDevActivateWithNAClose(t *testing.T) {
pool := openPGPool(t)
defer pool.Close()
ctx := context.Background()
wfStore := workflowdef.NewStore(pool)
def, err := workflowdef.LoadManifestDefinition("rdev.v2.json")
if err != nil {
t.Fatalf("load rdev manifest: %v", err)
}
if err := wfStore.UpsertPublishedSeed(ctx, workflowdef.CreateDefinitionInput{
Key: workflowdef.OfficialKeyRDev,
Name: "研发设计控制流程",
Definition: def,
}, 1); err != nil {
t.Fatalf("seed rdev: %v", err)
}
pwStore := projectworkflow.NewStore(pool)
instStore := projectinstance.NewStore(pool)
svc := projectinstance.NewService(instStore, wfStore, pwStore, nil)
var projectID int64
code := "pg-rdev-" + time.Now().Format("150405.000")
err = pool.QueryRow(ctx, `
INSERT INTO projects (code, name, status, creator_user_id, lifecycle_status, active_workflow_key, workflow_selection_version, workflow_plan_revision)
VALUES ($1, $2, 'active', 1, 'planning', '', 1, 0) RETURNING id
`, code, "PG RDev Activation "+code).Scan(&projectID)
if err != nil {
t.Fatalf("insert project: %v", err)
}
t.Cleanup(func() {
_, _ = pool.Exec(context.Background(), `DELETE FROM projects WHERE id = $1`, projectID)
})
plan, err := svc.BuildDefaultPlan(ctx, workflowdef.OfficialKeyRDev, 0)
if err != nil {
t.Fatalf("default plan: %v", err)
}
if len(plan.Stages) != 13 {
t.Fatalf("want 13 stages, got %d", len(plan.Stages))
}
taskCount := 0
for i := range plan.Stages {
for j := range plan.Stages[i].DocTasks {
taskCount++
plan.Stages[i].DocTasks[j].Duties = projectinstance.DocDuty{
AuthorUserID: 1, ReviewerUserID: 2, ApproverUserID: 3,
}
if plan.Stages[i].DocTasks[j].TaskKey == "rd_sw_plan" {
plan.Stages[i].DocTasks[j].Enabled = false
}
}
}
if taskCount != 60 {
t.Fatalf("want 60 tasks, got %d", taskCount)
}
if _, err := svc.SaveWorkflowPlan(ctx, projectID, 1, true, projectinstance.SavePlanInput{
Plan: *plan, ExpectedPlanRevision: 0, ExpectedSelectionVersion: 1,
}); err != nil {
t.Fatalf("save plan: %v", err)
}
preview, err := svc.ActivationPreview(ctx, projectID, 1, true)
if err != nil {
t.Fatalf("preview: %v", err)
}
activated, err := svc.Activate(ctx, projectID, 1, true, projectinstance.ActivateInput{
ConfirmationToken: preview.ConfirmationToken,
ExpectedProjectVersion: preview.ExpectedProjectVersion,
ExpectedPlanRevision: preview.ExpectedPlanRevision,
})
if err != nil {
t.Fatalf("activate: %v", err)
}
if activated.Instance.Status != projectinstance.InstanceActive {
t.Fatalf("expected active, got %q", activated.Instance.Status)
}
if activated.Instance.ConfigSnapshot.WorkflowDefinitionKey != workflowdef.OfficialKeyRDev {
t.Fatalf("key=%s", activated.Instance.ConfigSnapshot.WorkflowDefinitionKey)
}
var executorKey string
var enabled bool
err = pool.QueryRow(ctx, `
SELECT dti.executor_key, dti.enabled
FROM project_doc_task_instances dti
JOIN project_stage_instances si ON si.id = dti.stage_instance_id
WHERE si.workflow_instance_id = $1 AND dti.task_key = 'rd_proposal'
`, activated.Instance.ID).Scan(&executorKey, &enabled)
if err != nil {
t.Fatalf("query rd_proposal: %v", err)
}
if executorKey != "squad.rdev_doc.v1" || !enabled {
t.Fatalf("rd_proposal executor=%q enabled=%v", executorKey, enabled)
}
err = pool.QueryRow(ctx, `
SELECT dti.enabled
FROM project_doc_task_instances dti
JOIN project_stage_instances si ON si.id = dti.stage_instance_id
WHERE si.workflow_instance_id = $1 AND dti.task_key = 'rd_sw_plan'
`, activated.Instance.ID).Scan(&enabled)
if err != nil {
t.Fatalf("query rd_sw_plan: %v", err)
}
if enabled {
t.Fatal("rd_sw_plan should be disabled (N/A planning close)")
}
}