fix(windows99): project scoped relink dry run
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
AWOOOI Harbor 110 Local Repair / workflow-shape (push) Successful in 1s
AWOOOI Harbor 110 Local Repair / harbor-110-local-repair (push) Successful in 43s

This commit is contained in:
ogt
2026-07-10 02:13:40 +08:00
parent e240573c34
commit f29bc594ea
2 changed files with 168 additions and 0 deletions

View File

@@ -35,6 +35,9 @@ _CANDIDATE_CONFIRMATION_VALIDATION_SCHEMA_VERSION = (
_CANDIDATE_CONFIRMATION_PACKET_SCHEMA_VERSION = (
"windows99_vmx_source_candidate_confirmation_packet_v1"
)
_SCOPED_RELINK_DRY_RUN_SCHEMA_VERSION = (
"windows99_vmx_source_scoped_relink_dry_run_v1"
)
_RECEIPT_FILE = "windows99-vmx-source-locator-receipt.snapshot.json"
_COLLECTOR_SCRIPT_PATH = "scripts/reboot-recovery/locate-windows99-vmx-source.sh"
_LOCATOR_SCRIPT_PATH = "scripts/reboot-recovery/windows99-vmx-source-locator.ps1"
@@ -289,6 +292,104 @@ def _build_candidate_confirmation_gate(
}
def _build_projected_scoped_relink_dry_run_plan(
*,
accepted: bool,
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
evidence_ref = (
str(packet.get("candidate_identity_evidence_ref") or "").strip()
if accepted
else ""
)
candidate_identity_kind = (
str(packet.get("candidate_identity_kind") or "").strip() if accepted else ""
)
ready = bool(accepted)
existing_plan = _dict(locator.get("controlled_relink_dry_run_plan"))
return {
"schema_version": _SCOPED_RELINK_DRY_RUN_SCHEMA_VERSION,
"plan_id": (
"windows99-vmx-source-relink-dry-run-"
f"{','.join(missing_aliases) or 'none'}"
),
"status": (
"ready_for_no_write_review"
if ready
else "blocked_candidate_confirmation_not_accepted"
),
"ready": ready,
"mode": "dry_run_no_windows_or_vm_write",
"target_selector": {
"host_alias": "99",
"vm_aliases": target_aliases,
"missing_vmx_aliases": missing_aliases,
"candidate_identity_kind": candidate_identity_kind,
"secret_collection_allowed": False,
"vm_power_change_allowed": False,
"runtime_write_allowed": False,
},
"source_diff": {
"expected_vmx_path_count": locator.get("expected_vmx_path_count"),
"expected_vmx_path_present_count": locator.get(
"expected_vmx_path_present_count"
),
"candidate_source_count": locator.get("candidate_source_count"),
"candidate_source_fingerprint_count": locator.get(
"candidate_source_fingerprint_count"
),
"alias_hint_candidate_count": locator.get("alias_hint_candidate_count"),
"identity_target_hint_count": locator.get("identity_target_hint_count"),
"identity_unassigned_ubuntu_candidate_count": locator.get(
"identity_unassigned_ubuntu_candidate_count"
),
"candidate_identity_evidence_ref": evidence_ref,
"raw_path_output": False,
"path_fingerprint_only": True,
"bounded_identity_metadata_only": True,
},
"pre_apply_backup_plan": {
"required": True,
"status": (
"review_required_before_apply"
if ready
else "blocked_candidate_confirmation_not_accepted"
),
"backup_ref_required": True,
"rollback_ref": "rollback://awoooi/windows99-vmx-source-relink-dry-run",
},
"rollback_ref": "rollback://awoooi/windows99-vmx-source-relink-dry-run",
"post_verifier": [
"bash scripts/reboot-recovery/collect-windows99-vmware-verify.sh --collect",
"GET /api/v1/agents/reboot-auto-recovery-slo-scorecard",
"GET /api/v1/agents/windows99-vmx-source-repair-package",
"GET /api/v1/agents/windows99-vmx-source-locator-readback",
],
"km_writeback_ref": (
str(existing_plan.get("km_writeback_ref") or "")
or "km://awoooi/reboot-slo/windows99-vmx-source-locator-111"
),
"playbook_trust_writeback_ref": (
str(existing_plan.get("playbook_trust_writeback_ref") or "")
or "playbook://awoooi/windows99-vmx-source-locator/windows99-vmx-source-locator-111"
),
"apply_allowed_by_this_plan": False,
"remote_write_performed": False,
"vm_power_change_performed": False,
"secret_value_read": False,
"request_payload_saved": False,
"safe_next_step": (
"review_scoped_relink_dry_run_then_run_post_verifier_no_vm_power_change"
if ready
else "submit_redacted_single_candidate_identity_evidence_without_raw_paths"
),
}
def validate_windows99_vmx_source_candidate_confirmation_packet(
packet: dict[str, Any],
*,
@@ -362,6 +463,13 @@ def validate_windows99_vmx_source_candidate_confirmation_packet(
if accepted
else "submit_redacted_single_candidate_identity_evidence_without_raw_paths"
)
projected_scoped_relink_dry_run_plan = (
_build_projected_scoped_relink_dry_run_plan(
accepted=accepted,
locator=locator,
packet=packet,
)
)
return {
"schema_version": _CANDIDATE_CONFIRMATION_VALIDATION_SCHEMA_VERSION,
@@ -398,6 +506,14 @@ def validate_windows99_vmx_source_candidate_confirmation_packet(
"secret_value_read": False,
"safe_next_step": next_safe_step,
},
"scoped_relink_dry_run_ready": accepted,
"pre_apply_backup_plan_ready": accepted,
"post_verifier_ready": accepted,
"km_writeback_ready": accepted,
"playbook_trust_writeback_ready": accepted,
"projected_scoped_relink_dry_run_plan": (
projected_scoped_relink_dry_run_plan
),
"operation_boundaries": {
"no_persist_validator": True,
"request_payload_saved": False,