Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
165 changes: 76 additions & 89 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,90 +1,77 @@
# ZASCA 环境配置文件模板
# 复制此文件为 .env 并填写实际配置值

# ========== 核心配置(影响功能或必须在初始化时定义) ==========

# 调试模式(生产环境必须设置为 False)
DEBUG=True

# Django 密钥(生产环境必须修改)
DJANGO_SECRET_KEY=your-secret-key-here-change-this-in-production

# 允许访问的主机(生产环境必须配置)
ALLOWED_HOSTS=localhost,127.0.0.1

# CSRF 可信来源(生产环境必须配置)
CSRF_TRUSTED_ORIGINS=https://localhost,https://127.0.0.1

# ========== 数据库配置 ==========
# 数据库引擎: sqlite, mysql 或 postgresql
DB_ENGINE=sqlite
# MySQL 配置(DB_ENGINE=mysql 时生效)
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=zasca
DB_USER=root
DB_PASSWORD=your_database_password_here
# PostgreSQL 配置(DB_ENGINE=postgresql 时生效)
# 安装依赖: uv sync --extra postgresql
#DB_HOST=127.0.0.1
#DB_PORT=5432
#DB_NAME=zasca
#DB_USER=postgres
#DB_PASSWORD=your_database_password_here

# ========== Redis 配置(可选增强) ==========
# Redis 是锦上添花的组件,不配置时程序使用本地替代方案:
# 缓存 -> LocMemCache(本地内存)
# 会话 -> 数据库存储
# Celery -> SQLite broker
# 配置 REDIS_URL 且 Redis 服务可达时,自动切换到 Redis:
# 缓存 -> Redis(高性能,支持分布式)
# 会话 -> Redis 缓存(更快,支持多进程共享)
# Celery -> Redis broker(更稳定,支持结果过期清理)
#REDIS_URL=redis://localhost:6379/0

# ========== Celery 配置 ==========
# 未配置 Redis 时默认使用 SQLite broker,无需手动设置
# 配置了 Redis 后默认自动使用 Redis broker(db1/db2),也可手动覆盖:
#CELERY_BROKER_URL=redis://localhost:6379/1
#CELERY_RESULT_BACKEND=redis://localhost:6379/2

# ========== 演示模式 ==========
# 设置为 1 启用演示模式
ZASCA_DEMO=0

# ========== 安全配置 ==========
# 生产环境必须设置为 True
SECURE_SSL_REDIRECT=False
SESSION_COOKIE_SECURE=False
CSRF_COOKIE_SECURE=False

# 可信反向代理 IP(逗号分隔)
# 使用 nginx 反向代理时必须配置,否则所有用户共享同一 IP 导致限流误触发
TRUSTED_PROXY_IPS=127.0.0.1,::1

# ========== 日志配置 ==========
LOG_LEVEL=DEBUG
LOG_FILE=/var/log/2c2a/application.log

# ========== WinRM 配置 ==========
# 2c2a 异步架构 - 环境变量配置示例
# 复制为 .env 并修改:cp .env.example .env

# ── 运行环境 ──
ENV=production # production / staging / development
DEBUG=false
2C2A_DEMO=0 # 1=演示模式(自动生成密钥,仅本地)

# ── Granian / FastAPI ──
HOST=0.0.0.0
PORT=8000
WORKERS=4 # 生产建议 CPU 核心数

# ── 密钥(生产必须显式配置)──
SECRET_KEY= # 生成:python -c "import secrets;print(secrets.token_urlsafe(48))"

# Ed25519 密钥对(生成见下方说明)
ED25519_PRIVATE_KEY_PEM=
ED25519_PUBLIC_KEY_PEM=

# AES-GCM 主密钥(32 字节 base64)
# 生成:python -c "import base64,os;print(base64.b64encode(os.urandom(32)).decode())"
CRYPTO_MASTER_KEY_B64=

# keyed-BLAKE2b 缓存签名密钥
CACHE_SIGNING_KEY= # 生成:python -c "import secrets;print(secrets.token_urlsafe(32))"

# ── 数据库 ──
DB_ENGINE=sqlite # sqlite / postgresql / mysql
DB_NAME=2c2a
# PostgreSQL/MySQL 专用
DB_HOST=localhost
DB_PORT=5432
DB_USER=2c2a
DB_PASSWORD=
DB_POOL_SIZE=10
DB_MAX_OVERFLOW=20

