mirror of
https://github.com/larksuite/cli.git
synced 2026-07-09 18:34:03 +08:00
Every failure on the authentication, authorization, and configuration
path now surfaces as a typed structured error instead of an ad-hoc
envelope. Users and scripts that consume CLI output get:
- a fixed nine-category taxonomy on the wire, each mapped to a
stable shell exit code (authentication/authorization/config = 3,
network = 4, internal = 5, policy = 6, confirmation = 10)
- identity-aware detail fields (missing_scopes, requested_scopes,
granted_scopes, console_url, log_id, retryable, hint) carried
uniformly on the envelope
- a single canonical policy envelope at exit 6; the legacy
auth_error carve-out is retired
- per-subtype canonical message + hint that preserves Lark's
diagnostic phrasing and routes recovery to the right actor:
app developer (app_scope_not_applied), user (missing_scope,
token_scope_insufficient, user_unauthorized), or tenant admin
(app_unavailable, app_disabled)
- wrong app credentials classify as config/invalid_client whether
surfaced by the Open API endpoint (99991543) or the tenant
access-token mint endpoint (10003 / 10014), instead of
collapsing to a transport error or api/unknown
- local shortcut scope preflight emits the same
authorization/missing_scope envelope (identity + deterministic
missing-scope set) used by the post-call permission path, so AI
consumers read the same structured shape from precheck and from
server-returned permission denial
- streaming download/upload failures keep the same network subtype
split (timeout / TLS / DNS / transport) as the non-stream path
instead of collapsing every cause to a generic transport failure
- console_url is carried only on the bot-perspective
app_scope_not_applied envelope (where the recovery action is
"developer applies the scope at the developer console"); the
user-perspective missing_scope envelope drops the field, since
the only actionable user recovery is `lark-cli auth login --scope`
and pointing an end user at a console they cannot modify is
misleading
- bind workflows (Hermes / OpenClaw / lark-channel) flatten dynamic
Type tags to wire 'config' with the original module name kept
as a metric label
All 10 typed errors are cause-bearing, nil-safe on .Error() and
.Unwrap(), and defensively clone slice setter inputs. Four lint
rules (CheckNilSafeError / CheckBuilderImmutable / CheckUnwrapSymmetry
/ CheckBuildAPIErrorArms) lock these invariants on migrated paths.
170 lines
7.8 KiB
YAML
170 lines
7.8 KiB
YAML
version: "2"
|
|
|
|
run:
|
|
timeout: 5m
|
|
|
|
linters:
|
|
default: none
|
|
enable:
|
|
- asasalint # checks for pass []any as any in variadic func(...any)
|
|
- asciicheck # checks that code does not contain non-ASCII identifiers
|
|
- bidichk # checks for dangerous unicode character sequences
|
|
- bodyclose # checks whether HTTP response body is closed successfully
|
|
- copyloopvar # detects places where loop variables are copied
|
|
- durationcheck # checks for two durations multiplied together
|
|
- exptostd # detects functions from golang.org/x/exp/ replaceable by std
|
|
- fatcontext # detects nested contexts in loops
|
|
- gocheckcompilerdirectives # validates go compiler directive comments (//go:)
|
|
- gochecksumtype # checks exhaustiveness on Go "sum types"
|
|
- gocritic # diagnostics for bugs, performance and style
|
|
- gomoddirectives # checks for replace, retract, and exclude in go.mod
|
|
- goprintffuncname # checks that printf-like functions end with f
|
|
- govet # reports suspicious constructs
|
|
- ineffassign # detects ineffective assignments
|
|
- nilerr # finds code that returns nil even if error is not nil
|
|
- nolintlint # reports ill-formed nolint directives
|
|
- nosprintfhostport # checks for misuse of Sprintf to construct host:port
|
|
- reassign # checks that package variables are not reassigned
|
|
- unconvert # removes unnecessary type conversions
|
|
- unused # checks for unused constants, variables, functions and types
|
|
- depguard # blocks forbidden package imports
|
|
- forbidigo # forbids specific function calls
|
|
|
|
# To enable later after fixing existing issues:
|
|
# - errcheck # checks for unchecked errors
|
|
# - errname # checks that error types are named XxxError
|
|
# - errorlint # checks error wrapping best practices
|
|
# - gosec # security-oriented linter
|
|
# - misspell # finds commonly misspelled English words
|
|
# - staticcheck # comprehensive static analysis
|
|
|
|
exclusions:
|
|
paths:
|
|
- generated
|
|
rules:
|
|
- path: _test\.go$
|
|
linters:
|
|
- bodyclose
|
|
- bidichk
|
|
- gocritic
|
|
- depguard
|
|
- forbidigo
|
|
# Paths that run forbidigo. Add an entry when a path joins one of
|
|
# the rules below.
|
|
- path-except: (shortcuts/|internal/|cmd/auth/|cmd/config/|cmd/service/)
|
|
linters:
|
|
- forbidigo
|
|
- path: internal/vfs/
|
|
linters:
|
|
- forbidigo
|
|
# shortcuts-no-raw-http is shortcuts-only; internal/ wraps raw HTTP
|
|
# for the client / credential layer.
|
|
- path-except: shortcuts/
|
|
text: shortcuts-no-raw-http
|
|
linters:
|
|
- forbidigo
|
|
# errs-typed-only enforced on paths already migrated to errs.NewXxxError.
|
|
# Add a path when its migration is complete.
|
|
- path-except: (internal/auth/|internal/errcompat/|internal/errclass/|internal/client/|internal/cmdutil/factory\.go|cmd/auth/|cmd/config/|cmd/service/|shortcuts/common/mcp_client\.go|shortcuts/calendar/helpers\.go)
|
|
text: errs-typed-only
|
|
linters:
|
|
- forbidigo
|
|
|
|
settings:
|
|
depguard:
|
|
rules:
|
|
shortcuts-no-vfs:
|
|
files:
|
|
- "**/shortcuts/**"
|
|
deny:
|
|
- pkg: "github.com/larksuite/cli/internal/vfs"
|
|
desc: >-
|
|
shortcuts must not import internal/vfs directly.
|
|
Use runtime.FileIO() for file operations or runtime.ValidatePath() for path validation.
|
|
- pkg: "github.com/larksuite/cli/internal/vfs/localfileio"
|
|
desc: >-
|
|
shortcuts must not import internal/vfs/localfileio directly.
|
|
Use runtime.FileIO() for file operations or runtime.ValidatePath() for path validation.
|
|
forbidigo:
|
|
forbid:
|
|
# ── legacy output.Err* helpers banned on migrated paths ──
|
|
# output.ErrBare is intentionally not listed — it is the predicate-
|
|
# command silent-exit signal, outside the typed envelope contract.
|
|
- pattern: output\.(ErrValidation|ErrAuth|ErrNetwork|ErrAPI|ErrWithHint|Errorf)\b
|
|
msg: >-
|
|
[errs-typed-only] use errs.NewXxxError(...) builder
|
|
(see errs/types.go).
|
|
# ── http: shortcuts must not construct raw HTTP requests ──
|
|
# Bans request / client construction; constants (http.MethodPost,
|
|
# http.StatusOK) and pure helpers (http.StatusText, http.Header) are
|
|
# intentionally allowed since they don't bypass the runtime layer.
|
|
- pattern: http\.(Client|NewRequest|NewRequestWithContext|Get|Post|PostForm|Head|DefaultClient|DefaultTransport|RoundTripper|Do|Serve|ListenAndServe)\b
|
|
msg: >-
|
|
[shortcuts-no-raw-http] use RuntimeContext.DoAPI/CallAPI/DoAPIJSON
|
|
instead of constructing raw HTTP. The runtime handles auth, headers,
|
|
and error normalization. (Constants and helpers like http.MethodPost,
|
|
http.StatusOK, http.StatusText remain allowed.)
|
|
# ── os: already wrapped in internal/vfs ──
|
|
- pattern: os\.(Stat|Lstat|Open|OpenFile|Rename|ReadFile|WriteFile|Getwd|UserHomeDir|ReadDir)\b
|
|
msg: "use the corresponding vfs.Xxx() from internal/vfs"
|
|
- pattern: os\.(Create|CreateTemp|MkdirTemp)\b
|
|
msg: >-
|
|
internal/: use vfs.CreateTemp() or vfs.OpenFile().
|
|
shortcuts/: avoid temp files — use io.Reader streaming or in-memory buffers.
|
|
- pattern: os\.Mkdir(All)?\b
|
|
msg: "use vfs.MkdirAll() from internal/vfs"
|
|
- pattern: os\.Remove\b
|
|
msg: >-
|
|
internal/: use vfs.Remove() from internal/vfs.
|
|
shortcuts/: avoid temp files — use io.Reader streaming or in-memory buffers.
|
|
- pattern: os\.RemoveAll\b
|
|
msg: >-
|
|
internal/: add RemoveAll to internal/vfs/fs.go first, then use vfs.RemoveAll().
|
|
shortcuts/: avoid temp files — use io.Reader streaming or in-memory buffers.
|
|
# ── os: not yet in vfs — add to vfs/fs.go first ──
|
|
- pattern: os\.(Chdir|Chmod|Chown|Lchown|Chtimes|CopyFS|DirFS|Link|Symlink|Readlink|Truncate|SameFile)\b
|
|
msg: "add this function to internal/vfs/fs.go first, then use vfs.Xxx()"
|
|
# ── os: IO streams ──
|
|
- pattern: os\.Std(in|out|err)\b
|
|
msg: "use IOStreams (In/Out/ErrOut) instead of os.Stdin/Stdout/Stderr"
|
|
# ── os: process ──
|
|
- pattern: os\.Exit\b
|
|
msg: >-
|
|
Do not use os.Exit in shortcuts/. Return an error instead and let
|
|
the caller (cmd layer) decide how to terminate.
|
|
# ── output: shortcuts must use ctx.Out() ──
|
|
- pattern: fmt\.Print(f|ln)?\b
|
|
msg: >-
|
|
use ctx.Out() or ctx.OutFormat() for structured JSON output.
|
|
fmt.Print* bypasses the output envelope and breaks --jq/--format.
|
|
# ── logging: shortcuts must return errors, not log.Fatal ──
|
|
- pattern: log\.(Print|Fatal|Panic)(f|ln)?\b
|
|
msg: >-
|
|
use structured error return, not log.Fatal/Panic.
|
|
Shortcuts must return errors to the framework for proper exit code handling.
|
|
# ── filepath: functions that access the filesystem ──
|
|
- pattern: filepath\.(EvalSymlinks|Walk|WalkDir|Glob|Abs)\b
|
|
msg: >-
|
|
These filepath functions access the filesystem directly.
|
|
internal/: use vfs helpers or localfileio path validation.
|
|
shortcuts/: use runtime.ValidatePath() or runtime.FileIO().
|
|
analyze-types: true
|
|
gocritic:
|
|
disabled-checks:
|
|
- appendAssign
|
|
- hugeParam
|
|
disabled-tags:
|
|
- style
|
|
govet:
|
|
enable:
|
|
- httpresponse
|
|
|
|
formatters:
|
|
enable:
|
|
- gofmt
|
|
- goimports
|
|
|
|
issues:
|
|
max-issues-per-linter: 0
|
|
max-same-issues: 0
|