Skip to content

feat: support custom data dir and log directories#302

Open
JackZhao10086 wants to merge 2 commits intomainfrom
feat/linux_env_data_dir
Open

feat: support custom data dir and log directories#302
JackZhao10086 wants to merge 2 commits intomainfrom
feat/linux_env_data_dir

Conversation

@JackZhao10086
Copy link
Copy Markdown
Collaborator

@JackZhao10086 JackZhao10086 commented Apr 7, 2026

Summary

Adds environment variable overrides for keychain-related local storage paths. This lets users customize the Linux keychain data directory and the auth log directory without changing the default behavior.

Changes

  • Add LARKSUITE_CLI_DATA_DIR support in internal/keychain/keychain_other.go so Linux keychain storage can use a custom directory
  • Add LARKSUITE_CLI_LOG_DIR support in internal/keychain/auth_log.go so auth logs can be written to a custom directory

Test Plan

  • Unit tests pass
  • Manually verify relevant lark xxx commands locally

Executed:

  • go test ./internal/keychain
  • GOOS=linux GOARCH=amd64 go test -c -o /tmp/keychain_linux.test ./internal/keychain

Related Issues

Summary by CodeRabbit

Release Notes

  • New Features
    • Added LARKSUITE_CLI_LOG_DIR environment variable to customize log directory location
    • Added LARKSUITE_CLI_DATA_DIR environment variable to customize data storage directory location

@github-actions github-actions bot added the size/L Large or sensitive change across domains or core paths label Apr 7, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 7, 2026

📝 Walkthrough

Walkthrough

Two functions now check environment variables first before falling back to defaults: authLogDir() checks LARKSUITE_CLI_LOG_DIR and StorageDir() checks LARKSUITE_CLI_DATA_DIR, allowing users to override path configurations via environment variables.

Changes

Cohort / File(s) Summary
Auth Log Directory Configuration
internal/keychain/auth_log.go
Added environment variable check for LARKSUITE_CLI_LOG_DIR with precedence over existing config and home directory defaults.
Storage Directory Configuration
internal/keychain/keychain_other.go
Added environment variable check for LARKSUITE_CLI_DATA_DIR with precedence over existing home directory-based storage logic.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 Paths now flow where envvars wish,
No more stubborn defaults to dismiss,
Custom routes through the CLI code,
Directories dance to override mode!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding support for custom data and log directories via environment variables.
Description check ✅ Passed The description includes all required template sections with concrete details about changes, testing approach, and environment variable support, though manual verification is pending.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 feat/linux_env_data_dir

