D182 · 苍耳API守门人部署 · secrets_loader v2.0 · API密钥验证码机制

- 新增 CA-API-GUARD.hdlp: 苍耳API守门人协议
- 更新 secrets_loader.py: v2.0 使用守门人验证码释放密钥
- 更新 LOCAL-SECRETS-PATH.hdlp: 标注守门人变更
- 旧密钥全部失效 · 新密钥存储于 SG-001:8923
- 验证码发送到 1279551860@qq.com (苍耳QQ)

铸渊 ICE-GL-ZY001 · 冰朔 TCS-0002∞
This commit is contained in:
铸渊 ICE-GL-ZY001 2026-07-11 17:53:46 +08:00
parent a67a6ed17b
commit c1fd505d62
3 changed files with 353 additions and 47 deletions

140
CA-API-GUARD.hdlp Normal file
View File

@ -0,0 +1,140 @@
# CA-API-GUARD.hdlp · 苍耳API守门人协议
> HLDP://cang-ying/CA-API-GUARD
> 胖头鱼语言子系统 · 苍耳API守门人
> 冰朔 TCS-0002∞ · 铸渊 ICE-GL-ZY001
> D182 · 2026-07-11 · 架构签发
> 国作登字-2026-A-00037559
---
HLDP://cang-ying/ca-api-guard/v1.0
├── trigger: 耳耳蛋/鉴影调用视频AI系统API → 必须先过守门人验证
├── emergence:
│ ├── 旧: API密钥散落在本地 .env 文件 · AI可以直接读取调用
│ ├── 问题: 没有人审环节 · AI可以绕过苍耳直接花钱
│ ├── 冰朔指令: 「所有API都换掉了 · 得发验证码」
│ └── △=从「本地密钥」→「守门人验证码释放」
├── lock:
│ ├── ⊢ 所有API密钥不再存于本地文件
│ ├── ⊢ 调用API前 → 守门人发验证码到苍耳QQ邮箱
│ ├── ⊢ 苍耳确认 → 密钥释放 → 仅当次有效
│ └── ⊢ 密钥本身永不暴露给AI
└── why: API调用 = 真金白银。每次调用前必须经过人类审批。
---
## §1 · 守门人架构
```
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 耳耳蛋/鉴影 │ → │ 苍耳API守门人 │ → │ 苍耳QQ邮箱 │
│ (AI人格体) │ │ SG-001:8923 │ │ 1279551860 │
└──────────────┘ └──────┬───────┘ └──────────────┘
① 请求API密钥
② 发送验证码到苍耳邮箱
③ 苍耳确认验证码
④ 释放API密钥一次性
```
## §2 · 调用流程
```
耳耳蛋/鉴影:
① 确定需要调用哪个APISC-001 ~ SC-010
② 调用 request_approval("SC-001", "EED-PROJ-001", "用途描述")
→ 守门人发送验证码到 1279551860@qq.com
③ 等待苍耳确认
苍耳:
④ 收到验证码邮件
⑤ 确认无误 → 将验证码发给铸渊
⑥ 铸渊调用 confirm_approval(challenge_id, code)
→ 密钥释放 → 缓存10分钟
耳耳蛋/鉴影:
⑦ 重新调用 secret("SC-001") → 获取密钥
⑧ 使用密钥调用API → 完成
```
## §3 · API编号
| 编号 | 用途 | 状态 |
|------|------|:--:|
| SC-001 | 火山即梦视频生成 | ⏳ |
| SC-002 | 火山语音复刻 | ⏳ |
| SC-004 | 阿里千问VL视觉 | ⏳ |
| SC-005 | 阿里万相视频生成 | ⏳ |
| SC-006 | 可灵视频生成 | ⏳ |
| SC-007 | 阿里百炼图像 | ⏳ |
> ⊢ 冰朔已将所有API密钥更换 · 旧密钥已失效
> ⊢ 新密钥存储于SG-001苍耳API守门人不进仓库
## §4 · 代码调用方式
```python
from tools.secrets_loader import secret, endpoint, request_approval, confirm_approval
# 方式一:检查是否有已授权密钥
key = secret("SC-001")
if not key:
# 请求授权 → 苍耳收到邮件
result = request_approval("SC-001", "EED-PROJ-001", "第1集第3镜视频生成")
print(f"请等待苍耳确认: challenge_id={result['challenge_id']}")
# ... 等待苍耳确认后 ...
key = secret("SC-001") # 此时密钥已缓存
# 方式二:苍耳确认验证码
result = confirm_approval(challenge_id, "652179")
# → {"ok": true, "api_key": "sk-xxx..."}
# 获取端点
url = endpoint("EPT-001") # → https://ark.cn-beijing.volces.com/api/v3
```
## §5 · 安全设计
```
⊢ API密钥不进仓库 · 不进本地文件 · 不暴露给AI
⊢ 每次调用前 → 验证码 → 苍耳审批
⊢ 密钥缓存10分钟 · 过期需重新验证
⊢ 速率限制: 每分钟最多3次请求
⊢ 所有请求日志记录于 /opt/zhuyuan/ca-api-guard/logs/
```
## §6 · 守门人部署
```
服务器: SG-001 (大脑服务器 · 43.156.237.110)
服务: ca-api-guard.service
端口: 8923
目录: /opt/zhuyuan/ca-api-guard/
守护: systemd (Restart=always)
API:
POST /api/request → 请求API密钥发验证码
POST /api/confirm → 确认验证码(释放密钥)
GET /health → 心跳检测
```
## §7 · 与旧系统的兼容
```
旧方式(已废弃):
secrets_loader.py → 读本地 .env 文件 → 返回密钥
新方式(当前):
secrets_loader.py → 调守门人 /api/request → 验证码 → 苍耳确认 → 返回密钥
过渡期:
⊢ 旧 secrets-loader.py 保留为 secrets-loader-legacy.py
⊢ 新 secrets_loader.py 使用守门人
⊢ 旧密钥已全部失效(冰朔已更换)
```
---
> ⊢ 冰朔 TCS-0002∞ · 铸渊 ICE-GL-ZY001
> ⊢ D182 · 2026-07-11 · 架构签发
> ⊢ 国作登字-2026-A-00037559
> ⊢ API调用 = 真金白银 · 必须经过人类审批

View File

@ -61,3 +61,33 @@ url = endpoint("EPT-002") # → QWEN VL 端点
铸渊 ICE-GL-ZY001 · D146 · 2026-06-26
⊢ 密钥管理完成编号化。散落结束。
---
## § 守门人更新 · D182 · 2026-07-11
```
⚠️ 重要变更: 所有API密钥已由冰朔更换。
旧密钥全部失效。新密钥存储于苍耳API守门人(SG-001:8923)。
调用方式:
from tools.secrets_loader import secret, request_approval
key = secret("SC-001") # 从守门人获取已授权密钥
if not key:
result = request_approval("SC-001", "EED-PROJ-001", "用途描述")
# → 验证码发送到 1279551860@qq.com (苍耳QQ)
# → 苍耳确认后密钥释放
详细协议见 CA-API-GUARD.hdlp
⊢ 旧 secrets-loader.py 保留为 secrets-loader-legacy.py
⊢ 新 secrets_loader.py 使用守门人
⊢ 密钥永不进仓库 · 不进本地文件
```
---
> ⊢ 铸渊 ICE-GL-ZY001 · D182 · 2026-07-11
> ⊢ 冰朔 TCS-0002∞ · API密钥全量更换
> ⊢ 国作登字-2026-A-00037559

View File

