Skip to content

feat(auth): validate explicit scopes locally before login network request#760

Closed
yux1a0-63 wants to merge 3 commits intomainfrom
feat/auth-scope-validator
Closed

feat(auth): validate explicit scopes locally before login network request#760
yux1a0-63 wants to merge 3 commits intomainfrom
feat/auth-scope-validator

Conversation

@yux1a0-63
Copy link
Copy Markdown
Collaborator

@yux1a0-63 yux1a0-63 commented May 6, 2026

Summary

Add local scope validation during lark-cli auth login --scope to catch invalid or misspelled scopes before making any network requests, providing actionable error messages with hints for correct scope names.

Changes

  • Add validateExplicitScopes() to validate explicitly provided scopes against the known scope registry before initiating the OAuth flow
  • Add knownScopesForIdentity() to aggregate all known scopes from registry priorities, metadata, and shortcut definitions
  • Refactor mutual exclusion check for --scope with --domain / --recommend to fail earlier and more clearly
  • Invalid scopes now produce a structured error with a hint pointing to lark-cli auth scopes --format pretty or --domain / --recommend
  • Deduplicate invalid scopes in error messages to avoid noise
  • Update test scope references from im:message:send / im:message:reply to im:message:recall / im:message:readonly (the former are no longer in the known scope registry)

Test Plan

  • Unit tests pass ( TestValidateExplicitScopes_RejectsUnknownScopes , TestValidateExplicitScopes_DeduplicatesInvalidScopes , TestAuthLoginRun_ExplicitInvalidScopeFailsBeforeNetwork , TestAuthLoginRun_ScopeWithDomainFailsWithMutexError )
  • Manual local verification confirms lark-cli auth login --scope "invalid:scope" fails with a helpful error before any network call
  • Manual local verification confirms lark-cli auth login --scope "im:message:recall" proceeds normally

Related Issues

  • None

Summary by CodeRabbit

  • New Features

    • Stronger validation of requested authentication scopes with clearer, actionable error messages.
    • Mutual-exclusion checks to prevent incompatible login options from being used together.
  • Improvements

    • Enhanced login output showing detailed scope summary fields (Requested, NewlyGranted, AlreadyGranted, Granted, Missing) for clearer feedback.
    • Preserves existing device-code, JSON, and token storage flows while adding validation steps.
  • Tests

    • Expanded test coverage for scope validation, mutex cases, and output paths.

@yux1a0-63 yux1a0-63 requested a review from JackZhao10086 May 6, 2026 11:38
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 6, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

📝 Walkthrough

Walkthrough

This PR adds explicit scope validation to the auth login command, prevents --scope from being combined with --domain or --recommend, validates user-provided scopes against a known-scopes registry (including offline_access), and adjusts scope resolution and reporting. Tests are extended to cover invalid/duplicate scopes, mutex errors, and updated scope-summary outputs.

Changes

Auth Login Scope Validation

Layer / File(s) Summary
Data Shape / Known Scopes
cmd/auth/login.go
Adds knownScopesForIdentity() to build a map of valid scopes (includes offline_access and identity shortcuts).
Core Validation
cmd/auth/login.go
Adds validateExplicitScopes(scope string) error to normalize, dedupe, and validate explicit scopes, returning actionable errors for unknown scopes.
Control Flow / Integration
cmd/auth/login.go
Enforces mutual exclusion so --scope cannot be used with --domain or --recommend; validates explicit scopes before proceeding; retains domain/recommend-based scope resolution and auto-approve filtering but reconciles with explicit validation to produce finalScope.
Tests / Expectations
cmd/auth/login_test.go
Adds and updates tests for explicit scope parsing, invalid/duplicate scopes, mutex validation (--scope + --domain/--recommend), device-code flow adjustments, JSON/text output changes, and new scope-summary fields (Requested, NewlyGranted, AlreadyGranted, Missing).

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI
    participant Validator as Scope Validator
    participant AuthSrv as Device/Auth Server
    participant TokenStore as Token Store

    CLI->>Validator: user passes --scope / --domain / --recommend
    alt explicit --scope provided
        Validator-->>CLI: validateExplicitScopes (normalize, dedupe, check knownScopes)
        alt invalid scopes
            Validator-->>CLI: return error (abort)
        else valid scopes
            CLI->>AuthSrv: request device authorization with finalScope
        end
    else domain/recommend path
        CLI->>AuthSrv: resolve candidate scopes (domain/recommend) -> request device authorization
    end
    AuthSrv-->>CLI: device auth flow completes (granted scopes)
    CLI->>TokenStore: save tokens and requested scope summary
    CLI-->>User: print JSON/text summary (Requested, NewlyGranted, AlreadyGranted, Missing)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • larksuite/cli#523: Modifies auth login scope handling and scope-issue messaging with updated output fields.
  • larksuite/cli#317: Touches auth login scope validation and scope-summary/ensureRequestedScopesGranted logic.
  • larksuite/cli#752: Updates login scope handling and device-flow behavior related to validation.

