Skip to content

feat(apps): gate apps domain off on Lark brand#1025

Merged
liangshuo-1 merged 5 commits into
mainfrom
feat/apps-brand-gate-lark
May 21, 2026
Merged

feat(apps): gate apps domain off on Lark brand#1025
liangshuo-1 merged 5 commits into
mainfrom
feat/apps-brand-gate-lark

Conversation

@liangshuo-1
Copy link
Copy Markdown
Collaborator

@liangshuo-1 liangshuo-1 commented May 21, 2026

Summary

The Miaoda apps OpenAPI is Feishu-only. This PR makes both the CLI and the lark-apps skill fail cleanly on Lark brand instead of presenting commands and scopes that can't possibly work.

  • Command surface: apps shortcuts stay registered but Hidden on Lark; every node under the subtree returns a structured type=validation error (the "apps" feature is not yet supported on the Lark brand) instead of cobra's unknown command. Wording avoids "currently unavailable" so AI consumers don't misread it as a transient failure worth retrying. lark-cli help apps reaches cobra's help renderer (bypassing RunE) and shows the same note via Long.
  • Auth login: --domain apps is rejected as unknown; --domain all skips apps; help-text domain list omits it; scope collection skips apps shortcuts so spark:* scopes never get requested.
  • lark-apps skill: brand-restriction flagged in both the frontmatter description (so skill-routing sees it before triggering) and a prominent banner at the top of SKILL.md (so any consumer hits it before reading the end-to-end flow). The banner tells the AI to run lark-cli config show --format json | jq -r '.brand' first, stop immediately on lark, and not to suggest brand-switching.
  • Mechanism: leaf-stub mirrors internal/cmdpolicy/apply.go::installDenyStubDisableFlagParsing + ArbitraryArgs + leaf-level PersistentPreRunE so cobra can't short-circuit with a missing-required-flag error or a parent-PreRunE detour before our stub runs.
  • Brand registry: single map brandRestrictedServices in shortcuts/register.go — adding future brand restrictions is one map entry, no per-shortcut changes.

Behavior matrix (Lark brand)

DisableFlagParsing=true causes --help / -h / unknown subcommands to fall through to our RunE stub as positional args. The only path that still hits cobra's help renderer is the explicit help subcommand.

Command Result
lark-cli --help apps hidden, not listed
lark-cli apps exit 2, type=validation, brand error
lark-cli apps --help / -h exit 2, brand error (DisableFlagParsing)
lark-cli apps +create --name x exit 2, brand error (no missing-flag detour)
lark-cli apps +create --help exit 2, brand error (DisableFlagParsing on leaf too)
lark-cli apps +nonexistent exit 2, brand error (ArbitraryArgs absorbs it)
lark-cli help apps shows Long brand note — only entry that bypasses RunE
lark-cli auth login --domain apps unknown domain "apps"
lark-cli auth login --domain all apps skipped from expansion

Feishu brand behavior is unchanged (verified via built binary — apps --help still lists all 6 subcommands).

Test plan

  • go test ./shortcuts/... ./cmd/auth/... -count=1 — all green
  • go vet clean
  • New regression tests:
    • shortcuts/register_brand_guard_test.go — 4 cases: hidden on Lark, dispatch returns brand error, untouched on Feishu, cobra-end-to-end dispatch
    • cmd/auth/login_brand_filter_test.go--domain apps / scope collection filtered on Lark
  • Manual smoke on a real Lark-brand config: apps +create returns the validation envelope; lark-cli apps --help returns validation error (not help text); lark-cli help apps shows the Long note

Summary by CodeRabbit

  • New Features

    • Login now respects configured brand when showing available domains, scopes and shortcut services; brand-aware restrictions are applied during interactive and non-interactive login flows.
    • The "apps" shortcut is brand-gated (available on Feishu, hidden/disabled on Lark).
  • Tests

    • Added tests covering brand-specific domain/scope filtering and restricted-service behavior.
  • Documentation

    • Updated skill docs with brand-availability guidance and a pre-check for the apps feature.

Review Change Stack

The Miaoda apps OpenAPI is Feishu-only. On Lark brand:

- shortcut subtree is registered + hidden, RunE returns a structured
  brand-restriction error so users see a clear message instead of
  cobra's generic "unknown command"
- auth login `--domain apps` is treated as unknown; `--domain all`
  skips apps; help text omits it
- scope collection skips apps shortcuts so spark:* scopes are never
  requested

