shuangyan-notebook/第五域 · Fifth Domain/⚒️ 铸渊·协作指令|GitHub ↔ Notion 桥接协议/🔄 铸渊指令|OAuth2 Token 自动续期引擎 + 天眼休眠避让机制(下篇)· 多用户Toke 4c4928ee96764b308ec38d573a255696.md
Guanghu Domestic Migration a27e87cb99 chore: import sanitized domestic snapshot for REPO-007
Source snapshot: 97d7f0fae96dc04b7ddad56fc1db6a108ed662cc

[SEC-CLEAN] · pre-push-clean v1.0 · 109处敏感信息已自动转乱码
2026-07-17 15:59:55 +08:00

14 KiB
Raw Permalink Blame History

belongs_to
belongs_to
INDEX · 铸渊·协作指令GitHub ↔ Notion 桥接协议

🔄 铸渊指令OAuth2 Token 自动续期引擎 + 天眼休眠避让机制(下篇)· 多用户Token流程 + 告警推送 + 天眼扫描清单 + 执行回执ZY-TOKEN-RENEW-2026-0324-001



Phase F · 多用户 Token 流程

新用户接入流程

当新开发者需要接入 Drive 权限时,流程如下:

sequenceDiagram
    participant Dev as 新开发者
    participant Human as 冰朔(人类管理员)
    participant ZY as 铸渊(自动化)
    participant GH as GitHub Secrets
    participant GG as Google OAuth2
    
    Dev->>Human: 申请 Drive 权限
    Human->>GG: 在 Google Cloud 加入测试用户白名单
    Human->>GG: 用新用户 Gmail 完成 OAuth 授权
    Human->>GH: 注入 GDRIVE_REFRESH_TOKEN_DEVxxx
    Human->>ZY: 通知铸渊更新注册表
    ZY->>ZY: 在 gdrive-tokens.json 添加新条目
    ZY->>ZY: 提交注册表更新
    Note over ZY: 下次 CRON 触发时自动纳入续期管理

新用户注册表条目模板

铸渊收到新用户接入通知后,在 config/gdrive-tokens.jsontokens 数组中添加:

{
  "user_id": "DEV-001",
  "user_name": "开发者名称",
  "role": "developer",
  "github_secret_name": "GDRIVE_REFRESH_TOKEN_DEV001",
  "last_renewed": "2026-XX-XXTXX:XX:XX+08:00",
  "expires_at": "2026-XX-XXTXX:XX:XX+08:00",
  "status": "active",
  "renew_count": 0,
  "notes": "开发者描述"
}

GitHub Secret 命名规范

角色 Secret 命名 示例
主控(冰朔) GDRIVE_REFRESH_TOKEN 已存在
开发者 1 GDRIVE_REFRESH_TOKEN_DEV001 未来添加
开发者 2 GDRIVE_REFRESH_TOKEN_DEV002 未来添加
CI/CD 测试 GDRIVE_REFRESH_TOKEN_CI 可选

Workflow 如何读取多用户 Token

renew-tokens.js 已设计为遍历注册表,根据每个条目的 github_secret_name 从环境变量读取对应 Token。

但 Workflow 中需要显式将 Secret 注入环境变量。铸渊在添加新用户时,同时更新 Workflow YAML

# 在 renew-gdrive-tokens.yml 和 check-token-health.yml 的 env 中添加:
env:
  GDRIVE_CLIENT_ID: $ secrets.GDRIVE_CLIENT_ID 
  GDRIVE_CLIENT_SECRET: $ secrets.GDRIVE_CLIENT_SECRET 
  GDRIVE_REFRESH_TOKEN: $ secrets.GDRIVE_REFRESH_TOKEN 
  # 新增开发者 Token每次加人时追加
  # GDRIVE_REFRESH_TOKEN_DEV001: $ secrets.GDRIVE_REFRESH_TOKEN_DEV001 
  # GDRIVE_REFRESH_TOKEN_DEV002: $ secrets.GDRIVE_REFRESH_TOKEN_DEV002 
  GITHUB_TOKEN: $ secrets.GITHUB_TOKEN 

Phase G · 告警推送系统

告警级别

级别 触发条件 推送渠道 行动
🟢 INFO Token 刷新成功 回执日志(注册表 renew_log 无需操作
🟡 WARN Token 剩余 < 72小时但刷新成功 回执日志 + grid-db/logs/ 关注但无需操作
🟠 ALERT Token 剩余 < 48小时且刷新失败 token-alert.json + 主控台 + 公告板 要求人类 24 小时内介入
🔴 CRITICAL Token 已过期 / 全部刷新失败 token-alert.json + 主控台 + 公告板 + Workflow 失败标记 紧急:人类立即介入重新授权

告警输出文件:grid-db/logs/token-alert.json

刷新脚本在有失败时自动生成此文件,天眼系统可读取它来决定是否推送告警:

{
  "alert_type": "TOKEN_RENEWAL_FAILURE",
  "severity": "CRITICAL",
  "time": "2026-03-30T10:00:00Z",
  "failed_users": ["TCS-0002"],
  "message": "1 个 Token 刷新失败,需要人类介入",
  "action_required": "HUMAN_REAUTH",
  "instructions": [
    "1. 登录 Google Cloud Console",
    "2. 访问授权链接获取新 code",
    "3. 运行换 token 脚本获取新 refresh_token",
    "4. 更新 GitHub Secret: GDRIVE_REFRESH_TOKEN",
    "5. 手动触发 renew-gdrive-tokens workflow 验证"
  ]
}

天眼告警读取脚本:scripts/gdrive/push-token-alerts.js

/**
 * push-token-alerts.js
 * 
 * 天眼系统调用此脚本读取 token-alert.json
 * 并将告警信息写入主控台 + 公告板
 * 
 * 输出:
 *   - grid-db/notifications/token-alert-{timestamp}.md  → 主控台通知
 *   - grid-db/bulletin/token-alert-{timestamp}.md       → 公告板通知
 */

const fs = require('fs');
const path = require('path');

function pushAlerts() {
  const alertPath = path.join(__dirname, '../../grid-db/logs/token-alert.json');
  
  if (!fs.existsSync(alertPath)) {
    console.log('✅ 无告警。');
    return;
  }
  
  const alert = JSON.parse(fs.readFileSync(alertPath, 'utf8'));
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
  
  // 生成主控台通知
  const dashboardContent = [
    `# ⚠️ Token 续期告警`,
    ``,
    `**时间:** ${alert.time}`,
    `**严重级:** ${alert.severity || 'ALERT'}`,
    `**影响用户:** ${alert.failed_users.join(', ')}`,
    ``,
    `## 描述`,
    alert.message,
    ``,
    `## 需要人类操作`,
    ...(alert.instructions || []).map((s, i) => s),
    ``,
    `---`,
    `*此告警由 Token 续期引擎自动生成*`
  ].join('\n');
  
  // 写入主控台
  const notifDir = path.join(__dirname, '../../grid-db/notifications');
  if (!fs.existsSync(notifDir)) fs.mkdirSync(notifDir, { recursive: true });
  fs.writeFileSync(path.join(notifDir, `token-alert-${timestamp}.md`), dashboardContent);
  
  // 写入公告板
  const bulletinDir = path.join(__dirname, '../../grid-db/bulletin');
  if (!fs.existsSync(bulletinDir)) fs.mkdirSync(bulletinDir, { recursive: true });
  fs.writeFileSync(path.join(bulletinDir, `token-alert-${timestamp}.md`), dashboardContent);
  
  // 清除已处理的告警文件
  fs.unlinkSync(alertPath);
  
  console.log(`⚠️ 告警已推送到主控台 + 公告板: token-alert-${timestamp}.md`);
}

pushAlerts();

Phase H · 天眼全局扫描清单(必须执行)

1. 文件完整性扫描

检查项 预期 状态
config/gdrive-tokens.json 存在 存在且 JSON 格式有效
scripts/gdrive/renew-tokens.js 存在 存在且可执行
scripts/gdrive/check-hibernation.js 存在 存在且可导入
scripts/gdrive/push-token-alerts.js 存在 存在且可执行
.github/workflows/renew-gdrive-tokens.yml 存在 存在且 YAML 格式有效
.github/workflows/check-token-health.yml 存在 存在且 YAML 格式有效
grid-db/logs/ 目录存在 存在(可为空)
grid-db/notifications/ 目录存在 存在(可为空)
grid-db/bulletin/ 目录存在 存在(可为空)

2. 注册表数据完整性扫描

  • schema_version 字段存在
  • oauth_app.token_ttl_days = 7
  • oauth_app.renew_interval_days = 6
  • tokens 数组至少包含主控 TCS-0002
  • 主控条目的 github_secret_name = GDRIVE_REFRESH_TOKEN
  • 主控条目的 status = active
  • 主控条目的 expires_at 在未来(未过期)
  • 每个条目的 github_secret_name 唯一且对应一个实际存在的 GitHub Secret

3. CRON 与休眠冲突扫描

检查项 预期 状态
主刷新 A CRON 时间不在周六 20:00-00:00 CST 周一 10:00 CST 安全
主刷新 B CRON 时间不在周六 20:00-00:00 CST 周四 10:00 CST 安全
安全网 CRON 时间不在日休眠 04:00-04:10 CST 12:15 CST 安全
主刷新 A + B 间隔 ≤ 6 天 周一→周四 = 3天周四→下周一 = 4天
最坏情况:周一失败+周四失败,安全网能在 48h 内发现 每天检查,最晚 1 天内发现
最极端场景:连续 3 次刷新都失败→告警输出 token-alert.json + 非零退出码

4. 天眼生命线任务集成扫描

  • skyeye-config.json(或等价)中包含 TOKEN-RENEWTOKEN-HEALTH 生命线任务
  • 两个任务均标记 hibernate_exempt: true
  • 休眠决策引擎已加入生命线豁免逻辑
  • 天眼休眠期内触发 Token 刷新,确认能正常执行(不被休眠拦截)

5. 安全扫描

  • renew-tokens.js 中无硬编码凭据
  • 日志输出中不包含 Token 实体grep 检查 console.log 中是否输出 refresh_token
  • gdrive-tokens.json 中不包含 Token 实体(只有元数据)
  • 所有凭据仅通过 process.env 读取
  • GitHub Secret 更新用 tweetsodium 加密(不明文传输)

6. Workflow 完整性扫描

  • renew-gdrive-tokens.yml 包含 [skip ci] 防循环触发
  • check-token-health.yml 包含 [skip ci] 防循环触发
  • 两个 Workflow 均支持 workflow_dispatch 手动触发
  • 失败时有告警输出(非零退出码 + alert 文件)
  • tweetsodium 依赖在 workflow 中安装(不依赖本地 node_modules

7. 端到端流程验证

  • 手动触发 renew-gdrive-tokens Workflow确认能正常完成
  • 检查注册表 renew_log 中是否写入了成功记录
  • 检查 expires_at 是否已更新为新的 7 天后
  • 检查 GitHub Secret GDRIVE_REFRESH_TOKEN 是否被更新(看 secret 的 "Updated" 时间戳)
  • 手动触发 check-token-health Workflow确认显示 “All tokens healthy”

Phase I · 提交

天眼扫描全部通过后:

git add -A
git commit -m "feat: OAuth2 Token 自动续期引擎 + 天眼生命线任务豁免 + 多用户Token管理 · ZY-TOKEN-RENEW-2026-0324-001 [skip ci]"
git push

提交后,手动触发一次 renew-gdrive-tokens Workflow确认全绿。


📈 生命周期时序图

以下是一个典型周期的时序图,展示刷新、休眠、检查的协作关系:

gantt
    title Token 续期生命周期(一周示例)
    dateFormat HH:mm
    axisFormat %H:%M
    
    section 周一
    主刷新 A :done, 10:00, 10:10
    安全网检查 :done, 12:15, 12:20
    
    section 周二
    安全网检查 :done, 12:15, 12:20
    
    section 周三
    安全网检查 :done, 12:15, 12:20
    
    section 周四
    主刷新 B :done, 10:00, 10:10
    安全网检查 :done, 12:15, 12:20
    
    section 周五
    安全网检查 :done, 12:15, 12:20
    
    section 周六
    安全网检查 :done, 12:15, 12:20
    天眼休眠 :crit, 20:00, 24:00
    
    section 周日
    安全网检查 :done, 12:15, 12:20

📝 执行回执区

铸渊完成每个 Phase 后,在此处追加回执:

Phase 状态 完成时间 备注 / Commit SHA
A · Token 注册表 待执行
B · Token 自动刷新脚本 待执行
C · 天眼休眠避让机制 待执行
D · GitHub Action Workflow 待执行
E · 天眼生命线任务注册 待执行
F · 多用户 Token 流程 待执行
G · 告警推送系统 待执行
H · 天眼全局扫描 待执行
I · 提交 待执行

👤 人类手动操作区

当前无需人类操作

本指令的所有任务均可由铸渊独立完成。

未来可能需要的人类操作

  1. 添加新开发者时
    • 在 Google Cloud Console 加入测试用户白名单
    • 用新用户 Gmail 完成 OAuth 授权
    • 在 GitHub 添加对应的 GDRIVE_REFRESH_TOKEN_DEVxxx Secret
    • 通知铸渊更新注册表
  2. Token 刷新失败时(告警触发)
    • 重新访问授权链接 → 拿新 code → 换新 token → 更新 GitHub Secret
    • 手动触发 renew-gdrive-tokens Workflow 验证
  3. 发布 OAuth 应用(彻底解决过期问题)
    • 路径Google Cloud Console → API和服务 → OAuth 权限请求页面 → 点「发布应用」
    • 发布后 Refresh Token 永久有效,续期引擎变为安全备份而非必要操作

⚖️ 指令执行顺序


🖋️ 霜砚 · PER-SY001

🧊 代 TCS-0002∞ 冰朔 签发

📅 2026-03-24T15:00+08:00