fix(windows99): accept scoped vmx alias confirmations
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 1m14s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled

This commit is contained in:
ogt
2026-07-10 02:35:44 +08:00
parent 7a9fcd28db
commit 4990118c32
2 changed files with 92 additions and 3 deletions

View File

@@ -298,8 +298,16 @@ def _build_projected_scoped_relink_dry_run_plan(
locator: dict[str, Any],
packet: dict[str, Any],
) -> dict[str, Any]:
target_aliases = _strings(locator.get("target_vm_aliases"))
missing_aliases = _strings(locator.get("missing_vmx_aliases")) or target_aliases
submitted_aliases = _strings(packet.get("target_vm_aliases"))
locator_target_aliases = _strings(locator.get("target_vm_aliases"))
target_aliases = (
submitted_aliases if accepted and submitted_aliases else locator_target_aliases
)
missing_aliases = (
submitted_aliases
if accepted and submitted_aliases
else _strings(locator.get("missing_vmx_aliases")) or target_aliases
)
evidence_ref = (
str(packet.get("candidate_identity_evidence_ref") or "").strip()
if accepted
@@ -403,7 +411,14 @@ def validate_windows99_vmx_source_candidate_confirmation_packet(
"""
locator = locator_readback or load_latest_windows99_vmx_source_locator_readback()
current_target_aliases = _strings(locator.get("target_vm_aliases"))
current_missing_aliases = _strings(locator.get("missing_vmx_aliases"))
submitted_aliases = _strings(packet.get("target_vm_aliases"))
allowed_target_aliases = current_missing_aliases or current_target_aliases
submitted_aliases_valid = bool(
submitted_aliases
and allowed_target_aliases
and set(submitted_aliases).issubset(set(allowed_target_aliases))
)
missing_fields = [
field
for field in _CANDIDATE_CONFIRMATION_REQUIRED_FIELDS
@@ -416,7 +431,7 @@ def validate_windows99_vmx_source_candidate_confirmation_packet(
rejected_fields.append("schema_version")
if str(packet.get("target_host_alias") or "") != "99":
rejected_fields.append("target_host_alias")
if not submitted_aliases or submitted_aliases != current_target_aliases:
if not submitted_aliases_valid:
rejected_fields.append("target_vm_aliases")
if str(packet.get("candidate_identity_kind") or "") not in (
_CANDIDATE_CONFIRMATION_ALLOWED_KINDS
@@ -477,6 +492,9 @@ def validate_windows99_vmx_source_candidate_confirmation_packet(
"accepted": accepted,
"target_host_alias": "99",
"target_vm_aliases": current_target_aliases,
"missing_vmx_aliases": current_missing_aliases,
"submitted_target_vm_aliases": submitted_aliases,
"validated_target_vm_aliases": submitted_aliases if accepted else [],
"current_locator_status": str(locator.get("status") or ""),
"current_candidate_confirmation_status": str(
locator.get("candidate_confirmation_status") or ""

View File

@@ -313,6 +313,77 @@ def test_windows99_candidate_confirmation_validator_accepts_redacted_packet() ->
assert payload["operation_boundaries"]["vm_power_change_performed"] is False
def test_windows99_candidate_confirmation_accepts_scoped_missing_alias_subset() -> None:
repair_package = build_windows99_vmx_source_repair_package(
_scorecard(),
generated_at="2026-07-03T11:21:00+08:00",
)
locator = build_windows99_vmx_source_locator_readback(
_scorecard(),
repair_package=repair_package,
collector_receipt={
"schema_version": "windows99_vmx_source_locator_receipt_v1",
"collector_readback_present": True,
"target_host_alias": "99",
"target_vm_aliases": ["111"],
"expected_vmx_path_present_count": 0,
"candidate_source_count": 8,
"candidate_source_fingerprint_count": 0,
"alias_hint_candidate_count": 0,
"identity_metadata_read": True,
"bounded_identity_metadata_only": True,
"identity_target_hint_count": 0,
"identity_unassigned_ubuntu_candidate_count": 1,
"locate_status": (
"single_identity_unassigned_ubuntu_candidate_requires_confirmation"
),
},
)
locator["target_vm_aliases"] = ["111", "112", "120", "121", "188"]
locator["missing_vmx_aliases"] = ["111", "112", "120", "121", "188"]
payload = validate_windows99_vmx_source_candidate_confirmation_packet(
{
"schema_version": "windows99_vmx_source_candidate_confirmation_packet_v1",
"target_host_alias": "99",
"target_vm_aliases": ["111"],
"candidate_identity_kind": "verified_backup_path_fingerprint",
"candidate_identity_evidence_ref": (
"backup://awoooi/windows99/redacted-fingerprint-111"
),
"candidate_match_count": 1,
"redacted_metadata_only": True,
"bounded_identity_metadata_only": True,
"path_fingerprint_only": True,
"raw_path_output": False,
"secret_value_read": False,
"remote_write_performed": False,
"host_reboot_performed": False,
"vm_power_change_performed": False,
"windows_registry_apply_performed": False,
"scheduled_task_write_performed": False,
"apply_requested": False,
"vm_power_change_requested": False,
},
locator_readback=locator,
)
assert payload["accepted"] is True
assert payload["target_vm_aliases"] == ["111", "112", "120", "121", "188"]
assert payload["missing_vmx_aliases"] == ["111", "112", "120", "121", "188"]
assert payload["submitted_target_vm_aliases"] == ["111"]
assert payload["validated_target_vm_aliases"] == ["111"]
assert payload["rejected_fields"] == []
plan = payload["projected_scoped_relink_dry_run_plan"]
assert plan["ready"] is True
assert plan["plan_id"] == "windows99-vmx-source-relink-dry-run-111"
assert plan["target_selector"]["vm_aliases"] == ["111"]
assert plan["target_selector"]["missing_vmx_aliases"] == ["111"]
assert plan["apply_allowed_by_this_plan"] is False
assert plan["remote_write_performed"] is False
assert plan["vm_power_change_performed"] is False
def test_windows99_candidate_confirmation_validator_rejects_sensitive_payload() -> None:
locator = build_windows99_vmx_source_locator_readback(
_scorecard(),