fix(dev): keep recovery commands behind confirmation

This commit is contained in:
玉澜 committed 2026-08-11 17:36:59 +08:00
1 parent 5ce391b49b
commit b7b78f0c16
2 files changed
+32 -4

No files matched your search

+4 -4
View File
@@ -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 <selectedUserId> --yes --format json", unifiedAppID, versionID),
Command: fmt.Sprintf("dws dev app version publish --unified-app-id %s --version-id %s --approver-user-id <selectedUserId> --format json", unifiedAppID, versionID),
DryRunCommand: fmt.Sprintf("dws dev app version publish --unified-app-id %s --version-id %s --approver-user-id <selectedUserId> --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 <versionId> --yes --format json", appID),
Command: fmt.Sprintf("dws dev app version publish --unified-app-id %s --version-id <versionId> --format json", appID),
DryRunCommand: fmt.Sprintf("dws dev app version publish --unified-app-id %s --version-id <versionId> --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 <name> --robot-name <robotName> --desc <desc>%s --yes --format json", taskIDFlag),
Command: fmt.Sprintf("dws dev app robot submit --name <name> --robot-name <robotName> --desc <desc>%s --format json", taskIDFlag),
DryRunCommand: fmt.Sprintf("dws dev app robot submit --name <name> --robot-name <robotName> --desc <desc>%s --dry-run --format json", taskIDFlag),
DoneWhen: "返回新的 WAITING taskId;FAIL 场景优先复用原 taskId,EXPIRED 场景重新提交",
Blocking: true,
@@ -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)