Skip to content

Commit 404318e

Browse files
committed
ci: merge latest main into live E2E branch
2 parents ceb5da9 + 4e0a6a9 commit 404318e

148 files changed

Lines changed: 17880 additions & 918 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,34 @@ jobs:
5454
exit 1
5555
fi
5656
57+
plugin-integration:
58+
needs: fast-gate
59+
runs-on: ubuntu-latest
60+
steps:
61+
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
62+
with:
63+
persist-credentials: false
64+
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
65+
with:
66+
go-version-file: go.mod
67+
# No fetch_meta: the git-archive clean tree must embed only the
68+
# committed meta_data stub (reproduces the bare-module customer state).
69+
- name: Run plugin-integration L4 tests
70+
run: go test -count=1 -timeout=15m ./tests/plugin_e2e/...
71+
72+
sidecar-integration:
73+
needs: fast-gate
74+
runs-on: ubuntu-latest
75+
steps:
76+
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
77+
with:
78+
persist-credentials: false
79+
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
80+
with:
81+
go-version-file: go.mod
82+
- name: Run sidecar tag build + HMAC round-trip
83+
run: make sidecar-test
84+
5785
# ── Layer 2: Quality Gate ──────────────────────────────────────────
5886
unit-test:
5987
needs: fast-gate
@@ -183,7 +211,11 @@ jobs:
183211
run: python3 scripts/fetch_meta.py
184212
- name: Run tests with coverage
185213
run: |
186-
packages=$(go list ./... | grep -v '^github.com/larksuite/cli/tests/cli_e2e$' | grep -v '^github.com/larksuite/cli/tests/cli_e2e/')
214+
# tests/ holds only L3/L4 suites (cli_e2e, plugin_e2e, sidecar_e2e) that
215+
# have dedicated jobs; exclude the whole subtree so none of them runs a
216+
# second time here — and, crucially, so an observe-only suite's failure
217+
# can never block merges through coverage's spot in the results loop.
218+
packages=$(go list ./... | grep -v '^github.com/larksuite/cli/tests/')
187219
go test -race -coverprofile=coverage.txt -covermode=atomic $packages
188220
- name: Upload coverage to Codecov
189221
if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork }}
@@ -468,7 +500,7 @@ jobs:
468500
# ── Results Gate (single required check for branch protection) ─────
469501
results:
470502
if: ${{ always() }}
471-
needs: [fast-gate, unit-test, lint, script-test, deterministic-gate, coverage, deadcode, e2e-dry-run, e2e-live, security, license-header]
503+
needs: [fast-gate, unit-test, lint, script-test, deterministic-gate, coverage, deadcode, e2e-dry-run, e2e-live, security, license-header, plugin-integration, sidecar-integration]
472504
runs-on: ubuntu-latest
473505
steps:
474506
- name: Evaluate results
@@ -488,10 +520,19 @@ jobs:
488520
echo "| L3 | e2e-live | ${{ needs.e2e-live.result }} |" >> $GITHUB_STEP_SUMMARY
489521
echo "| L4 | security | ${{ needs.security.result }} |" >> $GITHUB_STEP_SUMMARY
490522
echo "| L4 | license-header | ${{ needs.license-header.result }} |" >> $GITHUB_STEP_SUMMARY
523+
echo "| L4 | plugin-integration (observe-only) | ${{ needs.plugin-integration.result }} |" >> $GITHUB_STEP_SUMMARY
524+
echo "| L4 | sidecar-integration (observe-only) | ${{ needs.sidecar-integration.result }} |" >> $GITHUB_STEP_SUMMARY
491525
492526
# Any failure or cancellation in any job blocks the merge.
493527
# Legitimately skipped jobs (deadcode on push, e2e-live when not
494528
# needed or on a fork, license-header on push) are OK.
529+
#
530+
# plugin-integration and sidecar-integration are intentionally NOT
531+
# in this loop yet: they run on every PR and their status is shown
532+
# in the table above, but a failure is observe-only (non-blocking)
533+
# during the initial soak. Graduation to required is tracked in
534+
# https://github.com/larksuite/cli/issues/1894 (criteria: 4
535+
# consecutive weeks with zero false positives).
495536
FAILED=0
496537
for result in \
497538
"${{ needs.fast-gate.result }}" \

CHANGELOG.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,64 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [v1.0.71] - 2026-07-16
6+
7+
### Features
8+
9+
- add wiki move-to-drive shortcut (#1869)
10+
- **apps**: add role management shortcuts (#1881)
11+
- **drive**: add secure label support and clarify comment location API (#1913)
12+
13+
### Bug Fixes
14+
15+
- **base**: improve dashboard shortcut guidance (#1787)
16+
17+
### Documentation
18+
19+
- **apps**: add platform SQL authoring guide to the db-execute skill (#1912)
20+
21+
### Misc
22+
23+
- add L4 plugin-integration and sidecar-integration CI jobs (#1840)
24+
- **drive**: optimize drive +delete workflow (#1909)
25+
26+
## [v1.0.70] - 2026-07-15
27+
28+
### Features
29+
30+
- add minutes permission application shortcut (#1876)
31+
- **drive**: support apps in list comments (#1877)
32+
- slide style
33+
- edit ppt template
34+
- **slides**: add sxsd validation to slides lint
35+
- **slides**: validate iconpark icon types in slides lint
36+
- **slides**: lint before create
37+
- **apps**: add automation trigger commands for Miaoda (#1886)
38+
39+
### Bug Fixes
40+
41+
- unify dry-run output contract (#1870)
42+
- **skills**: align skill guidance with the typed error contract (#1786)
43+
- **slides**: limit slides screenshot page requests
44+
- **slides**: detect lark slides text overflow overlap
45+
- **vc**: align meeting query scopes by identity (#1850)
46+
47+
### Documentation
48+
49+
- clarify task search relevance filters (#1884)
50+
- surface minutes permission application in skill description (#1890)
51+
- clarify okr progress children (#1861)
52+
- **slides**: prefer slides xml-get shortcut
53+
- **calendar**: document setting meeting owner via full API (#1903)
54+
55+
### Refactoring
56+
57+
- **slides**: streamline create workflow and validate SML namespaces
58+
59+
### Misc
60+
61+
- **slides**: address PR review feedback
62+
563
## [v1.0.69] - 2026-07-13
664

765
### Features
@@ -1469,6 +1527,8 @@ Bundled AI agent skills for intelligent assistance:
14691527
- Bilingual documentation (English & Chinese).
14701528
- CI/CD pipelines: linting, testing, coverage reporting, and automated releases.
14711529

1530+
[v1.0.71]: https://github.com/larksuite/cli/releases/tag/v1.0.71
1531+
[v1.0.70]: https://github.com/larksuite/cli/releases/tag/v1.0.70
14721532
[v1.0.69]: https://github.com/larksuite/cli/releases/tag/v1.0.69
14731533
[v1.0.68]: https://github.com/larksuite/cli/releases/tag/v1.0.68
14741534
[v1.0.67]: https://github.com/larksuite/cli/releases/tag/v1.0.67

Makefile

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ PREFIX ?= /usr/local
2323
TEST_GOARCH := $(or $(GOARCH),$(shell go env GOARCH))
2424
RACE_FLAG := $(if $(filter riscv64,$(TEST_GOARCH)),,-race)
2525

26-
.PHONY: all build vet fmt-check script-test test unit-test integration-test examples-build quality-gate install uninstall clean fetch_meta gitleaks
26+
.PHONY: all build vet fmt-check script-test test unit-test integration-test examples-build quality-gate install uninstall clean fetch_meta gitleaks sidecar-test
2727

2828
all: test
2929

@@ -64,6 +64,9 @@ examples-build:
6464
go build ./extension/platform/examples/audit-observer
6565
go build ./extension/platform/examples/readonly-policy
6666

67+
# ./tests/... includes tests/plugin_e2e, which builds ~20 customer-fork
68+
# binaries (~1 min warm; a cold module cache also downloads via GOPROXY).
69+
# Deliberate: local `make test` exercises the L4 plugin contract by default.
6770
integration-test: build
6871
go test -v -count=1 ./tests/...
6972

@@ -105,6 +108,14 @@ uninstall:
105108
clean:
106109
rm -f $(BINARY)
107110

111+
# sidecar-test compiles and runs the authsidecar* build-tagged code that the
112+
# default CI matrix never sees (they carry //go:build tags).
113+
sidecar-test:
114+
go build -tags authsidecar -o /dev/null .
115+
go test $(RACE_FLAG) -count=1 -tags authsidecar ./extension/credential/sidecar/ ./extension/transport/sidecar/ ./internal/cmdutil/
116+
go test $(RACE_FLAG) -count=1 -tags authsidecar_demo ./sidecar/server-demo/
117+
go test $(RACE_FLAG) -count=1 -tags authsidecar ./tests/sidecar_e2e/
118+
108119
# Run secret-leak checks locally before pushing.
109120
# Step 1: check-doc-tokens catches realistic-looking example tokens in reference
110121
# docs and asks you to use _EXAMPLE_TOKEN placeholders instead.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
2+
// SPDX-License-Identifier: MIT
3+
4+
package errclass
5+
6+
import "github.com/larksuite/cli/errs"
7+
8+
// sparkCodeMeta holds stable Spark app-role business-code classifications.
9+
// Command-specific recovery guidance belongs in the Apps shortcut layer; the
10+
// numeric code remains the source-specific discriminator on the error envelope.
11+
var sparkCodeMeta = map[int]CodeMeta{
12+
3340001: {Category: errs.CategoryAPI, Subtype: errs.SubtypeInvalidParameters}, // request parameters are invalid
13+
3344027: {Category: errs.CategoryAPI, Subtype: errs.SubtypeQuotaExceeded}, // role user count exceeds the service limit
14+
3344028: {Category: errs.CategoryAPI, Subtype: errs.SubtypeQuotaExceeded}, // role department count exceeds the service limit
15+
3344029: {Category: errs.CategoryAPI, Subtype: errs.SubtypeQuotaExceeded}, // role chat count exceeds the service limit
16+
3344030: {Category: errs.CategoryAuthorization, Subtype: errs.SubtypePermissionDenied}, // app administrator required
17+
3344031: {Category: errs.CategoryAuthorization, Subtype: errs.SubtypePermissionDenied}, // app administrator or developer required
18+
3344034: {Category: errs.CategoryAPI, Subtype: errs.SubtypeInvalidParameters}, // invalid role ID
19+
3344035: {Category: errs.CategoryAPI, Subtype: errs.SubtypeNotFound}, // role does not exist
20+
3344036: {Category: errs.CategoryAPI, Subtype: errs.SubtypeAlreadyExists}, // role ID already exists
21+
3344037: {Category: errs.CategoryAPI, Subtype: errs.SubtypeQuotaExceeded}, // app role count exceeds the service limit
22+
3344038: {Category: errs.CategoryAPI, Subtype: errs.SubtypeInvalidParameters}, // invalid role name
23+
3344039: {Category: errs.CategoryAPI, Subtype: errs.SubtypeInvalidParameters}, // invalid role description
24+
3344040: {Category: errs.CategoryAPI, Subtype: errs.SubtypeInvalidParameters}, // unsupported member type
25+
3344041: {Category: errs.CategoryAPI, Subtype: errs.SubtypeInvalidParameters}, // invalid member ID
26+
}
27+
28+
func init() { mergeCodeMeta(sparkCodeMeta, "spark") }
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
2+
// SPDX-License-Identifier: MIT
3+
4+
package errclass
5+
6+
import (
7+
"fmt"
8+
"testing"
9+
10+
"github.com/larksuite/cli/errs"
11+
)
12+
13+
func TestLookupCodeMetaSparkRoleCodes(t *testing.T) {
14+
tests := []struct {
15+
code int
16+
category errs.Category
17+
subtype errs.Subtype
18+
}{
19+
{3340001, errs.CategoryAPI, errs.SubtypeInvalidParameters},
20+
{3344027, errs.CategoryAPI, errs.SubtypeQuotaExceeded},
21+
{3344028, errs.CategoryAPI, errs.SubtypeQuotaExceeded},
22+
{3344029, errs.CategoryAPI, errs.SubtypeQuotaExceeded},
23+
{3344030, errs.CategoryAuthorization, errs.SubtypePermissionDenied},
24+
{3344031, errs.CategoryAuthorization, errs.SubtypePermissionDenied},
25+
{3344034, errs.CategoryAPI, errs.SubtypeInvalidParameters},
26+
{3344035, errs.CategoryAPI, errs.SubtypeNotFound},
27+
{3344036, errs.CategoryAPI, errs.SubtypeAlreadyExists},
28+
{3344037, errs.CategoryAPI, errs.SubtypeQuotaExceeded},
29+
{3344038, errs.CategoryAPI, errs.SubtypeInvalidParameters},
30+
{3344039, errs.CategoryAPI, errs.SubtypeInvalidParameters},
31+
{3344040, errs.CategoryAPI, errs.SubtypeInvalidParameters},
32+
{3344041, errs.CategoryAPI, errs.SubtypeInvalidParameters},
33+
}
34+
35+
for _, tt := range tests {
36+
t.Run(fmt.Sprintf("%d", tt.code), func(t *testing.T) {
37+
meta, ok := LookupCodeMeta(tt.code)
38+
if !ok {
39+
t.Fatalf("code %d is not registered", tt.code)
40+
}
41+
if meta.Category != tt.category || meta.Subtype != tt.subtype || meta.Retryable {
42+
t.Fatalf("code %d metadata = %+v, want category=%s subtype=%s retryable=false", tt.code, meta, tt.category, tt.subtype)
43+
}
44+
45+
err := BuildAPIError(map[string]any{
46+
"code": tt.code,
47+
"msg": "spark role error",
48+
"log_id": "log-spark-role",
49+
}, ClassifyContext{Identity: "user"})
50+
problem, ok := errs.ProblemOf(err)
51+
if !ok {
52+
t.Fatalf("BuildAPIError(%d) = %#v, want typed problem", tt.code, err)
53+
}
54+
if problem.Category != tt.category || problem.Subtype != tt.subtype || problem.Code != tt.code || problem.LogID != "log-spark-role" || problem.Retryable {
55+
t.Fatalf("BuildAPIError(%d) problem = %+v", tt.code, problem)
56+
}
57+
})
58+
}
59+
}

internal/qualitygate/rules/dryrun.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ func fakeValueFromPlaceholderName(name string) (string, bool) {
337337
case name == "open_id" || hasPlaceholderToken(tokens, "user", "owner", "participant", "approver", "speaker"):
338338
return "ou_test123", true
339339
case hasPlaceholderToken(tokens, "department", "dept"):
340-
return "od_test123", true
340+
return "od-test123", true
341341
case hasPlaceholderToken(tokens, "message"):
342342
return "om_test123", true
343343
case name == "file_key":

internal/qualitygate/rules/dryrun_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,13 @@ func TestRunDryRunsMaterializesInlinePlaceholderFlagValues(t *testing.T) {
316316
}
317317
}
318318

319+
func TestFakeValueFromPlaceholderNameUsesOpenDepartmentPrefix(t *testing.T) {
320+
got, ok := fakeValueFromPlaceholderName("open_department_id")
321+
if !ok || got != "od-test123" {
322+
t.Fatalf("open_department_id placeholder = %q, %v; want od-test123, true", got, ok)
323+
}
324+
}
325+
319326
func TestRunDryRunsMaterializesNumericPlaceholderFlagValues(t *testing.T) {
320327
cliBin, argsPath := fakeDryRunCLI(t, `{"api":[{"method":"GET","url":"/open-apis/vc/v1/bots/events","params":{"meeting_id":"400000000001","page_size":50}}]}`)
321328
m := manifest.Manifest{Commands: []manifest.Command{{

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@larksuite/cli",
3-
"version": "1.0.69",
3+
"version": "1.0.71",
44
"description": "The official CLI for Lark/Feishu open platform",
55
"bin": {
66
"lark-cli": "scripts/run.js"

shortcuts/apps/apps_access_scope_get_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func TestAppsAccessScopeGet_Specific(t *testing.T) {
2020
"data": map[string]interface{}{
2121
"scope": "Range",
2222
"users": []interface{}{"ou_x", "ou_y"},
23-
"departments": []interface{}{"od_z"},
23+
"departments": []interface{}{"od-z"},
2424
"chats": []interface{}{"oc_g"},
2525
"apply_config": map[string]interface{}{
2626
"enabled": true,
@@ -39,7 +39,7 @@ func TestAppsAccessScopeGet_Specific(t *testing.T) {
3939
if !strings.Contains(got, `"scope": "Range"`) {
4040
t.Fatalf("scope string not preserved (expect raw \"Range\"): %s", got)
4141
}
42-
if !strings.Contains(got, `"ou_x"`) || !strings.Contains(got, `"od_z"`) || !strings.Contains(got, `"oc_g"`) {
42+
if !strings.Contains(got, `"ou_x"`) || !strings.Contains(got, `"od-z"`) || !strings.Contains(got, `"oc_g"`) {
4343
t.Fatalf("users/departments/chats fields missing in envelope: %s", got)
4444
}
4545
if !strings.Contains(got, `"ou_appr"`) {

0 commit comments

Comments
 (0)