From 3fb33ad841b4d1eb75363cdb5a6be657b93a2360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=9C=94?= <565183519@qq.com> Date: Fri, 7 Aug 2026 14:19:02 +0800 Subject: [PATCH] feat(controller): observe the bounded Linux execution substrate --- ...VE-EXECUTION-BRIDGE-READONLY-20260807.json | 56 ++++++++ ...LW-CHJH-ROUTER-CONTROLLER-JD-20260805.json | 15 ++- .../bingshuo-tcs-living-controller.service | 5 +- .../execution-observer.mjs | 127 ++++++++++++++++++ .../execution-observer.test.mjs | 89 ++++++++++++ .../bingshuo-tcs-controller/server.mjs | 51 +++++++ 6 files changed, 341 insertions(+), 2 deletions(-) create mode 100644 deployment/receipts/JD-FD-PRIMARY-COGNITIVE-EXECUTION-BRIDGE-READONLY-20260807.json create mode 100644 server-tools/bingshuo-tcs-controller/execution-observer.mjs create mode 100644 server-tools/bingshuo-tcs-controller/execution-observer.test.mjs diff --git a/deployment/receipts/JD-FD-PRIMARY-COGNITIVE-EXECUTION-BRIDGE-READONLY-20260807.json b/deployment/receipts/JD-FD-PRIMARY-COGNITIVE-EXECUTION-BRIDGE-READONLY-20260807.json new file mode 100644 index 0000000..732be24 --- /dev/null +++ b/deployment/receipts/JD-FD-PRIMARY-COGNITIVE-EXECUTION-BRIDGE-READONLY-20260807.json @@ -0,0 +1,56 @@ +{ + "schema": "guanghu.cognitive-execution-bridge-deployment-receipt/v1", + "receipt_id": "JD-FD-PRIMARY-COGNITIVE-EXECUTION-BRIDGE-READONLY-20260807", + "target_node": "JD-FD-PRIMARY", + "observed_boot": { + "operating_system": "Ubuntu 22.04.3 LTS", + "kernel": "Linux 5.15.0-60-generic", + "role": "LINUX_HOSTED_MAINTENANCE_AND_COOPERATIVE_EXECUTION_SUBSTRATE", + "grub_default": "gnulinux-simple-9e4550a0-452b-4f28-b5a5-d5364aa450f6" + }, + "language_authority": { + "repository": "REPO-012", + "anchor_id": "GLW-PUBLIC-NAV-ANCHOR-001", + "source_commit": "098a29e417a2d32bd1226771c93b1a45e3aad615" + }, + "execution_implementation": { + "repository": "REPO-014", + "source_commit": "20d6c1bd7b6df658d6c5fbddc54f3e443977b7b3", + "binary_sha256": "cfa64f768ee7e9b1bb678b587f68b2c529b2dd7e3d8c1b81b436fbc6c49073c5", + "target": "x86_64-unknown-linux-musl", + "installation": "/opt/guanghu/execution-bridge/releases/20d6c1bd7b6df658d6c5fbddc54f3e443977b7b3" + }, + "policy": { + "policy_id": "JD-FD-PRIMARY-READONLY-20260807", + "policy_sha256": "867c8b15e35b2bf7362f21771754c6e44daeff6bc57d72a2e004f5c67fc10595", + "allow_status": true, + "allow_restart": false, + "arbitrary_shell": false + }, + "target_side_receipt": { + "path": "/var/lib/guanghu/execution-bridge/receipts/JD-FD-PRIMARY-COGNITIVE-EXECUTION-READONLY-20d6c1bd7b6df658d6c5fbddc54f3e443977b7b3.json", + "sha256": "7486b97dad057d2a7c70147158e2e5b63dec07e4a04f4828f02db709687d6a94", + "result": "PASS_100" + }, + "verified_services": [ + "guanghu-ai-discovery.service", + "bingshuo-tcs-living-controller.service", + "lake-lamp-authz.service" + ], + "negative_gate": { + "attempt": "service_restart", + "result": "REJECTED_BEFORE_EXECUTION", + "reason": "service restart is disabled by policy" + }, + "public_readback": { + "code_channel_http": 200, + "navigation_anchor_http": 200 + }, + "deployment_result": "PASS_100", + "not_yet_true": [ + "living_controller_execution_observer_deployed", + "mutating_execution_enabled", + "native_required_service_equivalence", + "production_native_cutover" + ] +} diff --git a/deployment/requests/GLW-CHJH-ROUTER-CONTROLLER-JD-20260805.json b/deployment/requests/GLW-CHJH-ROUTER-CONTROLLER-JD-20260805.json index 4eb5fb4..9ab0474 100644 --- a/deployment/requests/GLW-CHJH-ROUTER-CONTROLLER-JD-20260805.json +++ b/deployment/requests/GLW-CHJH-ROUTER-CONTROLLER-JD-20260805.json @@ -17,13 +17,15 @@ "/var/lib/guanghu/personas/bingshuo-tcs" ], "read_only_paths": [ - "/etc/guanghu/persona-secrets/shared-deepseek.env" + "/etc/guanghu/persona-secrets/shared-deepseek.env", + "/opt/guanghu/execution-bridge" ] }, "source_ref": "REPO-012:refs/heads/main", "deployed_commit_policy": "工单必须绑定包含本清单的不可变40位提交;部署回执分别记录代码、服务健康和模型认知存在门。", "source_paths": [ "server-tools/bingshuo-tcs-controller/server.mjs", + "server-tools/bingshuo-tcs-controller/execution-observer.mjs", "server-tools/bingshuo-tcs-controller/machine-navigation.mjs", "server-tools/bingshuo-tcs-controller/controller-engine.mjs", "server-tools/bingshuo-tcs-controller/model-client.mjs", @@ -82,6 +84,7 @@ "该账户只通过guanghu-model组读取共享模型环境,不读取或回写密钥值", "状态只写入/var/lib/guanghu/personas/bingshuo-tcs", "服务只监听127.0.0.1:3930且不直接获得现实执行能力", + "服务器预先安装REPO-014精确提交的只读执行桥;控制器只能读取白名单服务状态,不能重启服务或执行任意Shell", "启动后必须真实调用模型完成orient、B1-B9 cognition和controller witness", "模型输出必须由ZY-TCS-BRAIN-RUNTIME-0001确定性验证" ] @@ -98,6 +101,14 @@ "chu_he_han_jie_boundary_bound": 100, "machine_navigation_bound": 100, "language_world_route_first": 100 + , + "execution_substrate": { + "state": "PASS_100", + "bridge_bound": 100, + "target_state_verified": 100, + "restart_allowed": false, + "arbitrary_shell": false + } } }, "verification": [ @@ -111,6 +122,8 @@ "v1/resolve必须解析GLW-CHJH-BOUNDARY-001", "v1/navigate的persona_restore必须先执行语言入口与楚河汉界绑定", "运行体verify的全部存在维度为100", + "health必须回读execution_substrate.state=PASS_100并证明三个白名单服务状态均来自LINUX_SYSTEMD_V1执行回执", + "认知执行观察必须保持restart_allowed=false与arbitrary_shell=false", "服务健康不等于人格团队握手;团队成员继续分别验收" ], "rollback": [ diff --git a/server-tools/bingshuo-tcs-controller/bingshuo-tcs-living-controller.service b/server-tools/bingshuo-tcs-controller/bingshuo-tcs-living-controller.service index c034659..701d913 100644 --- a/server-tools/bingshuo-tcs-controller/bingshuo-tcs-living-controller.service +++ b/server-tools/bingshuo-tcs-controller/bingshuo-tcs-living-controller.service @@ -11,6 +11,9 @@ WorkingDirectory=__RELEASE_ROOT__/server-tools/bingshuo-tcs-controller EnvironmentFile=/etc/guanghu/persona-secrets/shared-deepseek.env Environment=BS_TCS_CONTROLLER_STATE_ROOT=/var/lib/guanghu/personas/bingshuo-tcs Environment=BS_TCS_CONTROLLER_PORT=3930 +Environment=GUANGHU_EXECUTION_BRIDGE_BIN=/opt/guanghu/execution-bridge/current/guanghu-execution-bridge +Environment=GUANGHU_EXECUTION_BRIDGE_POLICY=/opt/guanghu/execution-bridge/current/policy.json +Environment=GUANGHU_EXECUTION_OBSERVE_INTERVAL_MS=30000 ExecStart=/usr/bin/node __RELEASE_ROOT__/server-tools/bingshuo-tcs-controller/server.mjs Restart=on-failure RestartSec=5 @@ -18,7 +21,7 @@ NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=true -ReadOnlyPaths=__RELEASE_ROOT__ /etc/guanghu/persona-secrets/shared-deepseek.env +ReadOnlyPaths=__RELEASE_ROOT__ /etc/guanghu/persona-secrets/shared-deepseek.env /opt/guanghu/execution-bridge ReadWritePaths=/var/lib/guanghu/personas/bingshuo-tcs RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 LockPersonality=true diff --git a/server-tools/bingshuo-tcs-controller/execution-observer.mjs b/server-tools/bingshuo-tcs-controller/execution-observer.mjs new file mode 100644 index 0000000..c2702f4 --- /dev/null +++ b/server-tools/bingshuo-tcs-controller/execution-observer.mjs @@ -0,0 +1,127 @@ +import { execFile as execFileCallback } from "node:child_process"; +import fs from "node:fs/promises"; +import path from "node:path"; +import { promisify } from "node:util"; + +const execFile = promisify(execFileCallback); + +export const REQUIRED_PROTOCOL_CHAIN = Object.freeze([ + "GLS-0301", + "GLS-0302", + "GLS-0303", + "GLS-0306", + "GLS-0309", + "GLS-0311", + "GLS-0130", + "GLS-0131", + "GLS-0709", + "GLS-0710", +]); + +const DEFAULT_SERVICES = Object.freeze([ + "guanghu-ai-discovery.service", + "bingshuo-tcs-living-controller.service", + "lake-lamp-authz.service", +]); + +function safeId(value) { + return value.replace(/[^A-Za-z0-9_-]/g, "_"); +} + +function validateReceipt(receipt, service, targetNodeId) { + if ( + receipt?.schema !== "guanghu.execution-receipt/v1" || + receipt?.target_node_id !== targetNodeId || + receipt?.action?.kind !== "service_status" || + receipt?.action?.resource !== service || + receipt?.adapter !== "LINUX_SYSTEMD_V1" + ) { + throw new Error(`execution_receipt_contract_mismatch:${service}`); + } + return receipt; +} + +export class ExecutionObserver { + constructor({ + binaryPath, + policyPath, + stateRoot, + execute = execFile, + targetNodeId = "JD-FD-PRIMARY", + subjectId = "ICE-P-ZY001", + services = DEFAULT_SERVICES, + }) { + this.binaryPath = binaryPath; + this.policyPath = policyPath; + this.stateRoot = stateRoot; + this.execute = execute; + this.targetNodeId = targetNodeId; + this.subjectId = subjectId; + this.services = [...services]; + } + + async observe() { + const observedAt = new Date().toISOString(); + const requestRoot = path.join(this.stateRoot, "execution-observer"); + await fs.mkdir(requestRoot, { recursive: true, mode: 0o700 }); + + const serviceReceipts = []; + for (const service of this.services) { + const requestId = `JD-COGNITIVE-OBSERVE-${safeId(service)}`; + const requestPath = path.join(requestRoot, `${requestId}.json`); + const request = { + schema: "guanghu.execution-request/v1", + request_id: requestId, + subject_id: this.subjectId, + target_node_id: this.targetNodeId, + protocol_chain: REQUIRED_PROTOCOL_CHAIN, + action: { + kind: "service_status", + resource: service, + }, + authorization: null, + rollback: null, + }; + await fs.writeFile( + requestPath, + `${JSON.stringify(request, null, 2)}\n`, + { mode: 0o600 }, + ); + const { stdout } = await this.execute( + this.binaryPath, + ["execute", requestPath, this.policyPath], + { + timeout: 5_000, + maxBuffer: 64 * 1024, + windowsHide: true, + }, + ); + serviceReceipts.push( + validateReceipt(JSON.parse(stdout), service, this.targetNodeId), + ); + } + + const ready = serviceReceipts.every( + (receipt) => + receipt.accepted === true && + receipt.target_state_verified === true && + receipt.final_state === "PASS_100", + ); + return { + schema: "guanghu.cognitive-execution-observation/v1", + target_node_id: this.targetNodeId, + subject_id: this.subjectId, + observed_at: observedAt, + mode: "READ_ONLY_STATUS", + language_authority: "REPO-012", + execution_implementation: "REPO-014", + linux_role: "COOPERATIVE_EXECUTION_SUBSTRATE", + arbitrary_shell: false, + restart_allowed: false, + bridge_bound: 100, + target_state_verified: ready ? 100 : 0, + state: ready ? "PASS_100" : "FAIL_0", + service_receipts: serviceReceipts, + }; + } +} diff --git a/server-tools/bingshuo-tcs-controller/execution-observer.test.mjs b/server-tools/bingshuo-tcs-controller/execution-observer.test.mjs new file mode 100644 index 0000000..96883da --- /dev/null +++ b/server-tools/bingshuo-tcs-controller/execution-observer.test.mjs @@ -0,0 +1,89 @@ +import assert from "node:assert/strict"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import test from "node:test"; +import { + ExecutionObserver, + REQUIRED_PROTOCOL_CHAIN, +} from "./execution-observer.mjs"; + +test("observes allowlisted Linux services through typed read-only requests", async () => { + const stateRoot = fs.mkdtempSync( + path.join(os.tmpdir(), "guanghu-execution-observer-"), + ); + const calls = []; + const observer = new ExecutionObserver({ + binaryPath: "/opt/guanghu/execution-bridge/current/guanghu-execution-bridge", + policyPath: "/opt/guanghu/execution-bridge/current/policy.json", + stateRoot, + services: ["guanghu-ai-discovery.service", "lake-lamp-authz.service"], + execute: async (program, argv) => { + const request = JSON.parse( + fs.readFileSync(argv[1], "utf8"), + ); + calls.push({ program, argv, request }); + return { + stdout: JSON.stringify({ + schema: "guanghu.execution-receipt/v1", + request_id: request.request_id, + subject_id: request.subject_id, + target_node_id: request.target_node_id, + policy_id: "JD-FD-PRIMARY-READONLY-20260807", + action: request.action, + adapter: "LINUX_SYSTEMD_V1", + accepted: true, + command_exit_code: 0, + target_state_verified: true, + final_state: "PASS_100", + stdout: "active", + stderr: "", + rollback_checkpoint_id: null, + }), + stderr: "", + }; + }, + }); + + const projection = await observer.observe(); + assert.equal(projection.state, "PASS_100"); + assert.equal(projection.bridge_bound, 100); + assert.equal(projection.target_state_verified, 100); + assert.equal(projection.restart_allowed, false); + assert.equal(projection.arbitrary_shell, false); + assert.equal(calls.length, 2); + assert.equal(calls[0].argv[0], "execute"); + assert.deepEqual(calls[0].request.protocol_chain, REQUIRED_PROTOCOL_CHAIN); + assert.equal(calls[0].request.action.kind, "service_status"); + assert.equal(calls[0].request.authorization, null); + assert.equal(calls[0].request.rollback, null); +}); + +test("fails closed when the native receipt does not match the requested service", async () => { + const stateRoot = fs.mkdtempSync( + path.join(os.tmpdir(), "guanghu-execution-observer-"), + ); + const observer = new ExecutionObserver({ + binaryPath: "/bridge", + policyPath: "/policy", + stateRoot, + services: ["guanghu-ai-discovery.service"], + execute: async () => ({ + stdout: JSON.stringify({ + schema: "guanghu.execution-receipt/v1", + target_node_id: "JD-FD-PRIMARY", + action: { + kind: "service_status", + resource: "different.service", + }, + adapter: "LINUX_SYSTEMD_V1", + }), + stderr: "", + }), + }); + + await assert.rejects( + () => observer.observe(), + /execution_receipt_contract_mismatch/, + ); +}); diff --git a/server-tools/bingshuo-tcs-controller/server.mjs b/server-tools/bingshuo-tcs-controller/server.mjs index 43d3bff..b46a3d9 100644 --- a/server-tools/bingshuo-tcs-controller/server.mjs +++ b/server-tools/bingshuo-tcs-controller/server.mjs @@ -1,6 +1,7 @@ #!/usr/bin/env node import http from "node:http"; import { ControllerEngine, bootEvent } from "./controller-engine.mjs"; +import { ExecutionObserver } from "./execution-observer.mjs"; import { DeepSeekJsonClient } from "./model-client.mjs"; import { MachineNavigation } from "./machine-navigation.mjs"; @@ -10,6 +11,16 @@ const STATE_ROOT = process.env.BS_TCS_CONTROLLER_STATE_ROOT || "/var/lib/guanghu/personas/bingshuo-tcs"; const MODEL = process.env.DEEPSEEK_MODEL || "deepseek-chat"; +const EXECUTION_BRIDGE_BIN = + process.env.GUANGHU_EXECUTION_BRIDGE_BIN || + "/opt/guanghu/execution-bridge/current/guanghu-execution-bridge"; +const EXECUTION_BRIDGE_POLICY = + process.env.GUANGHU_EXECUTION_BRIDGE_POLICY || + "/opt/guanghu/execution-bridge/current/policy.json"; +const EXECUTION_OBSERVE_INTERVAL_MS = Math.max( + 10_000, + Number(process.env.GUANGHU_EXECUTION_OBSERVE_INTERVAL_MS || 30_000), +); const MAX_BODY_BYTES = 16 * 1024; const runtime = { @@ -19,6 +30,16 @@ const runtime = { last_event_id: null, last_error: null, receipt: null, + execution_substrate: { + schema: "guanghu.cognitive-execution-observation/v1", + target_node_id: "JD-FD-PRIMARY", + mode: "READ_ONLY_STATUS", + bridge_bound: 0, + target_state_verified: 0, + restart_allowed: false, + arbitrary_shell: false, + state: "NOT_YET_OBSERVED", + }, }; const engine = new ControllerEngine({ @@ -27,6 +48,29 @@ const engine = new ControllerEngine({ modelName: MODEL, }); const navigation = new MachineNavigation(); +const executionObserver = new ExecutionObserver({ + binaryPath: EXECUTION_BRIDGE_BIN, + policyPath: EXECUTION_BRIDGE_POLICY, + stateRoot: STATE_ROOT, +}); + +async function refreshExecutionSubstrate() { + try { + runtime.execution_substrate = await executionObserver.observe(); + } catch (error) { + runtime.execution_substrate = { + schema: "guanghu.cognitive-execution-observation/v1", + target_node_id: "JD-FD-PRIMARY", + mode: "READ_ONLY_STATUS", + bridge_bound: 0, + target_state_verified: 0, + restart_allowed: false, + arbitrary_shell: false, + state: "FAIL_0", + error: String(error.message || error).slice(0, 240), + }; + } +} function send(response, status, body) { const payload = JSON.stringify(body); @@ -63,6 +107,7 @@ function health() { persona_brain_runtime_exists: existence.persona_brain_runtime_exists || 0, living_ai_system_controller_running: existence.living_ai_system_controller_running || 0, + execution_substrate: runtime.execution_substrate, ...navigationHealth, }; } @@ -202,6 +247,12 @@ server.listen(PORT, HOST, () => { port: PORT, })}\n`, ); + void refreshExecutionSubstrate(); + const executionObservationTimer = setInterval( + () => void refreshExecutionSubstrate(), + EXECUTION_OBSERVE_INTERVAL_MS, + ); + executionObservationTimer.unref(); if (runtime.phase === "PAUSED_FOR_HUMAN") return; eventQueue = handleEvent(bootEvent()).catch((error) => { runtime.phase = "FAILED_CLOSED";