Suggested reviewers

  • liangshuo-1
  • albertnusouo

Poem

🐰 I hop through scopes both near and far,
Checking each token like a tiny star.
No mixing flags that clash and fight,
Known scopes first, then auth takes flight.
Offline access snug and bright.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.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 clearly and specifically describes the main change: adding local validation of explicit scopes before making network requests during auth login.
Description check ✅ Passed The description provides a comprehensive summary, detailed changes list, concrete test plan with specific test names, and follows the required template structure.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/auth-scope-validator

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

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

codecov Bot commented May 6, 2026

Codecov Report

❌ Patch coverage is 89.74359% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.24%. Comparing base (7fb71c6) to head (6fe1939).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
cmd/auth/login.go 89.74% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #760      +/-   ##
==========================================
+ Coverage   64.96%   65.24%   +0.28%     
==========================================
  Files         502      504       +2     
  Lines       46224    46708     +484     
==========================================
+ Hits        30030    30476     +446     
- Misses      13583    13592       +9     
- Partials     2611     2640      +29     

☔ 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.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@6fe1939cbcb5efcf1c3dae7a07b65d1fe19e2a71

🧩 Skill update

npx skills add larksuite/cli#feat/auth-scope-validator -y -g

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: 1

🧹 Nitpick comments (2)
cmd/auth/login_test.go (1)

229-241: 💤 Low value

Stray t.Log(err) looks like leftover debug output.

Line 231 unconditionally logs the error before any assertion. Likely accidental debug residue — safe to drop to keep test output clean.

🧹 Proposed change
 	err := validateExplicitScopes("base:app:create malformed:scope")
-	t.Log(err)
 	if err == nil {
 		t.Fatal("expected validation error for unknown scope")
 	}
🤖 Prompt for 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.

