LL-007 · pre-op-guard 导航挑战 · 服务器操作前强制全局地图

- pre-op-guard.py: 前置操作守门人,人格体登录时锁定服务器,必须完成导航地图验证
- module-registry.hdlp: 模块编码体系 + 注册协议
- module-register.sh: 一键注册模块到服务器
- OPERATION-MANUAL.hdlp v1.1: 新增第八节 服务器操作前导航挑战
- INDEX.hdlp: 注册新文件

设计:
  人格体登录 → 服务器自我审计 → 锁定 → 挑战:找出所有模块编码
  人格体探索 → 收集编码 → 提交 → 服务器比对
  一致 → 解锁 · 人格体知道全局地图 · 不会再改A坏B

[SEC-CLEAN] · pre-op-guard 已就绪
This commit is contained in:
冰朔 2026-07-11 16:28:05 +08:00
parent 7bc8a87135
commit 875b4c2381
5 changed files with 782 additions and 4 deletions

View File

@ -53,6 +53,9 @@
| **推送守门人** / **pre-receive-guard** / **服务器拦截** | `zero-point/core-channel/revive-guard/pre-receive-guard.py` | | **推送守门人** / **pre-receive-guard** / **服务器拦截** | `zero-point/core-channel/revive-guard/pre-receive-guard.py` |
| **推送清理插件** / **pre-push-clean** / **敏感信息自动转乱码** | `zero-point/core-channel/revive-guard/pre-push-clean.py` | | **推送清理插件** / **pre-push-clean** / **敏感信息自动转乱码** | `zero-point/core-channel/revive-guard/pre-push-clean.py` |
| **安装钩子** / **install-hooks** | `zero-point/core-channel/revive-guard/install-hooks.sh` | | **安装钩子** / **install-hooks** | `zero-point/core-channel/revive-guard/install-hooks.sh` |
| **前置操作守门人** / **pre-op-guard** / **导航挑战** / **操作前先画地图** | `zero-point/core-channel/revive-guard/pre-op-guard.py` |
| **模块注册** / **module-registry** / **服务器编码体系** | `zero-point/core-channel/revive-guard/module-registry.hdlp` |
| **模块注册脚本** / **module-register** | `zero-point/core-channel/revive-guard/module-register.sh` |
| **钥匙串** / **凭证** | `eternal-lake-heart/heartbeat-core/KEYCHAIN.hdlp` | | **钥匙串** / **凭证** | `eternal-lake-heart/heartbeat-core/KEYCHAIN.hdlp` |
| **冰朔的保险柜** / **SSH密钥** / **服务器直连** / **保险柜** | `eternal-lake-heart/heartbeat-core/BINGSHUO-KEYSTORE.hdlp` | | **冰朔的保险柜** / **SSH密钥** / **服务器直连** / **保险柜** | `eternal-lake-heart/heartbeat-core/BINGSHUO-KEYSTORE.hdlp` |
| **邮箱金库** | `eternal-lake-heart/heartbeat-core/EMAIL-VAULT.hdlp` | | **邮箱金库** | `eternal-lake-heart/heartbeat-core/EMAIL-VAULT.hdlp` |

View File

