Compare commits

..
4 Commits
Author SHA1 Message Date
修雨 9e15115ad4 ci(release): add workflow_dispatch trigger as fallback (#261)
GitHub occasionally drops tag push events; this adds a manual trigger
so we can re-run the release job against any tag ref without having to
delete and re-push the tag.
2026-05-11 09:53:23 +08:00
xianfeng wangandgithub-actions[bot] 25bf3d12f2 feat(upgrade): block self-upgrade in embedded distributions (#248)
* chore: update coverage badge [skip ci]

* chore: update coverage badge [skip ci]

* chore: update coverage badge [skip ci]

* chore: update coverage badge [skip ci]

* chore: update coverage badge [skip ci]

* 1.0.19 changelog

* upgrade not in embed

* remove comment

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-09 20:27:20 +08:00
修雨 f78cc5c846 docs(auth): correct login help to reflect actual default + SSH guidance (#226) (#238)
* docs(auth): correct login help to reflect actual default + SSH guidance (#226)

The --help long description for `dws auth login` claimed the default mode was
"OAuth 设备流 (默认)", but the actual default starts a 127.0.0.1 loopback
listener (oauth_provider.go:131-136) and only switches to device flow when
--device is passed. SSH-into-headless-Linux users following the docs hit a
dead end because the local browser cannot reach 127.0.0.1 on the remote box.

Rewrite the description so each method is named after its real flag:
  - OAuth Loopback 流 (默认)
  - OAuth 设备流 (--device)
  - 直接提供 Token (--token)

Add an explicit warning callout and a `--device` example for SSH/headless
environments. Also realign two flagErrorWithSuggestions strings in root.go
that propagated the same misconception ("默认使用设备流" → loopback default,
SSH 用户加 --device).

No behavioural change.

* docs(auth): drop emoji from login help warning
2026-05-09 09:25:57 +08:00
修雨 72fe795f3f docs(changelog): add 1.0.23 release notes (#241)
Backfill 1.0.23 entry covering PR #237 (HTTP_PROXY/HTTPS_PROXY support
restored across the three custom http.Transport instances). Format
follows the 1.0.22 section: narrative + Fixed + Tests.
2026-05-08 20:41:11 +08:00
6 changed files with 101 additions and 5 deletions
+1
View File
@@ -4,6 +4,7 @@ on:
push:
tags:
- "v*"
workflow_dispatch:
permissions:
contents: write
+12
View File
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
The format is inspired by [Keep a Changelog](https://keepachangelog.com/) and this project follows [Semantic Versioning](https://semver.org/).
## [1.0.23] - 2026-05-08
A single fix for HTTP proxy support across the CLI's custom HTTP transports. No behaviour changes elsewhere.
### Fixed
- **`HTTP_PROXY` / `HTTPS_PROXY` environment variables silently ignored by all custom transports** (#237, fixes #236) — the three custom `http.Transport` instances built by the CLI (`internal/transport/client.go` MCP transport, `internal/apiclient/client.go` DingTalk OpenAPI client, `internal/app/legacy.go` IPv4-forcing registry client) all set `DialContext` / `TLSClientConfig` / timeouts but omitted the `Proxy` field. Per Go's `net/http` contract, a non-nil Transport without an explicit `Proxy` means "no proxy" — env vars are silently ignored, breaking sandboxed or air-gapped deployments that route outbound through `HTTP_PROXY` / `HTTPS_PROXY`. All three transports now set `Proxy: http.ProxyFromEnvironment`.
### Tests
- Per-package regression test that pointer-compares the Transport's `Proxy` func against `http.ProxyFromEnvironment`, avoiding flakiness from Go's `envProxyOnce` memoisation when running alongside tests that read proxy env early. (#237)
## [1.0.22] - 2026-05-07
Two release-blocking bug fixes: `dws attendance summary` now exposes the server-required `--stats-type` flag (without it, every call returned C0002), and the install scripts finally populate `~/.hermes/skills/dws/` for users who already have Hermes.
+8 -3
View File
@@ -68,16 +68,21 @@ func newAuthLoginCommand() *cobra.Command {
Long: `登录钉钉并获取认证凭证。
支持的登录方式:
- OAuth 设备流 (默认): 通过钉钉扫码授权登录
- 直接提供 Token: 通过 --token 参数传入已有 token
- OAuth Loopback 流 (默认): 本机自动起 127.0.0.1 监听接收回调,浏览器授权后自动完成
- OAuth 设备流 (--device): 显示 user_code + 短 URL,适合 SSH 远程 / 容器 / 无头环境
- 直接提供 Token (--token): 跳过授权,使用已有 token
不支持的登录方式:
- 邮箱/密码登录
- 手机号/验证码登录
- 应用凭证 (AppKey/AppSecret) 直接登录
注意: SSH 远程或无头环境(无本地浏览器可访问远端的 127.0.0.1)请使用 --device,
否则 OAuth 回调会跳到本机不可达的 127.0.0.1 链接,授权完成后无法回写 token。
示例:
dws auth login # 扫码登录
dws auth login # 本机扫码登录 (loopback 流)
dws auth login --device # SSH 远程 / 无头环境登录 (设备流)
dws auth login --force # 强制重新登录 (忽略缓存 token)
dws auth login --token xxx # 使用指定 token`,
DisableAutoGenTag: true,
+2 -2
View File
@@ -120,8 +120,8 @@ func flagErrorWithSuggestions(cmd *cobra.Command, err error) error {
// Common flag aliases and suggestions
suggestions := map[string]string{
"--json": "提示: 请使用 --format json 或 -f json 来输出 JSON 格式",
"--method": "提示: dws auth login 默认使用 OAuth 设备流登录,无需指定 --method",
"--device-flow": "提示: dws auth login 默认已使用设备流,无需 --device-flow 参数",
"--method": "提示: dws auth login 默认使用 OAuth loopback 流;SSH/无头环境请加 --device 走设备流",
"--device-flow": "提示: 设备流的标志名是 --device(不是 --device-flow),SSH/无头环境登录请用 dws auth login --device",
"--email": "提示: dws 不支持邮箱/密码登录,请使用 dws auth login 进行扫码登录",
"--code": "提示: dws 不支持验证码登录,请使用 dws auth login 进行扫码登录",
"--corp-id": "提示: corp-id 会在登录时自动获取,无需手动指定",
+9
View File
@@ -14,6 +14,7 @@ import (
"time"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/upgrade"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition"
"github.com/fatih/color"
"github.com/spf13/cobra"
)
@@ -57,6 +58,14 @@ func newUpgradeCommand() *cobra.Command {
dws upgrade -y # 跳过确认直接升级`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
if h := edition.Get(); h != nil && h.IsEmbedded {
name := h.Name
if name == "" {
name = "embedded"
}
return fmt.Errorf("当前运行在嵌入模式(%s),dws upgrade 已禁用;请通过宿主完成升级", name)
}
yes, _ := cmd.Flags().GetBool("yes")
format := resolveUpgradeFormat(cmd)
@@ -0,0 +1,69 @@
// Copyright 2026 Alibaba Group
// Licensed under the Apache License, Version 2.0
package app
import (
"bytes"
"strings"
"testing"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition"
)
func TestUpgradeCommand_BlockedInEmbeddedMode(t *testing.T) {
prev := edition.Get()
edition.Override(&edition.Hooks{IsEmbedded: true, Name: "embedded"})
t.Cleanup(func() { edition.Override(prev) })
cases := []struct {
name string
args []string
}{
{"check", []string{"--check"}},
{"list", []string{"--list"}},
{"rollback", []string{"--rollback"}},
{"plain", []string{}},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
cmd := newUpgradeCommand()
var out, errBuf bytes.Buffer
cmd.SetOut(&out)
cmd.SetErr(&errBuf)
cmd.SetArgs(tc.args)
err := cmd.Execute()
if err == nil {
t.Fatalf("upgrade %v in embedded mode must return error, got nil", tc.args)
}
msg := err.Error()
if !strings.Contains(msg, "嵌入模式") {
t.Errorf("error message should mention 嵌入模式, got: %q", msg)
}
if !strings.Contains(msg, "embedded") {
t.Errorf("error message should include edition name, got: %q", msg)
}
if !strings.Contains(msg, "dws upgrade") {
t.Errorf("error message should reference dws upgrade for clarity, got: %q", msg)
}
})
}
}
func TestUpgradeCommand_NotBlockedInOpenSourceMode(t *testing.T) {
prev := edition.Get()
edition.Override(&edition.Hooks{IsEmbedded: false, Name: "open"})
t.Cleanup(func() { edition.Override(prev) })
cmd := newUpgradeCommand()
var out, errBuf bytes.Buffer
cmd.SetOut(&out)
cmd.SetErr(&errBuf)
cmd.SetArgs([]string{"--check"})
err := cmd.Execute()
if err != nil && strings.Contains(err.Error(), "嵌入模式") {
t.Errorf("open-source mode must not be blocked by embedded guard, got: %v", err)
}
}