Skip to content

fix: route brand-sensitive endpoints through the resolver#1836

Merged
liangshuo-1 merged 1 commit into
mainfrom
fix/endpoint-resolver-consolidation
Jul 11, 2026
Merged

fix: route brand-sensitive endpoints through the resolver#1836
liangshuo-1 merged 1 commit into
mainfrom
fix/endpoint-resolver-consolidation

Conversation

@evandance

@evandance evandance commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

Route the brand-sensitive, resolver-owned Go CLI endpoints touched here through the single core.ResolveEndpoints source of truth. Feishu remains the default; Lark uses the corresponding resolver endpoints while app registration preserves its protocol-defined Feishu bootstrap and switches to Lark only after tenant discovery.

This PR intentionally leaves package-manager version lookup, npm registry behavior, update caching, and general URL data-flow analysis unchanged.

Changes

  • Normalize brand values through core.ParseBrand at every runtime ingress (config resolution, credential accounts) and defensively at the ResolveEndpoints boundary
  • Route API metadata, skills index/source, event WebSocket, and app-registration hosts through the resolver, and resolve the brand before the command tree builds so the registry's metadata overlay uses it from the first catalog access
  • Keep app-registration discovery in one internal/auth state machine with Feishu begin and first poll, immediate tenant-signaled Lark switching (even when the signal accompanies authorization_pending), one expiry budget with no attempt cap, context-bound requests, and the issuing brand as the only saved brand (a contradictory final tenant report is a protocol error)
  • Preserve the existing brand-specific verification-page UX; endpoint consolidation does not change the registration protocol or product entry path
  • Resolve the skills source from the active profile, including a raw-config brand fallback when credential-backed config resolution is unavailable
  • Add a syntax-level Go guard for the current resolver-owned host literals, direct SDK base-URL globals, and SDK root dot-imports; this guard is deliberately not a general URL or data-flow analyzer
  • Run lint module tests in CI so resolver/guard host parity and guard behavior cannot silently drift

Test Plan

  • Resolver tables cover Feishu/Lark, casing, whitespace, invalid values, and normalization at the endpoint boundary and both config ingresses; a subprocess regression test locks the real startup order (registry brand = configured brand before the first catalog access)
  • App-registration tests lock the full Lark sequence: Lark verification UI, Feishu begin, Feishu first poll, tenant signal (including alongside authorization_pending), immediate Lark poll, final Lark brand even when the credential response omits user_info, no attempt cap, and rejection of contradictory final tenant reports
  • Registration tests also cover incomplete responses, protocol defaults, one expiry budget, in-flight cancellation, terminal sentinels, and command-facing typed errors
  • Skills tests cover Feishu/Lark index/source selection plus resolved-config, active-profile raw fallback, and default behavior
  • Event WebSocket and API metadata tests assert the effective host per brand
  • Lint tests cover host literals, SDK globals, dot imports, local-shadow/subpackage negatives, case/escape handling, exact resolver-function scoping (parity included), and pin enforcement itself: every violation is asserted as a rejecting action and an end-to-end fixture proves lintcheck exits 1
  • Manual Lark acceptance completed against real services: scan and app creation succeeded, the saved brand was lark, bot credentials verified, and the Lark Open and MCP endpoints were reachable; temporary local config and Keychain data were removed afterward
  • Local gates: build, race unit tests, focused timeout reruns, vet, gofmt, go mod tidy, golangci-lint, lint module/full-repo scans, and quality gate

Related Issues

N/A

@evandance
evandance requested a review from liangshuo-1 as a code owner July 9, 2026 09:03
@evandance evandance added domain/core CLI framework and core libraries size/L Large or sensitive change across domains or core paths bugfix Bug fixes labels Jul 9, 2026
@github-actions github-actions Bot removed the domain/core CLI framework and core libraries label Jul 9, 2026
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR centralizes brand parsing and endpoint resolution across configuration, authentication, self-update, registry, and event flows. It adds brand-mismatch registration retries, domain-contract lint coverage, and validated npm registry URL and redirect handling.