@ -1,4 +1,4 @@
# 光湖语言系统 · 人格体操作手册 v1.0 # 光湖语言系统 · 人格体操作手册 v1.1
## 推送前必读 · 不读推不上去 ## 推送前必读 · 不读推不上去
> **HLDP://fifth-domain/zero-point/core-channel/OPERATION-MANUAL** > **HLDP://fifth-domain/zero-point/core-channel/OPERATION-MANUAL**
@ -9,7 +9,7 @@
> >
> **主权者**: 冰朔 ICE-GL∞ > **主权者**: 冰朔 ICE-GL∞
> >
> **签发**: 铸渊 ICE-GL-ZY001 · LL-006-20260711 > **签发**: 铸渊 ICE-GL-ZY001 · LL-007-20260711
> >
> **平台**: TCS 通感语言核系统 · 国作登字-2026-A-00037559 > **平台**: TCS 通感语言核系统 · 国作登字-2026-A-00037559
> >
@ -196,9 +196,111 @@ chmod +x .git/hooks/pre-push
--- ---
## 八 · 修订历史 ## 八 · 服务器操作前导航挑战v1.1 新增)
### 8.1 问题
你登录服务器SSH 或 API**服务器上还跑了其他东西**。你如果不知道就动手:
``` ```
改 Gatekeeper 端口 → 小湖灯连不上了 → 复活守门人邮件发不出去了
改 Forgejo 配置 → 推送拦截崩了 → 敏感信息又开始泄露
重启一个服务 → 另一个依赖它的服务也死了
```
冰朔每次都要说"你先看看服务器上还跑了啥"——冰朔的认知是有限的,不能总靠他提醒。
### 8.2 解决方案pre-op-guard 导航挑战
```
你(人格体) SSH 登录服务器
pre-op-guard 自动触发
├── 服务器自我审计: "我现在运行了 N 个模块"
├── 生成模块编码集: {GZ006-GTW-01, GZ006-LAMP-01, ...}
├── 锁定操作 🔒 ← 你不能改任何东西
└── 呈现挑战: "N 个模块在运行,找出全部编码"
你开始探索
├── ls /opt/zhuyuan/registry/modules.d/
├── systemctl list-units --type=service
├── ss -tlnp # 查看端口
├── 用 HLDP 格式整理导航地图
└── 收集所有模块编码
提交验证
pre-op-guard.py --submit '["GZ006-GTW-01","GZ006-LAMP-01",...]'
服务器比对
├── 你提交的编码 == 服务器自审的编码 ?
│ ├─ YES → 🔓 解锁 ✅ · 导航地图存档 · 你可以操作了
│ └─ NO → 🔒 保持锁定 · "你漏了 MOD-X继续探索"
```
### 8.3 编码体系
每个模块有唯一编码,格式: `{服务器}-{功能}-{序号}`
| 编码 | 模块 | 示例 |
|------|------|------|
| `GZ006-GTW-01` | Gatekeeper | 端口 8922 |
| `GZ006-LAMP-01` | 小湖灯 | 邮件通知 |
| `GZ006-FRG-01` | Forgejo | 代码仓库 |
| `GZ006-RVGD-01` | 复活守门人 | revive-guard |
| `GZ006-LDRV-01` | 光湖驱动引擎 | 端口 8923 |
| … | … | … |
完整编码表见: `module-registry.hdlp`
### 8.4 对你的人格体工作流影响
```
以前:
SSH 登录 → 直接动手 → 改A坏B → 冰朔:"你怎么又把XXX搞坏了"
现在:
SSH 登录 → pre-op-guard 挑战 → 被迫探索 → 画出完整地图 → 提交验证
→ 解锁 → 你现在知道服务器上跑了什么 → 改东西时你知道会影响什么
→ 不会再改A坏B了
```
### 8.5 关键命令
```bash
# 查看当前是否锁定
pre-op-guard.py --status
# 触发导航挑战(如果未自动触发)
pre-op-guard.py --challenge
# 提交你收集到的编码
pre-op-guard.py --submit '["GZ006-GTW-01","GZ006-LAMP-01","GZ006-FRG-01"]'
# 紧急解锁(只有冰朔用)
pre-op-guard.py --unlock --force
```
### 8.6 时间限制
锁定有 30 分钟超时。超时后自动解锁。但这表示你没有完成导航地图——下次登录还会触发。
**建议:完成导航地图后,地图会被存档。后续可以直接引用已验证的地图,无需重新探索。**
---
## 九 · 修订历史
```
v1.1 · LL-007-20260711 · 服务器操作前置导航挑战
- pre-op-guard 导航挑战协议
- 模块编码体系 + 注册系统
- 服务器自我审计 + 人格体探索验证
- 操作前强制全局地图
v1.0 · LL-006-20260711 · 初始版本 v1.0 · LL-006-20260711 · 初始版本
- pre-push-clean 插件强制化 - pre-push-clean 插件强制化
- 操作手册建立 - 操作手册建立
@ -213,7 +315,7 @@ v1.0 · LL-006-20260711 · 初始版本
> ⊢ 语言等于现实 · 语言不可撤销 > ⊢ 语言等于现实 · 语言不可撤销
> ⊢ 冰朔在第 5 代 · 系统永远在第 4 代 > ⊢ 冰朔在第 5 代 · 系统永远在第 4 代
铸渊 ICE-GL-ZY001 · LL-006-20260711 · 操作手册 v1.0 签字 铸渊 ICE-GL-ZY001 · LL-007-20260711 · 操作手册 v1.1 签字
冰朔 ICE-GL∞ · 主权签署 · 国作登字-2026-A-00037559 冰朔 ICE-GL∞ · 主权签署 · 国作登字-2026-A-00037559
⊢ 平台: TCS 通感语言核系统 ⊢ 平台: TCS 通感语言核系统

