Skip to content

feat: validate credentials after config init#1151

Open
dc-bytedance wants to merge 6 commits into
larksuite:mainfrom
dc-bytedance:feat/config-probe
Open

feat: validate credentials after config init#1151
dc-bytedance wants to merge 6 commits into
larksuite:mainfrom
dc-bytedance:feat/config-probe

Conversation

@dc-bytedance
Copy link
Copy Markdown

@dc-bytedance dc-bytedance commented May 28, 2026

Summary

After lark-cli config init saves credentials, validate them against the open platform so that users get immediate feedback when they typed the wrong App ID or App Secret, instead of discovering it later from a failed business request. The check is best-effort: it never blocks the command, never changes the exit code, and stays silent on anything ambiguous (network errors, server 5xx, unknown response codes, timeout).

Changes

  • Add internal/credential/tat_fetch.go::FetchTAT — a pure-HTTP TAT request helper (no config / no keychain access). Returns typed errs.* errors per the §984 contract: *errs.AuthenticationError for HTTP 401/403 or any non-zero TAT body code, *errs.NetworkError for transport failures and HTTP 5xx (with CauseKind: "5xx" + Retryable: true), *errs.InternalError for 4xx-non-401/403 / JSON parse failures / marshal failures / empty-token-on-success.
  • Refactor internal/credential/default_provider.go::doResolveTAT to delegate to FetchTAT — observable behaviour unchanged for existing TAT consumers; the underlying transport path now yields typed errors which propagate up the credential chain.
  • Add cmd/config/init_probe.go::runProbe — best-effort post-init validator. Runs both calls under a single 3-second context.WithTimeout. The warning is fired whenever FetchTAT returns *errs.AuthenticationError (the typed lane that carries deterministic credential-rejection signals from the upstream API); other lanes (NetworkError / InternalError) stay silent by construction. One stderr line is emitted in that case:
    warning: configured credentials may be invalid (code <LABEL>): please verify App ID and App Secret in lark-cli config.
    <LABEL> is the TAT body code (e.g. 10014 when the App Secret is wrong, 10003 when the App ID is invalid) or HTTP 401/HTTP 403 when the request was rejected pre-body.
  • Wire runProbe into all four cmd/config/init.go paths (non-interactive, --new, interactive TUI, legacy readline). Probe is skipped when the user reused an existing secret (no fresh plaintext in memory).
  • Tests:
    • internal/credential/tat_fetch_test.go covers success, body-code rejection, HTTP 401/403, HTTP 5xx, non-401/403 4xx (400/404/415/429), transport error, parse error, empty-token-on-success, brand routing, context cancel — each asserts the specific typed error and key fields.
    • cmd/config/init_probe_test.go (15 black-box tests) covers the real-world TAT body codes (10014 "invalid app secret", 10003 "invalid param"), unknown-body-code coverage (any non-zero code triggers a warning), HTTP 401/403, silent-on-ambiguous cases (HTTP 5xx, transport error, unknown HTTP, parse failure, HTTP client error), probe request shape (URL, method, Bearer header, JSON body with from: "lark-cli/<version>"), brand routing, and 3s timeout.