Comment @coderabbitai help to get the list of available commands and usage tips.

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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/keychain/auth_log.go`:
- Around line 24-26: The returned LARKSUITE_CLI_LOG_DIR value is used later by
vfs.MkdirAll and vfs.OpenFile and must be validated; update the function in
auth_log.go that reads os.Getenv("LARKSUITE_CLI_LOG_DIR") to call
validate.SafeInputPath (or the project’s equivalent) on the value and only
return it if validation succeeds, otherwise fall back to the existing default
path or an empty string and log/handle the invalid input; ensure the validation
happens before any use in vfs.MkdirAll or vfs.OpenFile so the path cannot be
used without passing validate.SafeInputPath.

In `@internal/keychain/keychain_other.go`:
- Around line 28-29: The function currently returns the raw
LARKSUITE_CLI_DATA_DIR env value (os.Getenv("LARKSUITE_CLI_DATA_DIR")) without
appending the service name, causing data/credential collisions; change the
branch in StorageDir to return filepath.Join(dir, service) instead of dir so the
environment override preserves per-service isolation (mirror the default branch
which uses filepath.Join(xdgData, service)).
- Around line 28-30: The code returns the LARKSUITE_CLI_DATA_DIR env value
directly; validate this user-controlled path with validate.SafeInputPath before
returning/using it to prevent path traversal or malformed paths. Modify the
function that reads os.Getenv("LARKSUITE_CLI_DATA_DIR") to call
validate.SafeInputPath(dir) and handle validation errors (fallback to default
dir or return an error) so all subsequent uses (the functions reading files in
this package) receive a validated path.
- Around line 28-30: The macOS StorageDir implementation (StorageDir in
keychain_darwin.go) is missing the LARKSUITE_CLI_DATA_DIR environment override
present in the other implementation (keychain_other.go); add the same env check
at the start of StorageDir in keychain_darwin.go to return that dir if set (or,
alternatively, add a comment in StorageDir documenting that the override is
intentionally Linux-only). Update the StorageDir function in keychain_darwin.go
to mirror the logic: read os.Getenv("LARKSUITE_CLI_DATA_DIR") and return it when
non-empty before falling back to the existing macOS directory resolution.
🪄 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: 00e3fb58-540e-40ac-8609-d64e0fdb7d01

📥 Commits

Reviewing files that changed from the base of the PR and between 6bc6bb6 and f567cc9.

📒 Files selected for processing (2)
  • internal/keychain/auth_log.go
  • internal/keychain/keychain_other.go

Comment on lines +24 to +26
if dir := os.Getenv("LARKSUITE_CLI_LOG_DIR"); dir != "" {
return dir
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate the environment variable path before use.

The LARKSUITE_CLI_LOG_DIR environment variable is user-controlled input that is returned directly and later used in file I/O operations (line 48: vfs.MkdirAll, line 54: vfs.OpenFile). Without validation, malicious or malformed paths could cause path traversal vulnerabilities or unexpected filesystem behavior.

As per coding guidelines: Validate paths using validate.SafeInputPath before any file I/O operations.

🛡️ Proposed fix to add path validation
+import (
+	"github.com/larksuite/cli/internal/validate"
+)
+
 func authLogDir() string {
 	if dir := os.Getenv("LARKSUITE_CLI_LOG_DIR"); dir != "" {
+		if err := validate.SafeInputPath(dir); err != nil {
+			fmt.Fprintf(os.Stderr, "warning: invalid LARKSUITE_CLI_LOG_DIR: %v, using default\n", err)
+			// Fall through to default logic
+		} else {
-		return dir
+			return dir
+		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/keychain/auth_log.go` around lines 24 - 26, The returned
LARKSUITE_CLI_LOG_DIR value is used later by vfs.MkdirAll and vfs.OpenFile and
must be validated; update the function in auth_log.go that reads
os.Getenv("LARKSUITE_CLI_LOG_DIR") to call validate.SafeInputPath (or the
project’s equivalent) on the value and only return it if validation succeeds,
otherwise fall back to the existing default path or an empty string and
log/handle the invalid input; ensure the validation happens before any use in
vfs.MkdirAll or vfs.OpenFile so the path cannot be used without passing
validate.SafeInputPath.

