Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a7b8169
fix: restrict the permission of database
feiyehua May 30, 2026
b13007d
fix: format
feiyehua May 30, 2026
13ff3ee
Merge branch 'feiyehua/db-permissions' into feiyehua/database-permiss…
feiyehua May 31, 2026
cfe9bc5
feat: ask for user permission to restrict folder permission
feiyehua May 31, 2026
a28227e
fix: remove untested codes on windows
feiyehua May 31, 2026
5988ff0
docs: add comments to explain create_secure_dir_all function design
feiyehua May 31, 2026
1854cd4
fix: permissions of backup file
feiyehua May 31, 2026
5a33fb6
refactor: move config dir validation to db init function
feiyehua May 31, 2026
f665741
fix: solve repeat permission query issue
feiyehua Jun 1, 2026
9fddd40
test: add tests for prompt_fix_permissions function
feiyehua Jun 1, 2026
8b47ef4
fix: incorrect tmp folder
feiyehua Jun 1, 2026
c656012
fix: correct canonicalize and reject config folders
feiyehua Jun 3, 2026
1eb7ae4
fix: check and log insecure permissions, reject insecure config folde…
feiyehua Jun 3, 2026
0974660
fix: internal command needs database access
feiyehua Jun 3, 2026
489ad4a
fix: add warnings for existing backup files
feiyehua Jun 3, 2026
3c79472
Merge branch 'main' into feiyehua/database-permissions
feiyehua Jun 3, 2026
02c4acc
fix: test fail of check_permissions_detects_insecure_sensitive_files_…
feiyehua Jun 3, 2026
8037b4d
fix: early drop of the temp folders
feiyehua Jun 4, 2026
f0548ef
Merge branch 'main' into feiyehua/database-permissions
feiyehua Jun 11, 2026
3b73fc3
fix: update benchmark to use correct file permissions
feiyehua Jun 11, 2026
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
12 changes: 11 additions & 1 deletion scripts/benchmark_cc_switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ def read_json(path: Path) -> dict:
def write_json(path: Path, data: dict) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
# cc-switch checks that sensitive files (.json, .db) have 0600 on Unix.
if sys.platform != "win32":
path.chmod(0o600)


@dataclass
Expand Down Expand Up @@ -188,7 +191,11 @@ def configure_environment(real_env: bool) -> BenchEnvironment:
}
old_env = {key: os.environ.get(key) for key in env_updates}
for path in env_updates.values():
Path(path).mkdir(parents=True, exist_ok=True)
p = Path(path)
p.mkdir(parents=True, exist_ok=True)
# cc-switch checks that its config dir has 0700 permissions on Unix.
if path == env_updates["CC_SWITCH_CONFIG_DIR"]:
p.chmod(0o700)
for key, value in env_updates.items():
os.environ[key] = value
return BenchEnvironment(mode="sandbox", root=root, old_env=old_env)
Expand Down Expand Up @@ -325,6 +332,9 @@ def connect_db(paths: Paths) -> sqlite3.Connection:
paths.cc_dir.mkdir(parents=True, exist_ok=True)
conn = sqlite3.connect(paths.db_path)
conn.execute("PRAGMA busy_timeout = 5000")
# cc-switch checks that .db files have 0600 permissions on Unix.
if sys.platform != "win32":
paths.db_path.chmod(0o600)
return conn


Expand Down
129 changes: 129 additions & 0 deletions src-tauri/src/cli/i18n.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11136,6 +11136,108 @@ pub mod texts {
"No live providers were imported"
}
}

// -----------------------------------------------------------------
// config.rs - validate_config_dir & prompt_fix_permissions
// -----------------------------------------------------------------

pub fn config_dir_is_system_dir(dir: &str, resolved: &str) -> String {
if is_chinese() {
format!("CC_SWITCH_CONFIG_DIR 不能设置为系统目录: {dir}(解析后: {resolved})")
} else {
format!(
"CC_SWITCH_CONFIG_DIR must not be a system directory: {dir} (resolved: {resolved})"
)
}
}

pub fn config_dir_invalid_last_component(path: &str) -> String {
if is_chinese() {
format!("配置目录路径无效,无法解析最后一层目录: {path}")
} else {
format!("Invalid config directory path; unable to resolve the final directory component: {path}")
}
}

pub fn config_dir_only_final_component_may_be_missing(path: &str) -> String {
if is_chinese() {
format!("配置目录路径无效,仅允许最后一层目录不存在: {path}")
} else {
format!("Invalid config directory path; only the final directory component may be missing: {path}")
}
}

