Skip to content

refactor: centralize HTTP transport policies#2021

Open
evandance wants to merge 1 commit into
mainfrom
refactor/http-transport-policy
Open

refactor: centralize HTTP transport policies#2021
evandance wants to merge 1 commit into
mainfrom
refactor/http-transport-policy

Conversation

@evandance

@evandance evandance commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

Centralize outbound HTTP transport construction and routing so platform-owned endpoints and external destinations use explicit, consistent policies. The change preserves existing provider and factory behavior while making proxy, redirect, security-header, and download handling easier to reason about and test.

Changes

  • Add endpoint-catalog-backed platform/external request classification and a central HTTP policy router.
  • Add optional provider scoping while preserving the all-request behavior of existing transport providers.
  • Route direct HTTP, SDK HTTP, and SDK bootstrap requests through the shared policy construction path.
  • Preserve proxy, custom TLS, retry, and extension layers when cloning transports for untrusted downloads; fail closed when safe cloning is impossible.
  • Harden redirect handling across origin and scheme changes, and add contract coverage for routing, compatibility, and downloader behavior.

Test Plan

  • make build
  • GOFLAGS=-p=4 make unit-test
  • go vet ./...
  • gofmt -l . produces no output
  • go mod tidy leaves go.mod and go.sum unchanged
  • go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 run --new-from-rev=origin/main
  • make sidecar-test
  • Manual local verification: lark-cli --version

Related Issues

  • None

Summary by CodeRabbit

  • New Features
    • Added request-aware network routing for platform and external destinations.
    • External downloads now use dedicated network handling while preserving proxy settings.
    • Improved SDK bootstrap connectivity through configured transport extensions.
  • Bug Fixes
    • Strengthened redirect protections by blocking insecure downgrades, unsafe cross-origin requests, and credential leakage.
    • Added fail-closed safeguards when download transports cannot be safely secured.
  • Documentation
    • Clarified network connectivity, proxy, and transport behavior in command and registry documentation.

@evandance
evandance requested a review from liangshuo-1 as a code owner July 23, 2026 03:46
@github-actions github-actions Bot added domain/ccm PR touches the ccm domain domain/im PR touches the im domain domain/mail PR touches the mail domain size/XL Architecture-level or global-impact change labels Jul 23, 2026
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR introduces platform/external HTTP request classification, policy-routed clients, scoped extension middleware, SDK bootstrap bridging, stricter redirect handling, and fail-closed transport cloning for downloads.

Changes

Provider-aware transport routing

