ThinkGrid-Labs/oxide-ci
GitHub: ThinkGrid-Labs/oxide-ci
一款 Rust 编写的零依赖 DevOps CLI,集密钥扫描、AST SAST、K8s/Docker 规范检查、依赖审计、覆盖率门禁于一体的 CI 质量门禁工具。
Stars: 0 | Forks: 0
# OxideCI — Rust DevOps CLI:Secret Scanner、AST SAST、Kubernetes Linter 与 CI Quality Gates
[](LICENSE)
[](https://github.com/ThinkGrid-Labs/oxide-ci/actions)
[](https://github.com/ThinkGrid-Labs/oxide-ci/releases/latest)
[](https://crates.io/crates/oxide-ci)
[](https://crates.io/crates/oxide-ci)
[](https://www.rust-lang.org)
[](https://github.com/ThinkGrid-Labs/oxide-ci/stargazers)
## 目录
- [为什么选择 OxideCI?](#why-oxideci)
- [功能](#features)
- [安装](#installation)
- [快速开始](#quick-start)
- [命令](#commands)
- [scan](#scan--secret--pii-scanning)
- [JS/TS/Python/Go 的 SAST](#sast-static-analysis-for-jstspythongo)
- [GitHub Annotations](#github-check-run-annotations---annotate)
- [Baseline 模式](#baseline-mode---update-baseline--since-baseline)
- [lint](#lint--kubernetes-manifest-linting)
- [docker-lint](#docker-lint--dockerfile-linting)
- [coverage](#coverage--coverage-threshold-gate)
- [audit](#audit--dependency-vulnerability-audit)
- [install-hooks](#install-hooks--git-pre-commit-hook)
- [lighthouse](#lighthouse--web-performance-audit)
- [reassure](#reassure--react-component-performance-gate)
- [sbom](#sbom--sbom-generation)
- [check-config](#check-config--validate-configuration)
- [init](#init--interactive-setup-wizard)
- [watch](#watch--live-file-watcher)
- [run](#run--pipeline-runner)
- [Secret 检测模式](#secret-detection-patterns)
- [SAST 规则参考](#sast-rules-reference)
- [抑制发现项](#suppressing-findings)
- [配置文件](#configuration-file-oxidecitorml)
- [配置 Profiles](#config-profiles)
- [输出格式](#output-formats)
- [退出码](#exit-codes)
- [CI/CD 集成](#cicd-integration)
- [架构](#architecture)
- [React Native](#react-native)
- [故障排除](#troubleshooting)
- [贡献](#contributing)
## 为什么选择 OxideCI?
大多数 DevOps 质量工具要么速度慢,要么需要运行时环境(Node、Python、Java),或者只能解决单一问题。OxideCI 将必要的 CI 门禁打包成一个单独的 Rust 编译二进制文件:
| 问题 | OxideCI 命令 |
|---|---|
| 硬编码的 secrets 被推送到 git | `oxide-ci scan` |
| JS/TS/Python/Go 中的 XSS、eval、命令注入 | `oxide-ci scan` (SAST) |
| Kubernetes manifests 缺少资源限制 | `oxide-ci lint` |
| Dockerfile 最佳实践违规 | `oxide-ci docker-lint` |
| 测试覆盖率静默下降 | `oxide-ci coverage` |
| 易受攻击的依赖项被发布到生产环境 | `oxide-ci audit` |
| 在任何人注意到之前 secrets 已被提交 | `oxide-ci install-hooks` |
| Web Lighthouse 分数在部署之间出现倒退 | `oxide-ci lighthouse` |
| React 组件渲染性能出现倒退 | `oxide-ci reassure` |
| 现有的发现项淹没 CI 噪音 | `oxide-ci scan --since-baseline` |
| 需要知道谁引入了一个 secret | `oxide-ci scan --blame` |
| 需要 SBOM 以满足合规要求 | `oxide-ci sbom` |
| 配置文件有语法错误 | `oxide-ci check-config` |
| 使用一个命令运行所有门禁 | `oxide-ci run` |
| 无需阅读文档即可开始 | `oxide-ci init` |
**核心优势:**
- **零运行时依赖** — 将单个二进制文件放入任何 CI pipeline、Docker 镜像或开发人员机器。无需 Node、Python 或 JVM。
- **极快** — 通过 `rayon` 在所有 CPU 核心上并行扫描文件。典型的仓库扫描不到一秒钟。
- **基于 AST 的 SAST** — tree-sitter 在模式匹配之前将 JS/TS/TSX/JSX/Python/Go 解析为真正的 AST。Secrets 仅在它们出现在字符串字面量中时才会被标记,从而消除注释噪音和误报。
- **云服务商无关** — 检测 AWS、Azure、GCP、DigitalOcean、Alibaba Cloud、Stripe、GitHub、Twilio、Expo、Sentry、Mapbox 等平台的 secrets。
- **gitignore 感知** — 使用 `ignore` crate 自动跳过 `.gitignore` 中的文件,因此您绝不会意外扫描 `node_modules/` 或 `target/`。
- **CI 原生输出** — `--format sarif` 生成 SARIF 2.1.0 输出,GitHub Advanced Security 无需额外配置即可显示为内联 PR annotations。
- **可配置** — 单个 `.oxideci.toml` 文件为所有命令设置默认值;CLI flags 始终覆盖它。
## 功能
| 功能 | 状态 |
|---|---|
| Secret & PII 扫描(26 种内置模式) | ✅ |
| 每个发现项的严重性级别(critical / high / medium / low) | ✅ |
| JS/TS/TSX/JSX 的基于 AST 的 SAST | ✅ |
| Python 的基于 AST 的 SAST(eval、exec、pickle、subprocess、yaml.load) | ✅ |
| Go 的基于 AST 的 SAST(unsafe、exec.Command、panic) | ✅ |
| 字符串字面量范围界定(无注释 / JSX 文本噪音) | ✅ |
| 危险模式检测(XSS、eval、命令注入) | ✅ |
| 代码异味 / 复杂度规则(长函数、深层嵌套、参数过多) | ✅ |
| 通过配置自定义 SAST 规则(tree-sitter S-expression 查询) | ✅ |
| 通过配置自定义额外模式 | ✅ |
| 通过 glob 模式排除路径 | ✅ |
| 内联抑制(`// oxide-ci: ignore`) | ✅ |
| Git diff / 仅暂存 / 完整历史扫描 | ✅ |
| Git blame 增强(`--blame`) | ✅ |
| JSON、SARIF 2.1.0、JUnit XML、GitLab SAST 输出格式 | ✅ |
| GitHub Check Run annotations + 富 PR 摘要评论(`--annotate`) | ✅ |
| Kubernetes manifest linting(7 条规则) | ✅ |
| Dockerfile linting(8 条规则) | ✅ |
| LCOV & Cobertura XML 覆盖率阈值门禁 | ✅ |
| 通过 OSV API 进行依赖审计(6 个生态系统) | ✅ |
| 离线 OSV 审计缓存(24 小时 TTL,适用于离线环境) | ✅ |
| CycloneDX 1.5 SBOM 生成(`oxide-ci sbom`) | ✅ |
| Git pre-commit hook 安装程序 | ✅ |
| 通过 PageSpeed Insights 进行 Web 性能审计 | ✅ |
| React 组件性能门禁(Reassure) | ✅ |
| 扫描基线(在 CI 中抑制已知发现项) | ✅ |
| 配置 profiles(`--profile strict\|relaxed\|ci`) | ✅ |
| 配置验证(`oxide-ci check-config`) | ✅ |
| Pipeline runner(`oxide-ci run`) | ✅ |
| 交互式设置向导(`oxide-ci init`) | ✅ |
| 实时文件监视器(`oxide-ci watch`) | ✅ |
| `.oxideci.toml` 配置文件 | ✅ |
| 遵循 `.gitignore` | ✅ |
## 安装
### 推荐:预编译二进制文件
**macOS (Apple Silicon / M1+):**
```
curl -sL https://github.com/ThinkGrid-Labs/oxide-ci/releases/latest/download/oxide-ci-macos-arm64 \
-o /usr/local/bin/oxide-ci && chmod +x /usr/local/bin/oxide-ci
```
**macOS (Intel):**
```
curl -sL https://github.com/ThinkGrid-Labs/oxide-ci/releases/latest/download/oxide-ci-macos-amd64 \
-o /usr/local/bin/oxide-ci && chmod +x /usr/local/bin/oxide-ci
```
**Linux (x64):**
```
curl -sL https://github.com/ThinkGrid-Labs/oxide-ci/releases/latest/download/oxide-ci-linux-amd64 \
-o /usr/local/bin/oxide-ci && chmod +x /usr/local/bin/oxide-ci
```
**Windows (x64) — PowerShell:**
```
Invoke-WebRequest -Uri "https://github.com/ThinkGrid-Labs/oxide-ci/releases/latest/download/oxide-ci-windows-amd64.exe" `
-OutFile "$env:USERPROFILE\.local\bin\oxide-ci.exe"
# 将 $env:USERPROFILE\.local\bin 添加到 PATH(如果尚未存在)
```
### 从源码构建(需要 Rust 1.85+)
```
cargo install --git https://github.com/ThinkGrid-Labs/oxide-ci
```
### 验证安装
```
$ oxide-ci --version
oxide-ci 0.2.6
$ oxide-ci --help
A high-performance DevOps CLI tool in Rust
Usage: oxide-ci [--profile ]
Commands:
scan Scans the current directory for hardcoded secrets and PII
lint Validates Kubernetes YAML manifests for resource limits and security issues
docker-lint Lints a Dockerfile for best-practice violations
coverage Parses an LCOV or Cobertura XML coverage file and fails if below threshold
audit Audits project dependencies for known vulnerabilities via the OSV database
install-hooks Installs oxide-ci as a git pre-commit hook
lighthouse Audits web performance via Google PageSpeed Insights (Lighthouse)
reassure Parses a Reassure performance report and gates on regressions
sbom Generates a CycloneDX 1.5 SBOM from the project's lock file
check-config Validates .oxideci.toml and prints all resolved configuration values
init Interactive wizard that generates a .oxideci.toml config file
watch Re-runs scan automatically whenever source files change
run Runs all pipeline steps defined in .oxideci.toml in order
help Print this message or the help of the given subcommand(s)
```
## 快速开始
```
# 扫描当前仓库中的 secrets(包含针对 JS/TS 文件的 SAST)
oxide-ci scan
# Lint 所有 Kubernetes YAML 文件
oxide-ci lint --dir ./k8s
# 强制执行最低 80% 覆盖率
oxide-ci coverage --file coverage/lcov.info --min 80
# 审计依赖项中的 CVE
oxide-ci audit
# 作为 git hook 安装(在每次提交时运行)
oxide-ci install-hooks
# 基于 Lighthouse web 性能分数进行把关
oxide-ci lighthouse --url https://yourapp.com
# 基于 React 组件性能回归进行把关(在 `reassure measure` 之后)
oxide-ci reassure
```
## 命令
### `scan` — Secret & PII 扫描
递归扫描当前目录中的每个文件,使用 26 种内置正则表达式模式查找硬编码的 secrets、凭证和 PII。自动遵循 `.gitignore`。
对于 JavaScript、TypeScript、Python 和 Go 文件,扫描器自动使用基于 AST 的传递(SAST)而不是普通正则表达式。这消除了来自注释和非字符串内容的误报,并额外标记危险的 API 模式。请参阅下面的 [SAST for JS/TS/Python/Go](#sast-static-analysis-for-jstspythongo)。
```
oxide-ci scan [OPTIONS]
Options:
--format Output format: text (default), json, sarif, junit, gitlab
--staged Only scan git-staged files (git diff --cached)
--since Only scan files changed since the given commit
--history Scan the entire git commit history (slow on large repos)
--annotate Post findings as a GitHub Check Run with per-line annotations
and a rich PR summary comment. Requires GITHUB_TOKEN,
GITHUB_REPOSITORY, and GITHUB_SHA env vars. No-op when absent.
--update-baseline Save current findings as the baseline (.oxide-baseline.json)
--since-baseline Only fail on findings not present in the saved baseline
--blame Enrich each finding with git blame info (author + commit)
-h, --help Print help
```
**示例:**
```
# 全量扫描,人类可读输出
oxide-ci scan
# 仅扫描您即将提交的内容(快速,非常适合 pre-commit)
oxide-ci scan --staged
# 仅扫描上次提交中更改的文件
oxide-ci scan --since HEAD~1
# 输出 SARIF 用于 GitHub Advanced Security PR 批注
oxide-ci scan --format sarif > results.sarif
# 用于 Jenkins / Azure DevOps 的 JUnit XML
oxide-ci scan --format junit > results.xml
# GitLab SAST Security Scanner JSON
oxide-ci scan --format gitlab > gl-sast-report.json
# 输出 JSON 用于自定义工具
oxide-ci scan --format json | jq '.findings[].rule'
# 利用 git blame 信息(作者 + 提交)丰富发现结果
oxide-ci scan --blame
# 将发现结果直接发布到 GitHub Checks 选项卡和详细的 PR 摘要评论
GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} \
GITHUB_REPOSITORY=owner/repo \
GITHUB_SHA=${{ github.sha }} \
oxide-ci scan --annotate
```
**示例输出(文本):**
```
ℹ️ Starting secret and PII scan...
ℹ️ Running SAST checks...
ℹ️ SAST: scanning 14 file(s)...
⚠️ Found 3 potential issue(s):
- [CRITICAL] [AWS Access Key] src/config.ts:14
- [CRITICAL] [SAST/EvalUsage] src/utils/parser.js:42
- [HIGH] [SAST/InnerHTMLAssignment] src/components/Widget.tsx:88
Error: Scan failed: 3 secret(s)/PII found. Review the findings above.
```
**示例输出(`--format json`):**
```
{
"total": 3,
"findings": [
{ "rule": "AWS Access Key", "file": "src/config.ts", "line": 14, "severity": "critical" },
{ "rule": "SAST/EvalUsage", "file": "src/utils/parser.js", "line": 42, "severity": "critical" },
{ "rule": "SAST/InnerHTMLAssignment", "file": "src/components/Widget.tsx", "line": 88, "severity": "high" }
]
}
```
#### SAST:JS/TS/Python/Go 的静态分析
当扫描 `.js`、`.jsx`、`.ts`、`.tsx`、`.py` 或 `.go` 文件时,oxide-ci 使用 [tree-sitter](https://tree-sitter.github.io/tree-sitter/) 在运行任何检查之前将每个文件解析为 AST。与普通正则表达式相比,这带来了两个重要的改进:
**1. 用于 secrets 的字符串字面量范围界定**
Secret 和 PII 正则表达式模式仅应用于字符串字面量值——而不是注释、导入声明或 JSX 文本内容。这意味着:
```
// AKIAIOSFODNN7EXAMPLE123 ← comment: NOT flagged ✅
const key = "AKIAIOSFODNN7EXAMPLE123"; // ← string literal: flagged ⚠️
const msg = `Contact us at admin@example.com`; // ← template literal: flagged ⚠️
```
```
// JSX text content is never flagged — only string attributes are:
Directory to scan for Kubernetes manifests [default: . or lint.target_dir from config]
-h, --help Print help
```
**执行的规则:**
| Rule ID | 描述 | 应用于 |
|---|---|---|
| `no-latest-image` | Container image 使用 `:latest` 标签或根本没有标签 | 所有 workloads |
| `no-resource-limits` | `resources.limits` 块完全缺失 | 所有 workloads |
| `no-cpu-limit` | `resources.limits.cpu` 未设置 | 所有 workloads |
| `no-memory-limit` | `resources.limits.memory` 未设置 | 所有 workloads |
| `run-as-root` | `securityContext.runAsUser` 为 `0` | 所有 workloads |
| `no-readiness-probe` | `readinessProbe` 未定义 | Deployment, DaemonSet, StatefulSet |
| `no-liveness-probe` | `livenessProbe` 未定义 | Deployment, DaemonSet, StatefulSet |
**示例:**
```
# Lint 当前目录中的 manifests
oxide-ci lint
# Lint 特定目录
oxide-ci lint --dir ./infrastructure/k8s
```
**示例输出:**
```
ℹ️ Linting Kubernetes manifests in './k8s'...
⚠️ Found 3 issue(s) across 2 file(s):
[no-latest-image] k8s/api.yaml (container: api) — Image 'myapp:latest' uses an unpinned or :latest tag
[no-memory-limit] k8s/api.yaml (container: api) — resources.limits.memory is not set
[no-readiness-probe] k8s/worker.yaml (container: worker) — readinessProbe is not defined
Error: K8s lint failed: 3 issue(s) found.
```
**完全合规的 manifest 示例:**
```
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
template:
spec:
containers:
- name: api
image: myapp:1.4.2 # pinned tag
resources:
limits:
cpu: "500m"
memory: "256Mi"
readinessProbe:
httpGet:
path: /health
port: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
```
### `coverage` — 覆盖率阈值门禁
解析覆盖率报告,如果总行覆盖率低于指定的最小值,则以退出码 1 失败。显示低于阈值的文件的逐文件细分。
支持两种格式,并通过文件扩展名自动检测(或通过查看文件内容以识别模糊扩展名):
| 格式 | 扩展名 | 使用者 |
|---|---|---|
| **LCOV** | `.info` 或无扩展名 | Rust (cargo-llvm-cov), Jest, pytest-cov, Go |
| **Cobertura XML** | `.xml` | Python (coverage.py), Java (JaCoCo), .NET |
```
oxide-ci coverage [OPTIONS]
Options:
-f, --file Path to the coverage file [default: coverage/lcov.info or coverage.file from config]
-m, --min Minimum coverage threshold percentage [default: 80 or coverage.min from config]
-h, --help Print help
```
**示例:**
```
# LCOV (Rust, Jest, pytest)
oxide-ci coverage --file coverage/lcov.info --min 80
# Cobertura XML (Python coverage.py, JaCoCo)
oxide-ci coverage --file coverage.xml --min 80
# 强制执行更严格的 90% 关卡
oxide-ci coverage --file coverage/lcov.info --min 90
# 从 .oxideci.toml 读取默认值
oxide-ci coverage
```
**按语言生成覆盖率报告:**
```
# Rust (cargo-llvm-cov) → LCOV
cargo llvm-cov --lcov --output-path coverage/lcov.info
# JavaScript / TypeScript (Jest) → LCOV
jest --coverage --coverageReporters=lcov
# Python (pytest-cov) → LCOV or Cobertura
pytest --cov=. --cov-report=lcov:coverage/lcov.info
pytest --cov=. --cov-report=xml:coverage.xml
# Go (go test) → LCOV
go test ./... -coverprofile=coverage/lcov.info
# Java (JaCoCo) → Cobertura XML
# 配置您的构建工具以输出 Cobertura 格式并传递 .xml 文件
```
**示例输出:**
```
ℹ️ Analyzing coverage file: coverage/lcov.info (threshold: 80.0%)
Files below threshold (80.0%):
61.2% src/handlers/auth.rs
72.4% src/utils/parser.rs
⚠️ Coverage 74.8% is below threshold 80.0% (12 files, 748/1000 lines covered)
Error: Coverage gate failed: 74.8% < 80.0%
```
### `audit` — 依赖漏洞审计
自动检测项目的 lock 文件,解析所有固定的依赖项,并在单个批处理请求中查询 [OSV (Open Source Vulnerabilities)](https://osv.dev) 数据库。跨六个生态系统工作。
```
oxide-ci audit
Options:
-h, --help Print help
```
**支持的 lock 文件(按顺序检查):**
| Lock file | Ecosystem | 备注 |
|---|---|---|
| `Cargo.lock` | `crates.io` | 所有 registry 包 |
| `package-lock.json` | `npm` | v2/v3 格式(`packages` map) |
| `yarn.lock` | `npm` | v1 (classic) 和 v2/Berry |
| `pnpm-lock.yaml` | `npm` | v5–v9(斜杠和无斜杠格式) |
| `requirements.txt` | `PyPI` | 仅 `==` 固定版本 |
| `go.sum` | `Go` | 所有模块校验和 |
**示例:**
```
# Rust 项目
oxide-ci audit
# Node.js 项目(npm, yarn, 或 pnpm — 自动检测)
oxide-ci audit
# Python 项目(自动检测)
oxide-ci audit
# Go 项目(自动检测)
oxide-ci audit
```
**示例输出:**
```
ℹ️ Auditing 312 packages from Cargo.lock (crates.io) via OSV...
⚠️ Found 2 vulnerability/-ies in 312 packages:
[GHSA-jfh8-c2jp-hdmh] openssl@0.10.55 — Use-after-free in X.509 certificate verification
[CVE-2023-26964] h2@0.3.15 — Denial of Service via CONTINUATION frames
Error: Audit failed: 2 known vulnerability/-ies found.
```
### `install-hooks` — Git Pre-commit Hook
将 oxide-ci 安装为 git pre-commit hook,在每次 `git commit` 之前自动运行 `scan --staged`,在 secrets 到达远程之前将其捕获。
```
oxide-ci install-hooks [OPTIONS]
Options:
--force Overwrite an existing hook without prompting
-h, --help Print help
```
**它安装的内容**(写入 `.git/hooks/pre-commit`):
```
#!/bin/sh
# oxide-ci pre-commit hook(自动安装)
# 在每次提交前仅扫描已暂存文件中的 secrets 和 PII。
oxide-ci scan --staged
```
**示例:**
```
# 安装(安全 — 不会覆盖现有的 hook)
oxide-ci install-hooks
# 覆盖现有的 hook
oxide-ci install-hooks --force
```
**示例输出:**
```
✅ Pre-commit hook installed at /your/repo/.git/hooks/pre-commit
ℹ️ oxide-ci scan --staged will now run before every commit.
```
### `lighthouse` — Web 性能审计
从 [Google PageSpeed Insights API v5](https://developers.google.com/speed/docs/insights/v5/get-started)(在服务端运行真实的 Lighthouse 审计)获取您部署的 URL,并对四个类别的分数进行门禁:Performance、Accessibility、Best Practices 和 SEO。不需要 Node.js — 这是一个通过 `audit` 使用的相同 HTTP 客户端进行的纯 HTTPS 调用。
```
oxide-ci lighthouse [OPTIONS]
Options:
--url URL to audit (overrides config)
--strategy Device strategy: mobile (default) or desktop (overrides config)
--min-performance Minimum Performance score 0–100 [default: 80]
--min-accessibility Minimum Accessibility score 0–100 [default: 90]
--min-best-practices Minimum Best Practices score 0–100 [default: 80]
--min-seo Minimum SEO score 0–100 [default: 80]
--key Google PageSpeed Insights API key (overrides PAGESPEED_API_KEY env var)
-h, --help Print help
```
**示例:**
```
# 使用默认阈值进行审计(移动端策略)
oxide-ci lighthouse --url https://yourapp.com
# 使用更严格性能阈值的桌面端审计
oxide-ci lighthouse --url https://yourapp.com --strategy desktop --min-performance 90
# 使用 API key 获取更高配额(未认证配额:少量请求/天)
oxide-ci lighthouse --url https://yourapp.com --key AIza...
# 从 .oxideci.toml 读取 URL 和阈值
oxide-ci lighthouse
```
**API key:** PageSpeed Insights API 偶尔运行(开发、不频繁的 CI)无需 key 即可工作。对于在每个 PR 上运行的生产 CI pipelines,请在 [Google Cloud Console](https://console.cloud.google.com/apis/library/pagespeedonline.googleapis.com) 中创建一个免费 key 并通过 `PAGESPEED_API_KEY` 环境变量传递它:
```
export PAGESPEED_API_KEY=AIza...
oxide-ci lighthouse --url https://yourapp.com
```
**示例输出:**
```
ℹ️ Running Lighthouse audit: https://yourapp.com (mobile)
Performance: 87 ✅ (min: 80)
Accessibility: 95 ✅ (min: 90)
Best Practices: 75 ❌ (min: 80)
SEO: 98 ✅ (min: 80)
Error: Lighthouse failed: 1 category/-ies below threshold.
```
**配置(`.oxideci.toml`):**
```
[lighthouse]
url = "https://yourapp.com"
strategy = "mobile" # mobile | desktop
min_performance = 80
min_accessibility = 90
min_best_practices = 80
min_seo = 80
# api_key = "" # 首选 PAGESPEED_API_KEY env var
```
### `reassure` — React 组件性能门禁
解析由 [Reassure](https://github.com/callstack/reassure)(`reassure measure`)生成的 JSON 性能报告,如果任何组件的平均渲染时间超过可配置的阈值倒退,或者渲染次数增加,则使 CI 失败。
Reassure 通过多次运行每个测试场景(默认 10 次迭代 × 5 次运行)来测量真实的组件性能。输出是一个 `.perf` JSON 文件,oxide-ci 直接读取该文件 — 门禁时不需要 Node.js。
```
oxide-ci reassure [OPTIONS]
Options:
--current Path to current.perf file [default: output/current.perf]
--baseline Path to baseline.perf file [default: output/baseline.perf]
--threshold % mean-time increase allowed before failure [default: 15]
-h, --help Print help
```
**典型的 CI 工作流:**
```
# 1. 在您的前端项目中,运行 Reassure 以生成 current.perf
npx reassure measure
# 2. 使用 oxide-ci 对回归进行把关
oxide-ci reassure
# 3. 要与保存的 baseline 进行比较,首先保存它:
cp output/current.perf output/baseline.perf # after a known-good run
# 然后在后续运行中,oxide-ci 会自动比较 current 与 baseline
```
**倒退规则:**
| 条件 | 结果 |
|---|---|
| `meanTime` 增加超过 `threshold`% | ❌ 失败 |
| `renders` 计数相对于 baseline 增加 | ❌ 失败 |
| 未找到 `baseline.perf` | 仅报告(信息性,无失败) |
| 新组件无 baseline 条目 | 列为 `new`,不标记 |
**示例输出(带 baseline):**
```
ℹ️ Parsing Reassure report: output/current.perf
ℹ️ Baseline found: output/baseline.perf
Component Mean (ms) Renders Δ Mean Δ Renders
────────────────────────────────────────────────────────────────────────────────────
ProductList render 15.4 2.3 +2.1% ─
HeavyList render 42.1 3.0 +21.3% ❌ ─
SearchBox render 8.9 1.0 -5.2% ─
NewComponent render 6.3 1.0 new ─
Error: Reassure failed: 1 component(s) exceed the 15.0% regression threshold.
```
**示例输出(无 baseline — 仅报告模式):**
```
ℹ️ Parsing Reassure report: output/current.perf
⚠️ Baseline file not found — running in report-only mode.
Component Mean (ms) Renders
─────────────────────────────────────────────────────────────
ProductList render 15.4 2.3
HeavyList render 42.1 3.0
SearchBox render 8.9 1.0
ℹ️ No baseline provided — metrics reported above (no gating applied).
```
**配置(`.oxideci.toml`):**
```
[reassure]
current = "output/current.perf"
baseline = "output/baseline.perf"
threshold = 15.0 # % mean-time regression allowed
```
**在 React 项目中设置 Reassure:**
```
# 安装
npm install --save-dev reassure
# 编写性能测试(例如 __perf__/ProductList.perf.tsx)
import { measureRenders } from 'reassure';
import { ProductList } from '../ProductList';
test('ProductList render', async () => {
await measureRenders( );
});
# 运行测量(生成 output/current.perf)
npx reassure measure
# 然后使用 oxide-ci 进行把关
oxide-ci reassure --threshold 10
```
### `sbom` — SBOM 生成
从项目的 lock 文件生成 [CycloneDX 1.5](https://cyclonedx.org/specification/overview/) 软件物料清单。不需要互联网访问。
```
oxide-ci sbom [OPTIONS]
Options:
-o, --output Write SBOM to a file instead of stdout
```
**支持的 lock 文件**(按顺序检查):`Cargo.lock`、`package-lock.json`、`requirements.txt`、`go.sum`
```
# 打印到 stdout
oxide-ci sbom
# 写入文件
oxide-ci sbom --output sbom.json
```
每个组件包括 `name`、`version`、`purl` (Package URL) 和 `scope: required`。CycloneDX SBOMs 被 Dependency-Track、FOSSA、Grype、Trivy 和大多数企业合规平台接受。
### `check-config` — 验证配置
读取 `.oxideci.toml`,验证它,并打印所有解析后的配置值。在运行 CI 之前确认覆盖已正确应用非常有用。
```
oxide-ci check-config
# 应用 profile 预览合并后的值
oxide-ci --profile strict check-config
```
配置有效时(或文件不存在时,打印内置默认值)退出码为 0。如果文件有解析错误则退出码为 1。
## `docker-lint` — Dockerfile Linting
检查 `Dockerfile` 是否违反 8 条规则的最佳实践。
```
oxide-ci docker-lint [--file ]
```
| 规则 | 捕获内容 |
|---|---|
| `no-latest-image` | `FROM node:latest` 或未标记的 `FROM node` |
| `prefer-copy-over-add` | `ADD` 在 `COPY` 足够的地方使用 |
| `no-user-directive` | 没有 `USER` 指令 — 默认以 root 运行 |
| `no-root-user` | 显式的 `USER root` 或 `USER 0` |
| `no-healthcheck` | 缺少 `HEALTHCHECK` 指令 |
| `secret-in-env` | `ENV API_KEY=…`、`ENV PASSWORD=…` 烘焙到镜像层中 |
| `apt-no-recommends` | `apt-get install` 没有 `--no-install-recommends` |
| `apt-stale-cache` | `apt-get update` 和 `apt-get install` 在单独的 `RUN` 层中 |
在 `.oxideci.toml` 中配置默认路径:
```
[docker]
dockerfile = "Dockerfile"
```
## Baseline 模式 — `--update-baseline` / `--since-baseline`
在有现有发现项的仓库中,baseline 模式允许 CI 仅对 PR 引入的**新**发现项进行门禁 — 而不会因团队尚未修复的先前存在的问题而失败。
**步骤 1:保存 baseline**(在您的主分支上运行一次,提交输出)
```
oxide-ci scan --update-baseline
# 写入 .oxide-baseline.json
git add .oxide-baseline.json && git commit -m "chore: add oxide-ci scan baseline"
```
**步骤 2:在 CI 中使用 baseline**(PR 仅因新发现项而失败)
```
oxide-ci scan --since-baseline
```
Baseline 存储 `(file, rule, line)` 指纹。移动到不同行的 secret 被视为新发现项并重新审查。
## `init` — 交互式设置向导
通过询问几个问题生成定制的 `.oxideci.toml`。最快的入门方式。
```
oxide-ci init # guided setup
oxide-ci init --force # overwrite existing config
```
示例会话:
```
oxide-ci init — generating .oxideci.toml
[ Secret & SAST Scanning ]
Enable entropy-based secret detection? [Y/n]:
Entropy threshold [4.5]:
[ Coverage Gate ]
LCOV file path [coverage/lcov.info]:
Minimum coverage % [80]:
[ Docker Lint ]
Dockerfile path (leave blank to skip) []:
[ Pipeline Runner ]
Generate a default pipeline (oxide-ci run)? [Y/n]:
✅ .oxideci.toml written successfully.
```
## `watch` — 实时文件监视器
每次源文件更改时自动重新运行扫描。在主动开发期间很有用。
```
oxide-ci watch # watch full working tree
oxide-ci watch --staged # only scan staged files on change
oxide-ci watch --interval 500 # poll every 500ms
```
与 CI 模式不同,`watch` **不会因发现项而退出** — 它报告它们并继续监视,以便您可以就地修复。
## `run` — Pipeline Runner
使用 `.oxideci.toml` 中定义的步骤按顺序运行所有质量门禁。第一次失败会停止 pipeline。
```
oxide-ci run
```
定义您的 pipeline:
```
[pipeline]
steps = [
"scan",
"audit",
"coverage --min 80",
"lint --dir ./k8s",
"docker-lint",
"lighthouse",
]
```
每个步骤直接映射到一个 `oxide-ci` 子命令。内联 flags 覆盖该步骤的配置值。使用 `oxide-ci init` 自动生成启动 pipeline。
## Secret 检测模式
OxideCI 附带 26 种内置模式,涵盖最常见的云提供商和服务。所有模式对于非 JS/TS 文件按行应用,对于 JS/TS/TSX/JSX 文件则范围限定为字符串字面量(无注释噪音)。
### AWS
| Rule ID | 检测内容 |
|---|---|
| `AWS Access Key` | IAM access key IDs(`AKIA…16 chars`) |
| `AWS Secret Key` | 配置文件中的 `aws_secret_access_key = …40 chars` |
### Azure
| Rule ID | 检测内容 |
|---|---|
| `Azure Storage Connection String` | 包含 `DefaultEndpointsProtocol` + `AccountKey` 的完整连接字符串 |
| `Azure SAS Token` | 包含 `sv=20XX-XX-XX` + `&sig=` 的 Shared Access Signature URLs |
### GCP / Google Cloud
| Rule ID | 检测内容 |
|---|---|
| `Google API Key` | Browser/server API keys(`AIza…35 chars`);也捕获 Firebase API keys |
| `GCP Service Account Key` | Service account JSON 文件(`"type": "service_account"`);也捕获 `google-services.json` |
| `GCP OAuth2 Token` | 短期访问令牌(`ya29.…`) |
### DigitalOcean
| Rule ID | 检测内容 |
|---|---|
| `DigitalOcean PAT` | 个人访问令牌(`dop_v1_…64 chars`) |
### Alibaba Cloud
| Rule ID | 检测内容 |
|---|---|
| `Alibaba Cloud Access Key ID` | Access key IDs(`LTAI…14-20 chars`) |
### GitHub
| Rule ID | 检测内容 |
|---|---|
| `GitHub PAT (classic)` | 经典个人访问令牌(`ghp_…36 chars`) |
| `GitHub PAT (fine-grained)` | 细粒度个人访问令牌(`github_pat_…82 chars`) |
### 通信与支付
| Rule ID | 检测内容 |
|---|---|
| `Slack Webhook` | Incoming webhook URLs(`hooks.slack.com/services/…`) |
| `Stripe Secret Key` | Live secret keys(`sk_live_…24 chars`) |
| `Stripe Publishable Key` | Live publishable keys(`pk_live_…24`) |
| `SendGrid API Key` | API keys(`SG.22chars.43chars`) |
| `Mailgun API Key` | API keys(`key-…32 chars`) |
| `Twilio Account SID` | Account SIDs(`AC` + 32 个小写十六进制字符) |
### 基础设施
| Rule ID | 检测内容 |
|---|---|
| `HashiCorp Vault Token` | Service tokens(`hvs.…90+ chars`) |
| `PEM Private Key` | RSA、EC、DSA、OPENSSH 私钥头 |
| `JWT Token` | 三部分 base64url 令牌(`eyJ…`) |
### React Native / Mobile
| Rule ID | 检测内容 |
|---|---|
| `Expo Access Token` | EAS CLI robot/personal tokens(`expa_…40+ chars`) |
| `Sentry DSN` | 错误报告 DSN(`https://key@o123.ingest.sentry.io/project`) |
| `Mapbox Secret Token` | Secret tokens(`sk.eyJ…`);public tokens(`pk.eyJ…`)不被标记 |
### PII
| Rule ID | 检测内容 |
|---|---|
| `Generic PII (SSN)` | 美国社会安全号码(`XXX-XX-XXXX`) |
| `Generic PII (Email)` | 电子邮件地址 |
### Shannon 熵检测
除了命名模式外,oxide-ci 还标记不匹配任何已知模式的高熵令牌 — 捕获无法识别的 API keys、随机 secrets 和不透明凭证:
```
[scan]
entropy = true # enable/disable (default: true)
entropy_threshold = 4.5 # Shannon entropy score; lower = more sensitive (default: 4.5)
entropy_min_length = 20 # minimum token length before entropy is checked (default: 20)
```
### 添加自定义模式
使用 `.oxideci.toml` 中的 `extra_patterns` 添加您自己的模式而无需 fork:
```
[scan]
extra_patterns = [
{ name = "Internal API Token", regex = "myapp_[a-z0-9]{32}" },
{ name = "Database URL", regex = "postgres://[^@]+@[^/]+" },
]
```
## SAST 规则参考
规则使用 tree-sitter AST 查询在 `.js`、`.jsx`、`.ts`、`.tsx`、`.py` 和 `.go` 文件上检查。它们基于代码结构触发,而不是字符串内容。
### XSS sinks (JS/TS)
| Rule ID | 触发条件 | 风险 |
|---|---|---|
| `SAST/DangerouslySetInnerHTML` | ` ` | 通过 React 绕过 XSS |
| `SAST/InnerHTMLAssignment` | `el.innerHTML = expr` | DOM XSS |
| `SAST/OuterHTMLAssignment` | `el.outerHTML = expr` | DOM XSS |
| `SAST/DocumentWrite` | `document.write(expr)` | 旧版 DOM XSS |
| `SAST/DocumentWriteln` | `document.writeln(expr)` | 旧版 DOM XSS |
### 代码注入 (JS/TS)
| Rule ID | 触发条件 | 风险 |
|---|---|---|
| `SAST/EvalUsage` | `eval(expr)` | 任意代码执行 |
| `SAST/FunctionConstructor` | `new Function(...)` | 任意代码执行 |
| `SAST/SetTimeoutString` | `setTimeout("string", delay)` | eval 等效 |
| `SAST/SetIntervalString` | `setInterval("string", delay)` | eval 等效 |
### 命令注入 (Node.js)
| Rule ID | 触发条件 | 风险 |
|---|---|---|
| `SAST/ChildProcessExec` | `cp.exec(cmd)` | OS 命令注入 |
| `SAST/ChildProcessExecSync` | `cp.execSync(cmd)` | OS 命令注入 |
| `SAST/ChildProcessSpawn` | `cp.spawn(cmd, args)` | OS 命令注入 |
| `SAST/ChildProcessExecFile` | `cp.execFile(path)` | OS 命令注入 |
### Python 规则
| Rule ID | 触发条件 | 严重性 |
|---|---|---|
| `SAST/PythonEval` | `eval(expr)` | critical |
| `SAST/PythonExec` | `exec(code)` | critical |
| `SAST/PythonPickle` | `pickle.load(f)` / `pickle.loads(data)` | high |
| `SAST/PythonSubprocessShell` | 任何带有 `shell=True` 关键字参数的调用 | high |
| `SAST/PythonYamlLoad` | `yaml.load(data)` — 改用 `yaml.safe_load` | high |
### Go 规则
| Rule ID | 触发条件 | 严重性 |
|---|---|---|
| `SAST/GoUnsafe` | `import "unsafe"` | high |
| `SAST/GoExecCommand` | `exec.Command(cmd, ...)` | high |
| `SAST/GoPanic` | `panic(...)` | medium |
### 代码异味 / 复杂度(仅限 JS/TS)
| Rule ID | 触发条件 | 默认值 |
|---|---|---|
| `SMELL/LongFunction` | 函数体超过 `max_function_lines` 行 | 50 行 |
| `SMELL/TooManyParameters` | 函数有超过 `max_parameters` 个参数 | 5 个参数 |
| `SMELL/DeepNesting` | 控制流嵌套深度超过 `max_nesting_depth` | 4 层 |
Rule IDs 嵌入测量值 — 例如 `SMELL/LongFunction (63 lines, max 50)` — 因此发现项无需额外上下文即可自我解释。阈值可在 `.oxideci.toml` 中按项目配置。详情请参阅 [配置文件](#configuration-file-oxidecitorml)。
## 抑制发现项
在发现项的同一行添加 `// oxide-ci: ignore` 以抑制它:
```
const legacyKey = "AKIAIOSFODNN7EXAMPLE123"; // oxide-ci: ignore
el.innerHTML = sanitizedHtml; // oxide-ci: ignore
eval(trustedAdminScript); // oxide-ci: ignore
```
抑制适用于 secret/PII 发现项和 SAST 危险模式发现项。它按行应用 — 仅抑制该确切行的发现项。
## 配置文件(`.oxideci.toml`)
将 `.oxideci.toml` 放在仓库的根目录中。CLI flags 始终覆盖配置文件值。
```
[scan]
# 扫描期间要跳过的路径 Glob 模式
exclude_patterns = [
"tests/**",
"*.test.ts",
"fixtures/**",
"vendor/**",
]
# 在 26 个内置模式之上的额外模式
extra_patterns = [
{ name = "Internal Service Token", regex = "svc_[a-z0-9]{40}" },
]
# Shannon entropy 检测(标记高熵令牌,如无法识别的 API keys)
entropy = true
entropy_threshold = 4.5 # lower = more sensitive
entropy_min_length = 20 # ignore tokens shorter than this
[sast]
# 设置为 false 以对 JS/TS 文件完全禁用 SAST(回退到纯 regex)
enabled = true
# 抑制在您的代码库中产生噪音的特定 SAST rule ID
disabled_rules = [
# "SAST/ChildProcessExec",
# "SAST/EvalUsage",
# "SMELL/LongFunction",
]
# 代码异味阈值(显示默认值)
max_function_lines = 50 # flag functions longer than this many lines
max_parameters = 5 # flag functions with more than this many parameters
max_nesting_depth = 4 # flag control-flow nesting deeper than this inside a function
# 使用 tree-sitter S-expression 查询的自定义规则
# 每条规则必须包含一个 @match capture,标记要报告的最外层节点。
custom_rules = [
# { id = "CUSTOM/FetchCall", query = "(call_expression function: (identifier) @_fn (#eq? @_fn \"fetch\") @match)" },
]
[coverage]
# 默认 LCOV 文件路径(被 --file 覆盖)
file = "coverage/lcov.info"
# 默认最低阈值(被 --min 覆盖)
min = 85.0
[lint]
# 扫描 Kubernetes manifests 的默认目录(被 --dir 覆盖)
target_dir = "./infrastructure/k8s"
[lighthouse]
# 要审计的已部署应用的 URL(被 --url 覆盖)
url = "https://yourapp.com"
# 设备策略:mobile(默认)或 desktop(被 --strategy 覆盖)
strategy = "mobile"
# 每类最低分数 0–100(被 --min-* flags 覆盖)
min_performance = 80
min_accessibility = 90
min_best_practices = 80
min_seo = 80
# API key(可选;首选 PAGESPEED_API_KEY env var)
# api_key = ""
[reassure]
# Reassure current 测量文件的路径(被 --current 覆盖)
current = "output/current.perf"
# Reassure baseline 文件的路径(被 --baseline 覆盖)
# 如果不存在,oxide-ci 将以仅报告模式运行(不会失败)
baseline = "output/baseline.perf"
# 失败前的最大平均耗时回归百分比(被 --threshold 覆盖)
threshold = 15.0
```
所有字段都是可选的。省略的值回退到安全默认值。CLI flags 始终优先于配置文件值。
## 输出格式
`scan` 命令通过 `--format` 支持五种输出格式:
### `text`(默认)
人类可读的输出到 stderr,每个发现项都有严重性前缀。
```
- [CRITICAL] [AWS Access Key] src/config.ts:14
- [HIGH] [SAST/InnerHTMLAssignment] src/components/Widget.tsx:88
```
### `json`
机器可读的 JSON 写入 stdout。每个发现项包含 `severity` 字段。
```
{
"total": 1,
"findings": [
{ "rule": "SAST/EvalUsage", "file": "./src/utils.js", "line": 42, "severity": "critical" }
]
}
```
### `sarif`
SARIF 2.1.0 JSON 写入 stdout。直接上传到 GitHub Advanced Security 以获取内联 PR annotations。
```
oxide-ci scan --format sarif > results.sarif
```
### `junit`
JUnit XML 写入 stdout。与 Jenkins、Azure DevOps 和 CircleCI 测试报告解析器兼容。
```
oxide-ci scan --format junit > results.xml
```
### `gitlab`
GitLab SAST Security Scanner JSON(schema v15.0.6)写入 stdout。用作 GitLab 安全 artifact 以在 Merge Request 安全报告中显示发现项。
```
# .gitlab-ci.yml
secret-scan:
script: oxide-ci scan --format gitlab > gl-sast-report.json
artifacts:
reports:
sast: gl-sast-report.json
```
## 配置 Profiles
在加载的配置之上应用命名质量 profile,而无需编辑 `.oxideci.toml`。在子命令之前传递 `--profile` 作为全局 flag:
```
oxide-ci --profile strict scan
oxide-ci --profile ci scan --staged
oxide-ci --profile relaxed coverage
```
| Profile | 效果 |
|---|---|
| `strict` | Coverage ≥ 90%,熵阈值 3.5(更敏感),Lighthouse performance ≥ 90 & accessibility ≥ 95,SAST 启用 |
| `relaxed` | Coverage ≥ 70%,熵阈值 5.0(更少误报) |
| `ci` | Coverage ≥ 80%,SAST 启用,`SMELL/*` 规则禁用以减少 CI 中的噪音 |
Profiles 仅修改内存中的配置 — 它们从不写入 `.oxideci.toml`。
## 退出码
| 代码 | 含义 |
|---|---|
| `0` | 所有检查通过 — 可以安全继续 |
| `1` | 检查失败(发现 secrets、SAST 问题、lint 问题、覆盖率低于阈值、检测到漏洞)或工具错误 |
## CI/CD 集成
### GitHub Actions — 完整 pipeline
```
name: OxideCI Quality Gate
on: [push, pull_request]
permissions:
contents: read
security-events: write # required for SARIF upload and Check Runs
checks: write # required for --annotate (GitHub Check Runs)
pull-requests: write # required for --annotate (PR review comment)
jobs:
# ── Security & code-quality gates ──────────────────────────────────────────
oxide-ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install OxideCI
run: |
curl -sL https://github.com/ThinkGrid-Labs/oxide-ci/releases/latest/download/oxide-ci-linux-amd64 \
-o /usr/local/bin/oxide-ci
chmod +x /usr/local/bin/oxide-ci
# Option A: Native GitHub Check Run annotations (no SARIF upload step needed)
- name: Secret, PII & SAST Scan
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: oxide-ci scan --annotate
# Option B: SARIF upload to GitHub Advanced Security (alternative to --annotate)
# - name: Scan (SARIF for PR annotations)
# run: oxide-ci scan --format sarif > results.sarif
# if: always()
# continue-on-error: true
# - name: Upload SARIF
# uses: github/codeql-action/upload-sarif@v4
# if: always()
# with:
# sarif_file: results.sarif
# continue-on-error: true
- name: Kubernetes Lint
run: oxide-ci lint --dir ./k8s
- name: Coverage Gate
run: oxide-ci coverage --file coverage/lcov.info --min 80
- name: Dependency Audit
run: oxide-ci audit
# ── Performance gates (post-deploy) ────────────────────────────────────────
perf:
runs-on: ubuntu-latest
# needs: [deploy] # uncomment and set your deploy job name
steps:
- uses: actions/checkout@v4
- name: Install OxideCI
run: |
curl -sL https://github.com/ThinkGrid-Labs/oxide-ci/releases/latest/download/oxide-ci-linux-amd64 \
-o /usr/local/bin/oxide-ci
chmod +x /usr/local/bin/oxide-ci
# Lighthouse — gates on PageSpeed scores for the deployed URL.
# Set LIGHTHOUSE_URL as a repository variable (Settings → Variables).
# Set PAGESPEED_API_KEY as a repository secret for higher quota.
- name: Lighthouse audit
if: ${{ vars.LIGHTHOUSE_URL != '' }}
env:
PAGESPEED_API_KEY: ${{ secrets.PAGESPEED_API_KEY }}
run: |
oxide-ci lighthouse \
--url "${{ vars.LIGHTHOUSE_URL }}" \
--strategy mobile \
--min-performance 80 \
--min-accessibility 90
# Reassure — gates on React component render regressions.
# Your frontend test job should run `reassure measure` and upload
# output/current.perf as an artifact, then download it here.
- name: Download Reassure report
uses: actions/download-artifact@v4
with:
name: reassure-report
path: output/
continue-on-error: true # skip gracefully if artifact not found
- name: Reassure performance gate
if: hashFiles('output/current.perf') != ''
run: oxide-ci reassure --threshold 15
```
### GitLab CI
```
stages:
- security
- quality
variables:
OXIDE_CI_URL: https://github.com/ThinkGrid-Labs/oxide-ci/releases/latest/download/oxide-ci-linux-amd64
.install_oxide: &install_oxide
before_script:
- curl -sL $OXIDE_CI_URL -o /usr/local/bin/oxide-ci
- chmod +x /usr/local/bin/oxide-ci
secret-and-sast-scan:
stage: security
<<: *install_oxide
script:
- oxide-ci scan
k8s-lint:
stage: security
<<: *install_oxide
script:
- oxide-ci lint --dir ./k8s
coverage-gate:
stage: quality
<<: *install_oxide
script:
- oxide-ci coverage --file coverage/lcov.info --min 80
dependency-audit:
stage: security
<<: *install_oxide
script:
- oxide-ci audit
allow_failure: true # optional: don't block pipeline on network issues
```
### Bitbucket Pipelines
```
image: ubuntu:22.04
pipelines:
default:
- step:
name: OxideCI Security & Quality Gates
script:
- apt-get update -qq && apt-get install -y curl
- curl -sL https://github.com/ThinkGrid-Labs/oxide-ci/releases/latest/download/oxide-ci-linux-amd64
-o /usr/local/bin/oxide-ci
- chmod +x /usr/local/bin/oxide-ci
- oxide-ci scan
- oxide-ci lint --dir ./k8s
- oxide-ci coverage --file coverage/lcov.info --min 80
- oxide-ci audit
```
### CircleCI
```
version: 2.1
jobs:
oxide-ci:
docker:
- image: cimg/base:stable
steps:
- checkout
- run:
name: Install OxideCI
command: |
curl -sL https://github.com/ThinkGrid-Labs/oxide-ci/releases/latest/download/oxide-ci-linux-amd64 \
-o /usr/local/bin/oxide-ci
chmod +x /usr/local/bin/oxide-ci
- run:
name: Secret, PII & SAST Scan
command: oxide-ci scan
- run:
name: Kubernetes Lint
command: oxide-ci lint --dir ./k8s
- run:
name: Coverage Gate
command: oxide-ci coverage --file coverage/lcov.info --min 80
- run:
name: Dependency Audit
command: oxide-ci audit
workflows:
quality:
jobs:
- oxide-ci
```
### Pre-commit(本地强制执行)
在本地强制执行 secrets 扫描的最快方法 — 在每次 `git commit` 时自动运行:
```
oxide-ci install-hooks
```
要移除 hook:
```
rm .git/hooks/pre-commit
```
## 架构
```
oxide-ci/
├── src/
│ ├── main.rs # CLI entry point (clap)
│ ├── modules/
│ │ ├── scanner.rs # Secret/PII scanning (rayon parallel) + SAST orchestration
│ │ ├── sast.rs # AST-based SAST for JS/TS/TSX/JSX (tree-sitter)
│ │ ├── github.rs # GitHub Check Runs + PR review comment (--annotate)
│ │ ├── k8s_lint.rs # Kubernetes manifest linter (serde_yaml)
│ │ ├── coverage.rs # LCOV & Cobertura XML parser and threshold gate
│ │ ├── audit.rs # OSV dependency audit (ureq)
│ │ ├── hooks.rs # Git hook installer
│ │ ├── perf_lighthouse.rs # PageSpeed Insights Lighthouse gate (ureq)
│ │ └── reassure.rs # Reassure .perf report parser and gate
│ └── utils/
│ ├── config.rs # .oxideci.toml loader (toml + serde)
│ ├── files.rs # File walker (ignore crate)
│ └── terminal.rs # Styled output + progress bars (indicatif)
└── tests/
└── integration_test.rs # End-to-end binary tests
```
**JS/TS 文件的扫描 pipeline:**
```
collect_findings()
│
├── non-JS/TS files ──→ run_regex_scan() (rayon parallel, per-line regex + entropy)
│
└── JS/TS files ──────→ run_sast_scan() (rayon parallel, tree-sitter per file)
│
├── parse AST (tree-sitter)
├── scan_string_literals() ← secrets/PII scoped to string nodes
├── scan_dangerous_patterns() ← 13 structural rules + custom rules
└── scan_complexity() ← 3 code smell rules
(long function, params, nesting)
emit_findings() ← text / JSON / SARIF
│
└── --annotate ──→ github::annotate() ← GitHub Check Run + PR comment (no-op if env absent)
```
**依赖项:**
| Crate | 用途 |
|---|---|
| `clap` | CLI 参数解析 |
| `rayon` | CPU 密集型并行(文件扫描) |
| `ignore` | gitignore 感知的文件遍历 |
| `regex` | Secret 模式匹配 |
| `tree-sitter` | AST 解析引擎 |
| `tree-sitter-javascript` | JS/JSX 语法 |
| `tree-sitter-typescript` | TS/TSX 语法 |
| `streaming-iterator` | tree-sitter 0.24 `QueryMatches` API 必需 |
| `serde` + `serde_json` | JSON 输出(SARIF、audit、GitHub API bodies) |
| `serde_yaml` | Kubernetes YAML 解析 |
| `roxmltree` | 零拷贝 Cobertura XML 解析 |
| `toml` | 配置文件解析 |
| `ureq` | HTTP 客户端(OSV audit、PageSpeed、GitHub APIs) |
| `indicatif` | 进度条 |
| `anyhow` | 错误处理和传播 |
## React Native
oxide-ci 开箱即用地支持 React Native 和 Expo 项目。npm、Yarn 和 pnpm lock 文件都支持依赖审计,SAST 自动在所有 JS/TS/TSX 文件上运行,而最初由 Callstack *为* React Native 构建的 Reassure 是一等公民。
### 命令兼容性
| 命令 | React Native 支持 | 备注 |
|---|---|---|
| `scan` | ✅ 完全 | Secrets + PII + JS/TS/TSX 文件上的 SAST;gitignore 感知(自动跳过 `node_modules/`) |
| `audit` | ✅ 完全 | 读取 `package-lock.json`、`yarn.lock` 和 `pnpm-lock.yaml`;查询 OSV 获取 npm CVEs |
| `coverage` | ✅ 完全 | 读取 Jest LCOV 输出(`--coverageReporters=lcov`) |
| `install-hooks` | ✅ 完全 | Pre-commit hook 适用于任何 git repo |
| `reassure` | ✅ 完全 | 为 React Native 构建;解析 `reassure measure` 的 `output/current.perf` |
| `lint` | ⚠️ 可选 | 仅在项目有 Kubernetes 后端时有用 |
| `lighthouse` | ⚠️ 仅限 Web | 审计公共 URL;如果您发布 React Native Web build 或营销网站则适用 |
### React Native 特定的 secrets 检测
除了 23 种内置云模式外,oxide-ci 还检测 RN 项目中常见的这些模式(范围限定为 JS/TS 文件中的字符串字面量):
| 规则 | 检测内容 |
|---|---|
| `Expo Access Token` | EAS CLI robot/personal tokens(`expa_…`) |
| `Sentry DSN` | Sentry 错误报告 DSN(配额耗尽 + 事件读取风险) |
| `Mapbox Secret Token` | Mapbox secret tokens(`sk.eyJ…`);public tokens(`pk.eyJ…`)不被标记 |
| `Google API Key` | Firebase API keys(`AIza…`) — 与 GCP 前缀相同,已内置 |
| `GCP Service Account Key` | `google-services.json` 泄露 — 已内置 |
### React Native 项目中的 SAST
SAST 在 RN/Expo 代码库中特别有价值,因为:
- **`dangerouslySetInnerHTML`** — `SAST/DangerouslySetInnerHTML` 在 TSX/JSX 文件中捕获此问题。React Native 本身不渲染 HTML,但 React Native Web builds 会。
- **`eval`** — `SAST/EvalUsage` 标记 JS bundles 中的动态代码评估。Metro bundler 在最终 bundle 中包含所有 JS,使 eval 成为供应链风险。
- **Node.js build scripts** — `SAST/ChildProcessExec` / `SAST/ChildProcessSpawn` 标记自定义 Metro 配置、build scripts 和 Expo plugins 中的 shell 命令。
### React Native 的推荐 `.oxideci.toml`
```
[scan]
exclude_patterns = [
# Build artifacts
"android/build/**",
"android/.gradle/**",
"ios/build/**",
"ios/Pods/**",
# Expo cache and generated files
".expo/**",
".expo-shared/**",
# Metro bundler cache
".metro-cache/**",
# Test fixtures that intentionally contain fake patterns
"__tests__/**",
"__mocks__/**",
# React Native generated bundle
"android/app/src/main/assets/index.android.bundle",
]
# Shannon entropy 捕获未被显式规则匹配的随机 API keys。
entropy = true
entropy_threshold = 4.5
entropy_min_length = 20
[sast]
enabled = true
# disabled_rules = [] # 取消注释以抑制特定规则
[coverage]
file = "coverage/lcov.info"
min = 80.0
[reassure]
current = "output/current.perf"
baseline = "output/baseline.perf"
threshold = 15.0
```
### GitHub Actions — React Native pipeline
```
name: React Native CI
on: [push, pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install oxide-ci
run: |
curl -sL https://github.com/ThinkGrid-Labs/oxide-ci/releases/latest/download/oxide-ci-linux-amd64 \
-o /usr/local/bin/oxide-ci
chmod +x /usr/local/bin/oxide-ci
- name: Secret, PII & SAST scan
run: oxide-ci scan
- name: Dependency audit (npm CVEs via OSV)
run: oxide-ci audit # reads package-lock.json / yarn.lock / pnpm-lock.yaml
- name: Coverage gate
run: oxide-ci coverage # reads coverage/lcov.info (generated by jest --coverage)
perf:
runs-on: ubuntu-latest
needs: quality
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Run Reassure measurement
run: npx reassure measure
# Produces output/current.perf
- name: Install oxide-ci
run: |
curl -sL https://github.com/ThinkGrid-Labs/oxide-ci/releases/latest/download/oxide-ci-linux-amd64 \
-o /usr/local/bin/oxide-ci
chmod +x /usr/local/bin/oxide-ci
- name: Reassure performance gate
run: oxide-ci reassure --threshold 15
# Fails if any component regresses > 15% vs baseline.perf
```
## 故障排除
### SARIF 上传失败并提示“Resource not accessible by integration”
```
Error: Resource not accessible by integration
```
这是**私有仓库的预期行为**。将 SARIF 结果上传到 GitHub Security 选项卡需要 [GitHub Advanced Security (GHAS)]( ),即:
- 对于公共仓库**免费**
- 对于私有仓库是**付费附加组件**(GitHub Enterprise 的一部分)
`oxide-ci scan` 步骤本身仍会运行,如果发现真正的 secrets 或 SAST 问题将使作业失败 — 您的安全门禁完好无损。SARIF 上传仅用于 Security 选项卡中的内联 PR annotations。
**选项:**
| 选项 | 何时使用 |
|---|---|
| 保留 `continue-on-error: true`(默认) | 私有 repo,无 GHAS — 扫描仍会因发现项而阻止 |
| 启用 GitHub Advanced Security | 您拥有 GitHub Enterprise 或想要内联 PR annotations |
| 移除 SARIF 上传步骤 | 您不需要 Security 选项卡集成 |
### 来自 lockfiles 的太多误报
包管理器在 lockfiles(`pnpm-lock.yaml`、`yarn.lock`、`package-lock.json`)中存储 sha512 完整性哈希。这些看起来像高熵 secrets 并会产生数百个误报。
**修复:** 在 `.oxideci.toml` 中排除 lockfiles:
```
[scan]
exclude_patterns = [
"pnpm-lock.yaml",
"yarn.lock",
"package-lock.json",
"Cargo.lock", # sha256 checksums
]
```
### 来自 SVG 和压缩文件的高熵误报
编译或生成的文件通常包含 base64 编码的数据和非 secrets 的高熵字符串:
| 文件类型 | 标记原因 |
|---|---|
| `favicon.svg` | 嵌入的 base64 图像数据 |
| `pdf.worker.min.mjs` / `*.min.js` | 压缩的第三方库代码 |
| `*.chunk.js` | Webpack/Next.js 构建输出 |
**修复:** 排除公共资源和压缩文件:
```
[scan]
exclude_patterns = [
"**/public/**", # static assets directory
"**/*.min.js",
"**/*.min.mjs",
".next/**", # Next.js build output
"dist/**",
"build/**",
]
```
### Sentry 配置文件因 PII (Email) 被标记
Sentry DSN URLs 包含 `@` 符号(例如 `https://abc123@o123.ingest.sentry.io/456`),这会触发 `Generic PII (Email)` 模式。在正确配置的项目中,DSN 从环境变量(`NEXT_PUBLIC_SENTRY_DSN`)加载,因此源文件不包含硬编码的 secret。
**修复:** 排除 Sentry 和 instrumentation 配置文件:
```
[scan]
exclude_patterns = [
"**/sentry.client.config.ts",
"**/sentry.server.config.ts",
"**/sentry.edge.config.ts",
"**/instrumentation.ts",
]
```
### Test fixtures 因 PII (Email) 被标记
测试文件通常使用像 `user@example.com` 这样的占位符地址作为输入 fixtures。这些不是真正的 PII。
**修复:** 排除测试文件和目录:
```
[scan]
exclude_patterns = [
"**/*.test.ts",
"**/*.test.tsx",
"**/*.spec.ts",
"**/*.spec.tsx",
"**/__tests__/**",
]
```
### 文档或 UI 组件中的 Emails 被标记为 PII
`Generic PII (Email)` 模式捕获任何电子邮件形状的字符串。页脚、文档、表单占位符或帮助页面中的联系地址是有意的 — 不是 secrets。
**修复:** 排除特定文件或目录:
```
[scan]
exclude_patterns = [
"docs/**",
"*.md",
"**/components/footer/**",
"**/components/forms/**", # input placeholder emails
"**/app/**/help/**", # contact emails on help pages
]
```
### `.oxideci.toml` 本身被标记
如果您的配置文件在注释中包含示例电子邮件(例如 `user@example.com`),oxide-ci 将标记配置文件本身。排除它:
```
[scan]
exclude_patterns = [
".oxideci.toml",
]
```
### SAST 规则因故意使用而触发
某些 SAST 规则(例如 `SAST/ChildProcessExec`)在任何模式使用时都会触发,即使在 build script 或 CLI 工具中是故意的。有两种处理方法:
**选项 1 — 内联抑制**(适用于孤立情况):
```
child_process.exec(buildCmd, callback); // oxide-ci: ignore
```
**选项 2 — 全局禁用规则**(当模式广泛存在时首选):
```
[sast]
disabled_rules = ["SAST/ChildProcessExec"]
```
### Next.js / React monorepo 的参考 `.oxideci.toml`
复制此作为起点,并移除不适用于您项目的排除项:
```
[scan]
exclude_patterns = [
# Package manager lockfiles — sha512 integrity hashes, not secrets
"pnpm-lock.yaml",
"yarn.lock",
"package-lock.json",
# Public assets and minified files — base64 image data and bundled libraries
"**/public/**",
"**/*.min.js",
"**/*.min.mjs",
# Sentry / OpenTelemetry config — DSN URLs contain @ but are loaded from env vars
"**/sentry.client.config.ts",
"**/sentry.server.config.ts",
"**/sentry.edge.config.ts",
"**/instrumentation.ts",
# Test fixtures — placeholder emails used as test input, not real PII
"**/*.test.ts",
"**/*.test.tsx",
"**/*.spec.ts",
"**/*.spec.tsx",
"**/__tests__/**",
# The config file itself — comments may contain example emails like user@example.com
".oxideci.toml",
# Docs and markdown — example snippets and editorial emails
"docs/**",
"*.md",
# Build output
".next/**",
"dist/**",
"build/**",
".git/**",
]
entropy = true
entropy_threshold = 4.5
entropy_min_length = 20
[sast]
enabled = true
# disabled_rules = ["SAST/ChildProcessExec"]
```
### CodeQL Action v3 弃用警告
```
Warning: CodeQL Action v3 will be deprecated in December 2026.
```
将您工作流中的 SARIF 上传 action 从 `@v3` 更新到 `@v4`:
```
# 之前
uses: github/codeql-action/upload-sarif@v3
# 之后
uses: github/codeql-action/upload-sarif@v4
```
## 贡献
OxideCI 是 [MIT License](LICENSE) 下的开源项目。欢迎贡献。
**添加新的 secret 模式:**
1. 在 [src/modules/scanner.rs](src/modules/scanner.rs) 的 `BUILTIN_PATTERNS` 中添加一个 `(&str, &str)` 元组到适当的云提供商部分
2. 为正向匹配和误报检查添加一个匹配的 `#[test]`
3. 运行 `cargo test` 验证
**添加新的 SAST 规则:**
1. 在 [src/modules/sast.rs](src/modules/sast.rs) 的 `RULES` 中添加一个 `SastRule { id, query }` 条目
2. 编写 tree-sitter S-expression 查询 — `@match` 捕获标记用于位置报告的最外层节点
3. 在 `#[cfg(test)]` 块中添加一个单元测试,断言规则触发,并且(如果适用)安全变体不触发
4. 运行 `cargo test` 验证
**添加新的 lint 规则:**
1. 在 [src/modules/k8s_lint.rs](src/modules/k8s_lint.rs) 的 `check_manifest()` 中添加检查
2. 在 `#[cfg(test)]` 块中添加单元测试
**运行测试:**
```
cargo test # all unit + integration tests
cargo test scanner # only scanner tests
cargo test sast # only SAST tests
cargo clippy # lint
```
**问题 & 功能请求:** [github.com/ThinkGrid-Labs/oxide-ci/issues](https://github.com/ThinkGrid-Labs/oxide-ci/issues)
contact@example.com
// ← JSX text: NOT flagged ✅ // ← string attribute: flagged ⚠️ ``` **2. 危险模式检测** SAST 还运行结构性规则,检测危险的 API 调用,无论其参数是否为字符串字面量。这些规则捕获正则表达式无法可靠发现的 XSS sinks、代码注入、命令注入和不安全的反序列化模式。 *JavaScript / TypeScript:* | Rule ID | 标记内容 | |---|---| | `SAST/DangerouslySetInnerHTML` | TSX/JSX 中的 `` | | `SAST/InnerHTMLAssignment` | `element.innerHTML = expr` | | `SAST/OuterHTMLAssignment` | `element.outerHTML = expr` | | `SAST/EvalUsage` | `eval(expr)` | | `SAST/FunctionConstructor` | `new Function(...)` | | `SAST/SetTimeoutString` | `setTimeout("code", delay)` — 字符串作为第一个参数 | | `SAST/SetIntervalString` | `setInterval("code", delay)` — 字符串作为第一个参数 | | `SAST/ChildProcessExec` | `child_process.exec(cmd)` | | `SAST/ChildProcessExecSync` | `child_process.execSync(cmd)` | | `SAST/ChildProcessSpawn` | `child_process.spawn(cmd, args)` | | `SAST/ChildProcessExecFile` | `child_process.execFile(cmd)` | | `SAST/DocumentWrite` | `document.write(expr)` | | `SAST/DocumentWriteln` | `document.writeln(expr)` | *Python:* | Rule ID | 标记内容 | |---|---| | `SAST/PythonEval` | `eval(expr)` | | `SAST/PythonExec` | `exec(code)` | | `SAST/PythonPickle` | `pickle.load(f)` / `pickle.loads(data)` — 不安全的反序列化 | | `SAST/PythonSubprocessShell` | 任何带有 `shell=True` 的调用 — 命令注入风险 | | `SAST/PythonYamlLoad` | `yaml.load(data)` — 改用 `yaml.safe_load` | *Go:* | Rule ID | 标记内容 | |---|---| | `SAST/GoUnsafe` | `import "unsafe"` — 直接内存操作 | | `SAST/GoExecCommand` | `exec.Command(cmd, ...)` — 可能的命令注入 | | `SAST/GoPanic` | `panic(...)` — 意外的进程终止 | **3. 代码异味 / 复杂度规则**(仅限 JS/TS) 三个额外的规则在函数级别标记可维护性问题: | Rule ID | 触发条件 | 默认阈值 | |---|---|---| | `SMELL/LongFunction` | 函数体超过 `max_function_lines` 行 | 50 行 | | `SMELL/TooManyParameters` | 函数有超过 `max_parameters` 个参数 | 5 个参数 | | `SMELL/DeepNesting` | 函数内的控制流深度超过 `max_nesting_depth` | 4 层 | Rule IDs 包含用于提供即时上下文的测量值 — 例如 `SMELL/LongFunction (63 lines, max 50)`。阈值可在 `.oxidecil` 中配置: ``` [sast] max_function_lines = 60 # default 50 max_parameters = 6 # default 5 max_nesting_depth = 5 # default 4 ``` **4. 自定义 SAST 规则** 使用 [tree-sitter S-expression 查询](https://tree-sitter.github.io/tree-sitter/using-parsers/queries/) 定义项目特定的规则。每个规则必须包含一个标记要报告的最外层节点的 `@match` 捕获: ``` [sast] custom_rules = [ # Flag any direct call to eval() { id = "CUSTOM/EvalCall", query = "(call_expression function: (identifier) @_fn (#eq? @_fn \"eval\") arguments: (_) @match)" }, # Flag fetch() calls (useful for auditing outbound requests) { id = "CUSTOM/FetchCall", query = "(call_expression function: (identifier) @_fn (#eq? @_fn \"fetch\") @match)" }, ] ``` 自定义规则在启动时进行验证 — 无效的查询会被跳过并发出警告,绝不会导致 `oxide-ci scan` 崩溃。自定义 rule IDs 可以像任何内置规则一样使用 `disabled_rules` 禁用。 **禁用 SAST 或单个规则:** ``` # .oxideci.toml [sast] # 设置为 false 以完全禁用 SAST 并对所有文件回退到 regex enabled = true # 抑制在您的代码库中产生噪音的特定规则 disabled_rules = [ "SAST/ChildProcessExec", # if you intentionally shell out in a Node script "SAST/DocumentWrite", # if you have a legacy codebase that uses it "SAST/PythonSubprocessShell", # if subprocess with shell=True is intentional "SMELL/LongFunction", # if you have intentionally large generated files ] ``` **GitHub Check Run annotations + PR 摘要(`--annotate`):** 在 GitHub Actions 中运行时,传递 `--annotate` 让 oxide-ci 将发现项直接发布到 Checks 选项卡,附带逐行 annotations 和 PR 上的富 markdown 摘要评论。该评论包括严重性细分和逐项发现表(最多 20 行)。不需要 SARIF 上传步骤。 ``` - name: Secret, PII & SAST Scan env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: oxide-ci scan --annotate ``` 必需的环境变量(在 GitHub Actions 中自动设置):`GITHUB_TOKEN`、`GITHUB_REPOSITORY`、`GITHUB_SHA`。当任何环境变量缺失时,`--annotate` 无操作,扫描正常运行。干净的扫描(无发现项)会发布“No issues found”通过评论。 ### `lint` — Kubernetes Manifest Linting 根据安全性和可靠性最佳实践验证 Kubernetes workload YAML 文件(`Deployment`、`DaemonSet`、`StatefulSet`、`Job`、`CronJob`)。支持多文档 YAML 文件(`---` 分隔符)。 ``` oxide-ci lint [OPTIONS] Options: -d, --dir标签:CMS安全, DevSecOps, DNS 反向解析, Docker, GitHooks, Go, IP 地址批量处理, JavaScript, Linting, Pre-commit, Python, Ruby工具, Rust, SAST, SBOM, StruQ, TypeScript, Web性能, Web截图, 上游代理, 二进制工具, 云安全监控, 依赖审计, 可视化界面, 安全扫描, 安全插件, 安全防御评估, 容器安全, 文档安全, 无后门, 时序注入, 瑞士军刀, 盲注攻击, 硬件无关, 网络流量审计, 覆盖率, 质量门禁, 跌倒检测, 软件物料清单, 通知系统, 配置检查, 零依赖, 静态分析