The leaf-stub pattern mirrors internal/cmdpolicy/apply.go::installDenyStub
(DisableFlagParsing + ArbitraryArgs + leaf-level PersistentPreRunE
override) so cobra can't short-circuit the stub with a missing-flag or
parent-PreRunE detour.

Change-Id: I5817e87ae6fedabdb5faf05d0d32ea988f7effc9
@github-actions github-actions Bot added the size/L Large or sensitive change across domains or core paths label May 21, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 83a35ebd-fafc-4657-8837-7aca525ffd13

📥 Commits

Reviewing files that changed from the base of the PR and between c4c2865 and 8a9cddd.

📒 Files selected for processing (1)
  • skills/lark-apps/SKILL.md

📝 Walkthrough

Walkthrough

Auth login derives the CLI brand and uses it to filter known domains, shortcut services, and scope collection; shortcut registration enforces brand-restricted services (hiding and blocking execution). Tests exercise both domain/scope filtering and the runtime guard behavior.

Changes

Brand-aware domain filtering and service restrictions

Layer / File(s) Summary
Brand-aware domain and scope function signatures
cmd/auth/login.go
collectScopesForDomains, allKnownDomains, and sortedKnownDomains now accept core.LarkBrand and filter shortcut services via shortcuts.IsShortcutServiceAvailable.
Auth login command brand integration
cmd/auth/login.go
Login derives brand from config and applies it to --domain all expansion, domain validation, interactive invocation, and --recommend scope collection.
Interactive login with brand parameter
cmd/auth/login_interactive.go
runInteractiveLogin gains a brand core.LarkBrand parameter and forwards it into scope collection; core import added.
Shortcut service brand restriction infrastructure
shortcuts/register.go
Adds brandRestrictedServices map, exported IsShortcutServiceAvailable, derives brand during registration, and installs cobra guards that hide and return validation errors for restricted services (e.g., apps restricted to Feishu).
Auth login brand filtering tests
cmd/auth/login_brand_filter_test.go, cmd/auth/login_test.go
New unit test for brand-based domain/scope filtering; existing domain/scope tests updated to pass brand argument.
Shortcut brand restriction guard tests
shortcuts/register_brand_guard_test.go
Tests verify hidden registration, guard-stubbed execution returning validation errors on restricted brands, and normal execution on unrestricted brands.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Suggested labels

domain/ccm

Suggested reviewers

  • sang-neo03
  • hugang-lark

Poem

🐰 I hopped through code and found a brand,

Domains trimmed tidy by a careful hand,
Shortcuts tucked away where rules demand,
Tests hum softly to confirm the plan,
A rabbit's nod — all tucked and grand.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 43.75% 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 'feat(apps): gate apps domain off on Lark brand' clearly and specifically summarizes the main change: restricting the apps functionality to Feishu brand only.
Description check ✅ Passed The description is comprehensive and well-structured, covering Summary, Changes (implicit), Test Plan with checkbox verification, and Related Issues; all required template sections are present and substantively filled.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/apps-brand-gate-lark

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.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

license-eye has checked 1614 files.

Valid Invalid Ignored Fixed
1158 1 455 0
Click to see the invalid file list
  • cmd/auth/login_brand_filter_test.go
Use this command to fix any missing license headers
```bash

docker run -it --rm -v $(pwd):/github/workspace apache/skywalking-eyes header fix

</details>

Comment thread cmd/auth/login_brand_filter_test.go
@codecov
Copy link
Copy Markdown

codecov Bot commented May 21, 2026

Codecov Report

❌ Patch coverage is 87.93103% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.77%. Comparing base (e54220a) to head (8a9cddd).

Files with missing lines Patch % Lines
cmd/auth/login.go 72.22% 5 Missing ⚠️
cmd/auth/login_interactive.go 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1025      +/-   ##
==========================================
+ Coverage   67.75%   67.77%   +0.02%     
==========================================
  Files         590      590              
  Lines       55245    55291      +46     
==========================================
+ Hits        37432    37475      +43     
- Misses      14693    14696       +3     
  Partials     3120     3120              

☔ 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 21, 2026

🚀 PR Preview Install Guide

🧰 CLI update

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

🧩 Skill update

npx skills add larksuite/cli#feat/apps-brand-gate-lark -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.

Caution

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

⚠️ Outside diff range comments (1)
cmd/auth/login_interactive.go (1)

109-125: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Interactive picker still surfaces brand-restricted services (e.g. apps) on Lark.

runInteractiveLogin threads brand only into collectScopesForDomains (Line 169), but getDomainMetadata(lang) at Line 110 is brand-unaware and iterates shortcuts.AllShortcuts() without shortcuts.IsShortcutServiceAvailable. Net effect on Lark brand:

  • The multi-select shows apps as a selectable option.
  • If the user selects only apps, scope collection returns empty and the caller surfaces a generic "no matching scopes found" validation error.
  • If the user selects apps alongside other domains, no error is raised but the apps selection is silently dropped from the requested scope set.

This contradicts the PR objective ("Prevent the CLI from presenting … apps … on Lark") and is inconsistent with the brand-filtered --help (sortedKnownDomains(brand)) and --domain validation (allKnownDomains(brand)) in login.go.

♻️ Proposed fix: thread brand into domain metadata
-func getDomainMetadata(lang string) []domainMeta {
+func getDomainMetadata(lang string, brand core.LarkBrand) []domainMeta {
 	seen := make(map[string]bool)
 	var domains []domainMeta
 
 	// 1. Domains from from_meta projects (skip domains with auth_domain)
 	for _, project := range registry.ListFromMetaProjects() {
 		if registry.HasAuthDomain(project) {
 			seen[project] = true
 			continue
 		}
 		dm := buildDomainMeta(project, lang)
 		domains = append(domains, dm)
 		seen[project] = true
 	}
 
 	// 2. Shortcut-only domains
 	shortcutOnlyNames := getShortcutOnlyDomainNames()
 	for _, name := range shortcutOnlyNames {
-		if !seen[name] {
+		if !seen[name] && shortcuts.IsShortcutServiceAvailable(name, brand) {
 			dm := buildDomainMeta(name, lang)
 			domains = append(domains, dm)
 			seen[name] = true
 		}
 	}
 
 	// 3. Auto-discover remaining shortcut services...
 	shortcutOnlySet := make(map[string]bool)
 	for _, n := range shortcutOnlyNames {
 		shortcutOnlySet[n] = true
 	}
 	for _, sc := range shortcuts.AllShortcuts() {
+		if !shortcuts.IsShortcutServiceAvailable(sc.Service, brand) {
+			continue
+		}
 		if !seen[sc.Service] {
 			if shortcutOnlySet[sc.Service] && !registry.HasAuthDomain(sc.Service) {
 				dm := buildDomainMeta(sc.Service, lang)
 				domains = append(domains, dm)
 			}
 			seen[sc.Service] = true
 		}
 	}

And update the caller:

-	allDomains := getDomainMetadata(lang)
+	allDomains := getDomainMetadata(lang, brand)

The corresponding TestGetDomainMetadata_* tests in cmd/auth/login_test.go also need to be updated to pass a brand argument.

🤖 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_interactive.go` around lines 109 - 125, runInteractiveLogin
currently calls getDomainMetadata(lang) which is brand-unaware and lets
brand-restricted services (e.g. "apps") appear; change getDomainMetadata to
accept a core.LarkBrand (or similar) and filter domain list using
shortcuts.IsShortcutServiceAvailable when iterating shortcuts.AllShortcuts(),
then update runInteractiveLogin to pass the brand into getDomainMetadata and any
other callers (e.g. tests and the places that call
sortedKnownDomains/allKnownDomains) so the interactive picker, --help and
--domain validation all use the same brand-aware domain set; also update
TestGetDomainMetadata_* tests to pass the brand argument.
🧹 Nitpick comments (1)
shortcuts/register_brand_guard_test.go (1)

18-24: ⚡ Quick win

Use cmdutil.TestFactory here.

This helper manually assembles cmdutil.Factory, which skips the repo’s standard unit-test factory setup. Please build it with cmdutil.TestFactory(t, &core.CliConfig{Brand: brand}) instead and thread t through the helper.

