From b7b78f0c1622142fb4cd861a6bfa41c0cc4ee2bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=89=E6=BE=9C?= Date: Tue, 11 Aug 2026 17:36:59 +0800 Subject: [PATCH] fix(dev): keep recovery commands behind confirmation --- internal/helpers/devapp.go | 8 +++--- internal/helpers/devapp_shared_result_test.go | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/internal/helpers/devapp.go b/internal/helpers/devapp.go index abd78a70..bad84387 100644 --- a/internal/helpers/devapp.go +++ b/internal/helpers/devapp.go @@ -2388,7 +2388,7 @@ func normalizeDevAppVersionApproval(content map[string]any) { }, devAppNextStep(devAppStep{ ID: "publish_version", - Command: fmt.Sprintf("dws dev app version publish --unified-app-id %s --version-id %s --approver-user-id --yes --format json", unifiedAppID, versionID), + Command: fmt.Sprintf("dws dev app version publish --unified-app-id %s --version-id %s --approver-user-id --format json", unifiedAppID, versionID), DryRunCommand: fmt.Sprintf("dws dev app version publish --unified-app-id %s --version-id %s --approver-user-id --dry-run --format json", unifiedAppID, versionID), DoneWhen: "approvalSubmitted=true、versionStatus=AUDIT 或 processStatus=UNDER_REVIEW 表示已提交审批;published=true 表示已发布", Blocking: true, @@ -2510,7 +2510,7 @@ func devAppRobotPublishSteps(appID string) []map[string]any { steps := []map[string]any{ devAppNextStep(devAppStep{ ID: "create_version", - Command: fmt.Sprintf("dws dev app version create --unified-app-id %s --desc \"发布机器人能力\" --yes --format json", appID), + Command: fmt.Sprintf("dws dev app version create --unified-app-id %s --desc \"发布机器人能力\" --format json", appID), DryRunCommand: fmt.Sprintf("dws dev app version create --unified-app-id %s --desc \"发布机器人能力\" --dry-run --format json", appID), DoneWhen: "返回 versionId", Blocking: true, @@ -2523,7 +2523,7 @@ func devAppRobotPublishSteps(appID string) []map[string]any { }), devAppNextStep(devAppStep{ ID: "publish_version", - Command: fmt.Sprintf("dws dev app version publish --unified-app-id %s --version-id --yes --format json", appID), + Command: fmt.Sprintf("dws dev app version publish --unified-app-id %s --version-id --format json", appID), DryRunCommand: fmt.Sprintf("dws dev app version publish --unified-app-id %s --version-id --dry-run --format json", appID), DoneWhen: "published=true 表示已发布;approvalSubmitted=true、versionStatus=AUDIT 或 processStatus=UNDER_REVIEW 表示已提交审批;SELECT_APPROVER 时必须先让用户从 approvalCandidates 选择审批人后追加 --approver-user-id", RequiresUserInput: true, @@ -2574,7 +2574,7 @@ func devAppRobotRetryStep(taskID string, reuseTaskID bool) map[string]any { } return devAppNextStep(devAppStep{ ID: "retry_robot_submit", - Command: fmt.Sprintf("dws dev app robot submit --name --robot-name --desc %s --yes --format json", taskIDFlag), + Command: fmt.Sprintf("dws dev app robot submit --name --robot-name --desc %s --format json", taskIDFlag), DryRunCommand: fmt.Sprintf("dws dev app robot submit --name --robot-name --desc %s --dry-run --format json", taskIDFlag), DoneWhen: "返回新的 WAITING taskId;FAIL 场景优先复用原 taskId,EXPIRED 场景重新提交", Blocking: true, diff --git a/internal/helpers/devapp_shared_result_test.go b/internal/helpers/devapp_shared_result_test.go index 00f15216..2f5caa65 100644 --- a/internal/helpers/devapp_shared_result_test.go +++ b/internal/helpers/devapp_shared_result_test.go @@ -6,6 +6,7 @@ package helpers import ( "bytes" "context" + "strings" "testing" "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/executor" @@ -74,6 +75,9 @@ func TestDevAppSharedResultMapperClassifiesServiceOutcomes(t *testing.T) { if env.Meta.Operation.State != "waiting_for_approver_selection" || env.Meta.Operation.NextCommand == "" { t.Fatalf("approval operation=%+v", env.Meta.Operation) } + if strings.Contains(env.Meta.Operation.NextCommand, "--yes") { + t.Fatalf("approval next_command bypasses confirmation: %q", env.Meta.Operation.NextCommand) + } }) t.Run("pagination", func(t *testing.T) { @@ -237,6 +241,30 @@ func TestDevAppSharedResultMapperClassifiesServiceOutcomes(t *testing.T) { }) } +func TestDevAppRecoveryCommandsDoNotBypassConfirmation(t *testing.T) { + steps := append(devAppRobotPublishSteps("u1"), devAppRobotRetryStep("task1", true)) + approval := map[string]any{ + "approvalMode": "SELECT_APPROVER", + "unifiedAppId": "u1", + "versionId": "v1", + "approvalCandidates": []any{ + map[string]any{"userId": "user-1", "name": "Alice"}, + }, + } + normalizeDevAppVersionApproval(approval) + steps = append(steps, approval["nextSteps"].([]map[string]any)...) + for _, step := range steps { + for _, key := range []string{"command", "dryRunCommand"} { + command, _ := step[key].(string) + for _, field := range strings.Fields(command) { + if field == "--yes" || strings.HasPrefix(field, "--yes=") { + t.Fatalf("step %v publishes confirmation bypass in %s: %q", step["id"], key, command) + } + } + } + } +} + func TestFrameworkDevAppMapperBoundaryMatrix(t *testing.T) { if got := devAppDataWithoutPagination("scalar"); got != "scalar" { t.Fatalf("non-object data = %#v, want scalar preserved", got)