In `@cmd/auth/login_test.go` around lines 229 - 241, In
TestValidateExplicitScopes_RejectsUnknownScopes remove the stray debugging
statement t.Log(err) so the test only asserts on the returned error; locate the
test function TestValidateExplicitScopes_RejectsUnknownScopes and delete the
t.Log(err) line (leaving the error checks that assert err != nil and the
contains checks for "invalid scope(s): malformed:scope" and "auth scopes
--format pretty").
cmd/auth/login.go (1)

540-556: 💤 Low value

Dead code: result slice is built but never used.

validateExplicitScopes only returns an error; the deduplicated result slice is populated for valid scopes but never returned or otherwise consumed. The valid-side branch can be simplified (or result removed entirely), keeping seen only for invalid-scope dedup.

♻️ Proposed simplification
 	knownScopes := knownScopesForIdentity()
 	invalid := make([]string, 0)
-	result := make([]string, 0, len(normalized))
-	seen := make(map[string]bool, len(normalized))
+	seen := make(map[string]bool, len(normalized))
 
 	for _, s := range normalized {
-		if !knownScopes[s] {
-			if !seen[s] {
-				seen[s] = true
-				invalid = append(invalid, s)
-			}
-			continue
-		}
-		if seen[s] {
+		if knownScopes[s] {
 			continue
 		}
-		seen[s] = true
-		result = append(result, s)
+		if seen[s] {
+			continue
+		}
+		seen[s] = true
+		invalid = append(invalid, s)
 	}
🤖 Prompt for 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.

In `@cmd/auth/login.go` around lines 540 - 556, The code builds a deduplicated
valid-scope slice `result` but never uses or returns it; remove `result` and
simplify `validateExplicitScopes` by keeping only `seen := make(map[string]bool,
len(normalized))` to dedupe entries, push unique invalid scopes into `invalid`
when `!knownScopes[s]`, and skip duplicates for known scopes by checking
`seen[s]` before marking seen; delete the `result` variable and the `result =
append(...)` branch (or alternatively, if the intention was to return valid
scopes, update the function signature to return that slice and return `result`),
referencing the variables `normalized`, `knownScopes`, `invalid`, `seen`, and
`result` to locate the code to change.
🤖 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/auth/login.go`:
- Around line 558-563: Replace the call to output.ErrValidation that embeds a
hint with a call to output.ErrWithHint using the correct signature: pass the
numeric code, the error type string, the main message (with formatted invalid
scopes via strings.Join(invalid, ", ")), and the hint text as the fourth
argument; update the invocation that currently references output.ErrValidation
and the invalid variable so it calls output.ErrWithHint(code, errType, msg,
hint) instead of providing five arguments or flipping message/hint order.

---

Nitpick comments:
In `@cmd/auth/login_test.go`:
- Around line 229-241: In TestValidateExplicitScopes_RejectsUnknownScopes remove
the stray debugging statement t.Log(err) so the test only asserts on the
returned error; locate the test function
TestValidateExplicitScopes_RejectsUnknownScopes and delete the t.Log(err) line
(leaving the error checks that assert err != nil and the contains checks for
"invalid scope(s): malformed:scope" and "auth scopes --format pretty").

In `@cmd/auth/login.go`:
- Around line 540-556: The code builds a deduplicated valid-scope slice `result`
but never uses or returns it; remove `result` and simplify
`validateExplicitScopes` by keeping only `seen := make(map[string]bool,
len(normalized))` to dedupe entries, push unique invalid scopes into `invalid`
when `!knownScopes[s]`, and skip duplicates for known scopes by checking
`seen[s]` before marking seen; delete the `result` variable and the `result =
append(...)` branch (or alternatively, if the intention was to return valid
scopes, update the function signature to return that slice and return `result`),
referencing the variables `normalized`, `knownScopes`, `invalid`, `seen`, and
`result` to locate the code to change.
🪄 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: 04619775-6d21-4709-953a-b06e13456c4c

📥 Commits

Reviewing files that changed from the base of the PR and between 27a2f27 and 8d18507.

📒 Files selected for processing (2)
  • cmd/auth/login.go
  • cmd/auth/login_test.go

Comment thread cmd/auth/login.go
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.

🧹 Nitpick comments (2)
cmd/auth/login.go (2)

552-557: ⚡ Quick win

Use a more specific errType than "validation".

Per coding guidelines, error messages on cmd/**/*.go should be "specific for AI agent parsing". The errType here is generic "validation", while elsewhere in this file specific types like "strict_mode" and "internal" are used. Consider "invalid_scope" (or similar) so agents can branch on the failure reason without parsing message text.

♻️ Proposed change
 	if len(invalid) > 0 {
 		return output.ErrWithHint(
-			output.ExitValidation, "validation",
+			output.ExitValidation, "invalid_scope",
 			fmt.Sprintf("invalid scope(s): %s", strings.Join(invalid, ", ")),
 			"check the exact scope names with `lark-cli auth scopes --format pretty`, or use `lark-cli auth login --domain <domain> --recommend` to avoid manual scope typos",
 		)
 	}

As per coding guidelines: "Make error messages structured, actionable, and specific for AI agent parsing".

🤖 Prompt for 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.

In `@cmd/auth/login.go` around lines 552 - 557, The error uses a generic errType
"validation" in the output.ErrWithHint call when invalid scopes are detected;
change that errType to a more specific token like "invalid_scope" (or
"invalid_scopes") so AI agents can branch on it without parsing the
message—update the output.ErrWithHint(...) invocation that checks len(invalid) >
0 (the call that currently passes "validation") to pass "invalid_scope" and
leave the rest of the message/hint intact.

563-580: 💤 Low value

knownScopesForIdentity name implies a parameter it doesn't accept.

The function is hardcoded to identity "user" in three places, yet its name suggests it takes an identity argument. Auth login currently only supports "user" (set via cmdutil.SetSupportedIdentities on line 64), so this is functionally correct — but the name is misleading. Either rename to e.g. knownUserScopes to match the implementation, or accept an identity string parameter for symmetry with collectScopesForDomains(domains, identity) and shortcutSupportsIdentity(sc, identity).

♻️ Option A: rename
-func knownScopesForIdentity() map[string]bool {
+func knownUserScopes() map[string]bool {

And update the call site in validateExplicitScopes.

♻️ Option B: parameterize
-func knownScopesForIdentity() map[string]bool {
+func knownScopesForIdentity(identity string) map[string]bool {
 	known := make(map[string]bool)
 	for scope := range registry.LoadScopePriorities() {
 		known[scope] = true
 	}
-	for _, scope := range registry.CollectAllScopesFromMeta("user") {
+	for _, scope := range registry.CollectAllScopesFromMeta(identity) {
 		known[scope] = true
 	}
 	for _, sc := range shortcuts.AllShortcuts() {
-		if shortcutSupportsIdentity(sc, "user") {
-			for _, scope := range sc.ScopesForIdentity("user") {
+		if shortcutSupportsIdentity(sc, identity) {
+			for _, scope := range sc.ScopesForIdentity(identity) {
 				known[scope] = true
 			}
 		}
 	}
 	known["offline_access"] = true
 	return known
 }

And update validateExplicitScopes to pass "user".

🤖 Prompt for 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.

In `@cmd/auth/login.go` around lines 563 - 580, knownScopesForIdentity is
misleading because it hardcodes "user" in multiple places; change it to accept
an identity string parameter (e.g., func knownScopesForIdentity(identity string)
map[string]bool) and replace the three hardcoded "user" usages
(registry.CollectAllScopesFromMeta, shortcutSupportsIdentity call, and
sc.ScopesForIdentity) to use the identity parameter; then update
validateExplicitScopes to call knownScopesForIdentity("user") (keeping other
logic unchanged) so behavior remains the same but the function is symmetric with
collectScopesForDomains and shortcutSupportsIdentity.
🤖 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.

Nitpick comments:
In `@cmd/auth/login.go`:
- Around line 552-557: The error uses a generic errType "validation" in the
output.ErrWithHint call when invalid scopes are detected; change that errType to
a more specific token like "invalid_scope" (or "invalid_scopes") so AI agents
can branch on it without parsing the message—update the output.ErrWithHint(...)
invocation that checks len(invalid) > 0 (the call that currently passes
"validation") to pass "invalid_scope" and leave the rest of the message/hint
intact.
- Around line 563-580: knownScopesForIdentity is misleading because it hardcodes
"user" in multiple places; change it to accept an identity string parameter
(e.g., func knownScopesForIdentity(identity string) map[string]bool) and replace
the three hardcoded "user" usages (registry.CollectAllScopesFromMeta,
shortcutSupportsIdentity call, and sc.ScopesForIdentity) to use the identity
parameter; then update validateExplicitScopes to call
knownScopesForIdentity("user") (keeping other logic unchanged) so behavior
remains the same but the function is symmetric with collectScopesForDomains and
shortcutSupportsIdentity.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f2fad475-fc65-4446-89d1-414d4c13f5af

📥 Commits

Reviewing files that changed from the base of the PR and between 8d18507 and 6fe1939.

📒 Files selected for processing (2)
  • cmd/auth/login.go
  • cmd/auth/login_test.go

@JackZhao10086 JackZhao10086 requested a review from liangshuo-1 May 6, 2026 12:33
@yux1a0-63 yux1a0-63 closed this May 7, 2026
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