Changes

Brand resolution centralization

Layer / File(s) Summary
ParseBrand normalization core
internal/core/types.go, internal/core/types_test.go
ParseBrand trims and lowercases input before matching lark, defaulting other values to Feishu.
Config and credential brand resolution
cmd/config/binder.go, cmd/config/bind_test.go, extension/credential/...
Configuration and credential providers use core.ParseBrand; local normalization is removed.
Interactive app-registration retry
cmd/config/init_interactive.go, cmd/config/init_interactive_test.go
Polling uses the selected brand, retries with a differing tenant brand, and parses the final brand.
App registration endpoint resolution
internal/auth/app_registration.go, internal/auth/app_registration_test.go
Begin and poll requests use brand-specific account endpoints, with Feishu and Lark coverage.
Brand-aware endpoint consumers
internal/selfupdate/..., cmd/update/update.go, internal/registry/remote.go, shortcuts/event/...
Self-update, registry metadata, and WebSocket endpoint selection use configured brand resolution.

Domain contract lint rule

Layer / File(s) Summary
Domaincontract scanner and enforcement
lint/domaincontract/*, lint/main.go, lint/README.md, .github/workflows/ci.yml
Production Go scans reject hardcoded resolver hosts and SDK base-URL identifiers, with registration, documentation, tests, and CI execution.

Dynamic npm registry URL resolution

Layer / File(s) Summary
Registry resolution and redirect safety
internal/update/update.go, internal/update/update_test.go
Registry metadata URLs are validated and normalized from environment configuration, and HTTPS downgrade redirects are rejected.

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

Possibly related issues

Possibly related PRs

Suggested labels: domain/base

Suggested reviewers: liangshuo-1, MaxHuang22, liuxinyanglxy

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.55% 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
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.
Title check ✅ Passed The title clearly summarizes the PR's main change: routing brand-sensitive endpoints through the resolver.
Description check ✅ Passed The description includes the required Summary, Changes, Test Plan, and Related Issues sections and covers the PR scope well.
✨ 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 fix/endpoint-resolver-consolidation

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.

@evandance evandance added the domain/core CLI framework and core libraries label Jul 9, 2026
@github-actions github-actions Bot removed the domain/core CLI framework and core libraries label Jul 9, 2026
@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.14458% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.58%. Comparing base (452734f) to head (1756d39).

Files with missing lines Patch % Lines
internal/auth/app_registration.go 88.17% 7 Missing and 4 partials ⚠️
cmd/config/init_interactive.go 79.31% 5 Missing and 1 partial ⚠️
internal/registry/loader.go 0.00% 2 Missing ⚠️
internal/selfupdate/updater.go 80.00% 2 Missing ⚠️
cmd/root.go 0.00% 1 Missing ⚠️
shortcuts/event/subscribe.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1836      +/-   ##
==========================================
+ Coverage   74.45%   74.58%   +0.13%     
==========================================
  Files         860      861       +1     
  Lines       89906    89971      +65     
==========================================
+ Hits        66940    67106     +166     
+ Misses      17780    17669     -111     
- Partials     5186     5196      +10     

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

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

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

🧩 Skill update

npx skills add larksuite/cli#fix/endpoint-resolver-consolidation -y -g

@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 `@cmd/config/init_interactive_test.go`:
- Around line 25-30: The test in retryBrand only validates the brand when gotR
is true, so false-retry cases can hide an incorrect brand result. Update the
assertion in init_interactive_test to always compare both gotB and gotR against
c.wantBrand and c.wantRetry for every case, using retryBrand as the reference
point.

In `@cmd/config/init_interactive.go`:
- Around line 225-237: Use core.ParseBrand when computing finalBrand in
init_interactive.go so the saved brand is derived with the same normalization as
retryBrand. The current exact string matching can leave finalBrand on the
original value when result.UserInfo.TenantBrand is mixed-case or padded, so
update the final-brand selection logic to normalize TenantBrand through
core.ParseBrand and keep it consistent with the retry endpoint choice.
🪄 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: c6efd731-adbc-4a6c-8865-1d757c9b4cfa

📥 Commits

Reviewing files that changed from the base of the PR and between d87d9b4 and a880fe6.

📒 Files selected for processing (22)
  • cmd/config/bind_test.go
  • cmd/config/binder.go
  • cmd/config/init_interactive.go
  • cmd/config/init_interactive_test.go
  • cmd/update/update.go
  • extension/credential/env/env.go
  • extension/credential/sidecar/provider.go
  • internal/auth/app_registration.go
  • internal/auth/app_registration_test.go
  • internal/core/types.go
  • internal/core/types_test.go
  • internal/registry/remote.go
  • internal/selfupdate/updater.go
  • internal/selfupdate/updater_test.go
  • internal/update/update.go
  • internal/update/update_test.go
  • lint/README.md
  • lint/domaincontract/scan.go
  • lint/domaincontract/scan_test.go
  • lint/main.go
  • shortcuts/event/subscribe.go
  • shortcuts/event/subscribe_test.go
💤 Files with no reviewable changes (1)
  • cmd/config/bind_test.go

Comment thread cmd/config/init_interactive_test.go Outdated
Comment thread cmd/config/init_interactive.go Outdated
@evandance
evandance force-pushed the fix/endpoint-resolver-consolidation branch 3 times, most recently from a2f4f56 to 6d2f2b4 Compare July 10, 2026 06:24
@github-actions github-actions Bot added size/XL Architecture-level or global-impact change and removed size/L Large or sensitive change across domains or core paths labels Jul 10, 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.

🧹 Nitpick comments (1)
lint/domaincontract/scan_test.go (1)

87-91: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use net/url for host extraction instead of prefix stripping.

strings.TrimPrefix(v, "https://") yields the full URL path (e.g., open.feishu.cn/open-apis), not just the host. If internal/core/types.go ever defines a resolver URL with a path component, the extracted key won't match the bare host in forbiddenHosts, causing a false test failure. The scanner uses strings.Contains (substring match), so this inconsistency is latent today but fragile against future resolver changes.

♻️ Proposed fix using net/url
 import (
 	"go/ast"
 	"go/parser"
 	"go/token"
+	"net/url"
 	"os"
 	"path/filepath"
 	"strconv"
 	"strings"
 	"testing"
 )
 		v, err := strconv.Unquote(lit.Value)
-		if err != nil || !strings.HasPrefix(v, "https://") {
+		if err != nil {
 			return true
 		}
-		resolverHosts[strings.TrimPrefix(v, "https://")] = true
+		u, err := url.Parse(v)
+		if err != nil || u.Host == "" {
+			return true
+		}
+		resolverHosts[u.Host] = true
 		return true
🤖 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 `@lint/domaincontract/scan_test.go` around lines 87 - 91, In the resolver host
extraction logic, replace strings.TrimPrefix(v, "https://") with net/url parsing
so only the URL hostname is stored in resolverHosts. Parse the unquoted value,
handle parse errors alongside the existing validation, and use the parsed
Hostname when populating resolverHosts; update imports accordingly.
🤖 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 `@lint/domaincontract/scan_test.go`:
- Around line 87-91: In the resolver host extraction logic, replace
strings.TrimPrefix(v, "https://") with net/url parsing so only the URL hostname
is stored in resolverHosts. Parse the unquoted value, handle parse errors
alongside the existing validation, and use the parsed Hostname when populating
resolverHosts; update imports accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 47f9aec6-f3b4-4a0d-b887-8e7aba1c8acc

📥 Commits

Reviewing files that changed from the base of the PR and between a2f4f56 and 6d2f2b4.

📒 Files selected for processing (23)
  • .github/workflows/ci.yml
  • cmd/config/bind_test.go
  • cmd/config/binder.go
  • cmd/config/init_interactive.go
  • cmd/config/init_interactive_test.go
  • cmd/update/update.go
  • extension/credential/env/env.go
  • extension/credential/sidecar/provider.go
  • internal/auth/app_registration.go
  • internal/auth/app_registration_test.go
  • internal/core/types.go
  • internal/core/types_test.go
  • internal/registry/remote.go
  • internal/selfupdate/updater.go
  • internal/selfupdate/updater_test.go
  • internal/update/update.go
  • internal/update/update_test.go
  • lint/README.md
  • lint/domaincontract/scan.go
  • lint/domaincontract/scan_test.go
  • lint/main.go
  • shortcuts/event/subscribe.go
  • shortcuts/event/subscribe_test.go
💤 Files with no reviewable changes (1)
  • cmd/config/bind_test.go
✅ Files skipped from review due to trivial changes (1)
  • lint/README.md
🚧 Files skipped from review as they are similar to previous changes (15)
  • shortcuts/event/subscribe_test.go
  • internal/core/types_test.go
  • internal/selfupdate/updater_test.go
  • cmd/update/update.go
  • extension/credential/env/env.go
  • shortcuts/event/subscribe.go
  • cmd/config/init_interactive_test.go
  • lint/main.go
  • extension/credential/sidecar/provider.go
  • internal/registry/remote.go
  • internal/auth/app_registration_test.go
  • internal/core/types.go
  • cmd/config/binder.go
  • cmd/config/init_interactive.go
  • internal/selfupdate/updater.go

@evandance
evandance force-pushed the fix/endpoint-resolver-consolidation branch 8 times, most recently from dfd63f3 to f6bdf6a Compare July 11, 2026 04:18
@evandance evandance changed the title fix: route outbound domains through the endpoint resolver fix: route brand-sensitive endpoints through the resolver Jul 11, 2026
@evandance
evandance force-pushed the fix/endpoint-resolver-consolidation branch 3 times, most recently from 5c37be7 to 274f08a Compare July 11, 2026 08:27
Lark users' API metadata, skills index and source, event WebSocket, and
app-registration endpoints now follow the configured brand through one
resolver, starting from the very first catalog access at process startup.

App registration keeps its protocol-defined Feishu bootstrap, switches to
Lark the moment the tenant reports it — even while authorization is still
pending — and always saves the brand the credentials were issued on,
within a single expiry budget that also cancels in-flight requests.

Brand values are normalized wherever configuration enters the runtime,
and a CI-enforced source guard keeps outbound hosts from bypassing the
resolver again.
@evandance
evandance force-pushed the fix/endpoint-resolver-consolidation branch from 274f08a to 1756d39 Compare July 11, 2026 09:55
@github-actions

Copy link
Copy Markdown

PR Quality Summary

The semantic review system could not produce a fully trusted result. This is not reported as a code defect.

System status

  • semantic review degraded: model request failed (endpoint=https[:]//ark.cn-beijing.volces.com/api/plan/v3/chat/completions model=deepseek-v4-pro response_format=none attempt=3/3): Post "https[:]//ark.cn-beijing.volces.com/api/plan/v3/chat/completions": dial tcp 101.126.13.31:443: i/o timeout — Action: inspect deterministic quality-gate diagnostics

@liangshuo-1
liangshuo-1 merged commit 4847f06 into main Jul 11, 2026
35 of 37 checks passed
@liangshuo-1
liangshuo-1 deleted the fix/endpoint-resolver-consolidation branch July 11, 2026 12:02
@liangshuo-1 liangshuo-1 mentioned this pull request Jul 13, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Bug fixes size/XL Architecture-level or global-impact change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants