geldois/osint-engine

GitHub: geldois/osint-engine

一款将巴西企业 CNPJ 标识符扩展为可追溯实体关系图的 OSINT 引擎,基于官方公开记录构建内容寻址的不可变图结构。

Stars: 1 | Forks: 0

# OSINT 引擎 [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ce/ce733292a922c08274cf5a2096f8fa4cf01023bfa51a36ef6beecaaef371a9d9.svg)](https://github.com/geldois/osint-engine/actions) [![Release](https://img.shields.io/github/v/release/geldois/osint-engine)](https://github.com/geldois/osint-engine/releases) [![Python](https://img.shields.io/badge/python-%E2%89%A53.12-blue)](https://www.python.org) [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE) 实体关系图引擎,将标识符扩展为完全可追溯的连接网络,数据源完全来自官方公开记录。 ## 概述 **CNPJ** 作为根标识符进入引擎。引擎查询官方公开记录,构建类型化的不可变图,并将其返回以供遍历。每个 **Node** 代表一个现实世界中的实体:公司、个人、地址、CNAE 分类、电话号码或电子邮件。每个 **Edge** 命名了两个节点之间的关系:`company_has_member`、`person_owns_company`、`company_located_at` 等等。 每个节点和边都拥有一个稳定、确定性的标识,该标识完全由其内容派生。在不同的机器上、在不同的时间扩展同一个 CNPJ,始终会产生具有相同 ID 的相同图——这使得该结构在构建上即具备幂等性,而非依赖于约定。 ## API 除 `/auth/token` 外,所有 endpoint 都需要 Bearer token。请先获取一个 token,然后将其用于随后的每次请求中。 ### 身份验证 ``` POST /auth/token Content-Type: application/x-www-form-urlencoded username=admin&password= ``` 返回: ``` { "access_token": "", "token_type": "bearer" } ``` ### 图扩展 ``` GET /cnpj/{cnpj} Authorization: Bearer ``` 返回一个 `GraphSchema`,其中包含根公司、所有连接的实体以及所有类型化的关系。当前的数据源是 [BrasilAPI](https://brasilapi.com.br)(参见 [ADR-0005](docs/adr/0005-brasilapi-as-mvp-cnpj-data-source.md))。 每个响应都包含一个 `X-Correlation-ID` header,用于端到端的请求追踪。错误响应在正文中带有相同的 correlation ID,以及一个派生自领域错误层级的机器可读 `type` 字段。根据 RFC 6750,`401` 响应始终包含 `WWW-Authenticate: Bearer`。 ## 技术栈 - **Runtime:** Python 3.12, FastAPI, Uvicorn - **身份验证:** PyJWT (HS256 access token),passlib + argon2-cffi (Argon2id 密码哈希) - **HTTP client:** httpx2 (async) - **序列化:** Pydantic v2 (node 和 edge schema 的可辨识联合) - **可观测性:** structlog (生产环境使用 JSON,debug 环境使用 console) - **工具:** uv, Ruff, basedpyright (strict), Commitizen - **测试:** pytest, pytest-asyncio ## 设计 ### 内容寻址的实体身份 每个实体——node、edge 和 graph——都通过 UUID5 从其内容中派生出 ID。相同的输入在任何机器上、任何时间始终会产生相同的标识符。去重、幂等 upsert 和安全的并发写入是结构性的必然结果,而非实现选择。每种实体类型都占据其各自的 UUID namespace,因此从相同 payload 派生出的 `CompanyID` 和 `PersonID` 绝不会发生冲突。 参见 [ADR-0003](docs/adr/0003-uuid5-over-uuid4-for-entity-identity.md)。 ### 快速失败的实体契约 实体基类使用 `__init_subclass__` 在导入时(而非实例化时)验证每个子类。 缺少 namespace 或声明了不兼容 ID 类型的具体实体,会在模块加载时立即引发异常——在任何测试运行之前,在任何实例创建之前。该领域是自我防御的。 `__setattr__` 和 `__delattr__` 对每个实体都会引发 `FrozenInstanceError`。不可变性是结构性的,而非由约定强制执行。 参见 [ADR-0002](docs/adr/0002-manual-entity-base-class.md)。 ### 零开销的类型层级 每个具体实体都声明自己的 `NewType` ID(`CompanyID`、`PersonID`、`GraphID`、……),作为 `Entity[IDType_co]` 的泛型参数,其中 `IDType_co` 是绑定到 `UUID` 的协变 `TypeVar`。类型检查器会强制确保 `Node[CompanyID]` 不能替代 `Node[PersonID]`——并且 edge 的源 ID 和目标 ID 类型与其声明的约束相匹配——而无需任何运行时表示。`NewType` 在运行时是一个恒等函数;这种区分仅存在于类型检查器的世界中。 参见 [ADR-0004](docs/adr/0004-idtype-co-typevar-for-covariant-id-typing.md)。 ## 设置 ``` git clone https://github.com/geldois/osint-engine.git cd osint-engine ``` ### Linux 1. 安装 [Docker Engine](https://docs.docker.com/engine/install/) 并启动 daemon。 2. 安装 [mise](https://mise.jdx.dev) 并在你的 shell 中激活它(参见 [入门指南](https://mise.jdx.dev/getting-started.html))。 3. 安装项目工具链和 git hooks: ``` mise install uv run pre-commit install cp .env.example .env # then set SECRET_KEY and ADMIN_PASSWORD ``` ### Windows 1. 安装 [Docker Desktop](https://www.docker.com/products/docker-desktop/) 并启用 WSL2 后端。 2. 通过 PowerShell 安装 [mise](https://mise.jdx.dev) 并在你的 shell 中激活它(参见 [入门指南](https://mise.jdx.dev/getting-started.html))。 3. 安装项目工具链和 git hooks: ``` mise install uv run pre-commit install copy .env.example .env # then set SECRET_KEY and ADMIN_PASSWORD ``` ### 运行 ``` uv run python -m osint_engine ``` ### 测试 ``` uv run pytest ``` ### 本地 CI ``` act push ```
标签:GitHub, OSINT引擎, Python, RESTful API, 动态调用, 安全规则引擎, 实体关系, 实时处理, 提示词优化, 数据溯源, 无后门, 请求拦截