# ── Redis ──
REDIS_ENABLED=true
REDIS_URL=redis://localhost:6379/0

# ── 认证 ──
ACCESS_TOKEN_TTL_SECONDS=300 # Access Token 5 分钟
REFRESH_TOKEN_TTL_DAYS=7 # Refresh Token 7 天

# ── Argon2id 参数 ──
ARGON2_TIME_COST=3
ARGON2_MEMORY_COST=65536 # 64 MiB
ARGON2_PARALLELISM=2

# ── 缓存 ──
APP_SHELL_CACHE_TTL=300 # App Shell 边缘缓存 5 分钟
TENANT_CACHE_TTL=300

# ── WinRM ──
WINRM_TIMEOUT=30
WINRM_RETRY_COUNT=3

# ========== Gateway 配置 ==========
GATEWAY_ENABLED=False
GATEWAY_CONTROL_SOCKET=/run/2c2a/control.sock

# ========== Beta数据库配置(Beta推送插件) ==========
# 配置后可将生产数据推送到Beta版本数据库,仅支持PostgreSQL架构
#BETA_DB_NAME=zasca_beta
#BETA_DB_USER=postgres
#BETA_DB_PASSWORD=your_beta_database_password_here
#BETA_DB_HOST=127.0.0.1
#BETA_DB_PORT=5432
# Beta环境的SECRET_KEY(用于重加密:生产密钥解密 → Beta密钥加密)
# 若不配置则直接复制密文,Beta端需使用与生产相同的SECRET_KEY才能解密
#BETA_SECRET_KEY=

# ========== Bootstrap 认证配置 ==========
BOOTSTRAP_SHARED_SALT=
WINRM_MAX_RETRIES=3

# ── 速率限制 ──
LOGIN_RATE_LIMIT=5
API_RATE_LIMIT=100

# ── 可信代理 ──
TRUSTED_PROXY_IPS=
USE_X_FORWARDED_FOR=true

# ──────────────────────────────────────────────
# Ed25519 密钥对生成方法:
# python -c "
# from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
# from cryptography.hazmat.primitives import serialization
# k = Ed25519PrivateKey.generate()
# print('ED25519_PRIVATE_KEY_PEM=' + k.private_bytes(serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()).decode())
# print('ED25519_PUBLIC_KEY_PEM=' + k.public_key().public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo).decode())
# "
# ──────────────────────────────────────────────
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,6 @@ templates/components/input_simple.html
# Old project copies
zacs/

# trae
.trae/

# Tailwind CSS standalone CLI executables
static/vendor/tailwindcss
tools/tailwindcss
Expand Down
63 changes: 63 additions & 0 deletions .trae/rules/00-overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# 00 - 项目概览

## 项目定位

2c2a = **Zero Agent Security Control Architecture**。从 Django 同步架构全量重写为异步架构,核心目标:高性能、不阻塞前端、原生插件系统、原生站点隔离。

## 技术栈

| 层 | 技术 | 说明 |
| --- | --- | --- |
| ASGI 服务器 | Granian | 比 uvicorn 更高性能的 Rust 实现 |
| Web 框架 | FastAPI | 异步路由、依赖注入 |
| ORM | SQLAlchemy 2.0 Async | `Mapped`/`mapped_column` 新语法,全异步 |
| 迁移 | Alembic | 异步 env.py |
| 模板 | Jinja2 + JinjaX | 组件化模板 |
| 前端交互 | HTMX + HTMX OOB | 服务端渲染片段,无重前端框架 |
| 任务队列 | RedisHuey | 替代 Celery,更轻量 |
| Redis | redis[hiredis] | 缓存 + 队列 + 租户解析缓存 |
| 远程执行 | aiohttp | 替代同步 winrm,全异步 WS-Management |
| 安全 | argon2-cffi / pyjwt / cryptography | Argon2id / Ed25519 JWT / AES-256-GCM |
| CLI | Typer + Rich | `2c2a` 命令行工具 |
| 配置 | pydantic-settings | 环境变量 + `.env` |

Python 版本:**>=3.12**

## 目录结构