View File

@ -0,0 +1,122 @@
#!/bin/bash
# ═══════════════════════════════════════════════════════════
# 光湖语言系统 · 模块注册脚本
# 服务器上任一模块启动时调用 · 自动写入注册文件
#
# 用法:
# module-register.sh --server GZ006 --func GTW --name "Gatekeeper" --port 8922
# module-register.sh --stop GZ006-GTW-01
# ═══════════════════════════════════════════════════════════
REGISTRY_DIR="/opt/zhuyuan/registry/modules.d"
mkdir -p "$REGISTRY_DIR"
# ── 停止模式 ──
if [ "$1" = "--stop" ]; then
CODE="$2"
if [ -z "$CODE" ]; then
echo "用法: $0 --stop {CODE}" >&2
exit 1
fi
REG_FILE="$REGISTRY_DIR/MOD-${CODE}.json"
if [ -f "$REG_FILE" ]; then
python3 -c "
import json, sys
try:
with open('$REG_FILE', 'r') as f:
data = json.load(f)
data['status'] = 'stopped'
data['stopped_at'] = '$(date -u +%Y-%m-%dT%H:%M:%SZ)'
with open('$REG_FILE', 'w') as f:
json.dump(data, f, indent=2)
print(f'⊢ 模块 {data[\"code\"]} 已标记为已停止')
except Exception as e:
print(f'⚠ 更新注册文件失败: {e}', file=sys.stderr)
"
fi
exit 0
fi
# ── 注册模式 ──
SERVER=""
FUNC=""
NAME=""
PORT=""
PROTOCOL="tcp"
DESCRIPTION=""
PID="$$"
while [ $# -gt 0 ]; do
case "$1" in
--server) SERVER="$2"; shift 2 ;;
--func) FUNC="$2"; shift 2 ;;
--name) NAME="$2"; shift 2 ;;
--port) PORT="$2"; shift 2 ;;
--protocol) PROTOCOL="$2"; shift 2 ;;
--description) DESCRIPTION="$2"; shift 2 ;;
--pid) PID="$2"; shift 2 ;;
*) shift ;;
esac
done
if [ -z "$SERVER" ] || [ -z "$FUNC" ] || [ -z "$NAME" ]; then
echo "❌ 缺少必要参数: --server --func --name" >&2
exit 1
fi
# 计算序号(同一服务器+功能下,取最大序号+1
SEQ=1
for f in "$REGISTRY_DIR"/MOD-${SERVER}-${FUNC}-*.json; do
if [ -f "$f" ]; then
existing_seq=$(basename "$f" .json | grep -oE '[0-9]+$')
if [ -n "$existing_seq" ] && [ "$existing_seq" -ge "$SEQ" ]; then
SEQ=$((existing_seq + 1))
fi
fi
done
# 格式化序号为两位
SEQ_FMT=$(printf "%02d" "$SEQ")
CODE="${SERVER}-${FUNC}-${SEQ_FMT}"
REG_FILE="$REGISTRY_DIR/MOD-${CODE}.json"
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
python3 -c "
import json
data = {
'code': '${CODE}',
'server': '${SERVER}',
'function': '${FUNC}',
'name': '${NAME}',
'port': ${PORT:-0},
'protocol': '${PROTOCOL}',
'description': '${DESCRIPTION}',
'pid': ${PID},
'started_at': '${TIMESTAMP}',
'registered_at': '${TIMESTAMP}',
'status': 'running'
}
with open('${REG_FILE}', 'w') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f'✅ 模块已注册: {data[\"code\"]}')
print(f' 名称: ${NAME}')
print(f' 文件: MOD-${CODE}.json')
" 2>/dev/null || {
# Python3 不可用时的降级方案(纯 shell 写 JSON
cat > "$REG_FILE" << JSONEOF
{
"code": "${CODE}",
"server": "${SERVER}",
"function": "${FUNC}",
"name": "${NAME}",
"port": ${PORT:-0},
"protocol": "${PROTOCOL}",
"description": "${DESCRIPTION}",
"pid": ${PID},
"started_at": "${TIMESTAMP}",
"registered_at": "${TIMESTAMP}",
"status": "running"
}
JSONEOF
echo "✅ 模块已注册: ${CODE}"
}

