obrienma/Xylem-L6
GitHub: obrienma/Xylem-L6
一个独立的 TypeScript 有状态流处理器,用于摄取 SaaS API 审计日志并基于事件时间滑动窗口计算请求速率、认证失败突发等安全信号。
Stars: 0 | Forks: 0
**Xylem-L6** 是一个独立的 TypeScript 流处理器,用于摄取 SaaS API 活动日志(GitHub、Okta、Auth0、Slack 风格的审计格式)并基于它们计算有状态的安全信号——请求速率、认证失败突发、首次出现的 IP/设备/用户代理、不可能的旅行以及权限范围提升。它的存在是为了填补整个 Rhizome Risk 套件中的一个空白:套件中的其他任何组件([EventHorizon](https://github.com/obrienma/EventHorizon)、[Sentinel-L7](https://github.com/obrienma/sentinel-l7)、[Synapse-L4](https://github.com/obrienma/synapse-l4))都无法跨事件保持状态、在滑动时间窗口上进行计算、处理乱序到达,或者应用进程内反压。有关完整的基本原理,请参阅 [ADR 0001](docs/adr/0001-ingestion-target-stream-processor.md)。
## 📋 目录
- [📋 目录](#-contents)
- [🧰 技术栈](#-stack)
- [🚀 运行项目](#-running-the-project)
- [🏗️ 架构](#️-architecture)
- [🔀 流水线图](#-pipeline-diagram)
- [🗂️ Provider 适配器](#️-provider-adapters)
- [📚 文档](#-docs)
- [🗺️ 路线图](#️-roadmap)
- [📋 计划阶段](#-planned-phases)
- [🔭 刻意推迟的功能](#-deliberately-deferred)
## 🧰 技术栈
**⚡ 核心**
- **TypeScript + Zod:** 规范化的 `ApiActivityEvent` 契约和 provider 适配器输入在运行时通过 Zod 进行验证——特意作出此选择是为了面试相关性(即将到来的后端 TypeScript 面试),并填补该套件中唯一的后端 TypeScript 流式处理空白。请参阅 [ADR 0001](docs/adr/0001-ingestion-target-stream-processor.md)。
- **在一个共享接口(`ActivityAdapter`)之后实现了两个 provider 适配器:** `fixture-replay`(包含基准、突发、间隔以及延迟/乱序事件的手工编写示例计划——可控制每个事件的延迟和抖动)和 `github-events-live`(GitHub 的公开 Events API,针对真实账户进行轮询,按事件 ID 去重)。Okta 的 System Log API 是推迟的第三个候选方案。
- **内存中的滑动窗口速率计数器(`src/core/window.ts`):** 由事件时间驱动,而非挂钟时间驱动——每个参与者的 watermark 控制着数据保留,因此迟到的数据事件不会丢失在它之后记录的数据。保留 `2 × windowMs` 的历史记录,以正确响应迟到的数据事件自身的尾部窗口;如果事件落后于 watermark 达到一个完整的 `windowMs` 以上,则超出该界限,可能会被少计(这是一个已知的、有文档记录的阶段 1 限制——真正的“允许的延迟度”配置将在阶段 2 及以后提供)。
**🧪 测试与开发**
- **Vitest:** 测试运行器——`tests/` 镜像 `src/`,按模块同置。15 个测试涵盖 schema、速率计数器(包括迟到/乱序情况)、两个适配器(GitHub 调用通过可注入的 `fetchImpl` 进行模拟,从不进行真实的网络调用),以及一个领域隔离架构测试(`tests/arch.test.ts`)。
- **tsx:** 在开发中直接运行 TypeScript,无需单独的构建步骤。
**☁️ 部署(计划中,阶段 4+)**
- **GCP Pub/Sub** 作为摄取传输,替代适配器级别的轮询。
- **GCP Firestore** 用于检查点状态(跨重启的窗口恢复)。
- **GKE**,采用 EventHorizon 和 Rhizome Lens 已经使用的相同共享集群 namespace 模式。
- 部署目标是 GCP,而不是 Railway——有关完整推理请参阅 [ADR 0003](docs/adr/0003-gcp-deployment-target.md),包括 credits 与 Always-Free 的区别。
## 🚀 运行项目
### ✅ 前置条件
- **Node.js 24+** 及 npm
- 一个 **GitHub 个人访问令牌**(不需要特殊权限范围)——仅 `github-events-live` 适配器需要;`fixture-replay` 不需要任何配置。
### ⚡ 快速开始
```
# 安装依赖
npm install
# Type-check
npx tsc --noEmit
# 运行测试套件
npm test
# 针对 fixture-replay 运行 demo(默认,无需凭证)
npm run dev
# 或者针对真实的实时 GitHub 活动运行
XYLEM_ADAPTER=github-events-live GITHUB_USERNAME=
GITHUB_TOKEN= npm run dev
```
`npm run dev` 为每个事件打印一行:时间戳、参与者、操作以及该参与者当前的滑动窗口速率,并在窗口内出现 3 个或更多事件时标记 `[VELOCITY BREACH]`。没有持久化,也没有数据接收端 (sink)——这是阶段 1 的演示,而不是一个正在运行的服务。
## 🏗️ 架构
### 🔀 流水线图
```
flowchart LR
subgraph Adapters
F["fixture-replay\n(implemented)"]
G["github-events-live\n(implemented)"]
O["Okta System Log\n(deferred)"]
end
subgraph Core
E[ApiActivityEvent\nZod-validated]
W["SlidingWindowVelocityCounter\n(implemented)"]
end
subgraph Signals
V["Velocity\n(implemented)"]
FS["First-seen IP/device/UA\n(Phase 2)"]
IT["Impossible Travel\n(Phase 2)"]
SE["Scope Escalation\n(Phase 2)"]
end
subgraph Sink
S[Undecided—Phase 4]
end
F --> E
G --> E
O -.->|deferred| E
E --> W
W --> V
W -.->|Phase 2| FS
W -.->|Phase 2| IT
W -.->|Phase 2| SE
V -.-> S
FS -.-> S
IT -.-> S
SE -.-> S
```
在阶段 1 至 3 中假定没有 sink——在做出阶段 4 的决定(独立仪表板 vs. EventHorizon vs. Sentinel-L7)之前,流水线止于信号计算。面向未来的 Sentinel-L7 特定方向已记录在 [ADR 0002](docs/adr/0002-sentinel-l7-integration-direction.md) 中,但尚未承诺。
### 🗂️ Provider 适配器
| 适配器 | 来源 | 用途 |
| :--- | :--- | :--- |
| `fixture-replay` | 静态/手工编写的示例事件 | 唯一能够按需可靠地强制产生特定窗口条件的适配器——迟到/乱序事件、突发、间隔——而实时源无法按请求产生这些情况。 |
| `github-events-live` | GitHub 公开 Events API (`GET /users/{username}/events`) | 来自真实账户的真正实时流量。其数据结构比真正的审计日志更窄——仅限公开活动,没有认证/会话级别的事件——因此无法据此演示不可能的旅行和认证失败突发信号。 |
| Okta System Log API | _推迟_ | 唯一一个 schema 真正符合审计日志形式(认证/会话事件)的候选 provider;将填补 `github-events-live` 在演示不可能的旅行和认证失败突发信号方面留下的实时适配器空白。 |
## 📚 文档
| 文件 | 内容 | 最后更新 |
| --- | --- | --- |
| [README.md](README.md) | 项目概述 | 2026-07-13 |
| [ADR 0001](docs/adr/0001-ingestion-target-stream-processor.md) | 摄取目标(SaaS API 活动)和独立流处理器架构 | 2026-07-13 |
| [ADR 0002](docs/adr/0002-sentinel-l7-integration-direction.md) | Sentinel-L7 集成方向——具有前瞻性,尚未承诺 | 2026-07-13 |
| [ADR 0003](docs/adr/0003-gcp-deployment-target.md) | GCP 作为部署目标(Pub/Sub, Firestore, GKE) | 2026-07-13 |
| [journal/](docs/journal/) | 工程日志——每个阶段一个条目,与 [probes/](docs/probes/) 中的 Anki 探测配对 | 2026-07-13 |
## 🗺️ 路线图
### 📋 计划阶段
根据 [ADR 0001](docs/adr/0001-ingestion-target-stream-processor.md),每个阶段都可以独立演示:
* [x] **阶段 1** —— 规范的 `ApiActivityEvent` Zod schema,共享接口后的两个适配器(`fixture-replay` 和 `github-events-live`),内存中的滑动窗口速率计数器。没有持久化,没有外部连接。
* [ ] **阶段 2** —— 需要运行状态而不仅仅是仅限窗口计数器的有状态信号:首次出现集合、不可能的旅行。
* [ ] **阶段 3** —— 检查点机制,确保进程重启时不会默默丢失正在处理中的窗口/状态。
* [ ] **阶段 4** —— Sink 决策(独立仪表板 vs. EventHorizon vs. Sentinel-L7),在达到该阶段时通过 ADR 刻意作出决定,而不是现在假定。
### 🔭 刻意推迟的功能
* **Okta System Log 适配器** —— 真正符合审计日志形式的 provider(认证/会话事件);将解锁实时的“不可能的旅行”和认证失败突发信号演示。尚未开始。
* **Sentinel-L7 评分输出集成** —— 需要在 Xylem-L6 端具有一个融合函数(离散信号 → 单一评分),并在 Sentinel-L7 端具有一个 SaaS 领域策略语料库。这两者目前都不存在。请参阅 [ADR 0002](docs/adr/0002-sentinel-l7-integration-direction.md)。
* **GCP 部署(Pub/Sub, Firestore, GKE)** —— 架构上已决定([ADR 0003](docs/adr/0003-gcp-deployment-target.md))但尚未构建;取决于阶段 1 至 3 的先期落地。标签:MITM代理, SaaS安全, TypeScript, 安全插件, 流处理, 自动化攻击