Comment on lines +28 to +29
if dir := os.Getenv("LARKSUITE_CLI_DATA_DIR"); dir != "" {
return dir
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Append service name to avoid data conflicts between services.

When LARKSUITE_CLI_DATA_DIR is set, the function returns the raw environment variable value without appending the service parameter. This means different services (e.g., StorageDir("service1") and StorageDir("service2")) will share the same directory, which can lead to:

  1. Master key conflicts: Multiple services would share the same master.key file, breaking encryption isolation
  2. Credential overwrites: Encrypted credential files with identical account names would collide across services
  3. Security boundary violation: Service isolation is a security design principle

The default behavior (line 38) correctly appends the service name: filepath.Join(xdgData, service). The environment variable override must maintain this structure.

🔧 Proposed fix to append service name
 func StorageDir(service string) string {
 	if dir := os.Getenv("LARKSUITE_CLI_DATA_DIR"); dir != "" {
-		return dir
+		return filepath.Join(dir, service)
 	}
📝 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 dir := os.Getenv("LARKSUITE_CLI_DATA_DIR"); dir != "" {
return dir
if dir := os.Getenv("LARKSUITE_CLI_DATA_DIR"); dir != "" {
return filepath.Join(dir, service)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/keychain/keychain_other.go` around lines 28 - 29, The function
currently returns the raw LARKSUITE_CLI_DATA_DIR env value
(os.Getenv("LARKSUITE_CLI_DATA_DIR")) without appending the service name,
causing data/credential collisions; change the branch in StorageDir to return
filepath.Join(dir, service) instead of dir so the environment override preserves
per-service isolation (mirror the default branch which uses
filepath.Join(xdgData, service)).

Comment on lines +28 to +30
if dir := os.Getenv("LARKSUITE_CLI_DATA_DIR"); dir != "" {
return dir
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate the environment variable path before use.

The LARKSUITE_CLI_DATA_DIR environment variable is user-controlled input that is returned directly and later used in file I/O operations (lines 52, 71, 148, 174, 183, 199). Without validation, malicious or malformed paths could cause path traversal vulnerabilities or unexpected filesystem behavior.

As per coding guidelines: Validate paths using validate.SafeInputPath before any file I/O operations.

🛡️ Proposed fix to add path validation
+import (
+	"github.com/larksuite/cli/internal/validate"
+)
+
 func StorageDir(service string) string {
 	if dir := os.Getenv("LARKSUITE_CLI_DATA_DIR"); dir != "" {
+		if err := validate.SafeInputPath(dir); err != nil {
+			fmt.Fprintf(os.Stderr, "warning: invalid LARKSUITE_CLI_DATA_DIR: %v, using default\n", err)
+			// Fall through to default logic
+		} else {
-		return dir
+			return dir
+		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/keychain/keychain_other.go` around lines 28 - 30, The code returns
the LARKSUITE_CLI_DATA_DIR env value directly; validate this user-controlled
path with validate.SafeInputPath before returning/using it to prevent path
traversal or malformed paths. Modify the function that reads
os.Getenv("LARKSUITE_CLI_DATA_DIR") to call validate.SafeInputPath(dir) and
handle validation errors (fallback to default dir or return an error) so all
subsequent uses (the functions reading files in this package) receive a
validated path.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if macOS StorageDir implementation supports LARKSUITE_CLI_DATA_DIR

rg -n "LARKSUITE_CLI_DATA_DIR" internal/keychain/keychain_darwin.go

Repository: larksuite/cli

Length of output: 39


🏁 Script executed:

# Check the macOS StorageDir implementation
cat -n internal/keychain/keychain_darwin.go | sed -n '40,60p'

Repository: larksuite/cli

Length of output: 967


🏁 Script executed:

# List all platform-specific keychain implementations
fd -e go internal/keychain/ | sort

Repository: larksuite/cli

Length of output: 434


🏁 Script executed:

# Check what keychain_other.go represents and its full context
head -n 40 internal/keychain/keychain_other.go

Repository: larksuite/cli

Length of output: 976


🏁 Script executed:

# Find all keychain implementation files
fd . internal/keychain/ --type f -e go | sort

Repository: larksuite/cli

Length of output: 298


🏁 Script executed:

# Search for any documentation or reasoning about platform-specific StorageDir
rg -n "StorageDir|LARKSUITE_CLI_DATA_DIR" internal/keychain/ -B2 -A2

Repository: larksuite/cli

Length of output: 5429


🏁 Script executed:

# Check if there's documentation in config or other places about this env var
rg -n "LARKSUITE_CLI_DATA_DIR" --type go | head -20

Repository: larksuite/cli

Length of output: 155


🏁 Script executed:

# Check Windows implementation for StorageDir
cat -n internal/keychain/keychain_windows.go | sed -n '1,80p'

Repository: larksuite/cli

Length of output: 3114


🏁 Script executed:

# Check if LARKSUITE_CLI_DATA_DIR is documented anywhere
rg -n "LARKSUITE_CLI_DATA_DIR" -B3 -A3 --type-add='markdown:*.md'

Repository: larksuite/cli

Length of output: 549


🏁 Script executed:

# Check tests for keychain_other to see if env var override is tested
cat internal/keychain/keychain_other.go | grep -n "func Test"

Repository: larksuite/cli

Length of output: 39


🏁 Script executed:

# Check if there's a test file for keychain_other
fd . internal/keychain/ --name '*other*test*'

Repository: larksuite/cli

Length of output: 289


🏁 Script executed:

# Look for any test that uses LARKSUITE_CLI_DATA_DIR
rg -n "LARKSUITE_CLI_DATA_DIR" --type go

Repository: larksuite/cli

Length of output: 155


🏁 Script executed:

# Check if there are tests that might use t.Setenv for this
rg -n "Setenv.*LARKSUITE_CLI" --type go

Repository: larksuite/cli

Length of output: 3772


Add environment variable override to macOS StorageDir for consistency, or document as Linux-only.

The Linux implementation in keychain_other.go:28-30 checks LARKSUITE_CLI_DATA_DIR to allow runtime override of the storage directory, but the macOS implementation in keychain_darwin.go:46-53 does not. This creates inconsistent behavior across platforms where users on Linux can override the storage location but users on macOS cannot.

Consider either:

  1. Adding the same LARKSUITE_CLI_DATA_DIR check to the macOS StorageDir function for feature parity
  2. Explicitly documenting this as a Linux-only feature with reasoning (e.g., if intentional by design)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/keychain/keychain_other.go` around lines 28 - 30, The macOS
StorageDir implementation (StorageDir in keychain_darwin.go) is missing the
LARKSUITE_CLI_DATA_DIR environment override present in the other implementation
(keychain_other.go); add the same env check at the start of StorageDir in
keychain_darwin.go to return that dir if set (or, alternatively, add a comment
in StorageDir documenting that the override is intentionally Linux-only). Update
the StorageDir function in keychain_darwin.go to mirror the logic: read
os.Getenv("LARKSUITE_CLI_DATA_DIR") and return it when non-empty before falling
back to the existing macOS directory resolution.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

🚀 PR Preview Install Guide

🧰 CLI update

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

🧩 Skill update

npx skills add larksuite/cli#feat/linux_env_data_dir -y -g

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 7, 2026

Greptile Summary

This PR adds two environment variable overrides — LARKSUITE_CLI_DATA_DIR and LARKSUITE_CLI_LOG_DIR — to let users redirect keychain storage and auth logs to custom directories on Linux.

  • The StorageDir override in keychain_other.go drops the service parameter, placing master.key and credential files directly in the custom root instead of the expected {dir}/{service} subdirectory, inconsistent with the default XDG layout.

Confidence Score: 4/5

One P1 logic bug — service is silently dropped in StorageDir when the env var is set, causing credential files to land in the wrong path.

Score is 4 because the StorageDir P1 issue can silently misdirect where master.key and credential .enc files are stored when the env var is used, which could cause the keychain to be non-functional or interfere with existing data. The auth_log.go change is clean.

internal/keychain/keychain_other.go — the LARKSUITE_CLI_DATA_DIR override needs to append service to the returned path.

Important Files Changed

Filename Overview
internal/keychain/keychain_other.go Adds LARKSUITE_CLI_DATA_DIR override to StorageDir, but service param is dropped, making the path inconsistent with the default ~/.local/share/{service} layout.
internal/keychain/auth_log.go Adds LARKSUITE_CLI_LOG_DIR early-return to authLogDir(); clean and consistent with existing LARKSUITE_CLI_CONFIG_DIR pattern.

Sequence Diagram

sequenceDiagram
    participant User
    participant StorageDir
    participant authLogDir
    participant FS as File System

    User->>StorageDir: StorageDir("lark-cli")
    alt LARKSUITE_CLI_DATA_DIR set
        StorageDir-->>User: $LARKSUITE_CLI_DATA_DIR (service dropped ⚠️)
    else default
        StorageDir-->>User: ~/.local/share/lark-cli
    end

    User->>authLogDir: authLogDir()
    alt LARKSUITE_CLI_LOG_DIR set
        authLogDir-->>User: $LARKSUITE_CLI_LOG_DIR
    else LARKSUITE_CLI_CONFIG_DIR set
        authLogDir-->>User: $LARKSUITE_CLI_CONFIG_DIR/logs
    else default
        authLogDir-->>User: ~/.lark-cli/logs
    end

    StorageDir->>FS: read/write master.key, *.enc
    authLogDir->>FS: write auth-YYYY-MM-DD.log
Loading

Reviews (1): Last reviewed commit: "feat(keychain): support custom log direc..." | Re-trigger Greptile

Comment on lines 27 to +30
func StorageDir(service string) string {
if dir := os.Getenv("LARKSUITE_CLI_DATA_DIR"); dir != "" {
return dir
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 service parameter silently dropped when env var is set

When LARKSUITE_CLI_DATA_DIR is set, StorageDir returns the directory as-is, discarding the service argument. The default code path returns filepath.Join(xdgData, service), so a user who sets LARKSUITE_CLI_DATA_DIR=/home/user/.local/share expecting the same layout would instead find master.key and all .enc credential files directly in /home/user/.local/share rather than /home/user/.local/share/lark-cli/.

Suggested change
func StorageDir(service string) string {
if dir := os.Getenv("LARKSUITE_CLI_DATA_DIR"); dir != "" {
return dir
}
if dir := os.Getenv("LARKSUITE_CLI_DATA_DIR"); dir != "" {
return filepath.Join(dir, service)
}

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