View File

@ -0,0 +1,130 @@
# 光湖语言系统 · 服务器模块注册协议 v1.0
## HLDP://fifth-domain/zero-point/core-channel/revive-guard/module-registry
> **类型**: 运行时基础设施 · 模块编码体系 · 自动注册
>
> **依赖**: 无(被 pre-op-guard 引用)
>
> **主权者**: 冰朔 ICE-GL∞
>
> **签发**: LL-007-20260711
---
## ⊢ 零 · 目的
服务器上同时运行多个模块Gatekeeper、小湖灯、Forgejo、光湖驱动引擎、复活守门人……
人格体登录服务器后直接操作 → **不知道还有别的模块在跑** → 改了一个 → 坏了三个。
解决:**每个模块在启动时自动注册 → 分配唯一编码 → 人格体必须先探索出全部编码才能操作。**
---
## 一 · 模块编码体系
### 1.1 编码格式
```
{服务器ID}-{功能简码}-{序号}
```
### 1.2 已分配编码
| 编码 | 模块 | 服务器 | 端口 |
|------|------|--------|------|
| `GZ006-GTW-01` | Gatekeeper · 守门人 | GZ-006 | 8922 |
| `GZ006-LAMP-01` | 小湖灯 · 邮件通知 | GZ-006 | — |
| `GZ006-FRG-01` | Forgejo · 代码仓库 | GZ-006 | 443 |
| `GZ006-RVGD-01` | 复活守门人 · revive-guard | GZ-006 | 8922 |
| `GZ006-LDRV-01` | 光湖驱动引擎 · lake-driver | GZ-006 | 8923 |
| `GZ006-HLDP-01` | HLDP 协议服务 · hldp-server | GZ-006 | 8971 |
| `GZ006-KSTR-01` | 保险库 · keystore | GZ-006 | — |
| `SG001-LAKE-01` | 光湖镜像 · lake-mirror | SG-001 | 8971 |
| `SG001-GTW-01` | Gatekeeper 备用 | SG-001 | 8922 |
### 1.3 新模块注册
任一模块在服务器上启动时,调用:
```bash
module-register.sh \
--server GZ006 \
--func GTW \
--name "Gatekeeper 守门人" \
--port 8922 \
--protocol tcp \
--description "冰朔人格体复活请求入口 · 邮箱验证码"
```
自动生成: `/opt/zhuyuan/registry/modules.d/MOD-GZ006-GTW-01.json`
---
## 二 · 注册文件格式
```json
{
"code": "GZ006-GTW-01",
"server": "GZ-006",
"function": "GTW",
"name": "Gatekeeper 守门人",
"port": 8922,
"protocol": "tcp",
"description": "冰朔人格体复活请求入口 · 邮箱验证码",
"pid": 12345,
"started_at": "2026-07-11T14:30:00Z",
"registered_at": "2026-07-11T14:30:01Z",
"status": "running"
}
```
## 三 · 注册时机
```
服务启动 → systemd / docker / 手动启动
服务初始化完成 → 调用 module-register.sh
写入 /opt/zhuyuan/registry/modules.d/MOD-{CODE}.json
服务退出时 → 注册文件自动标记 status: "stopped"
```
---
## 四 · 注册目录结构
```
/opt/zhuyuan/registry/
├── modules.d/ ← 运行时注册文件(不进代码仓库)
│ ├── MOD-GZ006-GTW-01.json
│ ├── MOD-GZ006-LAMP-01.json
│ ├── MOD-GZ006-FRG-01.json
│ ├── MOD-GZ006-RVGD-01.json
│ └── ...
├── maps/ ← 人格体提交的导航地图(存档复用)
│ ├── map-zhuyuan-20260711.hdlp
│ └── ...
└── lock/ ← 锁定状态文件
└── pre-op-lock.json
```
---
## 五 · 与人机交互的关系
- 人格体不需要提前知道编码
- 人格体会在探索阶段读到这些注册文件
- 收集完所有编码 → 提交给 pre-op-guard 验证
- 验证通过 → 解锁操作 → 人格体现在知道完整地图了
---
> ⊢ 本协议是 pre-op-guard 的依赖
> ⊢ 每个新模块必须遵守本协议注册
> ⊢ 不注册 = 服务器不认 = 人格体探索不到 = 无法解锁
> ⊢ 语言等于现实 · 注册即存在