Layer / File(s) Summary
Request classification and transport rebuilding
extension/transport/types.go, internal/core/*, internal/transport/policy_router.go, internal/transport/shared.go, internal/cmdutil/transport.go, internal/auth/transport.go
Adds platform/external request classes, platform endpoint validation, policy routing, client derivation, transport graph rebuilding, and cloneable transport decorators.
Extension middleware and SDK bridge
internal/transport/extension.go, internal/transport/default_client.go, internal/cmdutil/transport_test.go, internal/transport/*_test.go, extension/transport/sidecar/interceptor_test.go
Moves extension interception into shared transport middleware, supports scoped providers, and routes matching SDK bootstrap requests through platform middleware with same-origin redirect checks.
Factory clients and redirect policy
internal/cmdutil/factory.go, internal/cmdutil/factory_default.go, internal/cmdutil/factory_http_test.go
Adds ExternalHTTPClient, separates platform and external transport chains, installs the SDK bridge, and hardens redirect handling against downgrades, unsafe cross-origin requests, and credential leakage.
Download transport hardening
internal/validate/url.go, internal/validate/url_test.go, shortcuts/doc/doc_resource_cover.go, shortcuts/doc/doc_resource_cover_test.go
Adds proxy-aware transport cloning, freezes proxy selection per request, validates legacy TLS dialing, and blocks requests when transports cannot be safely cloned.
External client adoption
internal/update/update.go, shortcuts/apps/*, shortcuts/im/*, shortcuts/mail/*, shortcuts/minutes/*
Switches external URL, attachment, signature, media, file-transfer, and registry requests to externally classified HTTP clients.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Command
  participant Factory
  participant HTTPPolicyRouter
  participant ExtensionMiddleware
  participant ExternalServer
  Command->>Factory: Request ExternalHTTPClient
  Factory->>HTTPPolicyRouter: Force external RequestClass
  HTTPPolicyRouter->>ExtensionMiddleware: Apply eligible provider middleware
  ExtensionMiddleware->>ExternalServer: Send external request
  ExternalServer-->>Command: Return response
Loading

Possibly related PRs

  • larksuite/cli#292: Introduced the provider and interceptor APIs used by the new extension middleware.
  • larksuite/cli#532: Added sidecar interception behavior exercised by the new request-class tests.
  • larksuite/cli#1213: Refactored shared HTTP client APIs extended by the external client routing changes.

Suggested labels: feature

Suggested reviewers: liangshuo-1

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.81% 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 concisely and accurately summarizes the main change: centralizing HTTP transport policies.
Description check ✅ Passed The description matches the template with Summary, Changes, Test Plan, and Related Issues sections filled in.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/http-transport-policy

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

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

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

🧩 Skill update

npx skills add larksuite/cli#refactor/http-transport-policy -y -g

@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.58711% with 140 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.06%. Comparing base (67015ee) to head (e052549).

Files with missing lines Patch % Lines
internal/transport/policy_router.go 70.58% 19 Missing and 11 partials ⚠️
internal/cmdutil/transport.go 0.00% 28 Missing ⚠️
internal/transport/extension.go 53.06% 17 Missing and 6 partials ⚠️
internal/transport/default_client.go 66.66% 15 Missing and 4 partials ⚠️
internal/validate/url.go 78.33% 7 Missing and 6 partials ⚠️
internal/cmdutil/factory_default.go 80.76% 7 Missing and 3 partials ⚠️
internal/auth/transport.go 0.00% 6 Missing ⚠️
shortcuts/doc/doc_resource_cover.go 81.25% 4 Missing and 2 partials ⚠️
internal/cmdutil/factory.go 60.00% 1 Missing and 1 partial ⚠️
internal/update/update.go 0.00% 1 Missing ⚠️
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2021      +/-   ##
==========================================
- Coverage   75.06%   75.06%   -0.01%     
==========================================
  Files         902      905       +3     
  Lines       95944    96292     +348     
==========================================
+ Hits        72025    72279     +254     
- Misses      18380    18434      +54     
- Partials     5539     5579      +40     

☔ View full report in Codecov by Harness.
📢 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.

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
internal/validate/url.go (2)

1-1: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Extract a shared "hardened transport leaf" helper. Both sites independently implement the same clone-and-guard pattern (wrap DialContext/DialTLSContext/DialTLS with remote-IP validation, fail closed when safe cloning isn't possible), which has already caused the two implementations to diverge on error typing.

  • internal/validate/url.go#L195-271: extract newDownloadTransportLeaf/configureDirectDownloadTransport's dial-wrapping/guard logic into a shared helper (e.g., in internal/transport or internal/validate) parameterized by the remote-IP predicate and proxy-handling policy (freeze-selected-proxy vs. disable-proxy).
  • shortcuts/doc/doc_resource_cover.go#L727-801: adopt the same shared helper for cloneDocCoverTransport/newDocCoverTransportLeaf instead of re-implementing the dial/guard wiring, keeping its existing "always disable proxy" policy.
🤖 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 `@internal/validate/url.go` at line 1, Extract the duplicated transport
clone-and-guard wiring from
newDownloadTransportLeaf/configureDirectDownloadTransport and
cloneDocCoverTransport/newDocCoverTransportLeaf into one shared helper.
Parameterize it with the remote-IP validation predicate and proxy policy,
preserving frozen selected-proxy behavior for downloads and always-disabled
proxy behavior for document covers; ensure cloning failures fail closed and all
DialContext/DialTLSContext/DialTLS wrappers use consistent error handling.

195-271: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Duplicated fail-closed transport-cloning/IP-guard logic vs. shortcuts/doc/doc_resource_cover.go.

newDownloadTransportLeaf/configureDirectDownloadTransport are structurally near-identical to newDocCoverTransportLeaf in shortcuts/doc/doc_resource_cover.go (dial wrapping, DialTLSContext/DialTLS guards, remote-IP validation). See consolidated comment below.

🤖 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 `@internal/validate/url.go` around lines 195 - 271, The direct transport
cloning and dial/IP-validation logic in newDownloadTransportLeaf and
configureDirectDownloadTransport duplicates newDocCoverTransportLeaf;
consolidate these paths through the existing shared transport-wrapper helper or
extract their common implementation into one reusable symbol. Preserve
fail-closed handling, DialContext/DialTLSContext/DialTLS coverage, connection
closing on validation failure, and the distinct proxy behavior.
shortcuts/doc/doc_resource_cover.go (1)

727-801: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Duplicated fail-closed transport-cloning/IP-guard logic vs. internal/validate/url.go.

blockedDocCoverTransport/cloneDocCoverTransport/newDocCoverTransportLeaf closely mirror blockedDownloadTransport/cloneDownloadTransport/newDownloadTransportLeaf in internal/validate/url.go, including the new DialTLS-guard wrapping. See consolidated comment below.

🤖 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/doc/doc_resource_cover.go` around lines 727 - 801, Replace the
duplicated blocked transport, clone logic, and leaf IP-guard implementation in
blockedDocCoverTransport, cloneDocCoverTransport, and newDocCoverTransportLeaf
with the shared transport-cloning/validation utilities from
internal/validate/url.go. Reuse the existing blockedDownloadTransport,
cloneDownloadTransport, and newDownloadTransportLeaf behavior, including DialTLS
and DialTLSContext guarding, while preserving the document-cover fail-closed
behavior.
🤖 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 `@internal/cmdutil/factory_default.go`:
- Around line 97-126: The four rejection paths in safeRedirectPolicy must return
appropriately classified errs errors instead of fmt.Errorf: use validation for
redirect-count or invalid-request cases, network for transport redirect
failures, and security-policy errors for HTTPS downgrade or credential-stripping
policy violations. Preserve the existing messages and behavior, and update the
redirect assertions in factory_http_test.go to verify both the typed error and
message.

In `@internal/transport/policy_router.go`:
- Around line 56-68: Replace the bare fmt.Errorf calls with appropriate errs.*
constructors for all affected transport guards: the nil-request and
invalid-class handling in internal/transport/policy_router.go at lines 56-68 and
81-94, and the redirect-location and blocked-redirect handling in
internal/transport/default_client.go at lines 55-80. Update the relevant
RoundTrip and redirect-checking logic while preserving their existing control
flow and messages.

In `@internal/validate/url.go`:
- Around line 185-193: Replace the bare fmt.Errorf used to initialize
blockedDownloadTransport.err in the transport-cloning fallback with
errs.NewInternalError(errs.SubtypeUnknown, ...), matching the typed error
construction used by blockedDocCoverTransport. Preserve the existing "cannot
safely clone download transport %T" message and formatting arguments.

---

Outside diff comments:
In `@internal/validate/url.go`:
- Line 1: Extract the duplicated transport clone-and-guard wiring from
newDownloadTransportLeaf/configureDirectDownloadTransport and
cloneDocCoverTransport/newDocCoverTransportLeaf into one shared helper.
Parameterize it with the remote-IP validation predicate and proxy policy,
preserving frozen selected-proxy behavior for downloads and always-disabled
proxy behavior for document covers; ensure cloning failures fail closed and all
DialContext/DialTLSContext/DialTLS wrappers use consistent error handling.
- Around line 195-271: The direct transport cloning and dial/IP-validation logic
in newDownloadTransportLeaf and configureDirectDownloadTransport duplicates
newDocCoverTransportLeaf; consolidate these paths through the existing shared
transport-wrapper helper or extract their common implementation into one
reusable symbol. Preserve fail-closed handling,
DialContext/DialTLSContext/DialTLS coverage, connection closing on validation
failure, and the distinct proxy behavior.

In `@shortcuts/doc/doc_resource_cover.go`:
- Around line 727-801: Replace the duplicated blocked transport, clone logic,
and leaf IP-guard implementation in blockedDocCoverTransport,
cloneDocCoverTransport, and newDocCoverTransportLeaf with the shared
transport-cloning/validation utilities from internal/validate/url.go. Reuse the
existing blockedDownloadTransport, cloneDownloadTransport, and
newDownloadTransportLeaf behavior, including DialTLS and DialTLSContext
guarding, while preserving the document-cover fail-closed behavior.
🪄 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: b8af4ea3-abfb-4bed-b614-408a8887f761

📥 Commits

Reviewing files that changed from the base of the PR and between 67015ee and e052549.

📒 Files selected for processing (34)
  • cmd/config/init_interactive.go
  • cmd/doctor/doctor.go
  • extension/transport/sidecar/interceptor_test.go
  • extension/transport/types.go
  • internal/auth/transport.go
  • internal/cmdutil/factory.go
  • internal/cmdutil/factory_default.go
  • internal/cmdutil/factory_http_test.go
  • internal/cmdutil/factory_proxy_warn_test.go
  • internal/cmdutil/testing_test.go
  • internal/cmdutil/transport.go
  • internal/cmdutil/transport_test.go
  • internal/core/types.go
  • internal/core/types_test.go
  • internal/registry/remote.go
  • internal/transport/config.go
  • internal/transport/default_client.go
  • internal/transport/extension.go
  • internal/transport/extension_test.go
  • internal/transport/policy_router.go
  • internal/transport/policy_router_test.go
  • internal/transport/shared.go
  • internal/transport/shared_test.go
  • internal/update/update.go
  • internal/validate/url.go
  • internal/validate/url_test.go
  • shortcuts/apps/file_common.go
  • shortcuts/doc/doc_resource_cover.go
  • shortcuts/doc/doc_resource_cover_test.go
  • shortcuts/im/helpers.go
  • shortcuts/mail/helpers.go
  • shortcuts/mail/signature_compose.go
  • shortcuts/minutes/minutes_download.go
  • shortcuts/minutes/minutes_download_test.go

Comment on lines 97 to 126
func safeRedirectPolicy(req *http.Request, via []*http.Request) error {
if len(via) >= 10 {
return fmt.Errorf("too many redirects")
}
if len(via) > 0 && req.URL.Host != via[0].URL.Host {
if len(via) == 0 {
return nil
}
original := via[0]
previous := via[len(via)-1]
if previous.URL != nil && req.URL != nil && strings.EqualFold(previous.URL.Scheme, "https") && !strings.EqualFold(req.URL.Scheme, "https") {
return fmt.Errorf("redirect from HTTPS to %s is not allowed", req.URL.Scheme)
}
if !sameRedirectOrigin(previous.URL, req.URL) {
if req.Method != http.MethodGet && req.Method != http.MethodHead {
return fmt.Errorf("cross-origin redirect for HTTP method %s is not allowed", req.Method)
}
if req.Body != nil || req.GetBody != nil {
return fmt.Errorf("cross-origin redirect with a request body is not allowed")
}
}
// net/http copies initial headers onto every redirect request. Continue
// stripping credentials for every hop outside the initial origin, even when
// two consecutive redirect targets share an origin.
if !sameRedirectOrigin(original.URL, req.URL) {
req.Header.Del("Authorization")
req.Header.Del("X-Lark-MCP-UAT")
req.Header.Del("X-Lark-MCP-TAT")
}
return nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n --type=go 'func New.*Error' -g '!*_test.go' internal/errs errs 2>/dev/null
rg -n --type=go 'SubtypeNetwork|SubtypeInvalidArgument|SubtypeSecurity' -g '!*_test.go'

Repository: larksuite/cli

Length of output: 1218


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate relevant files =="
git ls-files | rg '(^|/)errs/types\.go$|errs/types_test\.go$|internal/cmdutil/factory_default\.go$|factory_http_test\.go$|internal/cmdutil/' | sed -n '1,220p'

echo
echo "== factory_default imports/usages around safeRedirectPolicy =="
sed -n '1,180p' internal/cmdutil/factory_default.go

echo
echo "== errs constructors and subtype enum =="
sed -n '1,260p' errs/types.go
sed -n '380,570p' errs/types.go
sed -n '700,780p' errs/types.go

echo
echo "== existing NewSecurityPolicyError usage patterns =="
rg -n --type=go 'NewSecurityPolicyError|Security.*Redirect|HTTPS.*redirect|redirect from HTTPS|cross-origin redirect|too many redirects' .

Repository: larksuite/cli

Length of output: 25333


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== factory_http_test redirect assertions =="
sed -n '1,260p' internal/cmdutil/factory_http_test.go

echo
echo "== errs subtype constants =="
sed -n '250,380p' errs/types.go

echo
echo "== validate too many redirects =="
sed -n '90,135p' internal/validate/url.go

echo
echo "== existing policy/security typed errors in transport/cmdutil =="
rg -n --type=go 'NewSecurityPolicyError|SubtypeAccessDenied|CategoryPolicy|too many redirects|HTTPS.*redirect|cross-origin redirect' internal/cmdutil internal/transport errs --glob '!*test.go' | sed -n '1,220p'

echo
echo "== imports of errs in cmdutil =="
rg -n --type=go '"github.com/larksuite/cli/errs"|errs\.' internal/cmdutil --glob '!*test.go' | sed -n '1,220p'

Repository: larksuite/cli

Length of output: 18745


Return typed errs.* errors from the redirect policy.

Replace the four fmt.Errorf cases in safeRedirectPolicy with the appropriate typed error constructors (errs.NewValidationError/errs.NewNetworkError/errs.NewSecurityPolicyError depending on the policy intent). These become the command-facing failure when http.Client.CheckRedirect rejects a redirect, so the error should stay typed rather than downgrading to an unclassified message. Update the factory_http_test.go redirect assertions to keep testing the typed error shape/message.

🤖 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 `@internal/cmdutil/factory_default.go` around lines 97 - 126, The four
rejection paths in safeRedirectPolicy must return appropriately classified errs
errors instead of fmt.Errorf: use validation for redirect-count or
invalid-request cases, network for transport redirect failures, and
security-policy errors for HTTPS downgrade or credential-stripping policy
violations. Preserve the existing messages and behavior, and update the redirect
assertions in factory_http_test.go to verify both the typed error and message.

Source: Coding guidelines

Comment on lines +56 to +68
func (r *HTTPPolicyRouter) RoundTrip(req *http.Request) (*http.Response, error) {
if req == nil {
return nil, fmt.Errorf("HTTP policy router received a nil request")
}
class, err := classifyRequest(req)
if err != nil {
return nil, err
}
if class == exttransport.RequestClassPlatform {
return r.platform.RoundTrip(req)
}
return r.external.RoundTrip(req)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether internal/errs (or wherever errs.* lives) imports internal/transport,
# which would create a cycle if internal/transport imports errs.
fd -t f '.go$' internal/errs 2>/dev/null | xargs grep -l 'internal/transport' 
rg -n 'package errs' -g '*.go' | head -5

Repository: larksuite/cli

Length of output: 151


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Relevant file locations:"
fd -t f '(^policy_router\.go$|^default_client\.go$|^go\.mod$|errs|error)' . | sed -n '1,200p'

echo
echo "policy_router.go outline:"
ast-grep outline internal/transport/policy_router.go || true

echo
echo "default_client.go outline:"
ast-grep outline internal/transport/default_client.go || true

echo
echo "transport imports/usages of errs/error helpers:"
rg -n 'internal/(errs|output)|errs\.[A-Za-z0-9]+' internal/transport internal/errs internal -g '*.go' | sed -n '1,200p'

echo
echo "Err* definitions/constructors:"
rg -n 'func [A-Z][A-Za-z0-9_]*\(.*Error|type .*Error struct|Err[A-Za-z0-9]\s*=|BuildAPIError|Err.*Error|Err[A-Z]' internal -g '*.go' | sed -n '1,300p'

Repository: larksuite/cli

Length of output: 24862


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Go module package paths:"
grep -n '^module ' go.mod
sed -n '1,120p' go.mod

echo
echo "Where errs package is declared:"
fd -t f '.go$' . | xargs grep -l '^package errs$' 2>/dev/null | sed -n '1,50p'

echo
echo "errs package files in module tree:"
fd -d 4 -t f '.go$' . | xargs grep -l '^package errs$' 2>/dev/null | sort

echo
echo "transport policy_router.go:"
cat -n internal/transport/policy_router.go | sed -n '1,180p'

echo
echo "transport default_client.go:"
cat -n internal/transport/default_client.go | sed -n '1,145p'

echo
echo "errors package candidates outline/slices:"
for f in $(fd -t f '.go$' . | xargs grep -l '^package errs$' 2>/dev/null | head -10); do
  echo "--- $f"
  ast-grep outline "$f" || true
  sed -n '1,220p' "$f"
done

echo
echo "any circular imports involving internal/errs candidates and internal/transport?"
python3 - <<'PY'
import pathlib, re
mods = []
for p in pathlib.Path('.').rglob('go.mod'):
    mods.append(p.read_text(errors='ignore'))
paths = set()
for m in mods:
    for line in m.splitlines():
        m = re.match(r'\s*-\s*(.+?)\s*(?://.*)?\s*$', line)
        if m:
            paths.add(m.group(1))
print("tracked paths:", paths)
PY

echo
echo "imports that mention errs in internal packages:"
python3 - <<'PY'
import pathlib, re
for p in pathlib.Path('.').rglob('*.go'):
    try:
        s=p.read_text(errors='ignore')
    except:
        continue
    lines=s.splitlines()
    has_err_import=False
    for i,line in enumerate(lines,1):
        if re.search(r'"[^"]+errs[^"]*"', line):
            print(f"{p}:{i}:{line.strip()}")
            has_err_import=True
            break
PY

Repository: larksuite/cli

Length of output: 50369


Replace bare transport-layer errors with typed errs.* errors. These failures can become the terminal error for command HTTP calls, so the nil-request and invalid-class guards in policy_router.go, plus the redirect location/blocked-redirect guards in default_client.go, should be created with errs.* error constructors instead of fmt.Errorf.

📍 Affects 2 files
  • internal/transport/policy_router.go#L56-L68 (this comment)
  • internal/transport/policy_router.go#L81-L94
  • internal/transport/default_client.go#L55-L80
🤖 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 `@internal/transport/policy_router.go` around lines 56 - 68, Replace the bare
fmt.Errorf calls with appropriate errs.* constructors for all affected transport
guards: the nil-request and invalid-class handling in
internal/transport/policy_router.go at lines 56-68 and 81-94, and the
redirect-location and blocked-redirect handling in
internal/transport/default_client.go at lines 55-80. Update the relevant
RoundTrip and redirect-checking logic while preserving their existing control
flow and messages.

Source: Coding guidelines

Comment thread internal/validate/url.go
Comment on lines +185 to +193
if source, ok := base.(*http.Transport); ok && source != nil {
cloned := source.Clone()
rebuilt, transformed := newDownloadTransportLeaf(cloned)
if transformed && rebuilt != nil {
return rebuilt
}
}
return &blockedDownloadTransport{err: fmt.Errorf("cannot safely clone download transport %T", base)}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a typed errs.* error instead of bare fmt.Errorf.

blockedDownloadTransport.err is built with a bare fmt.Errorf, whereas the equivalent blockedDocCoverTransport in shortcuts/doc/doc_resource_cover.go (line 752) uses errs.NewInternalError(errs.SubtypeUnknown, ...). Once this error propagates up through callers that classify errors into typed errs.* (e.g., a network-error wrapper), a raw error here risks being misclassified as a generic transport failure instead of preserved as the specific "cannot safely clone" internal condition.

🔧 Proposed fix
-	return &blockedDownloadTransport{err: fmt.Errorf("cannot safely clone download transport %T", base)}
+	return &blockedDownloadTransport{err: errs.NewInternalError(errs.SubtypeUnknown, "cannot safely clone download transport %T", base)}

As per coding guidelines, "Command-facing failures must use typed errs.* errors; do not use legacy output.Err* helpers, final bare fmt.Errorf, or bare errors.New."

📝 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
if source, ok := base.(*http.Transport); ok && source != nil {
cloned := source.Clone()
rebuilt, transformed := newDownloadTransportLeaf(cloned)
if transformed && rebuilt != nil {
return rebuilt
}
}
return &blockedDownloadTransport{err: fmt.Errorf("cannot safely clone download transport %T", base)}
}
if source, ok := base.(*http.Transport); ok && source != nil {
cloned := source.Clone()
rebuilt, transformed := newDownloadTransportLeaf(cloned)
if transformed && rebuilt != nil {
return rebuilt
}
}
return &blockedDownloadTransport{err: errs.NewInternalError(errs.SubtypeUnknown, "cannot safely clone download transport %T", base)}
}
🤖 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 `@internal/validate/url.go` around lines 185 - 193, Replace the bare fmt.Errorf
used to initialize blockedDownloadTransport.err in the transport-cloning
fallback with errs.NewInternalError(errs.SubtypeUnknown, ...), matching the
typed error construction used by blockedDocCoverTransport. Preserve the existing
"cannot safely clone download transport %T" message and formatting arguments.

Source: Coding guidelines

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

Labels

domain/ccm PR touches the ccm domain domain/im PR touches the im domain domain/mail PR touches the mail domain size/XL Architecture-level or global-impact change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant