feat: add isolated Linux shadow backend

This commit is contained in:
冰朔 2026-08-15 17:34:30 +08:00
commit f5217fef0f
6 changed files with 283 additions and 2 deletions

View file

@ -78,6 +78,19 @@ at 100% of declared source lines and functions. No production Linux
subcontrol backend, independent Guanghu boot supervisor, JD boot change, or subcontrol backend, independent Guanghu boot supervisor, JD boot change, or
physical cutover is implied by that source result. physical cutover is implied by that source result.
`scripts/linux-subcontrol-docker-backend.sh` is the first executable shadow
backend for the Linux-hosted transition. It binds the exact JD instance,
backend id, immutable Ubuntu image digest, and preserved GRUB rescue slot. A
wake starts a networkless, read-only, capability-free container with explicit
CPU, memory, and PID limits. Only the registered runtime-identity readback is
accepted; reclaim removes the container and verifies `DORMANT`. Environment
path overrides are rejected outside the isolated test harness.
This backend can prove the bounded Linux lifecycle while Ubuntu is still the
host. It cannot prove Guanghu-first boot control or the final topology. Those
remain `0` until the same lifecycle is owned by an independently booted
Guanghu supervisor and has a current JD server receipt.
## Language-primary boot target ## Language-primary boot target
`guanghu-language-primary.target` makes the accepted cognitive-control model `guanghu-language-primary.target` makes the accepted cognitive-control model

View file