```
app/
├── main.py # FastAPI 应用工厂 + lifespan
├── core/ # 基础设施:config / db / redis / logging / exceptions
├── models/ # SQLAlchemy 模型(按领域分文件)
├── security/ # 加密原语 / JWT / 密码 / ban_version / 字段加密
├── cache/ # App Shell 缓存 / HTMX 片段 / 缓存键
├── tenant/ # 租户解析 / 中间件 / 依赖
├── auth/ # 认证路由 / 依赖 / schemas
├── api/v1/ # REST API(hosts / operations / tickets / audit)
├── web/ # 页面骨架路由 + HTMX 片段路由
├── winrm/ # 异步 WinRM 客户端(transport / client / commands)
├── tasks/ # RedisHuey 任务(hosts / operations)
├── plugins/ # 插件系统(base / loader / manager / registry)+ example/
├── templates/ # Jinja2 模板(layouts / pages / fragments)
├── static/ # 应用静态资源(css / js / vendor)
└── cli/ # CLI 工具(main / db / account / server / plugins / tenant / static)
```

## 核心架构理念

1. **App Shell 边缘全量缓存 + HTMX 动态片段分离**
- 页面骨架(HTML 壳)仅依据域名解析租户配置渲染,绝不依赖用户状态 → 可被 CDN 全量缓存
- 用户导航、统计等动态内容由 HTMX 在页面加载后独立请求获取 → 不可缓存

2. **站点隔离**
- 按域名解析 `SiteGroup`,所有业务数据按 `site_group_id` 过滤
- 中间件层注入 `TenantContext`,依赖注入层强制过滤

3. **无状态秒级令牌撤销**
- JWT Payload 携带 `ban_version`,封禁时递增数据库版本号
- 无需 Redis 黑名单,验签时比对版本号即可

4. **字段级加密**
- HKDF-SHA256 按字段名派生子密钥 + AES-256-GCM 加密
- 每个敏感字段独立密钥,防篡改、防跨字段关联
95 changes: 95 additions & 0 deletions .trae/rules/01-iron-laws.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# 01 - 铁律(违反 = 严重错误)

这些规则**不可违反**。违反会导致性能退化、安全漏洞或架构腐化。

## 命令执行

### 1. 禁止同步阻塞调用出现在异步上下文

```python
# ✗ 禁止:在 async 函数中调用同步阻塞 IO
async def bad_handler():
time.sleep(1) # 阻塞事件循环
requests.get("https://...") # 同步 HTTP

# ✓ 正确
async def good_handler():
await asyncio.sleep(1)
async with aiohttp.ClientSession() as s:
await s.get("https://...")
```

详见 `02-async-patterns.md`。

## 架构

### 2. 禁止重新引入 Django

本项目已从 Django 全量重写为 FastAPI 异步架构。**禁止**:
- 引入 `django`、`django-admin`、`django-bootstrap5` 等 Django 包
- 用 Django ORM 替代 SQLAlchemy
- 用 Django 模板替代 Jinja2/JinjaX

### 3. 禁止用同步 WinRM 库

```python
# ✗ 禁止
from winrm import Protocol

# ✓ 正确
from app.winrm.client import WinRMClient
```

### 4. 禁止移除或绕过站点隔离

所有业务数据查询**必须**按 `site_group_id` 过滤。详见 `05-tenant.md`。

## 安全

### 5. 禁止明文存储密码

密码哈希链路:**前端 BLAKE2b 预哈希 → 后端 Argon2id 加盐慢哈希**。

### 6. 禁止在 App Shell 缓存中包含用户状态

App Shell 缓存的 HTML **不得**包含:用户名、用户 ID、token、个性化数据、`Set-Cookie` 头。
违反会导致跨用户数据泄漏。详见 `04-caching.md`。

### 7. 生产环境必须显式配置所有密钥

开发模式(`DEBUG=1` 或 `2C2A_DEMO=1`)允许从 `SECRET_KEY` 自动派生,生产**禁止**。
生成密钥:`2c2a keys generate`。

## 前端

### 8. 禁止 CDN 链接

所有前端资源**必须**下载到 `app/static/vendor/` 本地服务。

### 9. 禁止内联样式

样式统一放 `app/static/css/base.css`。

## Git

### 10. 禁止 force push 到 main/master

功能分支可 force push,main/master 禁止。

### 11. feat/* 和 hotfix/* 分支合并后立即删除

## 迁移

### 12. 禁止 `SeparateDatabaseAndState` 空操作

```python
# ✗ 禁止
def upgrade():
pass
```

## 提交

### 13. 未经用户明确要求不得提交

**只有用户明确说"提交"/"commit"时才执行 git commit**。
Loading