-
-
Notifications
You must be signed in to change notification settings - Fork 40
Contributing
感谢你对 Zephyr 项目的关注!Zephyr 是基于 Tauri v2 的 Mihomo GUI 代理客户端。本文档将帮助你了解项目的 CI/CD 流水线、发布流程、代码规范以及如何为项目做出贡献。
- 发布流程
- CI/CD 安全扫描流水线
- 代码规范
- Semgrep 自定义规则
- Secret Detection 双层检测策略
- 许可证合规 (deny.toml)
- Dependabot 配置
- Issue 提交指南
Zephyr 采用自动化发布流程,当推送版本 tag 时触发完整的构建与发布流水线。整个流程涵盖版本同步、内核获取与校验、多平台编译以及产物上传。
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[推送版本 Tag<br/>例如 v1.0.0] --> B[触发 Release Workflow]
B --> V[版本同步机制<br/>自动更新 3 个文件版本号]
V --> C[并行构建 4 个平台]
C --> C1["Windows x64 构建<br/>x86_64-pc-windows-msvc"]
C --> C2["macOS ARM64 构建<br/>aarch64-apple-darwin"]
C --> C3["macOS x64 构建<br/>x86_64-apple-darwin"]
C --> C4["Ubuntu x64 构建<br/>x86_64-unknown-linux-gnu"]
C1 --> D[Mihomo 内核获取]
C2 --> D
C3 --> D
C4 --> D
D --> D1[查询 GitHub API<br/>获取最新 Release Tag]
D1 --> D2[下载平台对应归档]
D2 --> D3[SHA256 校验和验证]
D3 --> D4{校验通过?}
D4 -->|否| ABORT[中止构建]
D4 -->|是| D5[下载 GeoIP + GeoSite 数据]
D5 --> F[Full 版本构建<br/>含 Mihomo 内核 + Geo 数据]
D5 --> G[Lite 版本构建<br/>不含 Mihomo 内核]
F --> H[生成 Checksums 文件]
G --> H
H --> I[创建 Draft Release]
I --> J[上传所有构建产物]
J --> K[人工审核]
K --> L[发布 Release]
发布流水线在 4 个平台上并行构建,覆盖主流操作系统和 CPU 架构:
| Platform | Runner | Target Triple | Architecture |
|---|---|---|---|
| macOS | macos-latest | aarch64-apple-darwin | arm64 (Apple Silicon) |
| macOS | macos-latest | x86_64-apple-darwin | x64 (Intel Mac) |
| Ubuntu | ubuntu-22.04 | x86_64-unknown-linux-gnu | x64 |
| Windows | windows-latest | x86_64-pc-windows-msvc | x64 |
Source: .github/workflows/release.yml 构建矩阵配置
在构建开始之前,流水线会自动将版本号同步到项目中的 3 个关键文件,确保所有组件版本一致。这一步骤通过解析 Git Tag 中的版本号(去除 v 前缀)实现。
%%{init: {'themeVariables': {'fontSize': '10px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '10px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 15, 'rankSpacing': 25}}}%%
flowchart LR
A[Git Tag<br/>v1.2.3] --> B[提取版本号<br/>1.2.3]
B --> C["jq 更新<br/>apps/desktop/src-tauri/tauri.conf.json<br/>.version 字段"]
B --> D["sed 更新<br/>apps/desktop/src-tauri/Cargo.toml<br/>version = \"...\""]
B --> E["jq 更新<br/>package.json<br/>.version 字段"]
C --> F[版本同步完成]
D --> F
E --> F
同步的 3 个文件及其更新方式:
| # | 文件路径 | 更新工具 | 更新位置 |
|---|---|---|---|
| 1 | apps/desktop/src-tauri/tauri.conf.json |
jq |
.version 字段 |
| 2 | apps/desktop/src-tauri/Cargo.toml |
sed |
[package] 下的 version 字段 |
| 3 | package.json |
jq |
.version 字段 |
Source: .github/workflows/release.yml:39-71
Mihomo 内核的获取和校验是发布流程中最关键的安全环节,分为三个阶段:
流水线通过 GitHub API 查询 Mihomo 项目的最新 Release Tag,使用 GITHUB_TOKEN 进行认证以避免 API 速率限制。
# 伪代码示意
LATEST_TAG=$(curl -H "Authorization: token $GITHUB_TOKEN" \
https://api.github.com/repos/MetaCubeX/mihomo/releases/latest | jq -r .tag_name)下载平台对应的 Mihomo 归档后,流水线会执行严格的完整性校验:
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[下载平台归档文件] --> B[从 Release Assets 获取<br/>预期 SHA256 哈希值]
B --> C["执行 sha256sum 计算<br/>本地文件哈希"]
C --> D{本地哈希 == 预期哈希?}
D -->|是| E[校验通过,继续构建]
D -->|否| F["中止构建<br/>报告完整性错误"]
校验流程:
- 下载目标平台对应的 Mihomo 压缩包
- 通过
jq从 GitHub Release Assets 中提取预期 SHA256 哈希值 - 使用
sha256sum计算本地文件的哈希值 - 比较两个哈希值,不匹配则立即中止构建
校验通过后,流水线会下载地理数据文件到 apps/desktop/src-tauri/bundled/ 目录:
| 文件 | 用途 |
|---|---|
geoip.dat |
IP 地理位置数据库,用于路由规则匹配 |
geosite.dat |
域名分类数据库,用于域名规则匹配 |
Country.mmdb |
MaxMind GeoIP2 数据库,用于 IP 地理位置查询 |
Source: .github/workflows/release.yml:106-255
每个平台都会同时构建 Full 和 Lite 两个版本,满足不同用户的需求:
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[构建完成] --> B{选择构建策略}
B --> C["Full 版本"]
B --> D["Lite 版本"]
C --> C1[打包 Mihomo 内核]
C --> C2[打包 GeoIP + GeoSite 数据]
C1 --> C3["产物: Zephyr_Full_{version}_{target}"]
C2 --> C3
D --> D1[不包含内核]
D --> D2[不包含 Geo 数据]
D1 --> D3["产物: Zephyr_Lite_{version}_{target}"]
D2 --> D3
| Feature | Full Version | Lite Version |
|---|---|---|
| Mihomo Core | Included in apps/desktop/src-tauri/bundled/
|
Not included |
| Geo-Data | Included (geoip.dat, geosite.dat, Country.mmdb) |
Not included |
| Binary Path | Internal (App Bundle) | User-defined or Auto-downloaded |
| Artifact Name | Zephyr_Full_{version}_{target} |
Zephyr_Lite_{version}_{target} |
Source: .github/workflows/release.yml 双构建配置
各平台的编译环境配置如下:
| 工具 | 版本/来源 | 说明 |
|---|---|---|
| Rust | dtolnay/rust-toolchain@stable |
使用 stable 工具链 |
| Node.js | actions/setup-node@v4 |
前端构建环境 |
| 平台 | 依赖包 | 说明 |
|---|---|---|
| Linux | libwebkit2gtk-4.1-dev |
Tauri WebView2 运行时 |
| Linux | libappindicator3-dev |
系统托盘支持 |
| Linux | librsvg2-dev |
SVG 图标渲染 |
macOS 平台需要同时构建 ARM64 和 x64 两个架构,通过以下环境变量实现交叉编译:
| 环境变量 | 用途 |
|---|---|
PKG_CONFIG_ALLOW_CROSS=1 |
允许交叉编译时的 pkg-config 查找 |
SDK_PATH (via xcrun) |
指定 macOS SDK 路径,用于 aarch64 目标编译 |
Source: .github/workflows/release.yml:73-104
构建完成后,所有产物通过 softprops/action-gh-release 上传至 GitHub Release:
| 平台 | 产物格式 | 说明 |
|---|---|---|
| Windows |
.msi / .exe
|
MSI 安装包 + 便携版 |
| macOS |
.dmg / .app.tar.gz
|
DMG 镜像 + App 压缩包 |
| Linux |
.deb / .rpm / .AppImage
|
Debian/Ubuntu 安装包 + RPM 安装包 + AppImage 便携版 |
产物命名规则:
- Full 版本:
Zephyr_Full_{version}_{target_triple}.{ext} - Lite 版本:
Zephyr_Lite_{version}_{target_triple}.{ext}
Source: .github/workflows/release.yml 产物上传配置
Zephyr 遵循 语义化版本 规范:
- 主版本号 (MAJOR):不兼容的 API 变更
- 次版本号 (MINOR):向下兼容的功能新增
- 修订号 (PATCH):向下兼容的问题修复
Tag 格式:v{MAJOR}.{MINOR}.{PATCH},例如 v1.2.3。
Zephyr 在每次提交和 PR 时都会运行完整的安全扫描流水线,确保代码质量和安全性。流水线包含 12 个安全扫描 Job,分为三大检查组。
安全扫描流水线在以下场景自动触发:
| 触发类型 | 条件 |
|---|---|
| Push | 推送到 main 或 dev 分支 |
| Pull Request | 所有 PR |
| 定时任务 | 每日 UTC 03:00 (0 3 * * *) |
Source: .github/workflows/security.yml:8-14
%%{init: {'themeVariables': {'fontSize': '10px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '10px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 15, 'rankSpacing': 25}}}%%
graph LR
subgraph 触发
A[Push / PR / Cron]
end
subgraph Rust 后端检查
B[job: rust-dependency-audit<br/>Rust 漏洞扫描]
C[job: cargo-deny<br/>许可证与依赖审计]
D[job: rust-clippy<br/>Clippy 检查]
E[job: rust-fmt<br/>格式化验证]
end
subgraph 前端与安全检查
F[job: frontend-audit<br/>前端依赖审计]
G[job: semgrep<br/>静态安全分析]
H[job: dependency-review<br/>GitHub 依赖审查]
I[job: secret-scan<br/>密钥检测]
J[job: tauri-security<br/>Tauri 安全检查]
end
subgraph 构建验证
K[job: build-verification<br/>编译验证]
L[job: macos-build-check<br/>macOS 交叉编译检查]
end
A --> B
A --> C
A --> D
A --> E
A --> F
A --> G
A --> H
A --> I
A --> J
A --> K
A --> L
B --> M{全部通过?}
C --> M
D --> M
E --> M
F --> M
G --> M
H --> M
I --> M
J --> M
K --> M
L --> M
M -->|是| N[合并允许]
M -->|否| O[阻止合并<br/>报告错误]
| Job 名称 | 检查组 | 说明 | 运行时间 |
|---|---|---|---|
rust-dependency-audit |
Rust 后端 | Rust 依赖安全漏洞扫描 | ~1min |
cargo-deny |
Rust 后端 | 依赖许可证与审计检查 | ~2min |
rust-clippy |
Rust 后端 | Rust 代码 Clippy 检查 | ~2min |
rust-fmt |
Rust 后端 | Rust 代码格式化验证 | ~30s |
frontend-audit |
前端与安全 | 前端依赖安全审计 | ~1min |
dependency-review |
前端与安全 | GitHub 依赖审查 | ~1min |
semgrep |
前端与安全 | Semgrep 静态安全分析(官方规则 + 8 条自定义规则) | ~3min |
secret-scan |
前端与安全 | 密钥检测(Trufflehog + 正则扫描) | ~2min |
tauri-security |
前端与安全 | Tauri 安全检查 | ~1min |
build-verification |
构建验证 | 全平台编译验证 + ESLint | ~5min |
macos-build-check |
构建验证 | macOS 原生编译检查(x86_64 + aarch64) | ~3min |
注意:
codeql-analysis是独立的工作流(不在security.yml中),不属于security.yml安全扫描流水线。
Release 流水线(.github/workflows/release.yml)在推送版本标签(v*)时触发,负责构建和发布多平台安装包。包含以下关键步骤:
| 步骤 | 说明 | 产物 |
|---|---|---|
| 版本同步 | 从 git tag 提取版本,同步到 tauri.conf.json、Cargo.toml、package.json
|
— |
| Mihomo 下载 | 从 GitHub Release 下载 Mihomo 核心,SHA256 校验 | src-tauri/bundled/mihomo* |
| Geo-Data 下载 | 下载 geoip.dat、geosite.dat、Country.mmdb,SHA256 校验 |
src-tauri/bundled/*.dat |
| 构建矩阵 | macOS (x64/arm64)、Linux (x64)、Windows (x64) |
.dmg, .deb, .rpm, .msi, .exe, .AppImage
|
| 便携版打包 | Windows .zip、Linux .tar.gz(含 .portable 标记文件) |
Zephyr-windows-portable.zip, Zephyr-linux-portable.tar.gz
|
| 产物上传 | 使用 softprops/action-gh-release 上传到 GitHub Release |
— |
Full vs Lite vs 便携版:
| 特性 | Full | Lite | 便携版 |
|---|---|---|---|
| Mihomo 核心 | 内置 | 用户自行下载 | 内置 |
| Geo-Data | 内置 | 用户自行下载 | 内置 |
| 安装步骤 | 安装程序 | 安装程序 | 解压即用 |
| 数据位置 | 系统目录 | 系统目录 | 程序目录 |
| 开机自启 | ✅ | ✅ | ❌ |
| 客户端更新 | ✅ | ✅ | ❌ |
Source: .github/workflows/release.yml
项目采用分层 Clippy 严格配置,通过 Cargo.toml 的 [lints.clippy] 和 .clippy.toml 强制执行 165 条 deny 级别规则。所有规则分为 7 层,从正确性/安全性到性能优化逐层递进。CI 中通过 cargo clippy --all-targets -- -D warnings 执行,任何违规都会导致构建失败。
| 文件 | 作用 |
|---|---|
apps/desktop/src-tauri/Cargo.toml [lints.clippy]
|
165 条 deny 级别 Clippy 规则(主要配置) |
.clippy.toml |
全局 Clippy 配置:avoid-breaking-exported-api = true、cognitive-complexity-threshold = 25
|
| Clippy 规则 | 说明 |
|---|---|
correctness (group) |
整个 correctness lint 组,deny 级别 |
suspicious (group) |
整个 suspicious lint 组,deny 级别 |
panic |
禁止 panic! 宏 |
unimplemented |
禁止 unimplemented! 宏 |
todo |
禁止遗留 todo! 宏 |
unwrap_used |
禁止 .unwrap(),强制错误处理 |
expect_used |
禁止 .expect(),强制错误处理 |
dbg_macro |
禁止 dbg! 调试宏 |
indexing_slicing |
禁止直接索引,强制 .get() 安全访问 |
cast_possible_truncation |
检测可能截断的整数类型转换 |
cast_possible_wrap |
检测可能溢出回绕的整数转换 |
cast_sign_loss |
检测有符号到无符号的符号丢失 |
undocumented_unsafe_blocks |
所有 unsafe 块必须有 // SAFETY: 注释 |
multiple_unsafe_ops_per_block |
每个 unsafe 块只允许一个 unsafe 操作 |
missing_safety_doc |
unsafe 函数必须有 # Safety 文档 |
map_err_ignore |
禁止 `.map_err( |
| Clippy 规则 | 说明 |
|---|---|
rc_mutex |
禁止 Rc<Mutex<T>>,建议使用 Arc
|
clone_on_ref_ptr |
禁止在 Rc/Arc 上调用 .clone()
|
rc_clone_in_vec_init |
禁止 vec![Rc::new(x); n]
|
mutex_atomic |
建议简单类型用 AtomicBool 替代 Mutex<bool>
|
mutex_integer |
建议整数类型用 AtomicI32 替代 Mutex<i32>
|
await_holding_lock |
禁止 await 时持有锁(防死锁) |
async_yields_async |
禁止 async 函数中不必要的 .await
|
unused_async |
禁止非 async 函数标记为 async |
future_not_send |
禁止非 Send 的 Future |
large_futures |
检测过大的 Future |
large_stack_arrays |
检测过大的栈上数组 |
large_const_arrays |
检测过大的常量数组 |
涵盖内存分配优化(redundant_clone、unnecessary_box_returns、vec_box 等)、CPU & 算法优化(float_cmp、manual_memcpy、naive_bytecount 等)、迭代器 & 闭包优化(redundant_closure、manual_filter_map、needless_collect 等)、内存操作优化(significant_drop_tightening、let_underscore_lock 等)、类型系统优化(derive_partial_eq_without_eq、missing_const_for_fn 等)。
Source: apps/desktop/src-tauri/Cargo.toml:83-239、.clippy.toml
上述 100+ 条 Clippy 规则中,以下直接关联安全性:
| Clippy Lint | 安全类别 | 说明 |
|---|---|---|
correctness (group) |
正确性 | 整个 correctness lint 组全部 deny |
suspicious (group) |
可疑代码 | 整个 suspicious lint 组全部 deny |
unwrap_used / expect_used
|
错误处理 | 禁止 .unwrap() / .expect(),强制显式错误处理,防止 panic |
indexing_slicing |
内存安全 | 强制 .get() 安全访问,防止越界 panic |
undocumented_unsafe_blocks |
审计可追溯性 | 所有 unsafe 块必须有 // SAFETY: 注释 |
multiple_unsafe_ops_per_block |
最小化 unsafe | 每个 unsafe 块只允许一个 unsafe 操作 |
missing_safety_doc |
文档完整性 | unsafe 函数必须有 # Safety 文档 |
await_holding_lock |
并发安全 | 禁止 await 时持有锁,防止死锁 |
future_not_send |
并发安全 | 禁止非 Send 的 Future |
map_err_ignore |
错误处理 | 禁止丢弃错误信息 |
cast_possible_truncation |
类型安全 | 捕获不安全的整数类型转换 |
cast_possible_wrap |
类型安全 | 捕获可能溢出回绕的整数转换 |
cast_sign_loss |
类型安全 | 捕获有符号到无符号转换时的符号丢失 |
这些 Lints 在 Cargo.toml 的 [lints.clippy] 中配置为 deny 级别,CI 中通过 cargo clippy --all-targets -- -D warnings 执行。
Source: apps/desktop/src-tauri/Cargo.toml:88-108
项目使用 ESLint 进行前端代码质量检查,配置文件为 eslint.config.js。配置非常简洁,仅包含 2 条规则,并定义了 60+ 个浏览器/运行时全局变量:
// eslint.config.js — 实际配置(节选)
export default [
{
ignores: ["node_modules/**", "apps/desktop/src-tauri/**", "dist/**", "apps/desktop/src/js-yaml.min.js"]
},
{
files: ["**/*.js"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
globals: {
window: "readonly", document: "readonly", console: "readonly",
fetch: "readonly", setTimeout: "readonly", clearTimeout: "readonly",
// ... 60+ 个全局变量声明
queueMicrotask: "readonly", Intl: "readonly", Proxy: "readonly",
Reflect: "readonly", Symbol: "readonly", WeakMap: "readonly",
// ...
}
},
rules: {
"no-unused-vars": "off",
"no-undef": "error"
}
}
];规则说明:
| 规则 | 级别 | 说明 |
|---|---|---|
no-unused-vars |
"off" |
关闭未使用变量检查 |
no-undef |
"error" |
禁止使用未定义的变量(配合 globals 声明) |
此外,配置还通过 ignores 忽略了 node_modules、apps/desktop/src-tauri、dist 和 apps/desktop/src/js-yaml.min.js,通过 languageOptions.globals 声明了 60+ 个浏览器/运行时全局变量为 readonly,确保 no-undef 规则不会误报。项目还配置了 jsconfig.json 启用 TypeScript 严格检查(checkJs: true, strict: true),提供类型安全辅助。
前端依赖安全通过 pnpm audit 进行扫描,在 CI 的安全流水线中自动执行:
pnpm audit --audit-level=moderatemoderate 级别即阻断构建。参数说明:
| 参数 | 说明 |
|---|---|
--omit=dev |
排除开发依赖,仅扫描生产依赖中的漏洞 |
--audit-level=moderate |
当发现 moderate 及以上级别的漏洞时报告失败 |
Source: .github/workflows/security.yml:133
所有前端代码必须编写单元测试,使用 Vitest 作为测试框架:
// 示例测试
import { describe, it, expect } from "vitest";
describe("工具函数", () => {
it("应正确解析订阅链接", () => {
const result = parseSubscription("clash://...");
expect(result).toBeDefined();
expect(result.nodes.length).toBeGreaterThan(0);
});
});测试覆盖率要求:
- 语句覆盖率 >= 80%
- 分支覆盖率 >= 70%
- 函数覆盖率 >= 80%
项目使用 Semgrep 进行静态安全分析。CI 流水线通过 semgrep --config auto --config .semgrep.yml 同时加载官方标准规则集和 8 条自定义规则,实现全面覆盖:
以下为 .semgrep.yml 中配置的 8 条自定义规则:
| # | 规则 ID | 语言 | 严重程度 | 说明 |
|---|---|---|---|---|
| 1 | rust-osascript-privilege-escalation |
Rust | WARNING | 检测 with administrator privileges 特权提升风险 |
| 2 | rust-osascript-command-pattern |
Rust | WARNING | 检测 Command::new("osascript") 命令注入风险 |
| 3 | rust-command-format-arg |
Rust | WARNING | 检测 .arg(format!()) 命令拼接注入 |
| 4 | rust-unsafe-block |
Rust | INFO | 审计所有 unsafe 块 |
| 5 | rust-hardcoded-crypto-constant |
Rust | WARNING | 检测硬编码的加密密钥/凭证常量 |
| 6 | js-innerhtml-assignment |
JS/TS | WARNING | 检测 innerHTML 赋值(XSS 风险) |
| 7 | js-insertadjacenthtml |
JS/TS | INFO | 检测 insertAdjacentHTML 使用 |
| 8 | js-document-write |
JS/TS | WARNING | 检测 document.write() 调用 |
Source: .semgrep.yml:1-164
规则按语言分为 Rust(5 条)和 JS/TS(3 条)两大类,覆盖特权提升、命令注入、内存安全、硬编码凭证、XSS 等安全风险。
Zephyr 采用双层密钥检测策略,在 CI 安全流水线中自动扫描代码仓库,防止密钥和敏感信息泄露。
%%{init: {'themeVariables': {'fontSize': '9px', 'nodeBorder': '1px', 'clusterBorder': '1px', 'edgeLabelHeight': '8px'}, 'flowchart': {'curve': 'basis', 'nodeSpacing': 12, 'rankSpacing': 15}}}%%
flowchart TD
A[Secret Detection Job 启动] --> B[第一层: Trufflehog 扫描]
A --> C[第二层: 正则表达式源码扫描]
B --> B1["扫描完整 Git 历史<br/>使用 --only-verified 标志<br/>仅报告已验证的泄露"]
B1 --> B2{发现泄露?}
B2 -->|是| FAIL[报告失败,阻止合并]
B2 -->|否| PASS1[第一层通过]
C --> C1["正则匹配源码文件<br/>模式: (password|secret)\\s*[:=]\\s*["']"]
C --> C2["高熵字符串检测<br/>识别疑似随机生成的密钥"]
C1 --> C3{发现泄露?}
C2 --> C3
C3 -->|是| FAIL
C3 -->|否| PASS2[第二层通过]
PASS1 --> D[全部通过]
PASS2 --> D
Trufflehog 是专业的密钥扫描工具,能够扫描完整的 Git 提交历史:
| 配置项 | 说明 |
|---|---|
| 扫描范围 | 完整 Git 历史(包括已删除的内容) |
--only-verified 标志 |
仅报告经过验证的真实泄露,减少误报 |
| 认证 | 使用 GITHUB_TOKEN 访问仓库 |
作为 Trufflehog 的补充,流水线还使用正则表达式直接扫描源码文件:
| 检测模式 | 说明 |
|---|---|
(password|secret)\s*[:=]\s*["'] |
匹配密码和密钥的直接赋值 |
| 高熵字符串检测 | 识别疑似随机生成的 Token、API Key 等字符串 |
两层检测互为补充:Trufflehog 擅长发现 Git 历史中的已知密钥格式,正则扫描则能捕获源码中潜在的密钥赋值模式。
Source: .github/workflows/security.yml:179-206
Zephyr 使用 cargo-deny 管理依赖许可证合规性。项目根目录下的 deny.toml 配置了完整的依赖审计策略。
[advisories]
ignore = [
"RUSTSEC-2026-0097", # rand 0.8 间接依赖(tauri 生态),已升级到 rand 0.10.1
"RUSTSEC-2026-0098", # rustls-webpki 间接依赖,等待上游发布修复
"RUSTSEC-2026-0099", # rustls-webpki 间接依赖,等待上游发布修复
]
unmaintained = "workspace"
[licenses]
allow = [
"MIT",
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
"Unicode-DFS-2016",
"Zlib",
"OpenSSL",
"MPL-2.0",
"LGPL-3.0",
"0BSD",
"CC0-1.0", # notify (via clash-prism-core)
"Unicode-3.0",
]
[bans]
wildcards = "deny"
multiple-versions = "warn"
[sources]
unknown-registry = "deny"
unknown-git = "deny"
[graph]
targets = ["x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", "aarch64-apple-darwin"]Source: deny.toml:1-37
deny.toml 的 [licenses] 部分仅配置了 allow 白名单,未设置 unlicensed、copyleft、default、allow-osi-fsf-free 等字段(使用 cargo-deny 默认值)。
| 许可证 | 类型 | 说明 |
|---|---|---|
| MIT | 宽松 | 最常用的开源许可证 |
| Apache-2.0 | 宽松 | 含专利授权条款 |
| Apache-2.0 WITH LLVM-exception | 宽松 | LLVM 项目使用的变体 |
| BSD-2-Clause | 宽松 | 简化版 BSD 许可证 |
| BSD-3-Clause | 宽松 | 标准 BSD 许可证 |
| ISC | 宽松 | 功能等同 MIT |
| Unicode-DFS-2016 | 宽松 | Unicode 数据文件许可证 |
| Zlib | 宽松 | 压缩库许可证 |
| OpenSSL | 宽松 | OpenSSL 加密库许可证 |
| MPL-2.0 | 弱 Copyleft | Mozilla 公共许可证,文件级 Copyleft |
| LGPL-3.0 | 弱 Copyleft | 允许动态链接的 Copyleft(用于 GTK 系统库) |
| CC0-1.0 | 公共领域 | 公共领域奉献(notify crate,via clash-prism-core) |
注意:
MPL-2.0和LGPL-3.0属于弱 Copyleft 许可证,仅在特定场景下被允许。MPL-2.0 仅在文件级别有 Copyleft 要求,LGPL-3.0 则是因为 GTK 系统库的依赖需要。
| 策略 | 配置值 | 说明 |
|---|---|---|
wildcards |
deny |
禁止使用通配符版本依赖(如 *),确保版本明确 |
multiple-versions |
warn |
同一依赖存在多个版本时发出警告(不阻止构建) |
| 策略 | 配置值 | 说明 |
|---|---|---|
unknown-registry |
deny |
仅允许 crates.io,拒绝未知注册源 |
unknown-git |
deny |
拒绝所有 Git 依赖源 |
| 策略 | 配置值 | 说明 |
|---|---|---|
vulnerability |
deny |
发现安全漏洞时阻止构建(默认值) |
unmaintained |
workspace |
依赖不再维护时遵循工作区配置处理 |
ignore |
3 个 RUSTSEC | 忽略已评估的间接依赖 advisory(RUSTSEC-2026-0097/0098/0099,详见 deny.toml 注释) |
Zephyr 为 4 个生态系统配置了 Dependabot 自动依赖更新,配置文件为 .github/dependabot.yml:
version: 2
updates:
# 1. Rust 生态系统 (Cargo)
- package-ecosystem: "cargo"
directory: "/src-tauri"
schedule:
interval: "weekly"
day: "monday"
timezone: "UTC"
open-pull-requests-limit: 10
groups:
patch-and-minor:
update-types:
- "patch"
- "minor"
labels:
- "dependencies"
- "rust"
# 2. npm 生态系统 (前端)
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
timezone: "UTC"
open-pull-requests-limit: 10
versioning-strategy: "auto"
groups:
patch-and-minor:
update-types:
- "patch"
- "minor"
labels:
- "dependencies"
- "javascript"
# 3. GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
timezone: "UTC"
open-pull-requests-limit: 5
groups:
minor-and-patch:
update-types:
- "minor"
- "patch"
labels:
- "dependencies"
- "github-actions"
# 4. Pip (Semgrep 工具链)
- package-ecosystem: "pip"
directory: "/.github"
schedule:
interval: "weekly"
day: "monday"
timezone: "UTC"
open-pull-requests-limit: 3
labels:
- "dependencies"
- "security"Source: .github/dependabot.yml:1-68
| 生态系统 | 更新频率 | 目录 | 分组策略 | 说明 |
|---|---|---|---|---|
| Cargo (Rust) | 每周 | /src-tauri |
patch-and-minor 单组 |
将补丁更新和次要更新合并为单个 PR,减少 PR 数量 |
| npm (前端) | 每周 | / |
patch-and-minor 单组 |
将补丁更新和次要更新合并为单个 PR |
| GitHub Actions | 每周 | / |
minor-and-patch 单组 |
将次要更新和补丁更新合并为单个 PR |
| Pip (Semgrep) | 每周 | /.github |
无分组 | 保持 Semgrep 安全扫描工具链最新 |
分组策略说明:Cargo、npm 和 GitHub Actions 三个生态系统都配置了分组,将补丁和次要更新合并到单个 PR 中。例如,当 5 个依赖有补丁更新时,Dependabot 只会创建 1 个 PR 而非 5 个,大幅减少代码审查负担。Pip 生态系统未配置分组,每个包独立更新。
在提交 Issue 之前,请确认:
- 已搜索现有的 Issue,确认问题未被报告
- 已阅读 FAQ 文档,确认不是已知问题
- 使用的是最新版本的 Zephyr
- 问题可以在最新版本中复现
提交 Bug 报告时,请使用以下模板:
## Bug 描述
[清晰简洁地描述 Bug]
## 复现步骤
1. [步骤 1]
2. [步骤 2]
3. [步骤 3]
## 预期行为
[描述你期望发生的情况]
## 实际行为
[描述实际发生的情况]
## 环境信息
- 操作系统: [例如 Windows 11 / macOS 14 / Ubuntu 22.04]
- Zephyr 版本: [例如 v1.2.3]
- 安装版本: [Full / Lite]
- Mihomo 内核版本: [例如 v1.18.10]
## 日志
[粘贴相关日志,请使用代码块]
## 截图
[如有,附上截图]
## 附加信息
[其他有助于解决问题的信息]提交功能请求时,请使用以下模板:
## 功能描述
[清晰描述你希望添加的功能]
## 动机
[为什么需要这个功能?它解决了什么问题?]
## 建议的实现方式
[如有想法,描述你建议的实现方式]
## 替代方案
[你考虑过的其他替代方案]
## 附加信息
[其他相关信息]| 标签 | 说明 |
|---|---|
bug |
Bug 报告 |
feature |
功能请求 |
documentation |
文档相关 |
good first issue |
适合新贡献者 |
help wanted |
需要帮助 |
security |
安全相关问题 |
platform-windows |
Windows 平台相关 |
platform-macos |
macOS 平台相关 |
platform-linux |
Linux 平台相关 |
感谢你的贡献!如有任何问题,欢迎在 Issue 中讨论。