Files
Agent-System/internal/projectinstance/activation_official_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

100 lines
3.5 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_ActivateOfficialWorkflowRuntimeMetadata 回归激活链路:
// ActivateInstance.applyRuntimeMetadata 会遍历文档任务实例并逐条 UPDATE。
// 若在同一事务连接上 rows 未读完时就执行 Exec,pgx 会返回 "conn busy"。
// 本测试使用正式商务对接流程(3 阶段 7 任务)覆盖该路径。
func TestPG_ActivateOfficialWorkflowRuntimeMetadata(t *testing.T) {
pool := openPGPool(t)
defer pool.Close()
ctx := context.Background()
wfStore := workflowdef.NewStore(pool)
def, err := workflowdef.LoadManifestDefinition("main.v2.json")
if err != nil {
t.Fatalf("load main.v2 manifest: %v", err)
}
if err := wfStore.UpsertPublishedSeed(ctx, workflowdef.CreateDefinitionInput{
Key: workflowdef.OfficialKeyMain,
Name: "商务对接流程",
Definition: def,
}, 1); err != nil {
t.Fatalf("seed official main workflow: %v", err)
}
pwStore := projectworkflow.NewStore(pool)
instStore := projectinstance.NewStore(pool)
svc := projectinstance.NewService(instStore, wfStore, pwStore, nil)
var projectID int64
code := "pg-official-" + 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 Official Activation Test "+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.OfficialKeyMain, 0)
if err != nil {
t.Fatalf("default plan: %v", err)
}
for i := range plan.Stages {
for j := range plan.Stages[i].DocTasks {
plan.Stages[i].DocTasks[j].Duties = projectinstance.DocDuty{
AuthorUserID: 1, ReviewerUserID: 2, ApproverUserID: 3,
}
}
}
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 instance, got %q", activated.Instance.Status)
}
// 运行时元数据应写回文档任务实例(回归 applyRuntimeMetadata 的逐条 UPDATE)。
var executorKey string
err = pool.QueryRow(ctx, `
SELECT dti.executor_key
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 IN ('intake', 'bd_intake')
`, activated.Instance.ID).Scan(&executorKey)
if err != nil {
t.Fatalf("query runtime metadata: %v", err)
}
if executorKey != "bizdev.intake.v1" {
t.Fatalf("expected executor_key bizdev.intake.v1, got %q", executorKey)
}
}