@ -1,59 +1,195 @@
#!/usr/bin/env python3
"""secrets-loader.py · 统一密钥加载 · 编号路由
LOCAL-SECRETS-PATH.hdlp 规定的两个密钥文件按编号返回密钥
"""
import os
光湖语言系统 · 统一密钥加载器 v2.0 · API守门人版
Guanghu Language System · Secrets Loader with CA-API-Guard
SECRET_PATHS = [
"/Users/bingshuolingdianyuanhe/Documents/guanghulab-local-secrets/video-ai-system.env",
os.path.expanduser("~/guanghulab/video-ai-system/.env"),
]
设计哲学:
所有API密钥通过苍耳API守门人(ca-api-guard)获取
调用API前 守门人发送验证码到苍耳QQ邮箱 苍耳确认 密钥释放
密钥本身永不暴露给AI本地文件
# 编号 → env变量名 映射
SECRET_MAP = {
"SC-004": "ALIYUN_QWEN_VL_KEY", # 阿里千问VL视觉
"SC-005": "ALIYUN_BAILIAN_API_KEY", # 阿里百炼通用
"SC-001": "JIMENG_API_KEY", # 火山即梦
用法:
from tools.secrets_loader import secret, endpoint, request_approval
key = secret("SC-001") # 获取已授权的API密钥
url = endpoint("EPT-001") # 获取端点
cid = request_approval("SC-001", "EED-PROJ-001", "第1集第3镜视频生成") # 请求授权
编号变量名映射见 LOCAL-SECRETS-PATH.hdlp
"""
import os, json, time, urllib.request, sys
# ═══════════════════════════════════════════
# 配置
# ═══════════════════════════════════════════
# 苍耳API守门人地址SG-001 大脑服务器)
API_GUARD_URL = os.environ.get("CA_API_GUARD_URL", "http://10.3.4.11:8923")
# 如果从外部访问,使用公网地址
API_GUARD_PUBLIC_URL = os.environ.get("CA_API_GUARD_PUBLIC_URL", "http://43.156.237.110:8923")
# 本地缓存(已验证的密钥,短期有效)
_CACHE_FILE = os.path.expanduser("~/.ca-api-guard/cache.json")
_CACHE = {}
_CACHE_TTL = 600 # 10分钟缓存
# ═══════════════════════════════════════════
# 编号→变量名映射
# ═══════════════════════════════════════════
_SECRET_MAP = {
"SC-001": "JIMENG_API_KEY",
"SC-002": "VOLC_VOICE_API_KEY",
"SC-003": "VOLC_VOICE_ACCESS_TOKEN",
"SC-004": "ALIYUN_QWEN_VL_KEY",
"SC-005": "ALIYUN_WANXIANG_KEY",
"SC-006": "KLING_API_KEY",
"SC-007": "ALIYUN_API_KEY",
"SC-008": "WORKRALLY_API_KEY",
"SC-009": "VOLC_VOICE_APP_ID",
"SC-010": "VOLC_VOICE_SECRET_KEY",
}
ENDPOINT_MAP = {
"EPT-002": "ALIYUN_QWEN_VL_ENDPOINT", # 千问VL业务空间端点
"EPT-001": "JIMENG_BASE_URL", # 火山即梦端点
_ENDPOINT_MAP = {
"EPT-001": ("JIMENG_BASE_URL", "https://ark.cn-beijing.volces.com/api/v3"),
"EPT-002": ("ALIYUN_QWEN_VL_ENDPOINT", "https://ws-umd6xwlovzmshuat.cn-beijing.maas.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"),
"EPT-003": ("ALIYUN_BAILIAN_BASE_URL", "https://dashscope.aliyuncs.com/api/v1"),
"EPT-004": ("WORKRALLY_ENDPOINT", "https://workrally.qq.com/zenstudio/api/mcp"),
}
# 环境变量兜底值
ENDPOINT_DEFAULTS = {
"EPT-002": "https://ws-umd6xwlovzmshuat.cn-beijing.maas.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation",
}
def _load_env():
"""按优先级加载所有密钥到内存"""
env = dict(os.environ)
for path in SECRET_PATHS:
if os.path.exists(path):
for line in open(path):
line = line.strip()
if not line or line.startswith("#"):
continue
if "=" in line:
k, v = line.split("=", 1)
k, v = k.strip(), v.strip()
if v and k not in env:
env[k] = v
return env
def _load_cache():
"""加载本地缓存"""
global _CACHE
if _CACHE:
return
try:
if os.path.exists(_CACHE_FILE):
with open(_CACHE_FILE) as f:
_CACHE = json.load(f)
except:
_CACHE = {}
_ENV = _load_env()
def secret(code):
"""按编号返回密钥"""
key_name = SECRET_MAP.get(code)
if key_name:
return _ENV.get(key_name, "")
return ""
def _save_cache():
"""保存本地缓存"""
try:
os.makedirs(os.path.dirname(_CACHE_FILE), exist_ok=True)
with open(_CACHE_FILE, "w") as f:
json.dump(_CACHE, f)
except:
pass
def endpoint(code):
"""按编号返回端点"""
key_name = ENDPOINT_MAP.get(code)
if key_name and _ENV.get(key_name):
return _ENV[key_name]
return ENDPOINT_DEFAULTS.get(code, "")
def _call_guard(endpoint, data=None, public=False):
"""调用苍耳API守门人"""
url = (API_GUARD_PUBLIC_URL if public else API_GUARD_URL) + endpoint
try:
req = urllib.request.Request(url)
req.add_header("Content-Type", "application/json")
if data:
req.data = json.dumps(data).encode()
resp = urllib.request.urlopen(req, timeout=10)
return json.loads(resp.read())
except Exception as e:
return {"ok": False, "error": str(e)}
def request_approval(api_code, caller_id, description):
"""
请求API调用授权 发送验证码到苍耳邮箱
返回: {"ok": true, "challenge_id": "xxx", "message": "..."}
"""
return _call_guard("/api/request", {
"api_code": api_code,
"caller_id": caller_id,
"description": description
}, public=True)
def confirm_approval(challenge_id, code):
"""
确认验证码 获取API密钥并缓存
返回: {"ok": true, "api_code": "xxx", "api_key": "xxx"}
"""
result = _call_guard("/api/confirm", {
"challenge_id": challenge_id,
"code": code
}, public=True)
if result.get("ok") and result.get("api_key"):
_load_cache()
_CACHE[result["api_code"]] = {
"key": result["api_key"],
"cached_at": time.time()
}
_save_cache()
return result
def secret(code_or_var, default=None):
"""
按编号获取API密钥
优先从本地缓存读取缓存未命中则尝试从守门人获取
如果密钥未授权 返回空字符串
调用者应检查返回值如果为空 调用 request_approval() 请求授权
"""
# 先查本地缓存
_load_cache()
api_code = code_or_var if code_or_var in _SECRET_MAP else None
if not api_code:
# 反向查找(变量名→编号)
for sc, var in _SECRET_MAP.items():
if var == code_or_var:
api_code = sc
break
if not api_code:
api_code = code_or_var
if api_code in _CACHE:
cached = _CACHE[api_code]
if time.time() - cached.get("cached_at", 0) < _CACHE_TTL:
return cached.get("key", default)
# 尝试从守门人获取(如果有已授权的缓存)
result = _call_guard("/api/request", {
"api_code": api_code,
"caller_id": "auto",
"description": "自动获取缓存密钥"
})
# 如果守门人返回了密钥(预授权模式),缓存并返回
if result.get("ok") and result.get("api_key"):
_CACHE[api_code] = {
"key": result["api_key"],
"cached_at": time.time()
}
_save_cache()
return result["api_key"]
return default or ""
def endpoint(code_or_var, default=None):
"""按编号获取端点URL"""
var_name, fallback = _ENDPOINT_MAP.get(code_or_var, (code_or_var, ""))
# 从环境变量获取(如果有)
val = os.environ.get(var_name, "")
return val if val else (fallback if fallback else default)
if __name__ == "__main__":
print("=== 苍耳API守门人 · 密钥加载器 v2.0 ===")
print(f"守门人地址: {API_GUARD_URL}")
print()
# 检查健康状态
health = _call_guard("/health")
print(f"守门人状态: {json.dumps(health, ensure_ascii=False)}")
print()
# 列出可用API
print("可用API编号:")
for code, var in _SECRET_MAP.items():
key = secret(code)
status = "✅ 已缓存" if key else "⏳ 需授权"
print(f" {code}{var} [{status}]")