@ -0,0 +1,166 @@
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
die() {
echo "GUANGHU_LINUX_SUBCONTROL_FAIL_0: $*" >&2
exit 1
}
test_mode=${GH_SUBCONTROL_TEST_MODE:-0}
if [[ "${test_mode}" == 1 ]]; then
config_path=${GH_SUBCONTROL_CONFIG:?test config is required}
docker_bin=${GH_SUBCONTROL_DOCKER:?test docker is required}
dmi_path=${GH_SUBCONTROL_DMI_PATH:?test DMI path is required}
grub_cfg=${GH_SUBCONTROL_GRUB_CFG:?test GRUB path is required}
state_root=${GH_SUBCONTROL_STATE_ROOT:?test state root is required}
receipt_root=${GH_SUBCONTROL_RECEIPT_ROOT:?test receipt root is required}
else
[[ "${EUID}" == 0 ]] || die "root execution is required"
for override in \
GH_SUBCONTROL_CONFIG GH_SUBCONTROL_DOCKER GH_SUBCONTROL_DMI_PATH \
GH_SUBCONTROL_GRUB_CFG GH_SUBCONTROL_STATE_ROOT GH_SUBCONTROL_RECEIPT_ROOT; do
[[ -z "${!override:-}" ]] || die "production path override is forbidden: ${override}"
done
config_path=/etc/guanghu/linux-subcontrol.conf
docker_bin=/usr/bin/docker
dmi_path=/sys/class/dmi/id/product_uuid
grub_cfg=/boot/grub/grub.cfg
state_root=/run/guanghu/linux-subcontrol
receipt_root=/guanghu/receipts/linux-subcontrol
[[ -f "${config_path}" && ! -L "${config_path}" ]] || die "root-owned backend config is missing"
[[ "$(stat -c '%u:%a' "${config_path}")" =~ ^0:(600|640|644)$ ]] ||
die "backend config owner or mode is unsafe"
fi
schema=
node_id=
instance_id=
backend_id=
container_name=
image=
rescue_slot_id=
while IFS='=' read -r key value; do
[[ -n "${key}" ]] || continue
case "${key}" in
schema|node_id|instance_id|backend_id|container_name|image|rescue_slot_id)
printf -v "${key}" '%s' "${value}"
;;
*) die "unknown config field: ${key}" ;;
esac
done <"${config_path}"
[[ "${schema}" == "guanghu.linux-subcontrol-docker-backend/v1" ]] || die "config schema mismatch"
[[ "${node_id}" == "JD-FD-PRIMARY" ]] || die "target node mismatch"
[[ "${instance_id}" =~ ^[0-9a-f-]{36}$ ]] || die "instance id is invalid"
[[ "${backend_id}" =~ ^[a-z0-9-]+$ ]] || die "backend id is invalid"
[[ "${container_name}" =~ ^[a-z0-9-]+$ ]] || die "container name is invalid"
[[ "${image}" =~ ^ubuntu@sha256:[0-9a-f]{64}$ ]] || die "image must use an immutable Ubuntu digest"
[[ "${rescue_slot_id}" =~ ^[A-Za-z0-9._-]+$ ]] || die "rescue slot id is invalid"
[[ -x "${docker_bin}" ]] || die "docker executable is unavailable"
requested_backend=${2:-}
[[ -n "${requested_backend}" && "${requested_backend}" == "${backend_id}" ]] ||
die "backend binding mismatch"
verify_machine() {
local observed
observed=$(tr '[:upper:]' '[:lower:]' <"${dmi_path}")
[[ "${observed}" == "${instance_id}" ]] || die "machine identity mismatch"
}
verify_rescue() {
grep -Fq -- "--id '${rescue_slot_id}'" "${grub_cfg}" ||
die "independent Linux rescue slot is unavailable"
}
container_running() {
[[ "$("${docker_bin}" inspect --format '{{.State.Running}}' "${container_name}" 2>/dev/null || true)" == true ]]
}
observe() {
if container_running; then
echo ready
else
echo dormant
fi
}
action=${1:-}
case "${action}" in
preflight)
verify_machine
verify_rescue
"${docker_bin}" image inspect "${image}" >/dev/null
echo "GUANGHU_LINUX_SUBCONTROL_PREFLIGHT_OK"
;;
observe)
observe
;;
wake)
verify_machine
verify_rescue
[[ "$(observe)" == dormant ]] || die "backend is not dormant before wake"
"${docker_bin}" image inspect "${image}" >/dev/null
mkdir -p "${state_root}" "${receipt_root}"
"${docker_bin}" run \
--detach \
--pull never \
--name "${container_name}" \
--hostname jd-linux-subcontrol \
--label guanghu.owner=GUANGHU_OS \
--label "guanghu.node=${node_id}" \
--label "guanghu.backend=${backend_id}" \
--network none \
--read-only \
--tmpfs /run:rw,nosuid,nodev,noexec,size=16m \
--tmpfs /tmp:rw,nosuid,nodev,noexec,size=16m \
--cap-drop ALL \
--security-opt no-new-privileges \
--pids-limit 64 \
--memory 256m \
--cpus 0.50 \
"${image}" \
/bin/sh -ceu 'trap "exit 0" TERM INT; while :; do sleep 3600 & wait $!; done' \
>/dev/null
container_running || die "backend failed readiness readback"
echo "GUANGHU_LINUX_SUBCONTROL_READY"
;;
execute|verify)
capability=${3:-}
request_id=${4:-}
[[ "${capability}" == runtime-identity-readback ]] || die "capability is not allowlisted"
[[ "${request_id}" =~ ^[A-Za-z0-9._-]+$ ]] || die "request id is invalid"
container_running || die "backend is not ready"
mkdir -p "${state_root}" "${receipt_root}"
target_file="${state_root}/${request_id}.target"
if [[ "${action}" == execute ]]; then
temporary="${target_file}.tmp"
"${docker_bin}" exec "${container_name}" /bin/sh -ceu \
'. /etc/os-release; printf "ID=%s\nVERSION_ID=%s\n" "$ID" "$VERSION_ID"' \
>"${temporary}"
chmod 600 "${temporary}"
mv "${temporary}" "${target_file}"
echo "GUANGHU_LINUX_SUBCONTROL_EXECUTED"
else
[[ -f "${target_file}" ]] || die "target readback is missing"
expected=$'ID=ubuntu\nVERSION_ID=22.04'
stored=$(cat "${target_file}")
live=$("${docker_bin}" exec "${container_name}" /bin/sh -ceu \
'. /etc/os-release; printf "ID=%s\nVERSION_ID=%s\n" "$ID" "$VERSION_ID"')
[[ "${stored}" == "${expected}" && "${live}" == "${expected}" ]] ||
die "target readback mismatch"
echo "GUANGHU_LINUX_SUBCONTROL_TARGET_VERIFIED"
fi
;;
reclaim)
if container_running; then
"${docker_bin}" rm --force "${container_name}" >/dev/null
fi
[[ "$(observe)" == dormant ]] || die "backend reclaim failed"
echo "GUANGHU_LINUX_SUBCONTROL_DORMANT"
;;
*)
die "usage: $0 <preflight|observe|wake|execute|verify|reclaim> <backend-id> [capability] [request-id]"
;;
esac