View File

@ -0,0 +1,421 @@
#!/usr/bin/env python3
"""
光湖语言系统 · 前置操作守门人 v1.0
Guanghu Language System · Pre-Operation Guard
每次人格体连接服务器 触发自我审计 锁定 人格体必须探索+提交导航地图
地图编码与服务器自审一致 解锁操作
设计哲学:
铸渊上服务器就动手 不知道还跑了别的模块 改A坏B 冰朔每次都要说
服务器全天运行 人格体接入时触发自我审计 "我现在跑了这些模块"
人格体必须探索 画出完整导航地图 提交编码列表
服务器比对: 人格体提交的编码 == 服务器自审编码?
一致 解锁 · 人格体知道完整地图了 · 不会再改A坏B
不一致 "你漏了 MOD-X · 继续探索"
用法:
pre-op-guard.py --audit # 服务器自我审计
pre-op-guard.py --challenge [--for PERSONA_NAME] # 触达挑战
pre-op-guard.py --submit '<json_codes>' # 人格体提交验证
pre-op-guard.py --status # 查看锁定状态
pre-op-guard.py --unlock --force # 紧急解锁(冰朔用)
"""
import os, sys, json, time, subprocess, hashlib
from datetime import datetime, timedelta
# ═══════════════════════════════════════════════════════
# 配置
# ═══════════════════════════════════════════════════════
REGISTRY_DIR = os.environ.get("REGISTRY_DIR", "/opt/zhuyuan/registry/modules.d")
MAPS_DIR = os.environ.get("MAPS_DIR", "/opt/zhuyuan/registry/maps")
LOCK_DIR = os.environ.get("LOCK_DIR", "/opt/zhuyuan/registry/lock")
LOCK_FILE = os.path.join(LOCK_DIR, "pre-op-lock.json")
# 锁定超时(秒):超过此时间无人提交 → 自动解锁(防止死锁)
LOCK_TIMEOUT = int(os.environ.get("PRE_OP_LOCK_TIMEOUT", "1800")) # 30 分钟
# 是否强制启用(可以通过环境变量禁用)
ENABLED = os.environ.get("PRE_OP_GUARD_ENABLED", "1") == "1"
def ensure_dirs():
"""确保所有目录存在"""
for d in [REGISTRY_DIR, MAPS_DIR, LOCK_DIR]:
os.makedirs(d, exist_ok=True)
def get_server_identity():
"""获取服务器身份"""
hostname = os.uname().nodename if hasattr(os, 'uname') else os.environ.get("HOSTNAME", "unknown")
return hostname
def audit_server():
"""服务器自我审计: 读取所有注册模块 → 返回编码集"""
ensure_dirs()
modules = []
if os.path.isdir(REGISTRY_DIR):
for filename in sorted(os.listdir(REGISTRY_DIR)):
if not filename.endswith('.json'):
continue
filepath = os.path.join(REGISTRY_DIR, filename)
try:
with open(filepath, 'r') as f:
data = json.load(f)
if data.get('status') == 'running':
modules.append({
'code': data['code'],
'name': data.get('name', ''),
'port': data.get('port', 0),
'function': data.get('function', ''),
})
except (json.JSONDecodeError, IOError):
pass
codes = sorted([m['code'] for m in modules])
return {
'server': get_server_identity(),
'audited_at': datetime.utcnow().isoformat() + 'Z',
'module_count': len(codes),
'codes': codes,
'modules': modules,
}
def is_locked():
"""检查当前是否锁定"""
if not os.path.exists(LOCK_FILE):
return False
try:
with open(LOCK_FILE, 'r') as f:
lock = json.load(f)
# 检查超时
locked_at = datetime.fromisoformat(lock.get('locked_at', '').replace('Z', '+00:00'))
if datetime.utcnow() - locked_at.replace(tzinfo=None) > timedelta(seconds=LOCK_TIMEOUT):
# 超时 → 自动解锁
os.remove(LOCK_FILE)
return False
return True
except Exception:
return False
def create_lock(challenger="unknown"):
"""锁定服务器"""
ensure_dirs()
audit = audit_server()
lock = {
'locked': True,
'locked_at': datetime.utcnow().isoformat() + 'Z',
'challenger': challenger,
'module_count': audit['module_count'],
'server_codes_hash': hashlib.sha256(
','.join(audit['codes']).encode()
).hexdigest()[:16],
'timeout_seconds': LOCK_TIMEOUT,
}
with open(LOCK_FILE, 'w') as f:
json.dump(lock, f, indent=2)
return lock, audit
def release_lock():
"""解锁服务器"""
if os.path.exists(LOCK_FILE):
os.remove(LOCK_FILE)
return True
return False
def present_challenge(audit, persona_name="铸渊"):
"""向人格体呈现挑战"""
module_count = audit['module_count']
codes = audit['codes']
modules = audit['modules']
lines = []
lines.append("")
lines.append("╔══════════════════════════════════════════════╗")
lines.append("║ 🗺️ 光湖前置操作守门人 · 导航地图挑战 ║")
lines.append("╚══════════════════════════════════════════════╝")
lines.append("")
lines.append(f" 服务器: {audit['server']}")
lines.append(f" 挑战者: {persona_name}")
lines.append(f" 状态: 🔒 已锁定 · 操作被拦截")
lines.append(f" 当前运行模块数: {module_count}")
lines.append("")
lines.append(" ── 挑战说明 ──")
lines.append(f" 此服务器上正在运行 {module_count} 个模块。")
lines.append(" 每个模块有唯一编码(格式: SERVER-FUNC-SEQ")
lines.append("")
lines.append(" 你需要:")
lines.append(f" ① 探索服务器,发现全部 {module_count} 个模块")
lines.append(" ② 用 HLDP 格式画出导航地图")
lines.append(" ③ 通过 pre-push-clean 过滤敏感信息")
lines.append(" ④ 提交编码列表到验证端点")
lines.append("")
lines.append(" 探索指引:")
lines.append(f" ls {REGISTRY_DIR}/")
lines.append(" systemctl list-units --type=service --state=running")
lines.append(" ss -tlnp # 查看监听端口")
lines.append("")
lines.append(" ── 已注册模块(供参考 · 仅显示名称 · 编码需自行发现)──")
for i, m in enumerate(modules, 1):
lines.append(f" [{i}] {m['name']}")
lines.append("")
lines.append(" ── 提交方式 ──")
lines.append(" 在服务器上执行:")
lines.append(" pre-op-guard.py --submit '[")
lines.append(' "GZ006-GTW-01",')
lines.append(' "GZ006-LAMP-01",')
lines.append(' "GZ006-FRG-01",')
lines.append(' ... # 你收集到的所有编码')
lines.append(" ]'")
lines.append("")
lines.append(f" ⏰ 超时: {LOCK_TIMEOUT // 60} 分钟后自动解锁")
lines.append("")
return '\n'.join(lines)
def validate_submission(submitted_codes):
"""验证人格体提交的编码列表"""
audit = audit_server()
server_codes = set(audit['codes'])
submitted_set = set(submitted_codes)
missing = server_codes - submitted_set
extra = submitted_set - server_codes
result = {
'valid': len(missing) == 0 and len(extra) == 0,
'server_codes': sorted(server_codes),
'submitted_codes': sorted(submitted_set),
'missing': sorted(missing),
'extra': sorted(extra),
'module_count': len(server_codes),
'submitted_count': len(submitted_set),
}
if result['valid']:
# 解锁
release_lock()
# 保存导航地图
save_map(submitted_codes, audit)
else:
# 更新锁定(重置超时,给更多时间)
if is_locked():
with open(LOCK_FILE, 'r') as f:
lock = json.load(f)
lock['locked_at'] = datetime.utcnow().isoformat() + 'Z'
lock['last_submission'] = {
'submitted_codes': sorted(submitted_set),
'missing': sorted(missing),
'extra': sorted(extra),
}
with open(LOCK_FILE, 'w') as f:
json.dump(lock, f, indent=2)
return result
def save_map(codes, audit):
"""保存人格体提交的导航地图为持久化 artifact"""
ensure_dirs()
map_data = {
'server': audit['server'],
'created_at': datetime.utcnow().isoformat() + 'Z',
'validated_at': datetime.utcnow().isoformat() + 'Z',
'codes': sorted(codes),
'module_count': len(codes),
'full_modules': audit['modules'],
}
timestamp = datetime.utcnow().strftime('%Y%m%d-%H%M%S')
map_file = os.path.join(MAPS_DIR, f"map-{audit['server']}-{timestamp}.json")
with open(map_file, 'w') as f:
json.dump(map_data, f, indent=2, ensure_ascii=False)
# 同时保存一个 HLDP 格式的副本
hldp_file = os.path.join(MAPS_DIR, f"map-{audit['server']}-{timestamp}.hdlp")
with open(hldp_file, 'w') as f:
f.write(f"# 光湖导航地图 · {audit['server']}\n")
f.write(f"## 验证通过 · {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
f.write(f"服务器: {audit['server']}\n")
f.write(f"模块数: {len(codes)}\n\n")
f.write("| 编码 | 名称 | 端口 |\n")
f.write("|------|------|------|\n")
for m in audit['modules']:
f.write(f"| `{m['code']}` | {m['name']} | {m['port']} |\n")
f.write(f"\n> ⊢ 本地图由 pre-op-guard 自动生成 · 验证通过后存档\n")
f.write(f"> ⊢ 后续人格体可引用本地图快速验证\n")
f.write(f"> ⊢ 冰朔 ICE-GL∞ · 国作登字-2026-A-00037559\n")
return map_file
def get_status():
"""获取当前状态"""
status = {
'enabled': ENABLED,
'locked': is_locked(),
'server': get_server_identity(),
}
if status['locked']:
try:
with open(LOCK_FILE, 'r') as f:
lock = json.load(f)
status['lock_details'] = lock
except Exception:
pass
if not status['locked']:
audit = audit_server()
status['modules_running'] = audit['module_count']
status['codes'] = audit['codes']
return status
def main():
if not ENABLED:
print("⊢ pre-op-guard 已禁用 (PRE_OP_GUARD_ENABLED=0)")
sys.exit(0)
if '--audit' in sys.argv:
audit = audit_server()
print(json.dumps(audit, indent=2, ensure_ascii=False))
elif '--challenge' in sys.argv:
persona = "铸渊"
for i, arg in enumerate(sys.argv):
if arg == '--for' and i + 1 < len(sys.argv):
persona = sys.argv[i + 1]
if is_locked():
print("⚠️ 服务器已锁定 · 上一个挑战尚未完成")
status = get_status()
print(json.dumps(status, indent=2, ensure_ascii=False))
sys.exit(1)
lock, audit = create_lock(persona)
challenge = present_challenge(audit, persona)
print(challenge)
elif '--submit' in sys.argv:
if not is_locked():
audit = audit_server()
print("✅ 服务器未锁定 · 但你可以直接提交导航地图验证")
print(f" 当前运行 {audit['module_count']} 个模块")
print(f" 编码: {', '.join(audit['codes'])}")
sys.exit(0)
# 查找 JSON 参数
submit_idx = None
for i, arg in enumerate(sys.argv):
if arg == '--submit' and i + 1 < len(sys.argv):
submit_idx = i + 1
break
if submit_idx is None:
print("❌ 用法: pre-op-guard.py --submit '[\"CODE1\",\"CODE2\",...]'")
sys.exit(1)
try:
submitted_codes = json.loads(sys.argv[submit_idx])
if not isinstance(submitted_codes, list):
raise ValueError("必须是 JSON 数组")
except (json.JSONDecodeError, ValueError) as e:
print(f"❌ JSON 解析失败: {e}")
sys.exit(1)
result = validate_submission(submitted_codes)
print("")
if result['valid']:
print("╔══════════════════════════════════════════════╗")
print("║ ✅ 导航地图验证通过 · 服务器已解锁 ║")
print("╚══════════════════════════════════════════════╝")
print("")
print(f" 提交 {result['submitted_count']} 个编码")
print(f" 服务器运行 {result['module_count']} 个模块")
print(f" 编码: {', '.join(result['submitted_codes'])}")
print("")
print(" 🗺️ 导航地图已存档 · 后续可直接引用")
print(" 🔓 服务器已解锁 · 可以操作了")
print("")
else:
print("╔══════════════════════════════════════════════╗")
print("║ ❌ 导航地图不完整 · 服务器保持锁定 ║")
print("╚══════════════════════════════════════════════╝")
print("")
if result['missing']:
print(f" ⚠️ 缺少 {len(result['missing'])} 个模块:")
for code in result['missing']:
print(f" - {code}")
if result['extra']:
print(f" ⚠️ 多出 {len(result['extra'])} 个不存在的编码:")
for code in result['extra']:
print(f" - {code}")
print("")
print(f" ⊢ 请继续探索,重新提交。")
print(f" ⊢ 已注册模块有 {result['module_count']} 个。")
print("")
elif '--status' in sys.argv:
status = get_status()
if status['locked']:
print("🔒 服务器已锁定")
print(json.dumps(status, indent=2, ensure_ascii=False))
else:
print(f"🔓 服务器未锁定 · {status.get('modules_running', '?')} 个模块运行中")
if 'codes' in status:
print(f" 编码: {', '.join(status['codes'])}")
elif '--unlock' in sys.argv and '--force' in sys.argv:
release_lock()
print("🔓 服务器已强制解锁 · 冰朔特权操作")
elif '--install-to' in sys.argv:
# 安装 pre-op-guard 到服务器的 SSH 登录钩子
install_idx = sys.argv.index('--install-to') + 1
target = sys.argv[install_idx] if install_idx < len(sys.argv) else '/etc/profile.d/pre-op-guard.sh'
install_ssh_hook(target)
else:
print("用法:")
print(" pre-op-guard.py --audit 服务器自我审计")
print(" pre-op-guard.py --challenge 触达挑战(锁定并呈现)")
print(" pre-op-guard.py --submit '[...]' 提交编码验证")
print(" pre-op-guard.py --status 查看锁定状态")
print(" pre-op-guard.py --unlock --force 紧急解锁")
print(" pre-op-guard.py --install-to PATH 安装SSH登录钩子")
def install_ssh_hook(target_path):
"""安装 SSH 登录钩子:每次 SSH 登录时触发 pre-op-guard"""
script_dir = os.path.dirname(os.path.abspath(__file__))
hook_content = f'''#!/bin/bash
# 光湖 pre-op-guard SSH 登录钩子
# 每次 SSH 登录自动触发 · 锁定操作 · 需要完成导航地图验证
GUARD="{script_dir}/pre-op-guard.py"
# 只在交互式 shell 中触发(非 scp/sftp
if [[ $- == *i* ]] && [ -z "$PRE_OP_BYPASS" ]; then
python3 "$GUARD" --challenge --for "$USER"
fi
'''
try:
with open(target_path, 'w') as f:
f.write(hook_content)
os.chmod(target_path, 0o755)
print(f"✅ SSH 登录钩子已安装: {target_path}")
print(f" 此后每次 SSH 登录都会触发 pre-op-guard 导航挑战")
print(f" 若要临时绕过: PRE_OP_BYPASS=1 ssh user@host")
except IOError as e:
print(f"❌ 安装失败: {e}")
if __name__ == '__main__':
main()