pub fn config_permissions_insecure_header() -> &'static str {
if is_chinese() {
"⚠ 检测到以下文件/目录权限不安全:"
} else {
"⚠ Insecure file/directory permissions detected:"
}
}

pub fn config_permissions_detail(path: &str, current: u32, expected: u32) -> String {
if is_chinese() {
format!(" {path} 当前 {current:04o},期望 {expected:04o}")
} else {
format!(" {path} current {current:04o}, expected {expected:04o}")
}
}

pub fn config_permissions_fix_prompt() -> &'static str {
if is_chinese() {
"是否现在修复权限?(仅所有者可访问)"
} else {
"Fix permissions now? (owner-only access)"
}
}

pub fn config_permissions_fixed() -> &'static str {
if is_chinese() {
"✓ 权限已修复"
} else {
"✓ Permissions fixed"
}
}

pub fn config_permissions_fix_warn_interactive() -> &'static str {
if is_chinese() {
"⚠ 未来版本将拒绝在权限不安全的情况下启动,请尽快修复。"
} else {
"⚠ Future versions will refuse to start with insecure permissions. Please fix soon."
}
}

pub fn config_permissions_fix_warn_noninteractive() -> &'static str {
if is_chinese() {
"⚠ 检测到配置文件权限不安全(非交互模式),跳过修复。未来版本将拒绝启动。"
} else {
"⚠ Insecure config permissions detected (non-interactive). Skipped. Future versions will refuse to start."
}
}

pub fn config_permissions_custom_dir_notice(path: &str) -> String {
if is_chinese() {
format!("检测到自定义配置目录: {path},请核实此目录不是关键系统目录")
} else {
format!("Custom config directory detected: {path}, please verify this is not a critical system directory")
}
}

pub fn config_permissions_confirm_custom_dir() -> &'static str {
if is_chinese() {
"确认要修改此目录的权限吗?"
} else {
"Confirm modifying permissions on this directory?"
}
}

pub fn config_permissions_custom_dir_skipped() -> &'static str {
if is_chinese() {
"已跳过权限修复。"
} else {
"Skipped permission fix."
}
}
}

#[cfg(test)]
Expand Down Expand Up @@ -11183,6 +11285,33 @@ mod tests {
assert!(!help.contains("Settings:"));
}

#[test]
fn config_dir_validation_messages_are_localized() {
{
let _lang = use_test_language(Language::English);
assert_eq!(
texts::config_dir_invalid_last_component("/tmp/child/.."),
"Invalid config directory path; unable to resolve the final directory component: /tmp/child/.."
);
assert_eq!(
texts::config_dir_only_final_component_may_be_missing("/tmp/child/.."),
"Invalid config directory path; only the final directory component may be missing: /tmp/child/.."
);
}

{
let _lang = use_test_language(Language::Chinese);
assert_eq!(
texts::config_dir_invalid_last_component("/tmp/child/.."),
"配置目录路径无效,无法解析最后一层目录: /tmp/child/.."
);
assert_eq!(
texts::config_dir_only_final_component_may_be_missing("/tmp/child/.."),
"配置目录路径无效,仅允许最后一层目录不存在: /tmp/child/.."
);
}
}

#[test]
fn proxy_dashboard_copy_is_fully_localized_in_chinese() {
let _lang = use_test_language(Language::Chinese);
Expand Down
6 changes: 4 additions & 2 deletions src-tauri/src/cli/tui/app/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10557,7 +10557,8 @@ mod tests {
#[test]
#[serial]
fn prompt_save_runtime_creates_prompt_from_one_page_form() {
let _guard = TestEnvGuard::isolated(tempfile::tempdir().expect("tempdir").path());
let temp = tempfile::tempdir().expect("tempdir");
let _guard = TestEnvGuard::isolated(temp.path());
let state = crate::AppState::try_new().expect("load state");
state.save().expect("persist empty state");

Expand Down Expand Up @@ -10646,7 +10647,8 @@ mod tests {
#[test]
#[serial]
fn prompt_create_runtime_clears_filter_when_new_prompt_is_not_visible() {
let _guard = TestEnvGuard::isolated(tempfile::tempdir().expect("tempdir").path());
let temp = tempfile::tempdir().expect("tempdir");
let _guard = TestEnvGuard::isolated(temp.path());
let state = crate::AppState::try_new().expect("load state");
state.save().expect("persist empty state");

Expand Down
Loading
Loading