View file

@ -0,0 +1,96 @@
#!/usr/bin/env bash
set -Eeuo pipefail
source_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
adapter="${source_root}/scripts/linux-subcontrol-docker-backend.sh"
fixture=$(mktemp -d)
trap 'rm -rf "${fixture}"' EXIT
mkdir -p "${fixture}/bin" "${fixture}/state" "${fixture}/receipts"
printf '%s\n' 'f3d4b730-7f02-452f-975b-7091a4800431' >"${fixture}/dmi"
printf '%s\n' "menuentry 'Ubuntu' --id 'gnulinux-simple-9e4550a0-452b-4f28-b5a5-d5364aa450f6' {" >"${fixture}/grub.cfg"
cat >"${fixture}/backend.conf" <<'EOF'
schema=guanghu.linux-subcontrol-docker-backend/v1
node_id=JD-FD-PRIMARY
instance_id=f3d4b730-7f02-452f-975b-7091a4800431
backend_id=jd-linux-on-demand
container_name=guanghu-linux-subcontrol-jd
image=ubuntu@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
rescue_slot_id=gnulinux-simple-9e4550a0-452b-4f28-b5a5-d5364aa450f6
EOF
cat >"${fixture}/bin/docker" <<'EOF'
#!/usr/bin/env bash
set -Eeuo pipefail
printf '%s\n' "$*" >>"${FAKE_DOCKER_LOG}"
case "${1:-}" in
image)
[[ "${2:-}" == inspect ]]
;;
inspect)
[[ -f "${FAKE_DOCKER_STATE}" ]] || exit 1
printf '%s\n' true
;;
run)
touch "${FAKE_DOCKER_STATE}"
printf '%s\n' fixture-container-id
;;
exec)
[[ -f "${FAKE_DOCKER_STATE}" ]]
printf '%s\n' 'ID=ubuntu' 'VERSION_ID=22.04'
;;
rm)
rm -f "${FAKE_DOCKER_STATE}"
;;
*)
exit 64
;;
esac
EOF
chmod +x "${fixture}/bin/docker"
export GH_SUBCONTROL_TEST_MODE=1
export GH_SUBCONTROL_CONFIG="${fixture}/backend.conf"
export GH_SUBCONTROL_DOCKER="${fixture}/bin/docker"
export GH_SUBCONTROL_DMI_PATH="${fixture}/dmi"
export GH_SUBCONTROL_GRUB_CFG="${fixture}/grub.cfg"
export GH_SUBCONTROL_STATE_ROOT="${fixture}/state"
export GH_SUBCONTROL_RECEIPT_ROOT="${fixture}/receipts"
export FAKE_DOCKER_LOG="${fixture}/docker.log"
export FAKE_DOCKER_STATE="${fixture}/container.running"
[[ "$("${adapter}" observe jd-linux-on-demand)" == dormant ]]
"${adapter}" preflight jd-linux-on-demand
"${adapter}" wake jd-linux-on-demand
[[ "$("${adapter}" observe jd-linux-on-demand)" == ready ]]
"${adapter}" execute jd-linux-on-demand runtime-identity-readback REQ-001
"${adapter}" verify jd-linux-on-demand runtime-identity-readback REQ-001
"${adapter}" reclaim jd-linux-on-demand
[[ "$("${adapter}" observe jd-linux-on-demand)" == dormant ]]
grep -Fq -- '--network none' "${fixture}/docker.log"
grep -Fq -- '--read-only' "${fixture}/docker.log"
grep -Fq -- '--cap-drop ALL' "${fixture}/docker.log"
grep -Fq -- '--security-opt no-new-privileges' "${fixture}/docker.log"
grep -Fq -- '--pids-limit 64' "${fixture}/docker.log"
grep -Fq -- 'ubuntu@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' "${fixture}/docker.log"
if "${adapter}" execute jd-linux-on-demand arbitrary-shell REQ-002; then
echo "unregistered capability was accepted" >&2
exit 1
fi
printf '%s\n' 'wrong-instance' >"${fixture}/dmi"
if "${adapter}" wake jd-linux-on-demand; then
echo "wrong machine identity was accepted" >&2
exit 1
fi
printf '%s\n' 'f3d4b730-7f02-452f-975b-7091a4800431' >"${fixture}/dmi"
: >"${fixture}/grub.cfg"
if "${adapter}" wake jd-linux-on-demand; then
echo "missing rescue slot was accepted" >&2
exit 1
fi
echo "GUANGHU_LINUX_SUBCONTROL_DOCKER_BACKEND_OK"

