feat: expose live enterprise domain presence

This commit is contained in:
冰朔 2026-07-30 00:26:58 +08:00
commit ef1734baee
4 changed files with 81 additions and 2 deletions

View file

@ -4,6 +4,11 @@
部署后只监听本机 `127.0.0.1:8031`。公众网站与后续 GLSV 页面通过 Nginx 以单独的受控路由接入;在邮件确认与节点连接器完成前,不开放节点激活或执行。 部署后只监听本机 `127.0.0.1:8031`。公众网站与后续 GLSV 页面通过 Nginx 以单独的受控路由接入;在邮件确认与节点连接器完成前,不开放节点激活或执行。
`hololake-public-status.nginx.conf` 只公开两个精确的只读 GET 路由:
`/api/hololake/enterprise/health``/api/hololake/enterprise/status`。它们用于让
HoloLake 回读 `AW-GZ-001` 企业主机和四个本机承载域的实时状态,不转发管理凭据、写入或
任意路径。
人类管理员与人格体遵守同一条入口链: 人类管理员与人格体遵守同一条入口链:
```text ```text

View file

@ -0,0 +1,26 @@
# Public, read-only enterprise presence receipts for HoloLake.
# Include this file inside the TLS server block for guanghu.chat.
location = /api/hololake/enterprise/health {
limit_except GET {
deny all;
}
proxy_pass http://127.0.0.1:8031/health;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 10s;
add_header Cache-Control "no-store" always;
}
location = /api/hololake/enterprise/status {
limit_except GET {
deny all;
}
proxy_pass http://127.0.0.1:8031/v1/status;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 10s;
add_header Cache-Control "no-store" always;
}

View file

@ -36,6 +36,12 @@ DOMAINS = {
} }
ENTERPRISE_MANAGED_DOMAINS = {"DOMAIN-ZS", "DOMAIN-MAIN", "DOMAIN-SUB", "DOMAIN-ZERO"} ENTERPRISE_MANAGED_DOMAINS = {"DOMAIN-ZS", "DOMAIN-MAIN", "DOMAIN-SUB", "DOMAIN-ZERO"}
EXTERNAL_FOUNDATION_DOMAINS = {"DOMAIN-FIFTH"} EXTERNAL_FOUNDATION_DOMAINS = {"DOMAIN-FIFTH"}
HOSTED_DOMAIN_NODES = {
"DOMAIN-MAIN": ("AW-GZ-001-MAIN", "AW-GZ-001 · 光湖主域"),
"DOMAIN-SUB": ("AW-GZ-001-SUB", "AW-GZ-001 · 光湖分域"),
"DOMAIN-ZERO": ("AW-GZ-001-ZERO", "AW-GZ-001 · 光湖零域"),
"DOMAIN-ZS": ("AW-GZ-001-ZS", "AW-GZ-001 · 光湖零感域"),
}
def now(): def now():
@ -77,9 +83,28 @@ def connection():
capsule_hash TEXT NOT NULL, created_at INTEGER NOT NULL, expires_at INTEGER NOT NULL capsule_hash TEXT NOT NULL, created_at INTEGER NOT NULL, expires_at INTEGER NOT NULL
); );
""") """)
observed_at = now()
for domain_id, name in DOMAINS.items(): for domain_id, name in DOMAINS.items():
state = "EXTERNAL_PRIVATE_FOUNDATION" if domain_id in EXTERNAL_FOUNDATION_DOMAINS else "PENDING_ENTRY_NODE" state = "EXTERNAL_PRIVATE_FOUNDATION" if domain_id in EXTERNAL_FOUNDATION_DOMAINS else "PENDING_ENTRY_NODE"
db.execute("INSERT OR IGNORE INTO domains VALUES (?, ?, ?, ?)", (domain_id, name, state, now())) db.execute("INSERT OR IGNORE INTO domains VALUES (?, ?, ?, ?)", (domain_id, name, state, observed_at))
for domain_id, (node_id, display_name) in HOSTED_DOMAIN_NODES.items():
db.execute(
"INSERT OR IGNORE INTO nodes VALUES (?, ?, NULL, 'ACTIVE', ?, '127.0.0.1', ?, ?, ?, ?)",
(
node_id,
domain_id,
display_name,
json.dumps(["health_check"]),
"server-local-lighthouse",
observed_at,
observed_at,
),
)
db.execute(
"UPDATE nodes SET state='ACTIVE', last_heartbeat=? WHERE id=?",
(observed_at, node_id),
)
db.execute("UPDATE domains SET state='HOSTED_ACTIVE' WHERE id=?", (domain_id,))
db.commit() db.commit()
return db return db
@ -250,7 +275,16 @@ class Handler(BaseHTTPRequestHandler):
return self.respond(200, {"ok": True, "service": "guanghu-enterprise-lighthouse", "mode": "map-intent-agent-gate", "map_hash": map_hash, "execution": "disabled"}) return self.respond(200, {"ok": True, "service": "guanghu-enterprise-lighthouse", "mode": "map-intent-agent-gate", "map_hash": map_hash, "execution": "disabled"})
if self.path == "/v1/status": if self.path == "/v1/status":
counts = {row["state"]: row["count"] for row in db.execute("SELECT state, COUNT(*) AS count FROM nodes GROUP BY state")} counts = {row["state"]: row["count"] for row in db.execute("SELECT state, COUNT(*) AS count FROM nodes GROUP BY state")}
return self.respond(200, {"ok": True, "domains": [dict(row) for row in db.execute("SELECT id,name,state FROM domains ORDER BY id")], "node_counts": counts, "fixed_actions": sorted(FIXED_ACTIONS), "raw_shell": "rejected"}) return self.respond(200, {
"ok": True,
"node_id": "AW-GZ-001",
"host_state": "ONLINE",
"observed_at": now(),
"domains": [dict(row) for row in db.execute("SELECT id,name,state FROM domains ORDER BY id")],
"node_counts": counts,
"fixed_actions": sorted(FIXED_ACTIONS),
"raw_shell": "rejected",
})
if self.path in {"/v1/navigation-map", "/v2/global-navigation-map"}: if self.path in {"/v1/navigation-map", "/v2/global-navigation-map"}:
try: try:
body, map_hash = navigation_map() body, map_hash = navigation_map()

View file

@ -66,6 +66,20 @@ with tempfile.TemporaryDirectory() as temp:
else: else:
raise AssertionError("server did not start") raise AssertionError("server did not start")
status = json.load(urllib.request.urlopen(BASE + "/v1/status"))
assert status["node_id"] == "AW-GZ-001"
assert status["host_state"] == "ONLINE"
assert {domain["state"] for domain in status["domains"] if domain["id"] != "DOMAIN-FIFTH"} == {
"HOSTED_ACTIVE"
}
assert status["node_counts"]["ACTIVE"] == 4
nodes = json.load(urllib.request.urlopen(BASE + "/v1/nodes"))["nodes"]
hosted = {node["domain_id"]: node for node in nodes}
assert set(hosted) == {"DOMAIN-MAIN", "DOMAIN-SUB", "DOMAIN-ZERO", "DOMAIN-ZS"}
assert all(node["state"] == "ACTIVE" for node in hosted.values())
assert all(node["display_name"].startswith("AW-GZ-001") for node in hosted.values())
intake = { intake = {
"human_name": "Test", "human_name": "Test",
"email": "test@example.invalid", "email": "test@example.invalid",