Skip to content

feat(base): classify Base resource permission denials as typed errors - #2125

Open
yballul-bytedance wants to merge 1 commit into
larksuite:mainfrom
yballul-bytedance:auto-research-sync/01KWYNV56GBPYYSFEHMHM8ZWMP/mr-1031-22c2d3ca
Open

feat(base): classify Base resource permission denials as typed errors#2125
yballul-bytedance wants to merge 1 commit into
larksuite:mainfrom
yballul-bytedance:auto-research-sync/01KWYNV56GBPYYSFEHMHM8ZWMP/mr-1031-22c2d3ca

Conversation

@yballul-bytedance

@yballul-bytedance yballul-bytedance commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Base API responses with code 91403 (resource-level permission denial) were previously flowing through the generic API error path, producing a non-specific error that AI agents could not reliably act on. This change maps 91403 to a typed PermissionError so agents receive a structured, actionable signal instead of a bare API failure.

Changes

  • Add baseResourcePermissionError in shortcuts/base/base_errors.go, which detects the Base 91403 response code and returns a typed errs.PermissionError with SubtypePermissionDenied.
  • Populate the typed error with the resolved identity, the error code (91403), the server log ID when present, and a preserved upstream hint.
  • Emit an actionable hint that directs the caller to ask the Base owner for access (or retry once with --as user when a user identity is already logged in) rather than repeatedly running auth login or switching identities for a resource-level denial.
  • Wire the new classifier into baseAPIErrorFromResult so it runs before the generic errclass.BuildAPIError fallback.
  • Add TestHandleBaseAPIResultClassifiesBaseResourcePermission covering the 91403 path: asserts category/subtype/code, the *errs.PermissionError type, the default identity, and the hint content.

Test Plan

  • git diff --check — passed (no whitespace errors or conflict markers).
  • New unit test TestHandleBaseAPIResultClassifiesBaseResourcePermission asserts the typed metadata (Category, Subtype, Code), the concrete *errs.PermissionError type, the default Identity, and the presence of the actionable hint fragments.

Related Issues

Auto research task: 01KWYNV56GBPYYSFEHMHM8ZWMP

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of Base resource permission errors.
    • Displays clearer authorization-denied messages with helpful hints.
    • Preserves relevant error details, including identity and request reference information, to aid troubleshooting.

Map the Base API 91403 response code to a typed PermissionError instead
of a generic API error. The error carries the resolved identity, a
permission-denied subtype, code, and log ID, plus an actionable hint that
tells AI agents to ask the Base owner for access rather than repeatedly
running auth login or switching identities for a resource-level denial.

Co-authored-by: TRAE CLI <noreply@bytedance.com>
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Base error handling now classifies response code 91403 as a permission denial, preserving identity, hints, Base code, and trimmed log ID. Tests verify the typed authorization error and its contextual fields.

Changes

Base permission classification

Layer / File(s) Summary
Handle Base resource permission errors
shortcuts/base/base_errors.go, shortcuts/base/base_errors_test.go
baseAPIErrorFromResult detects Base code 91403 and creates a typed PermissionError with permission-denied subtype, identity, aggregated hint, and optional log_id; tests verify the resulting authorization classification and metadata.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • larksuite/cli#1791: Adds equivalent Base 91403 permission-error handling and classification tests.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the change: Base resource permission denials are now classified as typed errors.
Description check ✅ Passed The description follows the template with Summary, Changes, Test Plan, and Related Issues sections filled in.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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.

@github-actions github-actions Bot added domain/base PR touches the base domain size/M Single-domain feat or fix with limited business impact labels Jul 30, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@shortcuts/base/base_errors_test.go`:
- Around line 121-151: The test
TestHandleBaseAPIResultClassifiesBaseResourcePermission must cover the new
metadata behavior directly: add a log_id to the result fixture and assert it is
exposed through p.LogID, and include an upstream Base error hint in the response
then assert that hint is preserved alongside the generated guidance.

In `@shortcuts/base/base_errors.go`:
- Around line 185-196: Update the permission error construction around
PermissionError.Identity so unresolved cc.Identity remains empty, matching the
ClassifyContext.Identity contract. Keep the "current identity" fallback only in
the hint text, and assign err.Identity from the trimmed resolved identity
without replacing it with display text.
🪄 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 Plus

Run ID: bdc33d91-080a-4a66-85b7-957db54ab43e

📥 Commits

Reviewing files that changed from the base of the PR and between fa9c30c and e5ef7ef.

📒 Files selected for processing (2)
  • shortcuts/base/base_errors.go
  • shortcuts/base/base_errors_test.go

Comment on lines +121 to +151
func TestHandleBaseAPIResultClassifiesBaseResourcePermission(t *testing.T) {
result := map[string]interface{}{
"code": 91403,
"msg": "you don't have permission",
"data": map[string]interface{}{},
}

_, err := handleBaseAPIResultAny(result, nil, "list dashboards")
p, ok := errs.ProblemOf(err)
if !ok {
t.Fatalf("expected typed error, got %T %v", err, err)
}
if p.Code != 91403 {
t.Fatalf("code=%d", p.Code)
}
if p.Category != errs.CategoryAuthorization || p.Subtype != errs.SubtypePermissionDenied {
t.Fatalf("category/subtype=%s/%s", p.Category, p.Subtype)
}
perm, ok := err.(*errs.PermissionError)
if !ok {
t.Fatalf("err=%T, want *errs.PermissionError", err)
}
if perm.Identity != "current identity" {
t.Fatalf("identity=%q", perm.Identity)
}
for _, want := range []string{"resource access denied", "Base owner", "Do not run auth login"} {
if !strings.Contains(p.Hint, want) {
t.Fatalf("hint=%q missing %q", p.Hint, want)
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Cover the new metadata branches directly.

Add a log_id fixture and assert p.LogID; also include an upstream Base error hint and assert it is retained. The current test would still pass if either new behavior regressed.

As per coding guidelines, “Every behavior change must have an accompanying test, and contract tests must assert the changed field or behavior directly.”

🤖 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 `@shortcuts/base/base_errors_test.go` around lines 121 - 151, The test
TestHandleBaseAPIResultClassifiesBaseResourcePermission must cover the new
metadata behavior directly: add a log_id to the result fixture and assert it is
exposed through p.LogID, and include an upstream Base error hint in the response
then assert that hint is preserved alongside the generated guidance.

Source: Coding guidelines

Comment on lines +185 to +196
identity := strings.TrimSpace(cc.Identity)
if identity == "" {
identity = "current identity"
}
hint := fmt.Sprintf("resource access denied for %s; ask the Base owner to grant access, or retry once with --as user only if a user identity is already logged in. Do not run auth login or switch identities repeatedly for this resource-level permission error", identity)
if upstreamHint != "" {
hint = upstreamHint + "; " + hint
}
err := errs.NewPermissionError(errs.SubtypePermissionDenied, "%s", msg).
WithCode(91403).
WithHint("%s", hint)
err.Identity = identity

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep PermissionError.Identity within the classifier contract.

"current identity" is display text, but ClassifyContext.Identity is defined as "user", "bot", or empty. Preserve an empty err.Identity when unresolved; use a separate fallback only in the hint. Otherwise downstream identity-based handling receives an undocumented value.

Proposed fix
- identity := strings.TrimSpace(cc.Identity)
- if identity == "" {
-     identity = "current identity"
- }
- hint := fmt.Sprintf("resource access denied for %s; ...", identity)
+ identity := strings.TrimSpace(cc.Identity)
+ displayIdentity := identity
+ if displayIdentity == "" {
+     displayIdentity = "current identity"
+ }
+ hint := fmt.Sprintf("resource access denied for %s; ...", displayIdentity)
...
  err.Identity = identity
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
identity := strings.TrimSpace(cc.Identity)
if identity == "" {
identity = "current identity"
}
hint := fmt.Sprintf("resource access denied for %s; ask the Base owner to grant access, or retry once with --as user only if a user identity is already logged in. Do not run auth login or switch identities repeatedly for this resource-level permission error", identity)
if upstreamHint != "" {
hint = upstreamHint + "; " + hint
}
err := errs.NewPermissionError(errs.SubtypePermissionDenied, "%s", msg).
WithCode(91403).
WithHint("%s", hint)
err.Identity = identity
identity := strings.TrimSpace(cc.Identity)
displayIdentity := identity
if displayIdentity == "" {
displayIdentity = "current identity"
}
hint := fmt.Sprintf("resource access denied for %s; ask the Base owner to grant access, or retry once with --as user only if a user identity is already logged in. Do not run auth login or switch identities repeatedly for this resource-level permission error", displayIdentity)
if upstreamHint != "" {
hint = upstreamHint + "; " + hint
}
err := errs.NewPermissionError(errs.SubtypePermissionDenied, "%s", msg).
WithCode(91403).
WithHint("%s", hint)
err.Identity = identity
🤖 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 `@shortcuts/base/base_errors.go` around lines 185 - 196, Update the permission
error construction around PermissionError.Identity so unresolved cc.Identity
remains empty, matching the ClassifyContext.Identity contract. Keep the "current
identity" fallback only in the hint text, and assign err.Identity from the
trimmed resolved identity without replacing it with display text.

@github-actions

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

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

🧩 Skill update

npx skills add yballul-bytedance/cli#auto-research-sync/01KWYNV56GBPYYSFEHMHM8ZWMP/mr-1031-22c2d3ca -y -g

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

Labels

domain/base PR touches the base domain size/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant