Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions shortcuts/mail/mail_auth_types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT

package mail

import (
"strings"
"testing"

"github.com/larksuite/cli/internal/cmdutil"
"github.com/larksuite/cli/internal/core"
"github.com/larksuite/cli/shortcuts/common"
"github.com/spf13/cobra"
)

// TestUserMailboxShortcutsRequireUserIdentity verifies that shortcuts backed
// exclusively by user_mailbox.* APIs reject bot identity before making any
// API call. The error must contain "not supported" so the caller knows the
// issue is identity, not a bad parameter.
func TestUserMailboxShortcutsRequireUserIdentity(t *testing.T) {
tests := []struct {
shortcut common.Shortcut
args []string // minimum args to pass cobra's required-flag check
}{
{
shortcut: MailTriage,
args: []string{"+triage", "--as", "bot"},
},
{
shortcut: MailMessages,
args: []string{"+messages", "--as", "bot", "--message-ids", "dummy"},
},
{
shortcut: MailTemplateCreate,
args: []string{"+template-create", "--as", "bot", "--name", "dummy"},
},
{
shortcut: MailThread,
args: []string{"+thread", "--as", "bot", "--thread-id", "dummy"},
},
{
shortcut: MailTemplateUpdate,
args: []string{"+template-update", "--as", "bot"},
},
{
shortcut: MailMessage,
args: []string{"+message", "--as", "bot", "--message-id", "dummy"},
},
}

for _, tt := range tests {
t.Run(tt.shortcut.Command, func(t *testing.T) {
f, _, _, _ := cmdutil.TestFactory(t, &core.CliConfig{
AppID: "test-app",
AppSecret: "test-secret",
Brand: core.BrandFeishu,
})

parent := &cobra.Command{Use: "mail"}
tt.shortcut.Mount(parent, f)
parent.SetArgs(tt.args)
parent.SilenceErrors = true
parent.SilenceUsage = true

err := parent.Execute()
if err == nil {
t.Fatal("expected error for bot identity, got nil")
}
if !strings.Contains(err.Error(), "not supported") {
t.Errorf("expected 'not supported' in error, got: %v", err)
}
})
}
}
2 changes: 1 addition & 1 deletion shortcuts/mail/mail_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var MailMessage = common.Shortcut{
Description: "Use when reading full content for a single email by message ID. Returns normalized body content plus attachments metadata, including inline images.",
Risk: "read",
Scopes: []string{"mail:user_mailbox.message:readonly", "mail:user_mailbox.message.address:read", "mail:user_mailbox.message.subject:read", "mail:user_mailbox.message.body:read"},
AuthTypes: []string{"user", "bot"},
AuthTypes: []string{"user"},
HasFormat: true,
Flags: []common.Flag{
{Name: "mailbox", Default: "me", Desc: "email address (default: me)"},
Expand Down
2 changes: 1 addition & 1 deletion shortcuts/mail/mail_messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ var MailMessages = common.Shortcut{
Description: "Use when reading full content for multiple emails by message ID. Prefer this shortcut over calling raw mail user_mailbox.messages batch_get directly, because it base64url-decodes body fields and returns normalized per-message output that is easier to consume.",
Risk: "read",
Scopes: []string{"mail:user_mailbox.message:readonly", "mail:user_mailbox.message.address:read", "mail:user_mailbox.message.subject:read", "mail:user_mailbox.message.body:read"},
AuthTypes: []string{"user", "bot"},
AuthTypes: []string{"user"},
HasFormat: true,
Flags: []common.Flag{
{Name: "mailbox", Default: "me", Desc: "email address (default: me)"},
Expand Down
2 changes: 1 addition & 1 deletion shortcuts/mail/mail_template_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var MailTemplateCreate = common.Shortcut{
Description: "Create a personal mail template. Scans HTML <img src> local paths (reusing draft inline-image detection), uploads inline images and non-inline attachments to Drive, rewrites HTML to cid: references, and POSTs a Template payload to mail.user_mailbox.templates.create.",
Risk: "write",
Scopes: []string{"mail:user_mailbox.message:modify", "mail:user_mailbox:readonly"},
AuthTypes: []string{"user", "bot"},
AuthTypes: []string{"user"},
HasFormat: true,
Flags: []common.Flag{
{Name: "mailbox", Desc: "Mailbox email address that owns the template (default: me)."},
Expand Down
2 changes: 1 addition & 1 deletion shortcuts/mail/mail_template_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var MailTemplateUpdate = common.Shortcut{
Description: "Update an existing mail template. Supports --inspect (read-only projection), --print-patch-template (prints a JSON skeleton for --patch-file), and flat flags (--set-subject / --set-name / etc). Internally it GETs the template, applies the patch, rewrites <img> local paths to cid: refs, and PUTs a full-replace update (no optimistic locking: last-write-wins).",
Risk: "write",
Scopes: []string{"mail:user_mailbox.message:modify", "mail:user_mailbox:readonly"},
AuthTypes: []string{"user", "bot"},
AuthTypes: []string{"user"},
HasFormat: true,
Flags: []common.Flag{
{Name: "mailbox", Desc: "Mailbox email address that owns the template (default: me)."},
Expand Down
2 changes: 1 addition & 1 deletion shortcuts/mail/mail_thread.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ var MailThread = common.Shortcut{
Description: "Use when querying a full mail conversation/thread by thread ID. Returns all messages in chronological order, including replies and drafts, with body content and attachments metadata, including inline images.",
Risk: "read",
Scopes: []string{"mail:user_mailbox.message:readonly", "mail:user_mailbox.message.address:read", "mail:user_mailbox.message.subject:read", "mail:user_mailbox.message.body:read"},
AuthTypes: []string{"user", "bot"},
AuthTypes: []string{"user"},
HasFormat: true,
Flags: []common.Flag{
{Name: "mailbox", Default: "me", Desc: "email address (default: me)"},
Expand Down
2 changes: 1 addition & 1 deletion shortcuts/mail/mail_triage.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ var MailTriage = common.Shortcut{
Description: `List mail summaries (date/from/subject/message_id). Use --query for full-text search, --filter for exact-match conditions.`,
Risk: "read",
Scopes: []string{"mail:user_mailbox.message:readonly", "mail:user_mailbox.message.address:read", "mail:user_mailbox.message.subject:read", "mail:user_mailbox.message.body:read"},
AuthTypes: []string{"user", "bot"},
AuthTypes: []string{"user"},
Flags: []common.Flag{
{Name: "format", Default: "table", Desc: "output format: table | json | data (json/data output object with pagination fields)"},
{Name: "max", Type: "int", Default: "20", Desc: "maximum number of messages to fetch (1-400; auto-paginates internally)"},
Expand Down
Loading