feat(guanghu-os): add authenticated native public projection
This commit is contained in:
parent
95385e812a
commit
2e076c4d5e
14 changed files with 780 additions and 4 deletions
|
|
@ -0,0 +1,50 @@
|
||||||
|
---
|
||||||
|
type: ADR
|
||||||
|
id: "0180"
|
||||||
|
title: "Authenticated native public projection before boot cutover"
|
||||||
|
status: accepted
|
||||||
|
date: 2026-08-15
|
||||||
|
depends_on:
|
||||||
|
- "0179"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 原生公网投影先于启动切换
|
||||||
|
|
||||||
|
## 为什么来到这里
|
||||||
|
|
||||||
|
ADR-0179 已经在 JD-FD-PRIMARY 的隔离 QEMU 中证明原生只读锚点和代码发现面能够运行,
|
||||||
|
但这不等于公网能够在原生驻留时继续工作。当前 BS-GZ-006 公网入口经 SSH 隧道回到
|
||||||
|
JD Linux;一旦切换成光湖原生驻留,Linux 和隧道端点同时退出,公网会变成 502。
|
||||||
|
|
||||||
|
因此,下一步不能直接改启动项。必须先建立一个不依赖 JD Linux 的认证状态通道,并在
|
||||||
|
BS-GZ-006 上以影子方式完成回读。
|
||||||
|
|
||||||
|
## 为什么不是把原文塞进心跳
|
||||||
|
|
||||||
|
原生心跳只回答“这个候选现在是否活着并处于规定状态”。它不承担知识、源码、命令或
|
||||||
|
公网内容传输。这样既保持现有中继的最小权限,也避免把一次存活信号误当成内容来源或
|
||||||
|
授权。
|
||||||
|
|
||||||
|
公网锚点和只读代码发现面的字节来自固定的 REPO-012 main 快照;心跳只决定这些固定字节
|
||||||
|
当前能否被读出。这保留了两条互不冒充的因果链:内容由源码提交证明,在线状态由短时效
|
||||||
|
认证状态证明。
|
||||||
|
|
||||||
|
## 决定
|
||||||
|
|
||||||
|
采用单向三节点投影:JD-FD-PRIMARY 的既有六序列原生心跳到 BS-SG-003;BS-SG-003 只把
|
||||||
|
`ready` 或 `dormant` 通过专用 SSH 身份和强制命令投影到 BS-GZ-006;BS-GZ-006 只在状态
|
||||||
|
绑定完全匹配且未过期时,从回环地址提供固定只读快照。
|
||||||
|
|
||||||
|
任何缺失、格式错误、绑定不符、休眠、未来时间或过期状态都返回 503。中继不能提供或
|
||||||
|
修改公网内容。代码发现面明确不是 Forgejo 等价物。
|
||||||
|
|
||||||
|
## 为什么先影子部署
|
||||||
|
|
||||||
|
接收端先监听 BS-GZ-006 回环影子端口,不修改 nginx,不改变当前公网路径,也不修改
|
||||||
|
JD 启动、磁盘或默认启动项。只有接收端、认证投影器、真实新鲜度和公网回读分别取得独立
|
||||||
|
回执后,才能另行决定是否切公网;公网通过后仍不能自动推出物理启动切换。
|
||||||
|
|
||||||
|
## 当前结论
|
||||||
|
|
||||||
|
协议源码和隔离整链测试为 100。BS-GZ 接收端部署、BS-SG 认证投影器部署、真实原生新鲜度、
|
||||||
|
nginx 切换、原生公网等价、完整 Forgejo 等价和生产启动切换均保持 0。
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
schema: guanghu.native-public-projection-source-readiness/v1
|
||||||
|
receipt_id: GHOS-JD-NATIVE-PUBLIC-PROJECTION-SOURCE-20260815-001
|
||||||
|
observed_at: 2026-08-15T20:01:04+08:00
|
||||||
|
route: JD-FD-PRIMARY -> BS-SG-003 -> BS-GZ-006
|
||||||
|
why: existing BS-GZ public tunnels terminate in JD Linux and cannot survive native residency
|
||||||
|
causal_separation: native heartbeat proves liveness; pinned REPO-012 snapshot proves public bytes
|
||||||
|
candidate_sha256: 9807fa751616d4b421c103d60eecface1c5eb8013cbd89417ef9e027da281fb3
|
||||||
|
snapshot_source_commit: fb1096c5ecdcfb36015d51273f487c2f36d9c9cd
|
||||||
|
acceptor_sha256: 5a26f7fcf48a523ef598123d3c0eef524126ad87cf67c5b78bb6eda55cf05d14
|
||||||
|
gateway_sha256: cedea65bd1c3e21d5b5944fe65a0f51364ef806abbf0218812216bd34af35c10
|
||||||
|
relay_projector_sha256: 194af5f20843d5820090f2fa791b685d5d62289a3d649d0bd48d9f6be9a9556e
|
||||||
|
isolated_test_sha256: 22901d8ab180a3fdf9d0171058819c8a9a1632dd41113e5ea916aa2477ff7188
|
||||||
|
contract_sha256: 1566dfde3d5487f7de0c039024f38088168b90bc5c989fb5c1f2687d442082ef
|
||||||
|
isolated_end_to_end_result: NATIVE_PUBLIC_PROJECTION_TEST_PASS_100
|
||||||
|
contract_source: 100
|
||||||
|
isolated_end_to_end_test: 100
|
||||||
|
bs_gz_shadow_receiver_deployed: 0
|
||||||
|
bs_sg_authenticated_projector_deployed: 0
|
||||||
|
live_native_freshness_readback: 0
|
||||||
|
nginx_public_route_switched: 0
|
||||||
|
public_native_anchor_equivalence: 0
|
||||||
|
public_native_code_channel_equivalence: 0
|
||||||
|
full_forgejo_equivalence: 0
|
||||||
|
production_native_cutover: 0
|
||||||
|
bootloader_changed: false
|
||||||
|
default_boot_changed: false
|
||||||
|
reboot_performed: false
|
||||||
|
next_gate: publish exact source, then deploy loopback shadow receiver without nginx or boot changes
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Guanghu native public projection loopback shadow gateway
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=guanghu-native-projection
|
||||||
|
Group=guanghu-native-projection
|
||||||
|
ExecStart=/usr/bin/python3 /usr/local/libexec/guanghu-os/native-public-projection-gateway.py --listen-host 127.0.0.1 --listen-port 19223 --state-file /var/lib/guanghu-native-projection/state.json --anchor-file /etc/guanghu-os/native-public-projection/anchor.json --code-file /etc/guanghu-os/native-public-projection/code-channel.json --expected-node JD-FD-PRIMARY --expected-relay BS-SG-003 --expected-candidate-sha256 9807fa751616d4b421c103d60eecface1c5eb8013cbd89417ef9e027da281fb3 --expected-source-commit fb1096c5ecdcfb36015d51273f487c2f36d9c9cd --max-age-seconds 15
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=2
|
||||||
|
NoNewPrivileges=yes
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=strict
|
||||||
|
ProtectHome=yes
|
||||||
|
ProtectKernelTunables=yes
|
||||||
|
ProtectKernelModules=yes
|
||||||
|
ProtectControlGroups=yes
|
||||||
|
ReadOnlyPaths=/etc/guanghu-os/native-public-projection
|
||||||
|
ReadWritePaths=/var/lib/guanghu-native-projection
|
||||||
|
RestrictAddressFamilies=AF_INET AF_INET6
|
||||||
|
RestrictSUIDSGID=yes
|
||||||
|
LockPersonality=yes
|
||||||
|
MemoryDenyWriteExecute=yes
|
||||||
|
UMask=0027
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Project protected JD native residency state to the BS-GZ shadow receiver
|
||||||
|
After=network-online.target guanghu-jd-native-final-resident-relay.service
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/bin/python3 /usr/local/libexec/guanghu-os/native-public-projection-relay.py --relay-receipt /var/lib/guanghu-os/jd-final-resident-relay.hldp --max-receipt-age-seconds 15 --expected-nat-source 111.228.0.139 --node JD-FD-PRIMARY --relay BS-SG-003 --candidate-sha256 9807fa751616d4b421c103d60eecface1c5eb8013cbd89417ef9e027da281fb3 --source-commit fb1096c5ecdcfb36015d51273f487c2f36d9c9cd --ssh-config /etc/guanghu-os/native-public-projection-ssh.conf --ssh-target native-projection-gz
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
NoNewPrivileges=yes
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectSystem=strict
|
||||||
|
ProtectHome=yes
|
||||||
|
ProtectKernelTunables=yes
|
||||||
|
ProtectKernelModules=yes
|
||||||
|
ProtectControlGroups=yes
|
||||||
|
ReadOnlyPaths=/etc/guanghu-os /var/lib/guanghu-os/jd-final-resident-relay.hldp
|
||||||
|
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||||
|
RestrictSUIDSGID=yes
|
||||||
|
LockPersonality=yes
|
||||||
|
UMask=0077
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Refresh the Guanghu native public projection shadow state
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnBootSec=20s
|
||||||
|
OnUnitActiveSec=5s
|
||||||
|
AccuracySec=1s
|
||||||
|
Unit=guanghu-native-public-projection-relay.service
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Accept one SSH-authenticated native projection state transition."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import secrets
|
||||||
|
import shlex
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
SCHEMA = "guanghu.native-public-projection-state/v1"
|
||||||
|
|
||||||
|
|
||||||
|
def parse_command(command: str) -> tuple[str, str, str, str, str]:
|
||||||
|
fields = shlex.split(command)
|
||||||
|
if len(fields) != 5 or fields[0] not in {"ready", "dormant"}:
|
||||||
|
raise ValueError("exact ready or dormant projection command required")
|
||||||
|
return fields[0], fields[1], fields[2], fields[3], fields[4]
|
||||||
|
|
||||||
|
|
||||||
|
def atomic_write(path: pathlib.Path, payload: dict[str, object]) -> None:
|
||||||
|
if not path.is_absolute() or not path.parent.is_dir():
|
||||||
|
raise ValueError("state file must have an existing absolute parent")
|
||||||
|
encoded = (json.dumps(payload, sort_keys=True, separators=(",", ":")) + "\n").encode()
|
||||||
|
descriptor, temporary_name = tempfile.mkstemp(
|
||||||
|
dir=path.parent,
|
||||||
|
prefix=f".{path.name}.",
|
||||||
|
)
|
||||||
|
temporary = pathlib.Path(temporary_name)
|
||||||
|
try:
|
||||||
|
os.fchmod(descriptor, 0o640)
|
||||||
|
with os.fdopen(descriptor, "wb") as output:
|
||||||
|
output.write(encoded)
|
||||||
|
output.flush()
|
||||||
|
os.fsync(output.fileno())
|
||||||
|
os.replace(temporary, path)
|
||||||
|
finally:
|
||||||
|
temporary.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--state-file", required=True)
|
||||||
|
parser.add_argument("--expected-node", required=True)
|
||||||
|
parser.add_argument("--expected-relay", required=True)
|
||||||
|
parser.add_argument("--expected-candidate-sha256", required=True)
|
||||||
|
parser.add_argument("--expected-source-commit", required=True)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
action, node, candidate_sha, source_commit, relay = parse_command(
|
||||||
|
os.environ.get("SSH_ORIGINAL_COMMAND", "")
|
||||||
|
)
|
||||||
|
except ValueError as error:
|
||||||
|
raise SystemExit(str(error)) from error
|
||||||
|
expected = (
|
||||||
|
args.expected_node,
|
||||||
|
args.expected_candidate_sha256,
|
||||||
|
args.expected_source_commit,
|
||||||
|
args.expected_relay,
|
||||||
|
)
|
||||||
|
if (node, candidate_sha, source_commit, relay) != expected:
|
||||||
|
raise SystemExit("projection command does not match the pinned deployment")
|
||||||
|
if len(candidate_sha) != 64 or len(source_commit) != 40:
|
||||||
|
raise SystemExit("projection hashes are malformed")
|
||||||
|
|
||||||
|
payload: dict[str, object] = {
|
||||||
|
"schema": SCHEMA,
|
||||||
|
"status": "READY_NATIVE_RESIDENT" if action == "ready" else "DORMANT",
|
||||||
|
"node_id": node,
|
||||||
|
"relay_node": relay,
|
||||||
|
"candidate_sha256": candidate_sha,
|
||||||
|
"source_commit": source_commit,
|
||||||
|
"accepted_at_epoch": time.time(),
|
||||||
|
"receipt_nonce": secrets.token_hex(16),
|
||||||
|
"transport_authentication": "SSH_FORCED_COMMAND",
|
||||||
|
}
|
||||||
|
atomic_write(pathlib.Path(args.state_file), payload)
|
||||||
|
print(json.dumps(payload, sort_keys=True, separators=(",", ":")))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
|
|
@ -0,0 +1,177 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Serve pinned public snapshots only while an authenticated native state is fresh."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import time
|
||||||
|
from http import HTTPStatus
|
||||||
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
STATE_SCHEMA = "guanghu.native-public-projection-state/v1"
|
||||||
|
|
||||||
|
|
||||||
|
def load_snapshot(path: pathlib.Path, schema: str, source_commit: str) -> bytes:
|
||||||
|
payload = path.read_bytes()
|
||||||
|
value = json.loads(payload)
|
||||||
|
if not isinstance(value, dict) or value.get("schema") != schema:
|
||||||
|
raise ValueError(f"snapshot schema mismatch: {path}")
|
||||||
|
if schema == "guanghu.public-navigation-anchor/v1":
|
||||||
|
observed_commit = value.get("navigation_source", {}).get("source_commit")
|
||||||
|
else:
|
||||||
|
observed_commit = value.get("commit")
|
||||||
|
if value.get("full_forgejo_equivalence") is not False:
|
||||||
|
raise ValueError("code snapshot cannot claim full Forgejo equivalence")
|
||||||
|
if observed_commit != source_commit:
|
||||||
|
raise ValueError(f"snapshot source commit mismatch: {path}")
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
class Projection:
|
||||||
|
def __init__(self, args: argparse.Namespace) -> None:
|
||||||
|
self.state_file = pathlib.Path(args.state_file)
|
||||||
|
self.expected = {
|
||||||
|
"schema": STATE_SCHEMA,
|
||||||
|
"node_id": args.expected_node,
|
||||||
|
"relay_node": args.expected_relay,
|
||||||
|
"candidate_sha256": args.expected_candidate_sha256,
|
||||||
|
"source_commit": args.expected_source_commit,
|
||||||
|
"transport_authentication": "SSH_FORCED_COMMAND",
|
||||||
|
}
|
||||||
|
self.max_age_seconds = args.max_age_seconds
|
||||||
|
self.anchor = load_snapshot(
|
||||||
|
pathlib.Path(args.anchor_file),
|
||||||
|
"guanghu.public-navigation-anchor/v1",
|
||||||
|
args.expected_source_commit,
|
||||||
|
)
|
||||||
|
self.code = load_snapshot(
|
||||||
|
pathlib.Path(args.code_file),
|
||||||
|
"guanghu.native-code-channel-read-only/v1",
|
||||||
|
args.expected_source_commit,
|
||||||
|
)
|
||||||
|
|
||||||
|
def state(self) -> tuple[bool, str, dict[str, Any] | None]:
|
||||||
|
try:
|
||||||
|
if self.state_file.is_symlink():
|
||||||
|
return False, "state_file_symlink", None
|
||||||
|
value = json.loads(self.state_file.read_text(encoding="utf-8"))
|
||||||
|
except FileNotFoundError:
|
||||||
|
return False, "state_missing", None
|
||||||
|
except (OSError, json.JSONDecodeError):
|
||||||
|
return False, "state_invalid", None
|
||||||
|
if not isinstance(value, dict):
|
||||||
|
return False, "state_invalid", None
|
||||||
|
if any(value.get(key) != expected for key, expected in self.expected.items()):
|
||||||
|
return False, "state_binding_mismatch", value
|
||||||
|
if value.get("status") != "READY_NATIVE_RESIDENT":
|
||||||
|
return False, "native_not_ready", value
|
||||||
|
accepted_at = value.get("accepted_at_epoch")
|
||||||
|
if not isinstance(accepted_at, (int, float)):
|
||||||
|
return False, "state_time_invalid", value
|
||||||
|
age = time.time() - float(accepted_at)
|
||||||
|
if age < -5:
|
||||||
|
return False, "state_time_in_future", value
|
||||||
|
if age > self.max_age_seconds:
|
||||||
|
return False, "projection_expired", value
|
||||||
|
return True, "ready", value
|
||||||
|
|
||||||
|
|
||||||
|
def handler_for(projection: Projection) -> type[BaseHTTPRequestHandler]:
|
||||||
|
class Handler(BaseHTTPRequestHandler):
|
||||||
|
server_version = "GuanghuNativeProjection/1"
|
||||||
|
|
||||||
|
def log_message(self, _format: str, *_args: object) -> None:
|
||||||
|
return
|
||||||
|
|
||||||
|
def send_bytes(self, status: int, payload: bytes, content_type: str) -> None:
|
||||||
|
self.send_response(status)
|
||||||
|
self.send_header("Content-Type", content_type)
|
||||||
|
self.send_header("Content-Length", str(len(payload)))
|
||||||
|
self.send_header("Cache-Control", "no-store")
|
||||||
|
self.send_header("X-Content-Type-Options", "nosniff")
|
||||||
|
self.end_headers()
|
||||||
|
if self.command != "HEAD":
|
||||||
|
self.wfile.write(payload)
|
||||||
|
|
||||||
|
def send_json(self, status: int, value: dict[str, object]) -> None:
|
||||||
|
payload = (json.dumps(value, sort_keys=True, separators=(",", ":")) + "\n").encode()
|
||||||
|
self.send_bytes(status, payload, "application/json; charset=utf-8")
|
||||||
|
|
||||||
|
def do_HEAD(self) -> None: # noqa: N802
|
||||||
|
self.do_GET()
|
||||||
|
|
||||||
|
def do_GET(self) -> None: # noqa: N802
|
||||||
|
fresh, reason, state = projection.state()
|
||||||
|
if self.path == "/healthz":
|
||||||
|
self.send_json(
|
||||||
|
HTTPStatus.OK,
|
||||||
|
{
|
||||||
|
"schema": "guanghu.native-public-projection-health/v1",
|
||||||
|
"native_projection_fresh": fresh,
|
||||||
|
"reason": reason,
|
||||||
|
"node_id": projection.expected["node_id"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return
|
||||||
|
if self.path not in {
|
||||||
|
"/api/ai/v1/anchor",
|
||||||
|
"/api/ai/v1/code-channel",
|
||||||
|
}:
|
||||||
|
self.send_json(HTTPStatus.NOT_FOUND, {"error": "not_found"})
|
||||||
|
return
|
||||||
|
if not fresh:
|
||||||
|
self.send_json(
|
||||||
|
HTTPStatus.SERVICE_UNAVAILABLE,
|
||||||
|
{
|
||||||
|
"schema": "guanghu.native-public-projection-unavailable/v1",
|
||||||
|
"native_projection_fresh": False,
|
||||||
|
"reason": reason,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return
|
||||||
|
assert state is not None
|
||||||
|
payload = (
|
||||||
|
projection.anchor
|
||||||
|
if self.path == "/api/ai/v1/anchor"
|
||||||
|
else projection.code
|
||||||
|
)
|
||||||
|
self.send_bytes(HTTPStatus.OK, payload, "application/json; charset=utf-8")
|
||||||
|
|
||||||
|
def do_POST(self) -> None: # noqa: N802
|
||||||
|
self.send_json(HTTPStatus.METHOD_NOT_ALLOWED, {"error": "method_not_allowed"})
|
||||||
|
|
||||||
|
return Handler
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--listen-host", default="127.0.0.1")
|
||||||
|
parser.add_argument("--listen-port", required=True, type=int)
|
||||||
|
parser.add_argument("--state-file", required=True)
|
||||||
|
parser.add_argument("--anchor-file", required=True)
|
||||||
|
parser.add_argument("--code-file", required=True)
|
||||||
|
parser.add_argument("--expected-node", required=True)
|
||||||
|
parser.add_argument("--expected-relay", required=True)
|
||||||
|
parser.add_argument("--expected-candidate-sha256", required=True)
|
||||||
|
parser.add_argument("--expected-source-commit", required=True)
|
||||||
|
parser.add_argument("--max-age-seconds", type=float, default=15.0)
|
||||||
|
args = parser.parse_args()
|
||||||
|
if args.listen_host not in {"127.0.0.1", "::1"}:
|
||||||
|
raise SystemExit("projection gateway must remain loopback-only")
|
||||||
|
if not 1 <= args.listen_port <= 65535:
|
||||||
|
raise SystemExit("invalid listen port")
|
||||||
|
if args.max_age_seconds <= 0:
|
||||||
|
raise SystemExit("max age must be greater than zero")
|
||||||
|
projection = Projection(args)
|
||||||
|
server = ThreadingHTTPServer((args.listen_host, args.listen_port), handler_for(projection))
|
||||||
|
server.serve_forever()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Project a fresh protected native-relay receipt through one pinned SSH route."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def parse_receipt(path: pathlib.Path) -> tuple[dict[str, str], float]:
|
||||||
|
if path.is_symlink():
|
||||||
|
raise ValueError("relay receipt cannot be a symlink")
|
||||||
|
stat = path.stat()
|
||||||
|
values: dict[str, str] = {}
|
||||||
|
for line in path.read_text(encoding="utf-8").splitlines():
|
||||||
|
if not line or line[:1].isspace() or ": " not in line:
|
||||||
|
continue
|
||||||
|
key, value = line.split(": ", 1)
|
||||||
|
if key in values:
|
||||||
|
raise ValueError(f"duplicate relay receipt key: {key}")
|
||||||
|
values[key] = value
|
||||||
|
return values, time.time() - stat.st_mtime
|
||||||
|
|
||||||
|
|
||||||
|
def projection_action(
|
||||||
|
values: dict[str, str], age: float, max_age: float, expected_source: str
|
||||||
|
) -> str:
|
||||||
|
ready = (
|
||||||
|
age >= -5
|
||||||
|
and age <= max_age
|
||||||
|
and values.get("schema")
|
||||||
|
== "guanghu.physical-native-final-resident-relay/v1"
|
||||||
|
and values.get("status") == "READY_NATIVE_RESIDENT"
|
||||||
|
and values.get("recovery_capability_sent") == "false"
|
||||||
|
and values.get("acknowledged_sequences") == "1,2,3,4,5,6"
|
||||||
|
and values.get("observed_nat_sources") == expected_source
|
||||||
|
)
|
||||||
|
return "ready" if ready else "dormant"
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--relay-receipt", required=True)
|
||||||
|
parser.add_argument("--max-receipt-age-seconds", type=float, default=15.0)
|
||||||
|
parser.add_argument("--expected-nat-source", required=True)
|
||||||
|
parser.add_argument("--node", required=True)
|
||||||
|
parser.add_argument("--relay", required=True)
|
||||||
|
parser.add_argument("--candidate-sha256", required=True)
|
||||||
|
parser.add_argument("--source-commit", required=True)
|
||||||
|
parser.add_argument("--ssh-bin", default="/usr/bin/ssh")
|
||||||
|
parser.add_argument("--ssh-config", required=True)
|
||||||
|
parser.add_argument("--ssh-target", required=True)
|
||||||
|
args = parser.parse_args()
|
||||||
|
if args.max_receipt_age_seconds <= 0:
|
||||||
|
raise SystemExit("max receipt age must be greater than zero")
|
||||||
|
ssh_bin = pathlib.Path(args.ssh_bin)
|
||||||
|
ssh_config = pathlib.Path(args.ssh_config)
|
||||||
|
if not ssh_bin.is_absolute() or not os.access(ssh_bin, os.X_OK):
|
||||||
|
raise SystemExit("SSH binary must be an executable absolute path")
|
||||||
|
if not ssh_config.is_absolute() or not ssh_config.is_file():
|
||||||
|
raise SystemExit("SSH config must be an existing absolute file")
|
||||||
|
try:
|
||||||
|
values, age = parse_receipt(pathlib.Path(args.relay_receipt))
|
||||||
|
action = projection_action(
|
||||||
|
values,
|
||||||
|
age,
|
||||||
|
args.max_receipt_age_seconds,
|
||||||
|
args.expected_nat_source,
|
||||||
|
)
|
||||||
|
except (OSError, UnicodeError, ValueError):
|
||||||
|
action = "dormant"
|
||||||
|
command = [
|
||||||
|
str(ssh_bin),
|
||||||
|
"-F",
|
||||||
|
str(ssh_config),
|
||||||
|
"-o",
|
||||||
|
"BatchMode=yes",
|
||||||
|
"-o",
|
||||||
|
"ConnectTimeout=5",
|
||||||
|
args.ssh_target,
|
||||||
|
action,
|
||||||
|
args.node,
|
||||||
|
args.candidate_sha256,
|
||||||
|
args.source_commit,
|
||||||
|
args.relay,
|
||||||
|
]
|
||||||
|
completed = subprocess.run(command, check=False, timeout=10)
|
||||||
|
if completed.returncode != 0:
|
||||||
|
raise SystemExit("native projection transport failed closed")
|
||||||
|
print(f"NATIVE_PUBLIC_PROJECTION_RELAY_OK action={action}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
|
|
@ -21,6 +21,7 @@ grep -Fxq ' native_target: GOSK_CODE_CHANNEL_QUALITY_EXECUTOR' "${protocol}"
|
||||||
grep -Fq -- '--fail-under-lines 100' "${runner}"
|
grep -Fq -- '--fail-under-lines 100' "${runner}"
|
||||||
grep -Fq -- '--fail-under-functions 100' "${runner}"
|
grep -Fq -- '--fail-under-functions 100' "${runner}"
|
||||||
grep -Fq -- '--test broadcast_library' "${runner}"
|
grep -Fq -- '--test broadcast_library' "${runner}"
|
||||||
|
grep -Fq 'test-native-public-projection.sh' "${runner}"
|
||||||
grep -Fq 'GHNQG_PASS_100' "${runner}"
|
grep -Fq 'GHNQG_PASS_100' "${runner}"
|
||||||
grep -Fq 'GHNQG_FAIL_0' "${runner}"
|
grep -Fq 'GHNQG_FAIL_0' "${runner}"
|
||||||
grep -Fq 'total_score: ${total_score}' "${runner}"
|
grep -Fq 'total_score: ${total_score}' "${runner}"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
||||||
|
test_root=$(mktemp -d)
|
||||||
|
gateway_pid=
|
||||||
|
cleanup() {
|
||||||
|
if [[ -n ${gateway_pid} ]]; then
|
||||||
|
kill "${gateway_pid}" 2>/dev/null || true
|
||||||
|
wait "${gateway_pid}" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
rm -rf "${test_root}"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
port=$((35000 + ${BASHPID:-$$} % 1000))
|
||||||
|
state_file=${test_root}/state.json
|
||||||
|
anchor_file=${test_root}/anchor.json
|
||||||
|
code_file=${test_root}/code.json
|
||||||
|
relay_receipt=${test_root}/relay.hldp
|
||||||
|
fake_ssh=${test_root}/ssh
|
||||||
|
ssh_args=${test_root}/ssh-args.txt
|
||||||
|
ssh_config=${test_root}/ssh-config
|
||||||
|
candidate_sha=9807fa751616d4b421c103d60eecface1c5eb8013cbd89417ef9e027da281fb3
|
||||||
|
source_commit=fb1096c5ecdcfb36015d51273f487c2f36d9c9cd
|
||||||
|
|
||||||
|
cat >"${anchor_file}" <<EOF
|
||||||
|
{"schema":"guanghu.public-navigation-anchor/v1","anchor_id":"GLW-PUBLIC-NAV-ANCHOR-001","navigation_source":{"source_commit":"${source_commit}"}}
|
||||||
|
EOF
|
||||||
|
cat >"${code_file}" <<EOF
|
||||||
|
{"schema":"guanghu.native-code-channel-read-only/v1","repository_id":"REPO-012","branch":"main","commit":"${source_commit}","mode":"READ_ONLY_DISCOVERY","runtime":"GUANGHU_OS_NATIVE","full_forgejo_equivalence":false}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
python3 "${source_root}/scripts/native-public-projection-gateway.py" \
|
||||||
|
--listen-host 127.0.0.1 \
|
||||||
|
--listen-port "${port}" \
|
||||||
|
--state-file "${state_file}" \
|
||||||
|
--anchor-file "${anchor_file}" \
|
||||||
|
--code-file "${code_file}" \
|
||||||
|
--expected-node JD-FD-PRIMARY \
|
||||||
|
--expected-relay BS-SG-003 \
|
||||||
|
--expected-candidate-sha256 "${candidate_sha}" \
|
||||||
|
--expected-source-commit "${source_commit}" \
|
||||||
|
--max-age-seconds 1 >"${test_root}/gateway.log" 2>&1 &
|
||||||
|
gateway_pid=$!
|
||||||
|
|
||||||
|
for _ in $(seq 1 50); do
|
||||||
|
curl -fsS "http://127.0.0.1:${port}/healthz" >/dev/null 2>&1 && break
|
||||||
|
sleep 0.05
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ $(curl -sS -o "${test_root}/stale.json" -w '%{http_code}' \
|
||||||
|
"http://127.0.0.1:${port}/api/ai/v1/anchor") == 503 ]]
|
||||||
|
grep -q '"native_projection_fresh":false' "${test_root}/stale.json"
|
||||||
|
|
||||||
|
if SSH_ORIGINAL_COMMAND="ready JD-FD-PRIMARY ${candidate_sha} ${source_commit} BS-SG-003 extra" \
|
||||||
|
python3 "${source_root}/scripts/accept-native-public-projection.py" \
|
||||||
|
--state-file "${state_file}" \
|
||||||
|
--expected-node JD-FD-PRIMARY \
|
||||||
|
--expected-relay BS-SG-003 \
|
||||||
|
--expected-candidate-sha256 "${candidate_sha}" \
|
||||||
|
--expected-source-commit "${source_commit}"; then
|
||||||
|
echo "projection acceptor allowed an overlong command" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SSH_ORIGINAL_COMMAND="ready JD-FD-PRIMARY ${candidate_sha} ${source_commit} BS-SG-003" \
|
||||||
|
python3 "${source_root}/scripts/accept-native-public-projection.py" \
|
||||||
|
--state-file "${state_file}" \
|
||||||
|
--expected-node JD-FD-PRIMARY \
|
||||||
|
--expected-relay BS-SG-003 \
|
||||||
|
--expected-candidate-sha256 "${candidate_sha}" \
|
||||||
|
--expected-source-commit "${source_commit}"
|
||||||
|
|
||||||
|
curl -fsS "http://127.0.0.1:${port}/api/ai/v1/anchor" >"${test_root}/anchor-readback.json"
|
||||||
|
curl -fsS "http://127.0.0.1:${port}/api/ai/v1/code-channel" >"${test_root}/code-readback.json"
|
||||||
|
cmp "${anchor_file}" "${test_root}/anchor-readback.json"
|
||||||
|
cmp "${code_file}" "${test_root}/code-readback.json"
|
||||||
|
[[ $(curl -sS -o /dev/null -w '%{http_code}' -X POST \
|
||||||
|
"http://127.0.0.1:${port}/api/ai/v1/anchor") == 405 ]]
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
[[ $(curl -sS -o "${test_root}/expired.json" -w '%{http_code}' \
|
||||||
|
"http://127.0.0.1:${port}/api/ai/v1/anchor") == 503 ]]
|
||||||
|
grep -q '"reason":"projection_expired"' "${test_root}/expired.json"
|
||||||
|
|
||||||
|
SSH_ORIGINAL_COMMAND="dormant JD-FD-PRIMARY ${candidate_sha} ${source_commit} BS-SG-003" \
|
||||||
|
python3 "${source_root}/scripts/accept-native-public-projection.py" \
|
||||||
|
--state-file "${state_file}" \
|
||||||
|
--expected-node JD-FD-PRIMARY \
|
||||||
|
--expected-relay BS-SG-003 \
|
||||||
|
--expected-candidate-sha256 "${candidate_sha}" \
|
||||||
|
--expected-source-commit "${source_commit}"
|
||||||
|
[[ $(curl -sS -o "${test_root}/dormant.json" -w '%{http_code}' \
|
||||||
|
"http://127.0.0.1:${port}/api/ai/v1/code-channel") == 503 ]]
|
||||||
|
grep -q '"reason":"native_not_ready"' "${test_root}/dormant.json"
|
||||||
|
|
||||||
|
cat >"${fake_ssh}" <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
printf '%s\n' "$*" >"${GHOS_TEST_SSH_ARGS}"
|
||||||
|
EOF
|
||||||
|
chmod 0700 "${fake_ssh}"
|
||||||
|
: >"${ssh_config}"
|
||||||
|
cat >"${relay_receipt}" <<'EOF'
|
||||||
|
schema: guanghu.physical-native-final-resident-relay/v1
|
||||||
|
status: READY_NATIVE_RESIDENT
|
||||||
|
recovery_capability_sent: false
|
||||||
|
acknowledged_sequences: 1,2,3,4,5,6
|
||||||
|
observed_nat_sources: 111.228.0.139
|
||||||
|
EOF
|
||||||
|
GHOS_TEST_SSH_ARGS=${ssh_args} python3 \
|
||||||
|
"${source_root}/scripts/native-public-projection-relay.py" \
|
||||||
|
--relay-receipt "${relay_receipt}" \
|
||||||
|
--max-receipt-age-seconds 5 \
|
||||||
|
--expected-nat-source 111.228.0.139 \
|
||||||
|
--node JD-FD-PRIMARY \
|
||||||
|
--relay BS-SG-003 \
|
||||||
|
--candidate-sha256 "${candidate_sha}" \
|
||||||
|
--source-commit "${source_commit}" \
|
||||||
|
--ssh-bin "${fake_ssh}" \
|
||||||
|
--ssh-config "${ssh_config}" \
|
||||||
|
--ssh-target native-projection-gz
|
||||||
|
grep -q "native-projection-gz ready JD-FD-PRIMARY ${candidate_sha} ${source_commit} BS-SG-003$" \
|
||||||
|
"${ssh_args}"
|
||||||
|
|
||||||
|
sed -i.bak 's/recovery_capability_sent: false/recovery_capability_sent: true/' \
|
||||||
|
"${relay_receipt}"
|
||||||
|
GHOS_TEST_SSH_ARGS=${ssh_args} python3 \
|
||||||
|
"${source_root}/scripts/native-public-projection-relay.py" \
|
||||||
|
--relay-receipt "${relay_receipt}" \
|
||||||
|
--max-receipt-age-seconds 5 \
|
||||||
|
--expected-nat-source 111.228.0.139 \
|
||||||
|
--node JD-FD-PRIMARY \
|
||||||
|
--relay BS-SG-003 \
|
||||||
|
--candidate-sha256 "${candidate_sha}" \
|
||||||
|
--source-commit "${source_commit}" \
|
||||||
|
--ssh-bin "${fake_ssh}" \
|
||||||
|
--ssh-config "${ssh_config}" \
|
||||||
|
--ssh-target native-projection-gz
|
||||||
|
grep -q "native-projection-gz dormant JD-FD-PRIMARY ${candidate_sha} ${source_commit} BS-SG-003$" \
|
||||||
|
"${ssh_args}"
|
||||||
|
|
||||||
|
echo "NATIVE_PUBLIC_PROJECTION_TEST_PASS_100"
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
{
|
||||||
|
"schema": "guanghu.jd-native-public-projection-contract/v1",
|
||||||
|
"contract_id": "GHOS-JD-NATIVE-PUBLIC-PROJECTION-001",
|
||||||
|
"state": "SOURCE_AND_ISOLATED_TEST_ONLY",
|
||||||
|
"causal_route": [
|
||||||
|
"JD-FD-PRIMARY",
|
||||||
|
"BS-SG-003",
|
||||||
|
"BS-GZ-006"
|
||||||
|
],
|
||||||
|
"why": {
|
||||||
|
"problem": "The current BS-GZ-006 public route depends on SSH tunnels terminated by JD Linux and therefore cannot survive Guanghu native residency.",
|
||||||
|
"separation": "The native heartbeat proves current liveness only; public bytes come from a pinned repository snapshot and never from relay input.",
|
||||||
|
"transport": "A dedicated SSH identity and forced command carry only a bounded ready or dormant state transition from BS-SG-003 to BS-GZ-006.",
|
||||||
|
"failure_mode": "Missing, malformed, mismatched, dormant, future-dated, or stale state fails closed with HTTP 503."
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"native_node": "JD-FD-PRIMARY",
|
||||||
|
"relay_node": "BS-SG-003",
|
||||||
|
"front_door_node": "BS-GZ-006",
|
||||||
|
"native_candidate_sha256": "9807fa751616d4b421c103d60eecface1c5eb8013cbd89417ef9e027da281fb3",
|
||||||
|
"snapshot_repository_id": "REPO-012",
|
||||||
|
"snapshot_branch": "main",
|
||||||
|
"snapshot_source_commit": "fb1096c5ecdcfb36015d51273f487c2f36d9c9cd",
|
||||||
|
"expected_native_nat_source": "111.228.0.139"
|
||||||
|
},
|
||||||
|
"authentication": {
|
||||||
|
"native_to_relay": {
|
||||||
|
"evidence": "EXISTING_SOURCE_BOUND_SIX_SEQUENCE_NATIVE_HEARTBEAT",
|
||||||
|
"meaning": "NATIVE_LIVENESS_AND_RESIDENCY_ONLY",
|
||||||
|
"may_supply_public_content": false,
|
||||||
|
"max_receipt_age_seconds": 15
|
||||||
|
},
|
||||||
|
"relay_to_front_door": {
|
||||||
|
"transport": "DEDICATED_SSH_KEY_WITH_FORCED_COMMAND",
|
||||||
|
"allowed_actions": [
|
||||||
|
"ready",
|
||||||
|
"dormant"
|
||||||
|
],
|
||||||
|
"pty": false,
|
||||||
|
"port_forwarding": false,
|
||||||
|
"agent_forwarding": false,
|
||||||
|
"x11_forwarding": false,
|
||||||
|
"command_fields_are_exact_and_pinned": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"public_bytes": {
|
||||||
|
"provenance": "PINNED_REPO_012_SNAPSHOT",
|
||||||
|
"relay_may_supply_or_mutate_bytes": false,
|
||||||
|
"anchor_schema": "guanghu.public-navigation-anchor/v1",
|
||||||
|
"code_schema": "guanghu.native-code-channel-read-only/v1",
|
||||||
|
"full_forgejo_equivalence": false
|
||||||
|
},
|
||||||
|
"front_door_projection": {
|
||||||
|
"listen_scope": "LOOPBACK_ONLY",
|
||||||
|
"shadow_port": 19223,
|
||||||
|
"state_max_age_seconds": 15,
|
||||||
|
"paths": [
|
||||||
|
"/api/ai/v1/anchor",
|
||||||
|
"/api/ai/v1/code-channel"
|
||||||
|
],
|
||||||
|
"methods": [
|
||||||
|
"GET",
|
||||||
|
"HEAD"
|
||||||
|
],
|
||||||
|
"stale_or_invalid_http_status": 503,
|
||||||
|
"nginx_route_switch_authorized": false
|
||||||
|
},
|
||||||
|
"acceptance_gates": {
|
||||||
|
"contract_source": 100,
|
||||||
|
"isolated_end_to_end_test": 100,
|
||||||
|
"bs_gz_shadow_receiver_deployed": 0,
|
||||||
|
"bs_sg_authenticated_projector_deployed": 0,
|
||||||
|
"live_native_freshness_readback": 0,
|
||||||
|
"nginx_public_route_switched": 0,
|
||||||
|
"public_native_anchor_equivalence": 0,
|
||||||
|
"public_native_code_channel_equivalence": 0,
|
||||||
|
"full_forgejo_equivalence": 0,
|
||||||
|
"production_native_cutover": 0
|
||||||
|
},
|
||||||
|
"prohibited_claims": [
|
||||||
|
"HEARTBEAT_IS_CONTENT_PROVENANCE",
|
||||||
|
"RELAY_ACK_IS_NATIVE_AUTHORIZATION",
|
||||||
|
"SHADOW_LOOPBACK_DEPLOYMENT_IS_PUBLIC_CUTOVER",
|
||||||
|
"READ_ONLY_CODE_SNAPSHOT_IS_FULL_FORGEJO",
|
||||||
|
"SOURCE_AND_TEST_PASS_IS_LIVE_SERVER_DEPLOYMENT",
|
||||||
|
"PUBLIC_LINUX_TUNNEL_PROVES_NATIVE_RESIDENCY"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -79,7 +79,10 @@ run_gate() {
|
||||||
run_gate diff_whitespace git -C "${repository_root}" diff --check HEAD
|
run_gate diff_whitespace git -C "${repository_root}" diff --check HEAD
|
||||||
run_gate format cargo fmt --all --manifest-path "${source_root}/Cargo.toml" -- --check
|
run_gate format cargo fmt --all --manifest-path "${source_root}/Cargo.toml" -- --check
|
||||||
run_gate unit_and_integration_tests \
|
run_gate unit_and_integration_tests \
|
||||||
cargo test --manifest-path "${source_root}/Cargo.toml" --all-targets
|
bash -c '
|
||||||
|
cargo test --manifest-path "$1/Cargo.toml" --all-targets
|
||||||
|
"$1/scripts/test-native-public-projection.sh"
|
||||||
|
' _ "${source_root}"
|
||||||
run_gate zero_warning_lint \
|
run_gate zero_warning_lint \
|
||||||
cargo clippy --manifest-path "${source_root}/Cargo.toml" --all-targets -- -D warnings
|
cargo clippy --manifest-path "${source_root}/Cargo.toml" --all-targets -- -D warnings
|
||||||
run_gate world_and_protocol_validation \
|
run_gate world_and_protocol_validation \
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"schema": "guanghu.os-control-architecture/v1",
|
"schema": "guanghu.os-control-architecture/v1",
|
||||||
"record_id": "HLP-GUANGHU-OS-CONTROL-001",
|
"record_id": "HLP-GUANGHU-OS-CONTROL-001",
|
||||||
"version": "2026-08-15.5",
|
"version": "2026-08-15.6",
|
||||||
"state": "CURRENT_CANONICAL",
|
"state": "CURRENT_CANONICAL",
|
||||||
"final_topology": "GUANGHU_MASTER_WITH_ON_DEMAND_LINUX_SUBCONTROL_AND_RESCUE",
|
"final_topology": "GUANGHU_MASTER_WITH_ON_DEMAND_LINUX_SUBCONTROL_AND_RESCUE",
|
||||||
"control_ownership": {
|
"control_ownership": {
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
"linux_on_demand_subcontrol": 0,
|
"linux_on_demand_subcontrol": 0,
|
||||||
"linux_rescue_preserved": 100,
|
"linux_rescue_preserved": 100,
|
||||||
"final_guanghu_os_master": 0,
|
"final_guanghu_os_master": 0,
|
||||||
"next_engineering_gate": "IMPLEMENT_AUTHENTICATED_NATIVE_TO_BS_GZ_006_TRANSPORT_AND_PUBLIC_READBACK_BEFORE_ANY_BOOT_CUTOVER"
|
"next_engineering_gate": "DEPLOY_AND_VERIFY_BS_GZ_006_LOOPBACK_SHADOW_RECEIVER_WITHOUT_NGINX_OR_BOOT_CHANGES"
|
||||||
},
|
},
|
||||||
"implementation": {
|
"implementation": {
|
||||||
"guanghu_supervisor_lifecycle_contract_source": 100,
|
"guanghu_supervisor_lifecycle_contract_source": 100,
|
||||||
|
|
@ -54,6 +54,12 @@
|
||||||
"native_anchor_http_qemu_capability": 100,
|
"native_anchor_http_qemu_capability": 100,
|
||||||
"native_code_channel_read_only_qemu_capability": 100,
|
"native_code_channel_read_only_qemu_capability": 100,
|
||||||
"jd_physical_host_isolated_qemu_capability": 100,
|
"jd_physical_host_isolated_qemu_capability": 100,
|
||||||
|
"native_public_projection_contract_source": 100,
|
||||||
|
"native_public_projection_isolated_end_to_end_test": 100,
|
||||||
|
"bs_gz_shadow_projection_receiver": 0,
|
||||||
|
"bs_sg_authenticated_projection_sender": 0,
|
||||||
|
"live_native_projection_freshness": 0,
|
||||||
|
"nginx_native_projection_route_switch": 0,
|
||||||
"public_native_anchor_equivalence": 0,
|
"public_native_anchor_equivalence": 0,
|
||||||
"public_native_code_channel_equivalence": 0,
|
"public_native_code_channel_equivalence": 0,
|
||||||
"full_forgejo_equivalence": 0,
|
"full_forgejo_equivalence": 0,
|
||||||
|
|
@ -84,6 +90,7 @@
|
||||||
"adr_0172_linux_hosted_control_is_transition_not_final_topology": true
|
"adr_0172_linux_hosted_control_is_transition_not_final_topology": true
|
||||||
},
|
},
|
||||||
"native_service_equivalence_contract": "product-source/hololake-platform/guanghu-os/standards/jd-native-service-equivalence-contract.json",
|
"native_service_equivalence_contract": "product-source/hololake-platform/guanghu-os/standards/jd-native-service-equivalence-contract.json",
|
||||||
|
"native_public_projection_contract": "product-source/hololake-platform/guanghu-os/standards/jd-native-public-projection-contract.json",
|
||||||
"architecture_page": "product-source/hololake-platform/architecture/HOLOLAKE-GUANGHU-OS-MASTER-AND-ON-DEMAND-LINUX-SUBCONTROL-20260810.md",
|
"architecture_page": "product-source/hololake-platform/architecture/HOLOLAKE-GUANGHU-OS-MASTER-AND-ON-DEMAND-LINUX-SUBCONTROL-20260810.md",
|
||||||
"adr": "product-source/hololake-platform/docs/adr/0175-guanghu-os-master-and-on-demand-linux-subcontrol.md",
|
"adr": "product-source/hololake-platform/docs/adr/0175-guanghu-os-master-and-on-demand-linux-subcontrol.md",
|
||||||
"development_id": "DEV-20260810-012"
|
"development_id": "DEV-20260810-012"
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@ const rules = readJson("routing/hololake-engineering-rules.json");
|
||||||
const serviceContract = readJson(
|
const serviceContract = readJson(
|
||||||
"product-source/hololake-platform/guanghu-os/standards/jd-native-service-equivalence-contract.json",
|
"product-source/hololake-platform/guanghu-os/standards/jd-native-service-equivalence-contract.json",
|
||||||
);
|
);
|
||||||
|
const projectionContract = readJson(
|
||||||
|
"product-source/hololake-platform/guanghu-os/standards/jd-native-public-projection-contract.json",
|
||||||
|
);
|
||||||
|
|
||||||
test("final topology makes Guanghu the master while preserving Linux as on-demand subcontrol and rescue", () => {
|
test("final topology makes Guanghu the master while preserving Linux as on-demand subcontrol and rescue", () => {
|
||||||
assert.equal(contract.final_topology, "GUANGHU_MASTER_WITH_ON_DEMAND_LINUX_SUBCONTROL_AND_RESCUE");
|
assert.equal(contract.final_topology, "GUANGHU_MASTER_WITH_ON_DEMAND_LINUX_SUBCONTROL_AND_RESCUE");
|
||||||
|
|
@ -35,7 +38,7 @@ test("current JD state stays transitional and cannot impersonate final master co
|
||||||
});
|
});
|
||||||
|
|
||||||
test("the physical shadow and host QEMU cycles are registered without impersonating Guanghu-owned boot control", () => {
|
test("the physical shadow and host QEMU cycles are registered without impersonating Guanghu-owned boot control", () => {
|
||||||
assert.equal(contract.version, "2026-08-15.5");
|
assert.equal(contract.version, "2026-08-15.6");
|
||||||
assert.equal(contract.implementation.guanghu_supervisor_lifecycle_contract_source, 100);
|
assert.equal(contract.implementation.guanghu_supervisor_lifecycle_contract_source, 100);
|
||||||
assert.equal(contract.implementation.target_readback_and_mandatory_reclaim_state_machine, 100);
|
assert.equal(contract.implementation.target_readback_and_mandatory_reclaim_state_machine, 100);
|
||||||
assert.equal(contract.implementation.declared_supervisor_core_line_and_function_coverage, 100);
|
assert.equal(contract.implementation.declared_supervisor_core_line_and_function_coverage, 100);
|
||||||
|
|
@ -47,6 +50,12 @@ test("the physical shadow and host QEMU cycles are registered without impersonat
|
||||||
assert.equal(contract.implementation.native_anchor_http_qemu_capability, 100);
|
assert.equal(contract.implementation.native_anchor_http_qemu_capability, 100);
|
||||||
assert.equal(contract.implementation.native_code_channel_read_only_qemu_capability, 100);
|
assert.equal(contract.implementation.native_code_channel_read_only_qemu_capability, 100);
|
||||||
assert.equal(contract.implementation.jd_physical_host_isolated_qemu_capability, 100);
|
assert.equal(contract.implementation.jd_physical_host_isolated_qemu_capability, 100);
|
||||||
|
assert.equal(contract.implementation.native_public_projection_contract_source, 100);
|
||||||
|
assert.equal(contract.implementation.native_public_projection_isolated_end_to_end_test, 100);
|
||||||
|
assert.equal(contract.implementation.bs_gz_shadow_projection_receiver, 0);
|
||||||
|
assert.equal(contract.implementation.bs_sg_authenticated_projection_sender, 0);
|
||||||
|
assert.equal(contract.implementation.live_native_projection_freshness, 0);
|
||||||
|
assert.equal(contract.implementation.nginx_native_projection_route_switch, 0);
|
||||||
assert.equal(contract.implementation.public_native_anchor_equivalence, 0);
|
assert.equal(contract.implementation.public_native_anchor_equivalence, 0);
|
||||||
assert.equal(contract.implementation.public_native_code_channel_equivalence, 0);
|
assert.equal(contract.implementation.public_native_code_channel_equivalence, 0);
|
||||||
assert.equal(contract.implementation.full_forgejo_equivalence, 0);
|
assert.equal(contract.implementation.full_forgejo_equivalence, 0);
|
||||||
|
|
@ -59,6 +68,26 @@ test("the physical shadow and host QEMU cycles are registered without impersonat
|
||||||
assert.match(contract.native_service_qemu_evidence.server_receipt_sha256, /^[0-9a-f]{64}$/);
|
assert.match(contract.native_service_qemu_evidence.server_receipt_sha256, /^[0-9a-f]{64}$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("native public projection separates liveness, authenticated state, and pinned public bytes", () => {
|
||||||
|
assert.deepEqual(projectionContract.causal_route, ["JD-FD-PRIMARY", "BS-SG-003", "BS-GZ-006"]);
|
||||||
|
assert.equal(projectionContract.authentication.native_to_relay.may_supply_public_content, false);
|
||||||
|
assert.equal(projectionContract.public_bytes.provenance, "PINNED_REPO_012_SNAPSHOT");
|
||||||
|
assert.equal(projectionContract.public_bytes.relay_may_supply_or_mutate_bytes, false);
|
||||||
|
assert.equal(projectionContract.public_bytes.full_forgejo_equivalence, false);
|
||||||
|
assert.equal(projectionContract.front_door_projection.listen_scope, "LOOPBACK_ONLY");
|
||||||
|
assert.equal(projectionContract.front_door_projection.nginx_route_switch_authorized, false);
|
||||||
|
assert.equal(projectionContract.acceptance_gates.contract_source, 100);
|
||||||
|
assert.equal(projectionContract.acceptance_gates.isolated_end_to_end_test, 100);
|
||||||
|
assert.equal(projectionContract.acceptance_gates.bs_gz_shadow_receiver_deployed, 0);
|
||||||
|
assert.equal(projectionContract.acceptance_gates.bs_sg_authenticated_projector_deployed, 0);
|
||||||
|
assert.equal(projectionContract.acceptance_gates.live_native_freshness_readback, 0);
|
||||||
|
assert.equal(projectionContract.acceptance_gates.nginx_public_route_switched, 0);
|
||||||
|
assert.equal(projectionContract.acceptance_gates.public_native_anchor_equivalence, 0);
|
||||||
|
assert.equal(projectionContract.acceptance_gates.public_native_code_channel_equivalence, 0);
|
||||||
|
assert.equal(projectionContract.acceptance_gates.full_forgejo_equivalence, 0);
|
||||||
|
assert.equal(projectionContract.acceptance_gates.production_native_cutover, 0);
|
||||||
|
});
|
||||||
|
|
||||||
test("current architecture and global engineering rules project the same control contract", () => {
|
test("current architecture and global engineering rules project the same control contract", () => {
|
||||||
assert.equal(architecture.version, "2026-08-14.1");
|
assert.equal(architecture.version, "2026-08-14.1");
|
||||||
assert.equal(architecture.server_os_control.machine_projection, "routing/guanghu-os-control-architecture.json");
|
assert.equal(architecture.server_os_control.machine_projection, "routing/guanghu-os-control-architecture.json");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue