fix(host112): persist installer post-gate blockers

This commit is contained in:
ogt
2026-07-14 16:02:33 +08:00
parent 0d75dc9a9e
commit 12fc4b8914
2 changed files with 47 additions and 1 deletions

View File

@@ -43,6 +43,7 @@ INSTALL_RECEIPT_REF="none"
INSTALL_RECEIPT_PATH=""
INSTALL_ATTEMPT_ID=""
BACKUP_DIR=""
STATIC_POST_GATE_BLOCKERS="not_evaluated"
sudoers_tmp=""
AUTH_TMP=""
TIMER_ACTIVATION_PERFORMED=0
@@ -441,7 +442,7 @@ write_install_receipt() {
installer_sha="${installer_sha:-missing}"
receipt_tmp="${INSTALL_RECEIPT_PATH}.tmp.$$"
printf '%s\n' \
"schema_version=host112_guest_recovery_install_receipt_v1 generated_at=$generated_at trace_id=$TRACE_ID run_id=$RUN_ID work_item_id=$WORK_ITEM_ID terminal=$terminal install_verified=$install_verified installer_runtime_write_performed=1 manager_runtime_write_performed=0 static_post_gate_ready=${STATIC_POST_GATE_READY:-0} check_gate_ready=${CHECK_GATE_READY:-0} sudo_policy_ready=${SUDO_POLICY_READY:-0} agent99_99_direct_route_ready=${AGENT99_99_DIRECT_ROUTE_READY:-0} agent99_99_direct_runtime_probe=not_started timer_enabled=${TIMER_ENABLED:-unknown} timer_active=${TIMER_ACTIVE:-unknown} timer_activation_performed=$TIMER_ACTIVATION_PERFORMED synchronous_recovery_start=0 recovery_execution_performed=0 recovery_run_id=none recovery_receipt_ref=none rollback_attempted=$rollback_attempted rollback_verified=$rollback_verified error_exit=$error_exit backup_ref=$BACKUP_DIR readiness_sha256=$readiness_sha installer_sha256=$installer_sha prohibited_actions=host_reboot,vm_power_change,vm_reset,firewall_change,secret_read,database_write" \
"schema_version=host112_guest_recovery_install_receipt_v1 generated_at=$generated_at trace_id=$TRACE_ID run_id=$RUN_ID work_item_id=$WORK_ITEM_ID terminal=$terminal install_verified=$install_verified installer_runtime_write_performed=1 manager_runtime_write_performed=0 static_post_gate_ready=${STATIC_POST_GATE_READY:-0} static_post_gate_blockers=${STATIC_POST_GATE_BLOCKERS:-not_evaluated} check_gate_ready=${CHECK_GATE_READY:-0} sudo_policy_ready=${SUDO_POLICY_READY:-0} agent99_99_direct_route_ready=${AGENT99_99_DIRECT_ROUTE_READY:-0} agent99_99_direct_runtime_probe=not_started timer_enabled=${TIMER_ENABLED:-unknown} timer_active=${TIMER_ACTIVE:-unknown} timer_activation_performed=$TIMER_ACTIVATION_PERFORMED synchronous_recovery_start=0 recovery_execution_performed=0 recovery_run_id=none recovery_receipt_ref=none rollback_attempted=$rollback_attempted rollback_verified=$rollback_verified error_exit=$error_exit backup_ref=$BACKUP_DIR readiness_sha256=$readiness_sha installer_sha256=$installer_sha prohibited_actions=host_reboot,vm_power_change,vm_reset,firewall_change,secret_read,database_write" \
>"$receipt_tmp"
chmod 0640 "$receipt_tmp"
if ! mv -n "$receipt_tmp" "$INSTALL_RECEIPT_PATH" \
@@ -527,7 +528,9 @@ static_source_preflight() {
}
post_install_static_gate() {
local blockers=()
STATIC_POST_GATE_READY=0
STATIC_POST_GATE_BLOCKERS="none"
TARGET_HASHES_MATCH=0
UNIT_STATIC_VERIFY_READY=0
if cmp -s "$READINESS_SOURCE" "$READINESS_TARGET" \
@@ -540,6 +543,17 @@ post_install_static_gate() {
UNIT_STATIC_VERIFY_READY=1
fi
refresh_gate_state
[ "$TARGET_HASHES_MATCH" -eq 1 ] || blockers+=(target_hashes_mismatch)
[ "$UNIT_STATIC_VERIFY_READY" -eq 1 ] || blockers+=(unit_static_verify_failed)
[ "$TARGET_FILES_READY" -eq 1 ] || blockers+=(target_files_not_ready)
[ "$UNIT_CONTRACT_READY" -eq 1 ] || blockers+=(unit_contract_not_ready)
[ "$SUDO_POLICY_READY" -eq 1 ] || blockers+=(sudo_policy_not_ready)
[ "$AGENT99_99_DIRECT_ROUTE_READY" -eq 1 ] || blockers+=(agent99_direct_route_not_ready)
[ "$READINESS_NO_WRITE_READY" -eq 1 ] || blockers+=(readiness_no_write_not_ready)
[ "$TIMER_ENABLED" = "enabled" ] || blockers+=(timer_not_enabled)
if [ "${#blockers[@]}" -gt 0 ]; then
STATIC_POST_GATE_BLOCKERS="$(IFS=,; printf '%s' "${blockers[*]}")"
fi
if [ "$TARGET_HASHES_MATCH" -eq 1 ] \
&& [ "$UNIT_STATIC_VERIFY_READY" -eq 1 ] \
&& [ "$TARGET_FILES_READY" -eq 1 ] \
@@ -552,6 +566,14 @@ post_install_static_gate() {
fi
echo "TARGET_HASHES_MATCH=$TARGET_HASHES_MATCH"
echo "UNIT_STATIC_VERIFY_READY=$UNIT_STATIC_VERIFY_READY"
echo "TARGET_FILES_READY=$TARGET_FILES_READY"
echo "UNIT_CONTRACT_READY=$UNIT_CONTRACT_READY"
echo "SUDO_POLICY_READY=$SUDO_POLICY_READY"
echo "AGENT99_99_DIRECT_ROUTE_READY=$AGENT99_99_DIRECT_ROUTE_READY"
echo "READINESS_NO_WRITE_READY=$READINESS_NO_WRITE_READY"
echo "READINESS_CHECK_EXIT=$READINESS_CHECK_EXIT"
echo "TIMER_ENABLED=$TIMER_ENABLED"
echo "STATIC_POST_GATE_BLOCKERS=$STATIC_POST_GATE_BLOCKERS"
echo "STATIC_POST_GATE_READY=$STATIC_POST_GATE_READY"
[ "$STATIC_POST_GATE_READY" -eq 1 ]
}

View File

@@ -134,6 +134,30 @@ def test_install_receipt_does_not_claim_a_recovery_run() -> None:
assert 'agent99_99_direct_runtime_probe=not_started' in receipt
assert 'rollback_attempted=$rollback_attempted' in receipt
assert 'rollback_verified=$rollback_verified' in receipt
assert 'static_post_gate_blockers=${STATIC_POST_GATE_BLOCKERS:-not_evaluated}' in receipt
def test_static_post_gate_reports_named_blockers_before_rollback() -> None:
text = source()
gate = text[
text.index("post_install_static_gate() {") : text.index(
"wait_for_recovery_service_idle() {"
)
]
for blocker in (
"target_hashes_mismatch",
"unit_static_verify_failed",
"target_files_not_ready",
"unit_contract_not_ready",
"sudo_policy_not_ready",
"agent99_direct_route_not_ready",
"readiness_no_write_not_ready",
"timer_not_enabled",
):
assert blocker in gate
assert 'STATIC_POST_GATE_BLOCKERS=' in gate
assert 'READINESS_CHECK_EXIT=' in gate
def test_check_gate_requires_policy_route_timer_and_no_write_readback() -> None: