Commit Graph
29 Commits
Author SHA1 Message Date
fantiu 46192d68ba feat(api):client logic fixed. 2026-04-24 17:04:09 +08:00
fantiu eeb1782f7a feat(api): add raw DingTalk OpenAPI command with dual-version token support 2026-04-24 16:40:13 +08:00
ybc❤️zyrand猷诺 ad33a46883 fix: device flow defensively resets credentials before login (#155) (#157)
Device flow now always clears stale credential state and re-fetches
clientID from MCP server, regardless of what previous login methods
(OAuth scan, PAT, etc.) left in app.json or runtime globals.

This replaces the previous Source-field approach with a simpler
defensive reset that is future-proof against new login methods.

Root cause: after OAuth login saved app.json without MCP source marker,
subsequent --device login reused the stale clientID without setting
clientIDFromMCP flag, causing exchangeCode() to use direct mode which
requires clientSecret.

Changes:
- Add resetCredentialState() to DeviceFlowProvider
- Login() always calls resetCredentialState() + FetchClientIDFromMCP()
- Remove AppConfig.Source field (no longer needed)
- Remove app_config_source_test.go (replaced by device_flow_reset_test.go)
- Add 5 tests covering OAuth→device, legacy→device, direct→device scenarios

Co-authored-by: 猷诺 <bicheng.ybc@alibaba-inc.com>
2026-04-24 14:11:16 +08:00
xianfeng wang bbca507792 feat(discovery): MCP discovery service abstraction with positional params, examples, defaults, and schema v3 extensions (#156)
* discovery

* discovery

* wk discovery

* wk discovery

* wk discovery

* wk discovery

* wk discovery

* wk discovery

* discovery example and default

* position param

* Fix test

* dev auto login

* fix test

* fix conflict
2026-04-24 14:08:17 +08:00
xuan 89c5038446 fix(auth): restore device_code polling when flowId is absent (#145)
* fix(auth): fallback to device_code when flowId is missing

* chore(auth): remove dead helper and harden fallback tests
2026-04-22 15:13:40 +08:00
fantiuandgithub-actions[bot] e0544579d2 fix(auth): attribute CLI auth denial to channel before user scope (#144)
* chore: update coverage badge [skip ci]

* chore: update coverage badge [skip ci]

* fix(auth): attribute CLI auth denial to channel before user scope

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-22 12:05:30 +08:00
shangguanxuan633-labandshangguanxuan.sgx 725577103d feat: PAT scope error visualization and auto-retry with authorization polling (#113)
* feat: PAT scope error visualization and auto-retry with authorization polling

1. PAT error result visualization (non-JSON)
   - Human-readable error output matching lark-cli style
   - Shows error type, message, hint, and authorization command
   - JSON output also available via --format json

2. Auto-retry with polling after authorization wall
   - Detects missing_scope / insufficient_scope / permission errors
   - Polls every 5s for token update after user completes auth
   - 10 minute timeout before giving up
   - Automatically retries the original command after successful auth

Changes:
- internal/app/pat_auth_retry.go: Core PAT error handling and retry logic
- internal/app/pat_auth_retry_test.go: 11 unit tests
- internal/app/runner.go: Integration with executeInvocation error path
- internal/auth/device_flow.go: Add SetScope() method

* feat: migrate PAT (Permission Authorization) infrastructure to open-source core

Move PAT permission management code from dws-wukong overlay to the
open-source dingtalk-workspace-cli core. This enables PAT handling
in the public distribution while keeping dws-wukong fully compatible
through the edition.Hooks mechanism.

Changes:
- pkg/edition: add 6 new Hooks fields (AuthClientID, AuthClientFromMCP,
  SaveToken, LoadToken, DeleteToken, ClassifyToolResult) for overlay
  extensions to inject custom auth/token/error behaviour
- internal/errors/pat: new PATError type with ExitCode()=4 and
  RawStderr() for embedded-mode passthrough, plus ClassifyToolResultContent
  and ClassifyMCPResponseText classification functions
- internal/pat: new command group (pat chmod) with tool result handling
- internal/app/root: register PAT commands before RegisterExtraCommands hook
- internal/app/runner: integrate ClassifyToolResult hook in the
  callResult.IsError branch so overlays can intercept PAT/gateway errors
  before generic handling

The dws-wukong overlay remains unchanged — its existing pat/ package and
RegisterExtraCommands hook continue to work. Through the go.mod replace
directive and deduplicateCommands mechanism, both codebases coexist
without conflict.

* feat(pat): add PAT auth check with device flow polling and auto-retry

- Add ClassifyPatAuthCheck / AsPatAuthCheckError in pat.go for
  AGENT_CODE_NOT_EXISTS error detection
- Add handlePatAuthCheck in pat_auth_retry.go: inject clientId as
  x-robot-uid header, poll device flow endpoint, auto-retry on APPROVED
- Integrate PAT check into runner.go executeInvocation pipeline
  (edition hook + open-source fallback)
- Add patAuthRequiredCodes map for extensible auth-required code matching
- Remove test_parse.go (temporary test script)

* fix(pat): update poll path to /cli/oauth/device/poll and add x-user-access-token header

- Change DevicePollPath from /api/dingtalk-workspace-cli/oauth/device/poll
  to /cli/oauth/device/poll (aligning with backend endpoint convention)
- Add x-user-access-token header to poll requests (loaded from stored token)

* feat(auth): PAT device flow improvements and flowId empty guard

- pat_auth_retry: fix JSON field parsing (result -> data) using DevicePollResponse
- pat_auth_retry: fix elapsed time calculation based on start timestamp
- device_flow: add flowId empty guard - skip polling and show auth URL for manual handling
- device_flow: unify terminalBaseURL to GetMCPBaseURL for polling endpoint
- device_flow: remove unused PollFlowApproval dead code
- runner: integrate DWS_CLIENT_ID env and app.json persistence
- oauth_provider: add x-robot-uid header removal on logout
- client: add request/response logging for transport debugging

* feat(env): switch all service discovery URLs from pre-release to production

- endpoints: pre-login/pre-api/pre-mcp/pre-open-dev -> login/api/mcp/open-dev
- loader: DefaultMarketBaseURL -> mcp.dingtalk.com
- registry: defaultBaseURL -> mcp.dingtalk.com
- constants: DefaultTerminalBaseURL -> open-dev.dingtalk.com

* fix: remove residual merge conflict markers and duplicate Hooks fields in edition.go; unify developer-settings URL via config helper in device_flow.go

* chore: remove lark-cli reference from PrintPatAuthError comment

* test: add comprehensive unit tests for PAT auth modules

- Create internal/errors/pat_test.go (38 tests): covers ClassifyToolResultContent,
  ClassifyMCPResponseText, ClassifyPatAuthCheck, AsPatAuthCheckError, cleanPATJSON,
  stripClassFields, getDWSGatewayErrorCode, isNotLoggedInError, isBusinessError,
  IsPATError, IsPATNoPermissionCode, suggestForBusinessErrorText
- Supplement pat_auth_retry_test.go (+7 tests): IsPatRetrying context checks,
  pollPatDeviceFlow edge cases (server error fallback, SSO redirect skip),
  extractPatScopeError nil/identity extraction

* feat(pat): exchange authCode for fresh token after PAT APPROVED

Previously pollPatDeviceFlow discarded the authCode from the poll
response, so handlePatAuthCheck retried with the stale token after
APPROVED. This mirrors device_flow.go loginOnce which calls
exchangeCode → SaveTokenData.

Changes:
- pollPatDeviceFlow: return (status, authCode, error) instead of
  (status, error); extract Data.AuthCode on APPROVED
- handlePatAuthCheck APPROVED path: call ExchangeCodeForToken +
  SaveTokenData before ResetRuntimeTokenCache, with graceful
  fallback on exchange failure
- Update all 6 poll test cases for new 3-return signature; add
  authCode assertions for APPROVED/REJECTED/EXPIRED/CANCELLED/
  ServerError scenarios

* fix(pat): CR round-2 must-fix items

- scopeValueRegex: support multi-segment scopes (mail:a.b:send)
  Updated regex to ([a-zA-Z][a-zA-Z0-9_.]*(?::[a-zA-Z][a-zA-Z0-9_.]*)+)

- handlePatAuthCheck: add 3 integration tests (APPROVED/REJECTED/EmptyFlowID)
  Covers the 132-line main orchestrator with mock runner + httptest server

- Extract ParseDeviceFlowStatus + status constants to auth package
  Eliminates string literal duplication across device_flow.go and pat_auth_retry.go

* fix(pat): use direct OAuth path when clientSecret is provided

When PAT error response includes both clientId and clientSecret,
use SetClientID() (direct DingTalk API mode) instead of
SetClientIDFromMCP() (MCP proxy mode). The MCP proxy does not
hold the secret for the PAT-assigned app, causing HTTP 400
'invalidParameter.idOrSecret.notFound' on token exchange.

Now: clientSecret present → direct mode; absent → MCP proxy mode.

---------

Co-authored-by: shangguanxuan.sgx <shangguanxuan.sgx@alibaba-inc.com>
2026-04-19 19:12:34 +08:00
fantiu 4f1ee37508 fix(auth): improve login UX for terminal auth denial cases 2026-04-17 10:20:35 +08:00
fantiu fec0347cd6 feat(auth):improve login UX for terminal auth denial cases 2026-04-17 10:15:04 +08:00
fantiu 95d495f290 feat: supports claw-like products. 2026-04-16 19:49:28 +08:00
fantiu b78dd19cf9 feat: centralize scattered configs and add dws config list 2026-04-12 14:23:11 +08:00
wxianfeng c49583836b feat(auth): delegate token persistence to edition hooks with keychain fallback
Add SaveToken, LoadToken, and DeleteToken hook fields to edition.Hooks so overlay builds can provide custom token storage. Refactor SaveTokenData, LoadTokenData, and DeleteTokenData to delegate to hooks when present, falling back to default keychain-based storage.
2026-04-10 23:33:11 +08:00
wxianfeng aec852f971 feat(auth): add edition overlay auth credentials and token marker for embedded mode
- Add AuthClientID and AuthClientFromMCP fields to edition Hooks, allowing overlays to override the default OAuth client ID and route auth through MCP endpoints.

- Introduce token marker file (token.json) mechanism so the host application in embedded mode can detect authentication state without accessing the keychain.

- Update SaveTokenData/DeleteTokenData to write/remove the marker file when running in embedded mode.

- Update ClientID() and IsClientIDFromMCP() to respect edition overrides.
2026-04-10 17:02:18 +08:00
fantiu 7c4932154c fix:auth check test file gofmt. 2026-04-02 11:20:06 +08:00
fantiu e2dbaa7c78 feat(auth): unify MCP retry constant and add retry to remaining endpoints 2026-04-02 11:10:49 +08:00
fantiu 11a0dbc84a feat(auth): unify MCP retry constant and add retry to remaining endpoints 2026-04-02 10:55:51 +08:00
fantiu ee441643dd fix(auth): switch CLI auth check from fail-open to fail-closed
Previously, when the /cli/cliAuthEnabled API was unreachable (network
error, timeout, 5xx, etc.), both OAuth and Device Flow login modes
silently assumed CLI access was enabled (fail-open). This allowed users
to "successfully" log in even when their organization had not granted
CLI data access, leading to confusing failures on subsequent API calls.

Changes:
- Reverse the check logic in OAuth callback: treat any error as
  "not enabled" instead of "enabled", showing the permission request
  page so users can take action.
- Block login in Device Flow when the check fails, with a clear
  error message asking users to verify network connectivity.
- Add retry with backoff (3 attempts, 0s/1s/2s) to
  CheckCLIAuthEnabled to tolerate transient network issues.
- Add retry with backoff (3 attempts) to FetchClientIDFromMCP
  (/cli/clientId) for the same transient-error resilience.
- Add i18n entries (en/zh) for new error messages.
- Add 19 tests covering server error, connection refused, malformed
  JSON, timeout, transient-then-recovery, business error, and full
  Device Flow loginOnce integration scenarios for both endpoints.

Made-with: Cursor
2026-04-02 10:55:51 +08:00
xianfeng wang 5c0d2b274c Merge branch 'DingTalk-Real-AI:main' into feature/wk_merge 2026-04-01 21:05:35 +08:00
fantiu 15d495e56e style(auth): redesign OAuth authorization pages UI 2026-04-01 20:21:05 +08:00
fantiu 8406355e7f fix(auth): prevent auth code expiration error on OAuth callback page refresh 2026-04-01 14:48:58 +08:00
fantiu 2a056cc5d0 feat(auth): persist OAuth credentials for reliable token refresh 2026-04-01 11:03:08 +08:00
wxianfeng 933615003c merge upstream main 2026-04-01 09:53:18 +08:00
fantiu 773804ee80 feat(auth): enhance device flow with CLI auth check and admin guidance 2026-04-01 00:47:49 +08:00
wxianfeng 3c75c66d4d chore: group pkg imports per goimports
Move pkg/config next to other pkg/* imports after local internal packages.

Made-with: Cursor
2026-03-31 15:32:50 +08:00
wxianfeng 93d6fdb17e feat: edition layer for Wukong overlay; promote shared code to pkg/
Introduce a build-time edition hook so downstream overlays (e.g. Wukong)
can customize auth UX, config dir, static server list, visible products,
and extra root commands while keeping the default open-source behavior.

- Add pkg/edition (defaults) and pkg/editiontest contract tests; Makefile
  target edition-test; CI job edition-tests.
- Root: optional RegisterExtraCommands with tool caller adapter; inject
  static servers to skip market discovery when configured; deduplicate
  top-level commands so overlay wins; extend hideNonDirectRuntimeCommands
  with edition VisibleProducts and static commands (recovery/schema/mcp).
- Auth/config: gate login subcommand and auth login hints for embedded
  editions; optional token auto-purge; edition ConfigDir override.
- version: human-readable multi-line output plus JSON with edition,
  architecture, build, commit.
- Relocate internal/{config,convert,validate} to pkg/; add pkg/cli and
  pkg/cmdutil (flags/time helpers).
- CI: optional notify-downstream job (GitLab trigger via secrets) on main
  push; open_source_policy_test adjusted for new layout.

Secrets (repo settings): WUKONG_TRIGGER_TOKEN, WUKONG_TRIGGER_URL — optional;
if unset, downstream step is skipped.

Made-with: Cursor
2026-03-31 15:29:21 +08:00
fantiu 26263f8a17 feat(auth): persist client credentials and optimize keychain access
- Auto-persist client-id/client-secret after successful login (stored in keychain)
- Enhanced logout to clean up app.json, keychain secrets, and token.json
- Fixed OAuth callback race condition (write response before sending code)
- Added credentials cache to avoid repeated keychain access (improves CLI speed)
- Updated README with credential priority docs and bumped to v1.0.4
2026-03-30 11:57:07 +08:00
fantiu 964855373e feat(auth): persist client credentials for token refresh
When logging in with --client-id and --client-secret, credentials are now
automatically persisted to enable automatic token refresh after expiration.
Client secret is securely stored in system Keychain, config file only
contains a reference.
2026-03-30 10:53:26 +08:00
柏荣 a1dffe454d 逻辑优化 2026-03-28 17:51:22 +08:00
tianlei.qjb 5f938d3675 init 2026-03-27 17:55:57 +08:00