EricCogen/GauntletCI-Demo

GitHub: EricCogen/GauntletCI-Demo

GauntletCI演示仓库,展示如何在实际PR中通过GitHub Actions检测代码变更的行为风险。

Stars: 1 | Forks: 0

# GauntletCI 演示 ## 什么是此仓库 此仓库 **并非** 一个可运行的应用程序。它是一个受控的演示环境,其唯一目的是让您无需自行安装任何东西,就能查看 GauntletCI 在真实代码变更上的输出。 它包含: 1. 一个 **小型但真实的 .NET 8 示例应用**(`OrderService` - 一个支付处理服务,包含支付客户端和订单处理器),这样被分析的差异看起来就像您实际会编写的代码。 2. 一个 **GitHub Actions 工作流**(`.github/workflows/gauntlet.yml`),它在每个 PR 上安装从 NuGet 发布的 GauntletCI 工具,并针对 PR 差异运行它,将发现作为内联注释、PR 审阅评论和检查 API 判定发布。 3. 一个位于 `scenarios/` 下的 **标准演示场景库**。每个场景都是一次刻意的代码更改(静默异常吞没、硬编码密钥、破坏性 API 变更、日志中的 PII、并发竞争和一个无操作对照),用于测试不同的 GauntletCI 规则。 4. 一个 **`workflow_dispatch` 操作**(`.github/workflows/reopen-scenarios.yml`),用于按需重建每个场景分支并重新打开其 PR。这使得演示能够针对最新发布的工具版本自我更新,无需手动 git 操作。 ## 这个仓库 *不是* 什么 - ❌ 并非 `OrderService` 的生产级参考架构。 - ❌ 并非提交 GauntletCI 错误或功能请求的地方 - 请使用[主仓库的问题跟踪](https://github.com/EricCogen/GauntletCI/issues)。 - ❌ 并非在您自己的代码库上进行真实测试的替代品。请在您自己的差异上运行 `gauntletci analyze`,以查看针对您代码的发现。 ## 理解 GauntletCI 的价值主张 GauntletCI 在预提交分析期间检测 git 差异中的**行为变更风险**。这与全项目快照 SAST 工具在本质上是不同的。 ### 这意味着什么 **SAST 工具(CodeQL, Semgrep, SonarQube 等):** - 在 CI 期间扫描整个代码库(需数分钟过程) - 查找已知漏洞特征码和代码质量模式 - 非常擅长发现硬编码密钥、SQL 注入模式、标准反模式(如 `.Result` 死锁) - 作为 CI 门控,在编译/打包阶段运行 **GauntletCI:** - 在预提交期间仅分析 git 差异(亚秒级) - 检测特定变更增量内的结构变异、执行序列变更、边界漂移 - 捕获那些编译通过、所有测试通过、但会破坏生产系统的行为回归 - 在您提交代码之前、代码审查之前、CI 之前运行 ### 18 个场景:它们展示了什么 这 18 个行为场景展示了 GauntletCI 能检测到而全项目快照工具无法看到的内容: | 类别 | 场景 | 展示内容 | |------|------|----------| | **架构访问控制** | S19, S23, S24 | 差异中访问边界的移除/修改,而没有相应的验证更改 | | **执行序列变更** | S20, S28-S30 | 状态变异或外部调用被重新排序,其语法正确但依赖执行顺序 | | **异步传播丢失** | S21, S25-S27 | 差异中 CancellationToken 上下文的丢失、即发即忘任务模式、跨方法边界的传播失败 | | **公共契约漂移** | S22, S31-S32 | 方法签名、默认参数或 API 契约更改,能够编译但在特定更改中破坏调用者 | | **性能与资源** | S33-S34 | 配置更改、禁用连接池、移除缓存查找,这些对样式检查器不可见 | | **依赖注入作用域** | S35-S36 | 特定更改中 DI 配置的作用域边界不匹配 | 每个场景: - 编译成功并通过单元测试 - 能通过 SAST 和代码风格检查 - 引入了只有差异级分析才能在进入生产前捕获的行为风险 ### 现场演示 所有工具通过 GitHub Actions 现场运行: - **DEMO_FINDINGS.md** - 所有 18 个场景的详细工具间比较 - **实时 PR** - 每个场景都运行 CodeQL、Semgrep、SonarQube、StyleCop、Snyk 和 GauntletCI - **判定结果** - 查看 18/18 vs 0/18 的计分卡 - **总计 36 个场景** - 第 1 层(6),第 2 层(12),第 3 层(18) ## 如何自行验证 **最快的方法:** Fork 此仓库,启用 Actions,运行工作流 `Reopen demo scenarios` 所有分析工具都通过 `.github/workflows/` 中的 GitHub Actions 在每个 PR 上现场运行: - `codeql.yml` - 在每个 PR 上运行 CodeQL - `semgrep.yml` - 在每个 PR 上运行 Semgrep - `stylecop.yml` - 在每个 PR 上运行 StyleCop 检查 - `snyk.yml` - 在每个 PR 上运行 Snyk - `gauntletci.yml` - 在每个 PR 上运行 GauntletCI 您将实时看到发现(或无发现)。无需下载,无需本地设置——只需 fork,启用工作流,然后观察 PR。 ## 如何使用此仓库 ### 自行运行(推荐) 这是主打体验:您拥有仓库状态,控制运行,可以在不破坏演示的情况下随意操作。 #### 选项 1 - Fork 并使用 GitHub Actions 1. 将 [`EricCogen/GauntletCI-Demo`](https://github.com/EricCogen/GauntletCI-Demo) **Fork** 到您的账户。 2. **⚠️ 在您的 Fork 上启用 Actions。** GitHub 默认会在新 fork 上禁用工作流。在您的 fork 中,点击 **Actions** 标签页。如果您看到横幅 *"Workflows aren't being run on this forked repository"*(*工作流未在此 fork 仓库上运行*),请点击 **"I understand my workflows, go ahead and enable them"**(*我理解我的工作流,请继续启用它们*)。在您执行此操作之前,reopen-scenarios 工作流不会出现。 3. 前往 **Actions → Reopen demo scenarios → Run workflow**(**操作 → 重新打开演示场景 → 运行工作流**)。 4. 在输入框中键入 `all`(或单个场景文件夹名,如 `03-hardcoded-secret`),然后点击 **Run workflow**(**运行工作流**)。 5. **预计首次运行需约 2 分钟**:工作流重建 `demo/*` 分支并为每个场景打开一个 PR。每个 PR 随后触发 `gauntlet.yml`,该工作流从 NuGet 安装已发布的 GauntletCI 工具(约 30 秒)并在差异上运行(约 5 秒)。 6. 在您的 fork 中打开任何一个新 PR,查看 **Files Changed**(**文件更改**)注释、**Conversation**(**对话**)审阅摘要和 **Checks**(**检查**)判定。 **成功了吗?** - ✅ 预期:一批标题为 `demo: ` 的新 PR 会出现在您 fork 的 **Pull requests**(**拉取请求**)标签页中,每个 PR 都带有绿色或红色的 **GauntletCI** 检查(与 [`scenarios//README.md`](scenarios/) 中的判定一致)。 - ❌ *没有出现 PR* - 最常见的情况是 Actions 标签页仍然显示禁用横幅。请重新检查步骤 2。 - ❌ *工作流在 `Install GauntletCI` 步骤失败* - 通常是临时的 NuGet 中断。从 **Actions** 标签页重新运行。 - ❌ *工作流在 `Open PR` 步骤因 403 失败* - 您的 fork 在 `main` 分支上设置了阻止机器人的分支保护规则。要么移除该规则,要么将 `DEMO_PR_TOKEN` 设置为可以绕过它的 PAT。 #### 选项 2 - 克隆并在本地运行 如果您的机器上已安装 .NET 8 SDK,此路径最快。 **bash / macOS / Linux:** ``` git clone https://github.com/EricCogen/GauntletCI-Demo.git cd GauntletCI-Demo # 安装已发布的工具 dotnet tool install -g GauntletCI # 构建示例应用 dotnet build # 在本地应用场景并分析已暂存的差异 cp -r scenarios/02-silent-catch/files/. . git add -A gauntletci analyze --staged ``` **PowerShell / Windows:** ``` git clone https://github.com/EricCogen/GauntletCI-Demo.git Set-Location GauntletCI-Demo # 安装已发布的工具 dotnet tool install -g GauntletCI # 构建示例应用 dotnet build # 在本地应用场景并分析已暂存的差异 Copy-Item -Recurse -Force scenarios/02-silent-catch/files/* . git add -A gauntletci analyze --staged ``` 您将在自己的机器上,在不到一秒钟内获得与 GauntletCI 在 CI 中产生的相同发现。 **成功了吗?** - ✅ 预期:控制台输出以 `🛑 Block` 结束,并带有指向场景引入的静默 `catch { }` 块的 `[GCI0007] Error Handling Integrity`(`[GCI0007] 错误处理完整性`)发现。 - ❌ *`gauntletci: command not found`*(*`gauntletci: 命令未找到`*)- dotnet 全局工具文件夹不在您的 `PATH` 中。重启您的 shell 或将 `$HOME/.dotnet/tools`(Unix)/ `%USERPROFILE%\.dotnet\tools`(Windows)添加到 `PATH`。 - ❌ *`error: pathspec 'scenarios/02-silent-catch/files/.' did not match any file(s)`*(*错误:路径规格 'scenarios/02-silent-catch/files/.' 未匹配任何文件*)- 您不在仓库根目录。请先运行 `cd GauntletCI-Demo`。 - ❌ *工具已安装但 `analyze --staged` 报告 `0 findings`*(*0 个发现*)- 场景文件实际上未被暂存。检查 `git status` 并重新运行 `git add -A`。 ### 快速查看(无需安装,无需 fork) 如果您只是想*看看*该工具的输出,而无需设置任何东西: 1. 打开 **[Pull Requests 标签页](https://github.com/EricCogen/GauntletCI-Demo/pulls)**。 2. 选择任何带有 `demo:*` 标签的打开 PR。 3. 查看: - **Files Changed**(**文件更改**)标签页 - GauntletCI 的内联注释出现在触发它们的差异行旁。 - **Conversation**(**对话**)标签页 - GauntletCI 发布一份 PR 审阅,总结发现、严重性和理由。 - **Checks**(**检查**)标签页 - 一个 GauntletCI 检查运行显示整体通过/失败判定。 每个场景的预期判定都记录在其 [`scenarios//README.md`](scenarios/) 中,因此您可以将所见与工具本应捕获的内容进行比较。 ### 维护者说明(重新生成规范 PR) 此仓库中的规范 PR 具有自动恢复功能:`reopen-scenarios.yml` 按每周计划以及在每次推送到 `main` 分支时运行,因此展示内容与最新发布的 GauntletCI 版本保持同步。要强制手动重建,请前往 **Actions → Reopen demo scenarios → Run workflow**(**操作 → 重新打开演示场景 → 运行工作流**)。 ## 场景 ### 第 1 层 - 主打场景 | # | 场景 | 预期判定 | 演示的规则 | |---|------|----------|------------| | 01 | [safe-typo-fix](scenarios/01-safe-typo-fix/README.md) | ✅ 无问题 | (无 - 低噪声对照) | | 02 | [silent-catch](scenarios/02-silent-catch/README.md) | 🛑 阻止 | `GCI0007` 错误处理完整性 | | 03 | [hardcoded-secret](scenarios/03-hardcoded-secret/README.md) | 🛑 阻止 | `GCI0012` 安全风险 | | 04 | [breaking-api-change](scenarios/04-breaking-api-change/README.md) | 🛑 阻止 | `GCI0004` 破坏性变更风险 | | 05 | [pii-logging](scenarios/05-pii-logging/README.md) | ⚠️ 警告 | `GCI0029` PII 日志泄漏 | | 06 | [concurrency-race](scenarios/06-concurrency-race/README.md) | 🛑 阻止 | `GCI0016` 并发与状态风险 | ### 第 2 层 - 每个规则一个场景 第二波场景,每个在相同的 `OrderService` 示例应用上隔离单个 GauntletCI 规则。每个第 2 层条目的判定都是 ❌ 失败(更改的存在正是为了触发一个规则)。 | # | 场景 | 演示的规则 | |---|------|------------| | 07 | [magic-connection-string](scenarios/07-magic-connection-string/README.md) | `GCI0010` 硬编码与配置 | | 08 | [undisposed-httpclient](scenarios/08-undisposed-httpclient/README.md) | `GCI0024` 资源生命周期 | | 09 | [insecure-random-token](scenarios/09-insecure-random-token/README.md) | `GCI0048` 安全上下文中的不安全随机数 | | 10 | [sql-column-truncation](scenarios/10-sql-column-truncation/README.md) | `GCI0050` SQL 列截断风险 | | 11 | [float-money-equality](scenarios/11-float-money-equality/README.md) | `GCI0049` 浮点/双精度相等比较 | | 12 | [missing-null-guard](scenarios/12-missing-null-guard/README.md) | `GCI0006` 边界情况处理 | | 13 | [throw-bare-exception](scenarios/13-throw-bare-exception/README.md) | `GCI0032` 未捕获的异常路径 | | 14 | [todo-in-payment-flow](scenarios/14-todo-in-payment-flow/README.md) | `GCI0042` TODO/桩代码检测 | | 15 | [non-idempotent-retry](scenarios/15-non-idempotent-retry/README.md) | `GCI0022` 幂等性与重试安全性 | | 16 | [tolist-in-loop](scenarios/16-tolist-in-loop/README.md) | `GCI0044` 性能热路径风险 | | 17 | [captive-dependency](scenarios/17-captive-dependency/README.md) | `GCI0038` 依赖注入安全性 | | 18 | [dependabot-api-drift](scenarios/18-dependabot-api-drift/README.md) | `GCI0052` 依赖机器人 API 漂移 | ### 第 3 层 - 行为回归场景(扩展) **18 个高级行为回归场景**,旨在展示 GauntletCI **检测那些能通过传统分析工具(SonarQube, CodeQL, Semgrep, StyleCop, Snyk)的变更的独特能力**。每个场景展示了一个真实的生产错误,它能成功编译,但代表了一个关键回归。 **关键发现:** GauntletCI 检测到了全部 18 个第 3 层场景;竞争对手平均检测到 0/18。 完整比较请参见 [DEMO_FINDINGS.md](DEMO_FINDINGS.md)。 #### 安全与访问控制(S19, S23, S24) | # | 场景 | 生产影响 | |---|------|----------| | 19 | [access-control-drop](scenarios/19-access-control-drop/README.md) | 重构期间剥离安全属性 | | 23 | [role-based-bypass](scenarios/23-role-based-bypass/README.md) | 授权检查移至条件分支内部 | | 24 | [encryption-key-rotation-removal](scenarios/24-encryption-key-rotation-removal/README.md) | 简化了解密逻辑,破坏旧的加密数据 | #### 并发与异步(S21, S25, S26, S27) | # | 场景 | 生产影响 | |---|------|----------| | 21 | [static-mutation-async](scenarios/21-static-mutation-async/README.md) | 异步上下文中的未同步静态变异 | | 25 | [async-without-await](scenarios/25-async-without-await/README.md) | 调用异步方法而没有 await,导致异常丢失 | | 26 | [lock-scope-reduction](scenarios/26-lock-scope-reduction/README.md) | 缩小了临界区范围,暴露了竞态条件 | | 27 | [task-result-deadlock](scenarios/27-task-result-deadlock/README.md) | 同步覆盖异步模式导致挂起 | #### 数据完整性与业务逻辑(S20, S28, S29, S30) | # | 场景 | 生产影响 | |---|------|----------| | 20 | [audit-log-inversion](scenarios/20-audit-log-inversion/README.md) | 执行顺序变异破坏了合规性日志 | | 28 | [transaction-rollback-repositioning](scenarios/28-transaction-rollback-repositioning/README.md) | 移动了回滚点,提交了部分更改 | | 29 | [idempotency-key-removed](scenarios/29-idempotency-key-removed/README.md) | 移除了重复检测,导致重复扣款 | | 30 | [cascade-delete-to-restrict](scenarios/30-cascade-delete-to-restrict/README.md) | 更改了删除行为,导致关联记录孤立 | #### API 契约与版本控制(S22, S31, S32) | # | 场景 | 生产影响 | |---|------|----------| | 22 | [breaking-api-contract](scenarios/22-breaking-api-contract/README.md) | 移除了公共 API 参数而没有版本号变更 | | 31 | [exception-contract-violation](scenarios/31-exception-contract-violation/README.md) | 文档化的异常不再被抛出,破坏了消费者 | | 32 | [implicit-type-coercion-change](scenarios/32-implicit-type-coercion-change/README.md) | 简化了转换逻辑,改变了边界情况行为 | #### 性能与资源管理(S33, S34) | # | 场景 | 生产影响 | |---|------|----------| | 33 | [cache-lookup-removed](scenarios/33-cache-lookup-removed/README.md) | 添加了缓存绕过,导致数据库负载激增 | | 34 | [connection-pooling-disabled](scenarios/34-connection-pooling-disabled/README.md) | 禁用了连接池,引发连接风暴 | #### 依赖注入与作用域(S35, S36) | # | 场景 | 生产影响 | |---|------|----------| | 35 | [service-locator-anti-pattern](scenarios/35-service-locator-anti-pattern/README.md) | 从服务定位器解析依赖,导致不可测试 | | 36 | [singleton-captures-scoped](scenarios/36-singleton-captures-scoped/README.md) | 作用域依赖被单例捕获,导致数据泄漏 | 每个场景文件夹包含: - `README.md` - 变更内容以及预期的判定 - `files/` - 覆盖文件,将其复制到 `main` 以构建演示分支 ## 竞争分析:多工具 CI/CD 管道 该演示现在包括自动化的 CI/CD 工作流,在每个 PR 上运行 **5 种互补的分析工具**。这种混合方法让您可以看到免费工具的真实发现,并将其与 GauntletCI 的行为检测进行比较。 **第 3 层扩展:** 现在针对所有 5 个工具测试 18 个行为回归场景,以最大化 GauntletCI 竞争优势的证据。 ### 包含的工具 | 工具 | 类型 | 目的 | 免费 | 在 CI 中运行 | |------|------|------|------|--------------| | **CodeQL** | 数据流 | 安全污点跟踪 | ✅ | ✅ | | **Semgrep** | 基于模式 | 自定义规则匹配 | ✅ | ✅ | | **StyleCop** | 执行 | C# 样式规则 | ✅ | ✅ | | **Snyk** | 依赖 | 漏洞扫描 | ✅ | ✅ | | **GauntletCI** | 行为 | 回归检测 | ✅ | ✅ | ### 发现比较 完整分解每个工具在第 3 层场景上的发现(或遗漏),请参见 [**DEMO_FINDINGS.md**](DEMO_FINDINGS.md)。 **快速总结:** 在行为回归(第 3 层场景 - 现在 6 个类别共 18 个场景)上: - GauntletCI: ✅ 在所有场景中检测到行为变更 - CodeQL, Semgrep, SonarQube, Snyk, StyleCop: ❌ 一贯遗漏行为回归 **覆盖范围:** - 安全与访问控制:3 个场景 - 并发与异步:4 个场景 - 数据完整性与业务逻辑:4 个场景 - API 契约与版本控制:3 个场景 - 性能与资源管理:2 个场景 - 依赖注入与作用域:2 个场景 这说明了为什么团队在统一的 CI/CD 管道中使用多种工具:每种工具专攻不同的风险类别,而 GauntletCI 填补了行为回归检测的关键空白。 ### 自行运行多工具管道 `.github/workflows/` 中的工作流在每个 PR 上自动运行: ``` # 创建测试 PR git checkout -b test/try-scenarios main cp -r scenarios/19-access-control-drop/files/. . git add -A && git commit -m "test: behavioral regression scenario" git push origin test/try-scenarios ``` 然后向 `main` 提交一个 PR。GitHub Actions 将运行所有 5 个工具,并将发现发布在 **Checks** 标签页中。将结果与 [DEMO_FINDINGS.md](DEMO_FINDINGS.md) 进行比较。 ## CI 安装如何工作 CI 工作流使用 **真实用户遵循的相同安装路径**,因此该演示也充当了已发布工具的冒烟测试: ``` - run: dotnet tool install -g GauntletCI - run: | gauntletci analyze \ --commit ${{ github.event.pull_request.head.sha }} \ --no-banner \ --github-annotations \ --github-pr-comments \ --github-checks ``` 没有从源代码构建,没有预发布源 - 只是来自 NuGet 的 `dotnet tool install`。 ## 仓库布局 ``` GauntletCI-Demo/ ├── src/OrderService/ # sample .NET 8 app ├── tests/OrderService.Tests/ # xUnit tests for the sample app ├── scenarios/ # canonical demo scenarios (22 total) │ ├── 01-safe-typo-fix/ # tier 1 - control + 5 headline rules │ ├── 02-silent-catch/ │ ├── 03-hardcoded-secret/ │ ├── 04-breaking-api-change/ │ ├── 05-pii-logging/ │ ├── 06-concurrency-race/ │ ├── 07-magic-connection-string/ # tier 2 - one rule per scenario │ ├── 08-undisposed-httpclient/ │ ├── 09-insecure-random-token/ │ ├── 10-sql-column-truncation/ │ ├── 11-float-money-equality/ │ ├── 12-missing-null-guard/ │ ├── 13-throw-bare-exception/ │ ├── 14-todo-in-payment-flow/ │ ├── 15-non-idempotent-retry/ │ ├── 16-tolist-in-loop/ │ ├── 17-captive-dependency/ │ ├── 18-dependabot-api-drift/ │ ├── 19-access-control-drop/ # tier 3 - behavioral regressions │ ├── 20-audit-log-inversion/ │ ├── 21-static-mutation-async/ │ └── 22-breaking-api-contract/ ├── .github/workflows/ │ ├── gauntlet.yml # PR check that runs GauntletCI │ ├── reopen-scenarios.yml # rebuilds scenario branches on demand │ ├── codeql.yml # CodeQL security analysis │ ├── semgrep.yml # Semgrep pattern scanning │ ├── stylecop.yml # StyleCop enforcement │ ├── snyk.yml # Snyk dependency scanning │ └── gauntletci.yml # GauntletCI behavioral analysis ├── scripts/reopen-scenarios.sh # logic for the rebuild workflow ├── DEMO_FINDINGS.md # multi-tool findings comparison ├── COMPETITOR_COMPARISON.md # detailed tool analysis ├── HYBRID_DEMO_IMPLEMENTATION.md # CI/CD pipeline documentation ├── .gauntletci.json # GauntletCI rule configuration ├── .gauntletci-ignore # path-scoped rule suppressions └── OrderService.sln ``` ## 了解更多 - 🌐 **网站:** https://gauntletci.com - 📦 **源代码:** https://github.com/EricCogen/GauntletCI - 📚 **文档:** https://gauntletci.com/docs - 💬 **问题/疑问:** https://github.com/EricCogen/GauntletCI/issues ## 许可证 MIT - 详见 [LICENSE](LICENSE)。
标签:GauntletCI, GitHub Actions, .NET 8, NuGet, PR分析, SAST, SOC Prime, 云安全监控, 代码分析, 代码安全, 内联注释, 凭证管理, 安全测试, 开发工具, 开源框架, 持续集成, 攻击性安全, 漏洞枚举, 演示, 盲注攻击, 自动笔记, 行为风险, 静态分析, 风险检测, 风险裁决