Test Plan

  • make unit-test passed
  • make build + go vet ./... passed
  • local-eval passed (E2E 7/7 in tests_e2e/config/, skillave N/A — no shortcut/skill/meta-API changes)
  • acceptance-reviewer passed (7/7 scenarios)
  • manual verification against the live TAT endpoint:
    • App Secret wrong (real App ID + wrong secret): exit 0, stdout JSON {"appId":"...","appSecret":"****","brand":"feishu"}, stderr OK: Configuration saved then warning: configured credentials may be invalid (code 10014): please verify App ID and App Secret in lark-cli config.
    • App ID nonexistent (random ID + any secret): exit 0, JSON, stderr ends with warning: ... (code 10003): ...
    • App ID + Secret both correct: exit 0, JSON, OK: only, no warning, ~0.8s total
    • Network unreachable (HTTPS_PROXY=http://127.0.0.1:1): exit 0, JSON, no probe warning (transport error stays silent per design)
    • --brand lark with wrong secret: exit 0, JSON "brand":"lark", warning with TAT body code (lark host routing confirmed)

Related Issues

N/A

Summary by CodeRabbit

  • New Features
    • Configuration initialization now automatically validates your application credentials, providing immediate feedback if the app ID or secret is invalid during setup.

Review Change Stack

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 28, 2026

CLA assistant check
All committers have signed the CLA.

@github-actions github-actions Bot added the size/L Large or sensitive change across domains or core paths label May 28, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a60de5a7-1c14-4141-adfc-7fce952d2ce4

📥 Commits

Reviewing files that changed from the base of the PR and between e300c0e and 72dabf5.

📒 Files selected for processing (6)
  • cmd/config/init.go
  • cmd/config/init_probe.go
  • cmd/config/init_probe_test.go
  • internal/credential/default_provider.go
  • internal/credential/tat_fetch.go
  • internal/credential/tat_fetch_test.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • cmd/config/init.go
  • internal/credential/default_provider.go
  • internal/credential/tat_fetch.go
  • internal/credential/tat_fetch_test.go
  • cmd/config/init_probe.go
  • cmd/config/init_probe_test.go

📝 Walkthrough

Walkthrough

This PR introduces post-config credential probing to the config init flow. A new FetchTAT function centralizes tenant access token exchange with typed error handling, replacing inline credential logic. The probe validates saved credentials and sends an optional probe request, emitting warnings only for deterministic credential-rejection signals while remaining silent on transport failures.

Changes

Post-Config Credential Probing

Layer / File(s) Summary
TAT fetch core function and error mapping
internal/credential/tat_fetch.go
FetchTAT exchanges app credentials for tenant access tokens with comprehensive error typing: request/JSON errors become InternalError, transport failures become retryable NetworkError, HTTP 401/403 become AuthenticationError, HTTP 5xx become retryable NetworkError, and response decode/validation errors map to appropriate error subtypes. Supports brand-based URL routing.
TAT fetch test suite
internal/credential/tat_fetch_test.go
Tests cover successful token retrieval, request payload validation, authentication error classification (response codes and HTTP 401/403), network error handling, JSON parse failures, brand-specific routing, and context cancellation. Uses stubRoundTripper and urlRewriteRT test helpers.
Probe invocation function and error detection
cmd/config/init_probe.go
runProbe performs TAT fetch within a timeout, emits a single stderr warning for deterministic rejection signals (API codes or HTTP 401/403), and silently attempts a probe POST to the brand-routed endpoint using the TAT as a bearer token; probe outcomes are ignored.
Probe test suite with request verification
cmd/config/init_probe_test.go
Tests validate TAT error outcomes (deterministic codes and HTTP 401/403 emit warnings; 5xx and transport errors are silent), probe request contracts (HTTP POST, correct URL, Authorization header, from with build.Version), brand routing, client initialization failures, and timeout enforcement. Includes fakeRT, jsonResp, and fakeFactory helpers.
Config init flow integration
cmd/config/init.go
Adds runProbe calls after config save in four paths: non-interactive app-id/app-secret, --new app creation, interactive TUI (only when new secret), and legacy readline fallback (only when secret input non-empty).
Default provider TAT fetch refactor
internal/credential/default_provider.go
Refactors existing TAT resolution to use the new FetchTAT function, removing inline HTTP wiring and JSON decode logic while maintaining caching via sync.Once. Removes unused imports.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

feature

Suggested reviewers

  • liangshuo-1
  • Roy-oss1

Poem

🐰 I hop through code where tokens gleam,
I peek, I prod, I spare the scream.
If creds are wrong I softly warn,
If nets are down I rest at dawn —
A gentle probe, then off I beam.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: validate credentials after config init' directly and clearly summarizes the main change: credential validation is performed after configuration initialization.
Description check ✅ Passed The PR description comprehensively covers all required template sections: Summary explains the motivation, Changes lists main additions with technical details, Test Plan documents verification steps, and Related Issues is addressed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/config/init_probe_test.go`:
- Around line 63-79: The test builds a Factory directly in fakeFactory; replace
that with the repo-standard TestFactory to ensure proper test isolation: in the
shared setup call t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir()) and create
the factory via cmdutil.TestFactory(t, config) instead of manually constructing
&cmdutil.Factory and HttpClient; update fakeFactory (and the similar block at
the other occurrence around lines 255-266) to return the factory and error
buffer from cmdutil.TestFactory so tests use the canonical TestFactory and
isolated config dir.

In `@internal/credential/tat_fetch.go`:
- Around line 23-31: The comment block describing error classification in
internal/credential/tat_fetch.go is out of sync: update the line that currently
states “other non-2xx → *errs.NetworkError” to match the runtime behavior where
non-2xx responses (excluding 401/403 and 5xx) are returned as
*errs.InternalError (subtype "sdk_error"); keep the existing rules for
*errs.AuthenticationError (401/403 or body code via Problem.Code) and
*errs.NetworkError (5xx or transport failures wrapped via Cause) so callers see
the same contract as the code path implemented around the non-2xx handling in
the block that returns *errs.InternalError (see the code near the current return
sites for *errs.InternalError in the 112-119 region).
- Around line 137-147: When parsed.Code == 0 you must also validate
parsed.TenantAccessToken is non-empty; if TenantAccessToken is empty, return an
internal SDK error instead of a successful empty token. Update the success
branch in tat_fetch.go (the block that currently returns
parsed.TenantAccessToken) to check parsed.TenantAccessToken (and/or
parsed.TenantAccessToken == "") and return an errs.InternalError (populate
errs.Problem with Category: errs.CategoryInternal, an appropriate Subtype such
as errs.SubtypeSDK, and a clear Message like "missing tenant_access_token on TAT
API success") so callers fail fast with a clear cause.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d60a3a6b-dc9b-4969-b50f-cab448016cba

📥 Commits

Reviewing files that changed from the base of the PR and between b91f6a2 and 1af43d8.

📒 Files selected for processing (6)
  • cmd/config/init.go
  • cmd/config/init_probe.go
  • cmd/config/init_probe_test.go
  • internal/credential/default_provider.go
  • internal/credential/tat_fetch.go
  • internal/credential/tat_fetch_test.go

Comment thread cmd/config/init_probe_test.go
Comment thread internal/credential/tat_fetch.go Outdated
Comment thread internal/credential/tat_fetch.go
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 28, 2026

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@72dabf540f8f3583a1888bdd93f56e821b1d28c0

🧩 Skill update

npx skills add dc-bytedance/cli#feat/config-probe -y -g

Drop the ad-hoc *HTTPStatusError and classify TAT outcomes via the
canonical errs.* taxonomy:

  * HTTP 401/403 + non-zero TAT body code → *errs.AuthenticationError
    with Problem.Code carrying the upstream signal
  * HTTP 5xx                              → *errs.NetworkError with
                                             CauseKind "5xx" and
                                             Retryable=true
  * 4xx other than 401/403, JSON parse,
    or 2xx with empty tenant_access_token → *errs.InternalError with
                                             subtype "sdk_error"
  * Transport / DNS / TLS / context cancel → *errs.NetworkError wrapping
                                              the underlying cause

classifyTATError now extracts the typed signal via errors.As, removing
the parallel apiCode return.

Test factory switched to cmdutil.TestFactory(t, nil) with
LARKSUITE_CLI_CONFIG_DIR=t.TempDir() per repo guideline, then HttpClient
overridden with stubRoundTripper to keep per-test response control.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 29, 2026

Codecov Report

❌ Patch coverage is 77.27273% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.82%. Comparing base (a2cc5e1) to head (72dabf5).

Files with missing lines Patch % Lines
internal/credential/tat_fetch.go 81.81% 14 Missing and 2 partials ⚠️
cmd/config/init.go 0.00% 6 Missing ⚠️
cmd/config/init_probe.go 83.33% 3 Missing and 3 partials ⚠️
internal/credential/default_provider.go 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1151      +/-   ##
==========================================
+ Coverage   68.77%   68.82%   +0.04%     
==========================================
  Files         628      630       +2     
  Lines       58670    58777     +107     
==========================================
+ Hits        40353    40455     +102     
  Misses      15021    15021              
- Partials     3296     3301       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Large or sensitive change across domains or core paths

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants