diff --git a/product-source/hololake-platform/guanghu-os/README.md b/product-source/hololake-platform/guanghu-os/README.md index 0431eb7..1dcf025 100644 --- a/product-source/hololake-platform/guanghu-os/README.md +++ b/product-source/hololake-platform/guanghu-os/README.md @@ -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 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 `guanghu-language-primary.target` makes the accepted cognitive-control model diff --git a/product-source/hololake-platform/guanghu-os/scripts/linux-subcontrol-docker-backend.sh b/product-source/hololake-platform/guanghu-os/scripts/linux-subcontrol-docker-backend.sh new file mode 100755 index 0000000..0b212f7 --- /dev/null +++ b/product-source/hololake-platform/guanghu-os/scripts/linux-subcontrol-docker-backend.sh @@ -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 [capability] [request-id]" + ;; +esac diff --git a/product-source/hololake-platform/guanghu-os/scripts/test-linux-subcontrol-docker-backend.sh b/product-source/hololake-platform/guanghu-os/scripts/test-linux-subcontrol-docker-backend.sh new file mode 100755 index 0000000..2caf540 --- /dev/null +++ b/product-source/hololake-platform/guanghu-os/scripts/test-linux-subcontrol-docker-backend.sh @@ -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" diff --git a/product-source/hololake-platform/guanghu-os/world-seed/scripts/run-guanghu-native-quality-gate.sh b/product-source/hololake-platform/guanghu-os/world-seed/scripts/run-guanghu-native-quality-gate.sh index 94859b3..7ac8a1b 100755 --- a/product-source/hololake-platform/guanghu-os/world-seed/scripts/run-guanghu-native-quality-gate.sh +++ b/product-source/hololake-platform/guanghu-os/world-seed/scripts/run-guanghu-native-quality-gate.sh @@ -88,6 +88,8 @@ run_gate world_and_protocol_validation \ run_gate shell_syntax bash -c \ 'for script in "$1"/scripts/*.sh "$1"/world-seed/scripts/*.sh; do bash -n "$script"; done' \ _ "${source_root}" +run_gate linux_subcontrol_docker_backend \ + "${source_root}/scripts/test-linux-subcontrol-docker-backend.sh" run_gate auditable_line_coverage_100_percent \ bash -c ' cargo llvm-cov clean --workspace --manifest-path "$1/Cargo.toml" diff --git a/routing/guanghu-os-control-architecture.json b/routing/guanghu-os-control-architecture.json index d48b463..4056055 100644 --- a/routing/guanghu-os-control-architecture.json +++ b/routing/guanghu-os-control-architecture.json @@ -1,7 +1,7 @@ { "schema": "guanghu.os-control-architecture/v1", "record_id": "HLP-GUANGHU-OS-CONTROL-001", - "version": "2026-08-15.1", + "version": "2026-08-15.2", "state": "CURRENT_CANONICAL", "final_topology": "GUANGHU_MASTER_WITH_ON_DEMAND_LINUX_SUBCONTROL_AND_RESCUE", "control_ownership": { @@ -46,7 +46,9 @@ "typed_policy_authorization_and_rollback_binding": 100, "target_readback_and_mandatory_reclaim_state_machine": 100, "declared_supervisor_core_line_and_function_coverage": 100, + "docker_shadow_backend_source_and_isolation_contract": 100, "real_isolated_linux_backend": 0, + "jd_shadow_backend_physical_cycle": 0, "independent_guanghu_first_boot_supervisor": 0, "jd_physical_deployment": 0 }, diff --git a/routing/guanghu-os-control-architecture.test.mjs b/routing/guanghu-os-control-architecture.test.mjs index e6eadc0..66d6ef9 100644 --- a/routing/guanghu-os-control-architecture.test.mjs +++ b/routing/guanghu-os-control-architecture.test.mjs @@ -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", () => { - 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.target_readback_and_mandatory_reclaim_state_machine, 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.jd_shadow_backend_physical_cycle, 0); assert.equal(contract.implementation.independent_guanghu_first_boot_supervisor, 0); assert.equal(contract.implementation.jd_physical_deployment, 0); });