-
-
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/>src-tauri/tauri.conf.json<br/>.version 字段"]
B --> D["sed 更新<br/>src-tauri/Cargo.toml<br/>version = \"...\""]
B --> E["jq 更新<br/>package.json<br/>.version 字段"]
C --> F[版本同步完成]
D --> F
E --> F
同步的 3 个文件及其更新方式:
| # | 文件路径 | 更新工具 | 更新位置 |
|---|---|---|---|
| 1 | src-tauri/tauri.conf.json |
jq |
.version 字段 |
| 2 | 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计算本地文件的哈希值 - 比较两个哈希值,不匹配则立即中止构建
校验通过后,流水线会下载地理数据文件到 src-tauri/bundled/ 目录:
| 文件 | 用途 |
|---|---|
geoip.dat |
IP 地理位置数据库,用于路由规则匹配 |
geosite.dat |
域名分类数据库,用于域名规则匹配 |
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 src-tauri/bundled/
|
Not included |
| Geo-Data | Included (geoip.dat, geosite.dat) |
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 |
Debian/Ubuntu 安装包 |
产物命名规则:
- 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 时都会运行完整的安全扫描流水线,确保代码质量和安全性。流水线包含 10 个安全扫描 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: lint-rust<br/>Clippy 检查]
C[job: cargo-deny<br/>许可证与依赖审计]
D[job: cargo-audit<br/>Rust 漏洞扫描]
end
subgraph 前端 JS 检查
E[job: lint-frontend<br/>ESLint]
F[job: vitest-coverage<br/>单元测试与覆盖率]
G[job: npm-audit<br/>前端依赖漏洞扫描]
end
subgraph 密钥与审计检查
H[job: semgrep-scan<br/>静态安全分析]
I[job: codeql-analysis<br/>语义代码分析]
J[job: dependency-review<br/>GitHub 依赖审查]
K[job: check-license<br/>文件头许可证检查]
L[job: secret-detection<br/>Trufflehog + 正则扫描]
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 名称 | 检查组 | 说明 | 运行时间 |
|---|---|---|---|
lint-rust |
Rust 后端 | Rust 代码 Clippy 检查与格式化验证 | ~2min |
lint-frontend |
前端 JS | 前端 ESLint 检查 | ~1min |
semgrep-scan |
密钥与审计 | Semgrep 静态分析(自定义规则) | ~3min |
cargo-deny |
Rust 后端 | 依赖许可证与审计检查 | ~2min |
cargo-audit |
Rust 后端 | Rust 安全漏洞扫描 | ~1min |
dependency-review |
密钥与审计 | GitHub 依赖审查 | ~1min |
codeql-analysis |
密钥与审计 | CodeQL 语义代码分析 | ~10min |
check-license |
密钥与审计 | 文件头许可证检查 | ~30s |
vitest-coverage |
前端 JS | 前端单元测试与覆盖率 | ~2min |
build-test |
Rust 后端 | 全平台编译测试 | ~5min |
项目强制执行以下 12 条 Clippy 规则,在 CI 中任何违规都会导致构建失败:
| # | Clippy 规则 | 说明 |
|---|---|---|
| 1 | clippy::unwrap_used |
禁止使用 .unwrap(),强制使用错误处理 |
| 2 | clippy::expect_used |
禁止使用 .expect(),改用 ? 操作符或 match
|
| 3 | clippy::panic |
禁止使用 panic! 宏 |
| 4 | clippy::todo |
禁止遗留 todo! 宏,必须完成实现 |
| 5 | clippy::unimplemented |
禁止使用 unimplemented! 宏 |
| 6 | clippy::clone_on_copy |
禁止对 Copy 类型调用 .clone()
|
| 7 | clippy::needless_pass_by_value |
避免不必要的值传递,优先使用引用 |
| 8 | clippy::redundant_clone |
检测并移除多余的 .clone() 调用 |
| 9 | clippy::indexing_slicing |
禁止直接索引,使用 .get() 方法 |
| 10 | clippy::manual_let_else |
优先使用 let...else 语法 |
| 11 | clippy::explicit_iter_loop |
循环中优先使用 & 或 &mut 而非 .iter()
|
| 12 | clippy::string_add |
禁止使用 + 拼接字符串,使用 format! 或 concat!
|
在 clippy.toml 或 Cargo.toml 中配置:
[lints.clippy]
unwrap_used = "deny"
expect_used = "deny"
panic = "deny"
todo = "deny"
unimplemented = "deny"
clone_on_copy = "deny"
needless_pass_by_value = "warn"
redundant_clone = "warn"
indexing_slicing = "warn"
manual_let_else = "warn"
explicit_iter_loop = "warn"
string_add = "warn"除了上述通用代码质量规则外,项目还启用了以下专门针对安全性的 Clippy Lints:
| Clippy Lint | 安全类别 | 说明 |
|---|---|---|
clippy::indexing_slicing |
内存安全 | 防止数组/切片越界访问导致的 panic,强制使用 .get() 方法进行安全访问 |
clippy::cast_possible_truncation |
类型安全 | 捕获不安全的整数类型转换(如 i64 转 i32 可能导致数据截断) |
clippy::unnecessary_safety_comment |
审计可追溯性 | 确保 unsafe 块都有充分的安全说明注释,防止无注释的 unsafe 代码混入 |
这些 Lints 在 CI 的 lint-rust Job 中作为 Clippy 的额外警告级别检查执行。
Source: .github/workflows/security.yml:88-97
项目使用 ESLint 进行前端代码质量检查,配置文件为 eslint.config.js:
// eslint.config.js 核心配置
export default [
{
rules: {
"no-unused-vars": "error",
"no-console": ["warn", { allow: ["warn", "error"] }],
"typescript-eslint/no-explicit-any": "error",
"typescript-eslint/consistent-type-imports": "error",
"vue/no-unused-components": "error",
"vue/no-v-html": "warn",
},
},
];前端依赖安全通过 npm audit 进行扫描,在 CI 的安全流水线中自动执行:
npm audit --omit=dev --audit-level=moderate参数说明:
| 参数 | 说明 |
|---|---|
--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 进行额外的静态安全分析,配置文件为 .semgrep.yml。以下为项目中实际配置的 4 条自定义规则:
| # | Rule ID | Language | Target Risk | Description |
|---|---|---|---|---|
| 1 | rust-osascript-privilege-escalation |
Rust | Privilege Escalation | 检测通过 osascript 执行提权操作的代码,防止权限提升攻击 |
| 2 | rust-command-format-arg |
Rust | Command Injection | 标记使用 format!() 构造 Command 参数的代码,防止命令注入漏洞 |
| 3 | rust-unsafe-block |
Rust | Memory Safety | 审计所有 unsafe 块,确保内存安全操作有充分的审查 |
| 4 | js-innerhtml-assignment |
JS | XSS | 检测 innerHTML 赋值操作,防止跨站脚本攻击 (XSS) |
Source: .semgrep.yml:8-116
规则文件位于 .semgrep.yml,示例如下:
rules:
- id: rust-osascript-privilege-escalation
languages: [rust]
message: "检测到 osascript 提权操作,请确保此操作经过安全审查"
severity: ERROR
pattern: |
Command::new("osascript")
...
metadata:
category: security
subcategory: privilege-escalation
- id: rust-command-format-arg
languages: [rust]
message: "Command 参数通过 format!() 构建,存在命令注入风险"
severity: WARNING
pattern-either:
- pattern: |
Command::new(...).arg(format!(...))
- pattern: |
Command::new(...).args(format!(...))
metadata:
category: security
subcategory: injection
- id: rust-unsafe-block
languages: [rust]
message: "unsafe 块需要安全审查注释"
severity: WARNING
pattern: |
unsafe { ... }
metadata:
category: memory-safety
- id: js-innerhtml-assignment
languages: [javascript, typescript]
message: "innerHTML 赋值存在 XSS 风险,请使用 textContent"
severity: WARNING
pattern: |
$OBJ.innerHTML = $VALUE
metadata:
category: security
subcategory: xss
references:
- https://owasp.org/www-community/attacks/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 配置了完整的依赖审计策略。
[licenses]
unlicensed = "deny"
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",
]
copyleft = "deny"
allow-osi-fsf-free = "both"
default = "deny"
[licenses.private]
ignore = true
[bans]
multiple-versions = "warn"
wildcards = "deny"
[sources]
unknown-registry = "deny"
unknown-git = "deny"
[advisories]
vulnerability = "deny"
unmaintained = "warn"Source: deny.toml:1-37
| 策略 | 配置值 | 说明 |
|---|---|---|
unlicensed |
deny |
拒绝无许可证的依赖 |
copyleft |
deny |
拒绝 Copyleft 许可证(如 GPL) |
default |
deny |
默认拒绝未明确允许的许可证 |
allow-osi-fsf-free |
both |
同时认可 OSI 和 FSF 的自由软件定义 |
| 许可证 | 类型 | 说明 |
|---|---|---|
| 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 系统库) |
注意:
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 |
warn |
依赖不再维护时发出警告 |
Zephyr 为 4 个生态系统配置了 Dependabot 自动依赖更新,配置文件为 .github/dependabot.yml:
version: 2
updates:
# 1. Rust 生态系统 (Cargo)
- package-ecosystem: "cargo"
directory: "/src-tauri"
schedule:
interval: "weekly"
groups:
patch:
update-types:
- "patch"
minor:
update-types:
- "minor"
labels:
- "dependencies"
- "rust"
# 2. npm 生态系统 (前端)
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"
- "frontend"
# 3. GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
labels:
- "dependencies"
- "github-actions"
# 4. Pip (Semgrep 工具链)
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"
- "security-tools"Source: .github/dependabot.yml:1-68
| 生态系统 | 更新频率 | 目录 | 分组策略 | 说明 |
|---|---|---|---|---|
| Cargo (Rust) | 每周 | /src-tauri |
patch + minor 分组 | 将补丁更新和次要更新分别合并为单个 PR,减少 PR 数量 |
| npm (前端) | 每周 | / |
无分组 | 每个 npm 包独立更新 |
| GitHub Actions | 每月 | / |
无分组 | 保持 Actions 版本稳定 |
| Pip (Semgrep) | 每周 | / |
无分组 | 保持 Semgrep 安全扫描工具链最新 |
Cargo 分组策略说明:通过
groups配置,Cargo 生态系统的补丁更新(patch)和次要更新(minor)会被自动合并到各自的分组 PR 中。例如,当 5 个依赖有补丁更新时,Dependabot 只会创建 1 个 PR 而非 5 个,大幅减少代码审查负担。
在提交 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 中讨论。