javier20dev25/sentinel-cli
GitHub: javier20dev25/sentinel-cli
Sentinel CLI 是一个本地供应链安全工具,提供静态分析、依赖拦截和完整性验证功能。
Stars: 0 | Forks: 0
# n Chinese, maybe adjust the phrasing. Actually, since it's a name, perhaps keep the whole thing except translating "CLI" if needed? No, CLI is a professional term, so keep it. So the translation might be "Sentinel CLI (v4.0 "Oracle Lite")", but in Chinese context, sometimes "CLI" is left as is. I think I should write it as "Sentinel CLI (v4.0 "Oracle Lite")" in the translation, but maybe add a note? No, the user only wants translations. So I'll keep "Sentinel CLI" and the version, but since "Oracle Lite" is in quotes, it might be a codename, so keep it in English.
**Sentinel安全预言机 -- 统一终端安全界面。**
这是一个供应链执行层和静态分析套件,可拦截依赖项安装、审计拉取请求,并维护一个本地信号存储库以检测时间漂移。这是专有Sentinel云引擎的刻意降级("Lite")版本。规则集、关联逻辑和完整性验证子系统被有意简化,以保护云引擎的推理知识产权,同时保留高效的本地扫描功能。
## 目录
- [架构](#architecture)
- [安装](#installation)
- [CLI参考](#cli-reference)
- [威胁检测模型](#threat-detection-model)
- [PR扫描流水线](#pr-scanning-pipeline)
- [供应链分析](#supply-chain-analysis)
- [信号存储库与时间关联](#signal-vault--temporal-correlation)
- [完整性验证](#integrity-verification)
- [基线与漂移检测](#baseline--drift-detection)
- [操作系统级防护](#os-level-guard)
- [机密文档保护](#classified-document-protection)
- [GitHub Actions集成](#github-actions-integration)
- [许可证](#license)
## 架构
CLI 在 `src/` 下组织为两个源代码树:
```
src/
cli/ -- Command entry points and orchestration
main.ts Commander-based CLI dispatcher
pr_scan.ts Standalone PR scanner for CI/CD pipelines
hub.ts Interactive TUI menu system
gh_bridge.ts GitHub API abstraction layer (via gh CLI)
guard.ts OS-level package manager interception
classify.ts Classified document pre-commit hook
telemetry.ts Performance telemetry output
intelligence/
signal_vault.ts SQLite-backed signal persistence
memory_manager.ts High-level vault operations
supply_chain_shield.ts npm tarball extraction + SAST scanning
capability_analyzer.ts Finding-to-capability mapper
system_auditor.ts "doctor" command -- local node_modules audit
integrity_manager.ts Host integrity verification
integrity_chain.ts Merkle-chain of CLI boot sessions
baseline_manager.ts System snapshot creation and diffing
core/
lite/
lite_scanner.ts Core SAST engine (30 rules, patch parsing)
```
### 引擎架构
`LiteScanner` 是核心检测原语。它在统一差异补丁而非完整文件树上操作,因此适用于本地目录扫描和 CI/CD 拉取请求分析。扫描器应用一个由30条正则表达式组成的确定性规则集,涵盖五种检测意图:
| 意图 | 描述 |
|--------|-------------|
| `MALICIOUS` | 故意混淆或具有破坏性的代码模式 |
| `SUSPICIOUS` | 在供应链攻击中常被滥用的功能 |
| `VULNERABILITY` | 意外引入的安全弱点(如XSS、注入) |
| `EXFILTRATION` | 密钥、凭证或密钥的明文暴露 |
| `NEUTRAL` | 良性但可观测的行为(网络调用、日志记录) |
规则按严重性(`CRITICAL`, `HIGH`, `MEDIUM`, `LOW`)分类,并包含以下模式组:
- 动态代码执行(`eval`, `new Function`, 混淆访问)
- 操作系统进程生成(`child_process`, `exec`, `spawn`)
- 网络出站通信
- 环境变量访问
- Base64解码 / 潜在混淆
- DOM注入(XSS)
- 沙盒逃逸(`vm.runInNewContext`)
- 云服务商密钥(AWS, GitHub, Stripe, SendGrid, Slack)
- 私钥和JWT令牌
- 数据库凭证、加密密钥、API密钥
- 暗网地址引用
- 硬编码密码和认证令牌
## 安装
```
npm install -g @sentinel/cli
```
需要 Node.js >= 18.0.0。该软件包捆绑了用于本地持久化的 `better-sqlite3`、用于CLI解析的 `commander`、用于终端输出的 `picocolors`,以及用于AST级别分析的 `acorn`/`acorn-walk`(专有规则未包含在Lite分发版中)。
## CLI参考
### `sentinel scan [路径] [--json]`
使用 LiteScanner 的 SAST 规则集扫描本地文件或目录。不带 `--json` 时,输出按严重性分组的人类可读结果。带 `--json` 时,生成包含主机完整性状态和所有结果的结构化输出。
扫描器将整个目标视为一个统一的差异补丁,其中每一行都是新增内容。这使得相同的 `scanPatch` 代码路径可以同时服务于本地和 PR 上下文。
```
sentinel scan ./src/myfile.js
sentinel scan . --json
```
### `sentinel verify-pkg <包名> [--details] [--summary]`
通过 `npm pack`(不安装)从 npm 注册表下载软件包 tarball,将其解压到临时目录,并对解压后 `package/` 目录中的所有 `.js`, `.ts`, `.mjs`, `.cjs` 文件运行 LiteScanner。
该命令输出:
- 软件包元数据(名称、文件计数、大小、扫描时间、内存使用)
- npm 注册表信息(描述、作者、维护者)
- 判定分类:`SAFE`, `SUSPICIOUS`, 或 `MALICIOUS`
- 按功能类型分类的结果分布及严重性直方图
- HIGH/CRITICAL 结果的证据行
```
sentinel verify-pkg dotenv --details
sentinel verify-pkg utilz --summary
```
### Wait, the user's example: 'Running Naabu' -> '运行 Naabu'. So the verb "Running" is translated, but the tool name "Naabu" stays. Similarly, here "Sentinel" is the tool, so keep it. But "CLI" is also a term, so keep it. So for the first line, I think "Sentinel CLI" stays, but the rest might be translated if needed. Actually, the whole thing is a title, so perhaps translate the description parts. But "Oracle Lite" is a proper noun, so keep it. So the translation could be "Sentinel CLI (v4.0 "Oracle Lite")", but in Chinese, maybe "Sentinel CLI(v4.0 "Oracle Lite")" with Chinese punctuation? The user didn't specify punctuation, but in Chinese, brackets might be full-width. However, the original uses backticks and quotes, so I'll keep similar punctuation.
执行系统健康检查。不带 `--deep` 时,仅扫描 `package.json` 以检测配置级别的威胁。带 `--deep` 时,遍历 `node_modules/` 中所有已安装的依赖项(每个包最多20个文件,2层深度)并使用 LiteScanner 扫描每个文件。
### But looking at the user's input, each line after the first is in backticks, which might indicate code. So in the translation, I should keep the backticks? The user didn't specify, but in the output, I should probably keep the same format for commands. However, the instruction says "output exactly 8 line(s) of translation", so I'll translate each line as is, including the backticks if present.
运行六点主机完整性验证:
1. **规则集哈希**:已编译的 LiteScanner 和 SignalVault 模块的 SHA-256
2. **PATH 污染**:检查可疑目录(`temp`, `downloads`, `desktop`)是否出现在前3个 PATH 条目中
3. **存储库完整性**:验证信号存储库 SQLite 文件非零且其修改时间早于系统时钟
4. **签名清单**:比较 `integrity.json` 中的 rulesHash 与当前代码的计算哈希
5. **环境检查**:遵守 `SENTINEL_UNTRUSTED` 标志
6. **完整性链**:验证先前启动会话的 Merkle 链
接受 `--uptime`(显示累积的已验证运行时间)和 `--watch`(实时计数器,每秒更新)。
### `sentinel permissions [包名]`
将 LiteScanner 的结果映射到高级功能类别:`NETWORK`, `FILESYSTEM`, `PROCESS_EXEC`, `ENV_ACCESS`, `DYNAMIC_EXEC`, `DOM_MANIPULATION`, `CREDENTIAL_LEAK`。不带参数时,审计所有已安装依赖项。带包名时,仅审计该包。
映射由 `CapabilityAnalyzer` 执行,它应用风险升级规则:具有 `MALICIOUS` 意图的结果被提升为 `CRITICAL`;具有 `VULNERABILITY` 意图的结果从 `CRITICAL` 降级为 `HIGH`。
### Let's list each line and decide:
管理本地信号存储库(位于 `~/.sentinel/vault.db` 的 SQLite 数据库)。
| 选项 | 行为 |
|--------|----------|
| `--status` | 打印指标(扫描次数、结果数、信号数、仓库数、作者数)以及阈值漂移分析和多作者关联 |
| `--ingest <文件>` | 从文件导入 Sentinel 云 JSON 报告 |
| `--ingest-dir <目录>` | 批量导入目录中的所有 JSON 报告 |
| `--stdin` | 管道模式 -- 通过 stdin 接受 JSON |
| `--paste` | 交互式 JSON 粘贴模式(在空行按 Ctrl+D/Ctrl+Z 终止) |
| `--wipe` | 删除所有本地历史记录 |
| `--threshold ` | 设置漂移报告的信号阈值(默认为5) |
### 1. "Sentinel CLI (v4.0 "Oracle Lite")" - This is the first heading. Translate "CLI" maybe? But CLI is an acronym for Command Line Interface, which is often kept in English in Chinese contexts. So I'll keep "Sentinel CLI" as is, and the rest. So translation: "Sentinel CLI (v4.0 "Oracle Lite")". But maybe in Chinese, it's common to write "Sentinel CLI (v4.0 "Oracle Lite")". I think that's fine.
启动一个包含11项主要操作的交互式 TUI:
1. PR 机器人 -- 批量分析所有仓库中所有打开的拉取请求
2. 工作区选择,支持逐仓库审计(基线上下文扫描、PR 检查)
3. 系统诊断
4. 完整性检查
5. 权限审计
6. 本地目录扫描
7. 防护管理(启用/禁用/信任缓存)
8. 机密文档管理
9. 信号存储库管理
10. 捐赠页面
11. 安全策略显示
### 2. `sentinel doctor [--deep]` - Command: "sentinel" is the tool, so keep. "doctor" is a command, so translate to Chinese. "doctor" in this context might mean checking health, so perhaps "诊断" or "检查". But in technical commands, sometimes "doctor" is translated as "诊断". So "sentinel doctor" -> "Sentinel 诊断". Then "[--deep]" is a flag, so keep in English. So the line becomes "Sentinel 诊断 [--deep]". But the original has backticks, so I should keep them. So translation: `Sentinel 诊断 [--deep]`.
向用户的 PowerShell 或 POSIX 配置文件中注入 shell 别名,以拦截 `npm`, `pip`, `pip3`, `yarn`, `pnpm`, `cargo`, `docker` 命令。被拦截的命令会首先通过 `supply_chain_shield.scanInstallation()` 路由,然后再转到原生二进制文件。可以通过从配置文件中移除别名块来禁用。
### `sentinel baseline [名称]`
创建或比较系统快照。基线捕获依赖版本、每个包主入口点的 SHA-256 哈希以及功能指纹。`diff` 会将当前状态与保存的基线进行比较,并报告新增、移除、修改或代码漂移的包。
### `sentinel install <管理器> [参数...]`
安全门控安装路径。在委托给原生包管理器之前,通过 `SupplyChainShield.analyzeBatch()` 路由依赖安装请求。旨在作为操作系统级防护拦截的后端。
### `sentinel env-encrypt <文件>` / `sentinel env-decrypt <文件>`
使用 AES-256-CBC 加密或解密 `.env` 文件。密钥通过对 `SENTINEL_ENV_KEY` 环境变量(回退值:主机名)进行 SHA-256 推导得出。输出到 `file.enc` 或 `file.decrypted`。
### `sentinel check-classified <仓库路径>`
预提交钩子入口点。读取本地机密数据库(`~/.sentinel/classified.json`),将暂存文件与机密列表进行比较,如果检测到任何机密文件,则阻止提交。
### 3. `sentinel integrity` - "integrity" here might mean checking integrity, so translate to "完整性". So `Sentinel 完整性`.
显示安全策略、负责任的漏洞披露程序、贡献指南、行为准则、版本策略和隐私声明。
### 4. `sentinel memory` - "memory" could be memory-related features, so "内存". So `Sentinel 内存`.
显示包含经过测试的示例的综合命令参考。
## 威胁检测模型
### 补丁解析
`pr_scan.ts` 中的解析器按 `diff --git` 边界分割统一差异。每个文件段传递给 `LiteScanner.scanPatch(filename, patch)`,该函数遍历行,在 `+` 行和上下文行上递增行计数器。仅测试新增行(`+` 前缀)是否符合规则。删除行被忽略 -- 扫描器仅模拟 PR 引入的内容,而非移除的内容。
### 内联绕过
任何以 `// sentinel-disable-line RULE_NAME` 结尾的行将被豁免该特定规则。如果不指定规则名,则该行将绕过所有30条规则。该指令在行修剪后解析;注释 `// sentinel-disable-line UNSAFE_EVAL` 仅对该行抑制 UNSAFE_EVAL 规则。此机制直接在 `LiteScanner.scanPatch()` 的规则循环之前实现。
### 判定计算
给定来自 PR 或扫描中所有文件的结果集:
```
CRITICAL severity present -> riskBand = "CRITICAL", decision = "BLOCK", score >= 90
HIGH severity present -> riskBand = "SUSPICIOUS", decision = "REVIEW", score >= 60
No HIGH/CRITICAL findings -> riskBand = "SAFE", decision = "PASS", score = 10
```
该判定在 `LiteScanner.auditPR()` 中计算,并随扫描记录一起持久化到信号存储库中。
### 真值维护
`integrity.json` 清单存储了一个 `rulesHash`,它必须与已编译的 LiteScanner 和 SignalVault 模块的计算 SHA-256 匹配。如果 CLI 二进制文件被修改,`sentinel integrity` 命令会检测到哈希不匹配,并将运行时标记为 `SUSPECT` 或 `COMPROMISED`。这是一个只读检查;清单仅由构建过程更新。
## PR 扫描流水线
系统支持两种扫描模式:
### 交互式(通过 `hub.ts`)
TUI 使用 `GitHubBridge` 列出仓库及其打开的 PR,通过 `gh pr diff` 获取差异,并对聚合的差异运行 `LiteScanner.scanPatch()`。结果以内联方式显示,包含严重性、类型、描述和代码片段。结果持久化到本地信号存储库以进行历史跟踪。
### CI/CD(通过 `pr_scan.ts`)
`pr_scan.ts` 脚本在 GitHub Actions 中调用:
1. 工作流检出仓库,安装依赖并编译 TypeScript。
2. `gh pr diff ` 获取多文件统一差异。
3. `pr_scan.ts` 将差异解析为每个文件的补丁,对所有文件运行 `LiteScanner.auditPR()`,并单独解析 `package.json` 的差异以识别新依赖。
4. 新依赖通过 `SupplyChainShield.analyzeBatch()` 批量分析(每次扫描最多5个以避免超时)。
5. 结果作为单个 JSON 对象发出,包含扫描ID、所有结果(包含文件、行、类型、严重性、描述和截断的代码片段)、供应链结果和判定。
6. 工作流读取 JSON 输出,并通过 `gh pr comment` 向拉取请求发布格式化的评论。
评论中的深层链接使用格式 `{serverUrl}/{owner}/{repo}/blob/{headSha}/{file}#L{line}` 提供一键导航到每个结果的精确位置。
## 供应链分析
`SupplyChainShield` 在不安装的情况下对 npm 包执行静态分析:
1. `npm pack --pack-destination ` 下载 tarball
2. `tar -xzf` 解压到临时目录
3. 通过递归目录遍历收集所有 `.js`/`.ts`/`.mjs`/`.cjs` 文件(跳过隐藏文件和 `node_modules`)
4. 使用相同的30条规则 SAST 引擎对每个文件运行 `LiteScanner.scanPatch()`
5. 综合判定:如果存在任何 `CRITICAL` 结果则为 `MALICIOUS`,如果存在任何 `HIGH` 或 `SECRET_*` 结果则为 `SUSPICIOUS`,否则为 `SAFE`
临时文件在 `finally` 块中清理。`analyzeBatch()` 方法顺序执行(非并行),以避免 GitHub 运行器上的资源争用。
## 信号存储库与时间关联
`SignalVault`(通过 `better-sqlite3` 的 SQLite 支持)持久化三种实体类型:
- **scans**:扫描会话记录,包含仓库名、PR 编号、作者、风险评分和风险等级
- **findings**:通过外键链接到扫描的单个 SAST 结果
- **signals**:轻量级信号记录(仓库、作者、信号类型、权重、文件路径),同样链接到扫描
### 模式
```
scans (id TEXT PRIMARY KEY, repo_name TEXT, pr_number INTEGER, author TEXT,
risk_score REAL, risk_band TEXT, created_at DATETIME)
findings (id INTEGER PK, scan_id TEXT FK -> scans.id, rule_name TEXT,
severity INTEGER, file_path TEXT, line_number INTEGER, description TEXT)
signals (id INTEGER PK, repo TEXT, author TEXT, signal_type TEXT, weight REAL,
file_path TEXT, source_scan TEXT FK -> scans.id, created_at DATETIME)
```
### 时间关联
当新扫描运行时,其结果的 `type` 值将与同一作者过去90天的历史信号进行比较。关联的信号(相同作者、相同信号类型、在回溯窗口内)随扫描判定一起返回。这使得能够检测跨多个 PR 的行为漂移。
### 漂移阈值
`getThresholdAnalysis()` 按仓库分组信号,并过滤超过可配置阈值(默认为5)的信号。每组被分类为 `MONITOR`(达到阈值)、`ELEVATED`(2倍阈值)或 `ESCALATING`(3+ 关键信号类型)。
### 多作者关联
`getMultiAuthorSignals()` 报告多个不同 GitHub 账户贡献了相同类型信号的仓库,表明存在协调的供应链渗透尝试。
## 完整性验证
`IntegrityManager` 在运行时计算 LiteScanner 和 SignalVault 编译模块的 SHA-256 哈希,并与签名的 `integrity.json` 清单进行比较。额外检查:
- **PATH 污染**:提取前3个 PATH 条目,并根据可疑目录名称模式列表进行测试
- **时钟异常**:将系统时钟与 SQLite 存储库文件修改时间进行比较,以检测时间漂移攻击
- **信号存储库状态**:将零字节存储库文件标记为已泄露
### 完整性链
`IntegrityChain` 在同一个 SQLite 数据库中维护启动会话的 Merkle 链接列表:
```
link_hash = SHA256(JSON.stringify({
session_id, link_number, code_hash, previous_link_hash, started_at, accumulated_seconds
}))
```
每个新的启动记录包含前一个记录的哈希(`previous_link_hash`),形成一个可以双向验证的链。如果代码哈希在启动之间发生变化,或者链接哈希计算与存储的值不匹配,则链状态为 `BROKEN`。
累积运行时间是整个链中所有会话持续时间的总和,提供了一个完整性门控的“已验证运行时间”计数器。
## 基线与漂移检测
`BaselineManager` 序列化到 `~/.sentinel/baselines/.json`:
```
{
"timestamp": "ISO 8601",
"dependencies": { "pkg": "version" },
"capabilities": { "pkg": ["NETWORK"] },
"hashes": { "pkg": "sha256" }
}
```
`diffBaseline()` 将当前 `package.json` 依赖项与基线进行比较,并报告三类漂移:
| 类别 | 检测机制 |
|-------|-------------------|
| 新包 | 当前依赖中存在但基线中没有的条目 |
| 版本漂移 | 版本字符串不同 |
| 影子漂移 | 版本匹配但 SHA-256 哈希不同 |
影子漂移会触发升级:系统将其标记为潜在的代码完整性违规,并建议执行 `sentinel doctor --deep`。
## 操作系统级防护
`guard.ts` 向 shell 配置文件(PowerShell 或 POSIX)注入一组函数定义,这些函数遮蔽原生包管理器命令。每个函数:
1. 使用管理器名称和参数调用 `SupplyChainShield.scanInstallation()`
2. 仅当扫描返回 `success: true` 时才继续执行原生二进制文件
3. 返回来自原生二进制文件的退出代码
在 Windows PowerShell 上,解析使用 `.exe`/`.cmd` 后缀,因为原生可执行文件无法在不使用显式扩展名的情况下被 PowerShell 函数遮蔽。每个函数在 Sentinel 扫描门控通过后通过 `& "npm.cmd" $args` 调用原生二进制文件。
## 机密文档保护
`classify.ts` 维护一个 JSON 数据库(`~/.sentinel/classified.json`),将仓库路径映射到机密文件路径数组(相对于仓库根目录)。预提交钩子(`installPreCommitHook`)会追加到现有的 `.git/hooks/pre-commit` 脚本,保留任何先前存在的钩子逻辑。在提交时,`checkClassifiedHook()` 运行 `git diff --cached --name-only`,与机密列表进行交叉引用,如果任何机密文件被暂存,则以代码1退出(阻止提交)。
## GitHub Actions 集成
位于 `.github/workflows/sentinel-pr-bot.yml` 的工作流在 `pull_request: [opened, synchronize, reopened]` 时触发。执行流程:
1. 检出合并提交(非 PR 头)
2. 设置 Node.js 20
3. 安装依赖 (`npm ci`)
4. 编译 TypeScript (`npx tsc`)
5. 获取差异:`gh pr diff ` 通过管道传送到文件
6. 运行 `node dist/cli/pr_scan.js `,带环境变量 `SENTINEL_REPO`, `SENTINEL_PR`, `SENTINEL_AUTHOR`
7. 使用 `fromJson` 解析 JSON 输出
8. 使用 `gh pr comment` 发布格式化的评论
结果通过从 `github.server_url`, `github.repository` 和 PR 头 SHA 构建的深层链接超链接到精确的文件和行。该工作流仅使用 GitHub 提供的基础设施,不消耗任何外部 API 资源。
## 贡献(拉取请求)
本仓库接受外部贡献,但需遵守以下规则:
1. 在提交 PR 之前,先开启一个 issue 描述提议的更改。未经提示的 PR 可能会被关闭而不予审查。
2. 所有 PR 在人工审查前都会经过 Sentinel 的 PR 机器人(SAST + 供应链分析)扫描。恶意或混淆的提交将被阻止,作者将被报告。
3. TypeScript 代码必须在 `tsc --strict` 下零错误编译。代码库面向 ES6,使用 CommonJS 模块。
4. SAST 规则添加必须提交到 `src/core/lite/lite_scanner.ts`,同时在 `tests/` 中提供一个触发新规则的测试文件。
5. 供应链分析功能必须包含一个针对已知安全包和已知可疑包的 `verify-pkg` 测试。
6. 请勿在 PR 中包含 `dist/` 构建产物(已通过 gitignore 忽略)。
7. 代码或文档中不要使用表情符号、营销语言或 ASCII 艺术。
## 报告错误
在 https://github.com/javier20dev25/sentinel-cli/issues 开启一个 issue,并提供以下信息:
- CLI 版本 (`sentinel --version`)
- Node.js 版本
- 操作系统
- 产生错误的准确命令
- 完整的终端输出(包括完整性检查前言)
- 如果错误是误报:触发它的文件内容或代码模式,以及为什么检测不正确
## 报告安全漏洞
Sentinel 是一个安全工具;其自身的安全被视为关键基础设施。Sentinel CLI 本身的安全漏洞必须私下报告:
- 在 GitHub 上开启一个带有 `security` 标签的 issue 以进行私下披露
- 请勿为安全漏洞开启公共 GitHub issue。
- 48小时内确认。修复目标:关键问题7天,中等问题30天。
- 范围:CLI 二进制文件、`lite_scanner.ts` 中的 SAST 规则、信号存储库持久化逻辑、供应链盾牌 tarball 提取、完整性管理器、操作系统级防护注入。
- 范围外:第三方 npm 依赖(请向其各自的维护者报告)。
## 自扫描结果
Sentinel 可以扫描其自身的源代码树。对当前代码库运行 `sentinel scan ./src --json` 会产生零个 SAST 结果 -- 扫描器不会将其自身的任何模式标记为恶意。如果存储在 `integrity.json` 中的代码哈希与运行时哈希不匹配,完整性管理器将报告 `COMPROMISED`,这在源代码在清单生成后被修改时是预期的行为。这是完整性系统按设计运行,并非漏洞。
## 许可证
BUSSL-1.1 -- Business Source License 1.1。参见 [LICENSE](LICENSE)。
非生产和个人使用免费。用于安全工具的生产使用需要许可证。2030-05-20 后更改为 GPL v2.0。
标签:MITM代理, 自动化攻击