View file

@ -88,6 +88,8 @@ run_gate world_and_protocol_validation \
run_gate shell_syntax bash -c \ run_gate shell_syntax bash -c \
'for script in "$1"/scripts/*.sh "$1"/world-seed/scripts/*.sh; do bash -n "$script"; done' \ 'for script in "$1"/scripts/*.sh "$1"/world-seed/scripts/*.sh; do bash -n "$script"; done' \
_ "${source_root}" _ "${source_root}"
run_gate linux_subcontrol_docker_backend \
"${source_root}/scripts/test-linux-subcontrol-docker-backend.sh"
run_gate auditable_line_coverage_100_percent \ run_gate auditable_line_coverage_100_percent \
bash -c ' bash -c '
cargo llvm-cov clean --workspace --manifest-path "$1/Cargo.toml" cargo llvm-cov clean --workspace --manifest-path "$1/Cargo.toml"

View file

@ -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.1", "version": "2026-08-15.2",
"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": {
@ -46,7 +46,9 @@
"typed_policy_authorization_and_rollback_binding": 100, "typed_policy_authorization_and_rollback_binding": 100,
"target_readback_and_mandatory_reclaim_state_machine": 100, "target_readback_and_mandatory_reclaim_state_machine": 100,
"declared_supervisor_core_line_and_function_coverage": 100, "declared_supervisor_core_line_and_function_coverage": 100,
"docker_shadow_backend_source_and_isolation_contract": 100,
"real_isolated_linux_backend": 0, "real_isolated_linux_backend": 0,
"jd_shadow_backend_physical_cycle": 0,
"independent_guanghu_first_boot_supervisor": 0, "independent_guanghu_first_boot_supervisor": 0,
"jd_physical_deployment": 0 "jd_physical_deployment": 0
}, },

View file

@ -32,11 +32,13 @@ test("current JD state stays transitional and cannot impersonate final master co
}); });
test("source lifecycle progress does not impersonate backend, boot, or JD deployment", () => { test("source lifecycle progress does not impersonate backend, boot, or JD deployment", () => {
assert.equal(contract.version, "2026-08-15.1"); assert.equal(contract.version, "2026-08-15.2");
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);
assert.equal(contract.implementation.docker_shadow_backend_source_and_isolation_contract, 100);
assert.equal(contract.implementation.real_isolated_linux_backend, 0); assert.equal(contract.implementation.real_isolated_linux_backend, 0);
assert.equal(contract.implementation.jd_shadow_backend_physical_cycle, 0);
assert.equal(contract.implementation.independent_guanghu_first_boot_supervisor, 0); assert.equal(contract.implementation.independent_guanghu_first_boot_supervisor, 0);
assert.equal(contract.implementation.jd_physical_deployment, 0); assert.equal(contract.implementation.jd_physical_deployment, 0);
}); });