As per coding guidelines, **/*_test.go: Use cmdutil.TestFactory(t, config) for test factories in unit tests.

🤖 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/register_brand_guard_test.go` around lines 18 - 24, The test helper
newFactoryWithBrand currently constructs a cmdutil.Factory manually; change it
to accept testing.T (thread t through the helper) and return
cmdutil.TestFactory(t, &core.CliConfig{Brand: brand}) instead of assembling
cmdutil.Factory directly so the repo's standard test factory setup is used
(update the helper signature and all call sites to pass t).
🤖 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.

Outside diff comments:
In `@cmd/auth/login_interactive.go`:
- Around line 109-125: runInteractiveLogin currently calls
getDomainMetadata(lang) which is brand-unaware and lets brand-restricted
services (e.g. "apps") appear; change getDomainMetadata to accept a
core.LarkBrand (or similar) and filter domain list using
shortcuts.IsShortcutServiceAvailable when iterating shortcuts.AllShortcuts(),
then update runInteractiveLogin to pass the brand into getDomainMetadata and any
other callers (e.g. tests and the places that call
sortedKnownDomains/allKnownDomains) so the interactive picker, --help and
--domain validation all use the same brand-aware domain set; also update
TestGetDomainMetadata_* tests to pass the brand argument.

---

Nitpick comments:
In `@shortcuts/register_brand_guard_test.go`:
- Around line 18-24: The test helper newFactoryWithBrand currently constructs a
cmdutil.Factory manually; change it to accept testing.T (thread t through the
helper) and return cmdutil.TestFactory(t, &core.CliConfig{Brand: brand}) instead
of assembling cmdutil.Factory directly so the repo's standard test factory setup
is used (update the helper signature and all call sites to pass t).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3f3da1f8-d801-4e8e-8358-c62cc8739fa9

📥 Commits

Reviewing files that changed from the base of the PR and between e54220a and 9faf4fa.

📒 Files selected for processing (6)
  • cmd/auth/login.go
  • cmd/auth/login_brand_filter_test.go
  • cmd/auth/login_interactive.go
  • cmd/auth/login_test.go
  • shortcuts/register.go
  • shortcuts/register_brand_guard_test.go

Change-Id: Ic65b4eb17b982dab6a7c5382fb26e4e678da18fd
AI consumers parsed 'not currently available' as transient (retry-worthy). 'not yet supported' makes it categorical: feature isn't done on this brand, no point retrying or switching params.

Change-Id: I5a757700a9a242c065db4a53101dc4babc101c7c
…k brand

Without this, an AI consumer on Lark brand reads the skill description, sees a match on 'deploy HTML' intent, runs through the end-to-end flow, and only fails at step 1 when the CLI returns the brand error. Surface the limitation up front: in the description (so the skill router sees it) and as the first body section (so any consumer reading SKILL.md hits it before reading the operational guidance).

Change-Id: Ie316178fe361cc570756568aabea4c64d1ff80be
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

🤖 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 `@skills/lark-apps/SKILL.md`:
- Around line 16-20: The docs require jq for the command `lark-cli config show
--format json | jq -r '.brand'` but the package metadata only declares
`lark-cli` in `metadata.requires.bins`; either add `jq` to
`metadata.requires.bins` or add a no-`jq` fallback command (e.g., parse JSON in
a POSIX-tool-safe way or use `lark-cli`’s own flags) and document both options
in SKILL.md so environments that install only declared prerequisites won't fail;
update references to `metadata.requires.bins` and the example command
accordingly.
🪄 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: f75a3cd8-754f-4d28-b0c2-e6b2a802c6c3

📥 Commits

Reviewing files that changed from the base of the PR and between dfecc24 and c4c2865.

📒 Files selected for processing (1)
  • skills/lark-apps/SKILL.md

Comment thread skills/lark-apps/SKILL.md Outdated
Trim per Anthropic skills convention (anthropics/skills repo):
- description: capability-first opener, no CLI path in parens, no
  keyword soup, no execution policy duplication (already covered in
  body 端到端流程 + 快速决策). Adds explicit negative boundaries vs
  lark-doc / lark-drive / lark-slides — the slides boundary avoids
  routing conflict on 'PPT'/'演示文稿'.
- cliHelp: single 'lark-cli apps --help' (matches 8/10 other skills;
  the 5-entry enumeration was a one-off).
- Body: replace the ⛔ banner + config-show precheck with a one-line
  prereq under its own '品牌可用性(先做)' H2. Detection is semantic
  ('若提示暂未支持') rather than substring match, and the user-facing
  phrasing is left to the AI rather than a verbatim template.

Change-Id: Ib3bbfc5bcbb31ef15033c883d224d8de9686ec16
@liangshuo-1 liangshuo-1 merged commit daba3c9 into main May 21, 2026
22 checks passed
@liangshuo-1 liangshuo-1 deleted the feat/apps-brand-gate-lark branch May 21, 2026 19:03
@liangshuo-1 liangshuo-1 mentioned this pull request May 21, 2026
3 tasks
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.

1 participant