-
Notifications
You must be signed in to change notification settings - Fork 0
fix(phase4): finish Mac and Windows acceptance #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,11 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # Preserve exact artifact checks while making silent `[[ ... ]]` failures | ||
| # diagnosable from the job log. Without this, a failed launch/version/state | ||
| # assertion surfaces only as "exit code 1" after minutes of signature output. | ||
| trap 'status=$?; echo "::error::macOS acceptance failed at line ${LINENO} (exit ${status}): ${BASH_COMMAND}" >&2' ERR | ||
|
|
||
| ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" | ||
| DOWNLOAD="${HELM_MAC_CANDIDATE_DOWNLOAD:?exact Mac candidate directory is required}" | ||
| OUTPUT="${HELM_ACCEPTANCE_OUTPUT:?acceptance output is required}" | ||
|
|
@@ -27,6 +32,22 @@ node "$ROOT/scripts/pending-acceptance-evidence.mjs" | |
| artifact_field() { | ||
| node -p 'const m=JSON.parse(require("fs").readFileSync(process.argv[1])); const a=m.artifacts.find(x=>x.role===process.argv[2]); if(!a)process.exit(2); a[process.argv[3]]' "$MANIFEST" "$1" "$2" | ||
| } | ||
| wait_for_setup_health() { | ||
| local output="$1" port | ||
| for _ in {1..180}; do | ||
| while IFS= read -r port; do | ||
| [[ "$port" =~ ^[0-9]+$ ]] || continue | ||
| if curl -fsS "http://127.0.0.1:$port/api/setup/status" >"$output.tmp"; then | ||
| mv "$output.tmp" "$output" | ||
| return 0 | ||
| fi | ||
| rm -f -- "$output.tmp" | ||
| done < <(lsof -nP -a -u "$(id -un)" -c 1Helm -iTCP -sTCP:LISTEN 2>/dev/null \ | ||
| | awk '/127\.0\.0\.1:/ {split($9,a,":"); print a[length(a)]}' || true) | ||
| sleep 1 | ||
| done | ||
| return 1 | ||
| } | ||
| DMG_SHA="$(artifact_field mac_dmg sha256)"; ZIP_SHA="$(artifact_field mac_updater_zip sha256)" | ||
| [[ "$(shasum -a 256 "$DMG" | awk '{print $1}')" == "$DMG_SHA" ]] | ||
| [[ "$(shasum -a 256 "$ZIP" | awk '{print $1}')" == "$ZIP_SHA" ]] | ||
|
|
@@ -68,12 +89,7 @@ spctl --assess --type execute --verbose=4 "$work/update/1Helm.app" | |
| mkdir -p "$DATA_ROOT" | ||
| printf '%s\n' server >"$DATA_ROOT/desktop-mode" | ||
| open -n "$installed" --args --1helm-background | ||
| for _ in {1..180}; do | ||
| PORT="$(lsof -nP -a -u "$(id -un)" -c 1Helm -iTCP -sTCP:LISTEN 2>/dev/null | awk '/127\.0\.0\.1:/ {split($9,a,":"); print a[length(a)]; exit}')" | ||
| [[ "$PORT" =~ ^[0-9]+$ ]] && curl -fsS "http://127.0.0.1:$PORT/api/setup/status" >"$work/clean-health.json" && break | ||
| sleep 1 | ||
| done | ||
| [[ -s "$work/clean-health.json" ]] | ||
| wait_for_setup_health "$work/clean-health.json" | ||
| osascript -e 'tell application id "com.gitcommit90.1helm" to quit' || true | ||
| for _ in {1..30}; do pgrep -x -U "$(id -u)" 1Helm >/dev/null || break; sleep 1; done | ||
| ! pgrep -x -U "$(id -u)" 1Helm >/dev/null | ||
|
|
@@ -122,25 +138,15 @@ printf '%s\n' server >"$DATA_ROOT/desktop-mode" | |
| printf '%s\n' "phase4-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT" >"$DATA_ROOT/phase4-acceptance-state" | ||
| STATE_BEFORE="$(shasum -a 256 "$DATA_ROOT/phase4-acceptance-state" | awk '{print $1}')" | ||
| open -n "$installed" --args --1helm-background | ||
| for _ in {1..180}; do | ||
| PORT="$(lsof -nP -a -u "$(id -un)" -c 1Helm -iTCP -sTCP:LISTEN 2>/dev/null | awk '/127\.0\.0\.1:/ {split($9,a,":"); print a[length(a)]; exit}')" | ||
| [[ "$PORT" =~ ^[0-9]+$ ]] && curl -fsS "http://127.0.0.1:$PORT/api/setup/status" >"$work/prior-health.json" && break | ||
| sleep 1 | ||
| done | ||
| [[ -s "$work/prior-health.json" ]] | ||
| wait_for_setup_health "$work/prior-health.json" | ||
| osascript -e 'tell application id "com.gitcommit90.1helm" to quit' || true | ||
| for _ in {1..30}; do pgrep -x -U "$(id -u)" 1Helm >/dev/null || break; sleep 1; done | ||
| ! pgrep -x -U "$(id -u)" 1Helm >/dev/null | ||
| rm -rf -- "$installed" | ||
| ditto "$work/update/1Helm.app" "$installed" | ||
| [[ "$(defaults read "$installed/Contents/Info" CFBundleShortVersionString)" == "$VERSION" ]] | ||
| open -n "$installed" --args --1helm-background | ||
| for _ in {1..180}; do | ||
| PORT="$(lsof -nP -a -u "$(id -un)" -c 1Helm -iTCP -sTCP:LISTEN 2>/dev/null | awk '/127\.0\.0\.1:/ {split($9,a,":"); print a[length(a)]; exit}')" | ||
| [[ "$PORT" =~ ^[0-9]+$ ]] && curl -fsS "http://127.0.0.1:$PORT/api/setup/status" >"$work/update-health.json" && break | ||
| sleep 1 | ||
| done | ||
| [[ -s "$work/update-health.json" ]] | ||
| wait_for_setup_health "$work/update-health.json" | ||
|
Comment on lines
+141
to
+149
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- script header and relevant section ---'
sed -n '1,35p;125,160p' ops/platform-acceptance/macos.sh
printf '%s\n' '--- shell options and related process checks ---'
rg -n 'set -|errexit|pgrep|wait_for_setup_health|1Helm' ops/platform-acceptance/macos.sh
printf '%s\n' '--- shellcheck availability and targeted diagnostic ---'
if command -v shellcheck >/dev/null 2>&1; then
shellcheck --version
shellcheck --shell=bash --enable=all ops/platform-acceptance/macos.sh 2>&1 | sed -n '1,120p'
else
echo 'shellcheck: unavailable'
fiRepository: gitcommit90/1Helm Length of output: 13139 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- wait_for_setup_health implementation ---'
sed -n '35,60p' ops/platform-acceptance/macos.sh
printf '%s\n' '--- standalone errexit probe ---'
bash -c '
set -euo pipefail
trap '\''status=$?; printf "ERR trap: status=%s command=%s\n" "$status" "$BASH_COMMAND" >&2'\'' ERR
pgrep() { return 0; }
printf "before\n"
! pgrep -x -U "$(id -u)" 1Helm >/dev/null
printf "after negated check: status=%s\n" "$?"
printf "replacement would run\n"
'Repository: gitcommit90/1Helm Length of output: 1277 Fail when the When 🧰 Tools🪛 Shellcheck (0.11.0)[info] 144-144: This ! is not on a condition and skips errexit. Use (SC2251) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
| STATE_AFTER="$(shasum -a 256 "$DATA_ROOT/phase4-acceptance-state" | awk '{print $1}')" | ||
| [[ "$STATE_BEFORE" == "$STATE_AFTER" ]] | ||
| osascript -e 'tell application id "com.gitcommit90.1helm" to quit' || true | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # The per-site operator public key is never committed to this public repository. | ||
| authorized_key.pub |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <unattend xmlns="urn:schemas-microsoft-com:unattend" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"> | ||
| <settings pass="windowsPE"> | ||
| <component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> | ||
| <SetupUILanguage><UILanguage>en-US</UILanguage></SetupUILanguage> | ||
| <InputLocale>en-US</InputLocale><SystemLocale>en-US</SystemLocale><UILanguage>en-US</UILanguage><UserLocale>en-US</UserLocale> | ||
| </component> | ||
| <component name="Microsoft-Windows-PnpCustomizationsWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> | ||
| <DriverPaths> | ||
| <PathAndCredentials wcm:action="add" wcm:keyValue="1"><Path>E:\vioscsi\w11\amd64</Path></PathAndCredentials> | ||
| <PathAndCredentials wcm:action="add" wcm:keyValue="2"><Path>E:\NetKVM\w11\amd64</Path></PathAndCredentials> | ||
| </DriverPaths> | ||
| </component> | ||
| <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> | ||
| <DiskConfiguration> | ||
| <Disk wcm:action="add"><DiskID>0</DiskID><WillWipeDisk>true</WillWipeDisk> | ||
| <CreatePartitions> | ||
| <CreatePartition wcm:action="add"><Order>1</Order><Type>EFI</Type><Size>260</Size></CreatePartition> | ||
| <CreatePartition wcm:action="add"><Order>2</Order><Type>MSR</Type><Size>16</Size></CreatePartition> | ||
| <CreatePartition wcm:action="add"><Order>3</Order><Type>Primary</Type><Extend>true</Extend></CreatePartition> | ||
| </CreatePartitions> | ||
| <ModifyPartitions> | ||
| <ModifyPartition wcm:action="add"><Order>1</Order><PartitionID>1</PartitionID><Format>FAT32</Format><Label>System</Label></ModifyPartition> | ||
| <ModifyPartition wcm:action="add"><Order>2</Order><PartitionID>3</PartitionID><Format>NTFS</Format><Label>Windows</Label></ModifyPartition> | ||
| </ModifyPartitions> | ||
| </Disk> | ||
| </DiskConfiguration> | ||
| <ImageInstall><OSImage><InstallFrom><MetaData wcm:action="add"><Key>/IMAGE/INDEX</Key><Value>6</Value></MetaData></InstallFrom><InstallTo><DiskID>0</DiskID><PartitionID>3</PartitionID></InstallTo></OSImage></ImageInstall> | ||
| <UserData><AcceptEula>true</AcceptEula><FullName>1Helm</FullName><Organization>1Helm acceptance</Organization></UserData> | ||
| <DynamicUpdate><Enable>false</Enable><WillShowUI>OnError</WillShowUI></DynamicUpdate> | ||
| </component> | ||
| </settings> | ||
| <settings pass="specialize"> | ||
| <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> | ||
| <ComputerName>ONEHELM-WIN</ComputerName><TimeZone>UTC</TimeZone><RegisteredOwner>1Helm</RegisteredOwner><RegisteredOrganization>1Helm acceptance</RegisteredOrganization> | ||
| </component> | ||
| </settings> | ||
| <settings pass="oobeSystem"> | ||
| <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> | ||
| <Reseal><Mode>Audit</Mode></Reseal> | ||
| </component> | ||
| </settings> | ||
| <settings pass="auditUser"> | ||
| <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> | ||
| <RunSynchronous> | ||
| <RunSynchronousCommand wcm:action="add"><Order>1</Order><Description>Provision retained 1Helm acceptance host</Description><Path>powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "$v=(Get-Volume -FileSystemLabel ONEHELM); & ($v.DriveLetter + ':\setup.ps1')"</Path><WillReboot>Never</WillReboot></RunSynchronousCommand> | ||
| </RunSynchronous> | ||
| </component> | ||
| </settings> | ||
| </unattend> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| # Retained Windows acceptance-host provisioning | ||
|
|
||
| These files build the bootstrap ISO for the dedicated Windows 11 Phase 4 | ||
| acceptance host described in `docs/phase4-platform-acceptance.md`. They were | ||
| previously carried only as a pre-built ISO on the hypervisor, so a rebuild could | ||
| not be reviewed or reproduced. They are tracked here for that reason. | ||
|
|
||
| Nothing here publishes a release, creates a tag, deploys the website, or touches | ||
| production data or services. | ||
|
|
||
| ## What it does | ||
|
|
||
| `Autounattend.xml` partitions the disk (GPT, EFI + MSR + NTFS), installs the Pro | ||
| image, sets the computer name and UTC timezone, then reseals into **audit mode** | ||
| and runs `setup.ps1` during the `auditUser` pass. | ||
|
|
||
| `setup.ps1` installs the VirtIO network and serial drivers plus the QEMU guest | ||
| agent, enables OpenSSH Server pinned to the operator's public key (supplied at build | ||
| time, see below) with password authentication off, disables sleep and hibernate, and records | ||
| `C:\1HelmAcceptance\ready.json`. It is idempotent: an existing `ready.json` | ||
| makes it exit 0 immediately. | ||
|
|
||
| ## Build | ||
|
|
||
| ```sh | ||
| ./build-unattend-iso.sh 1helm-windows-unattend.iso /path/to/operator_key.pub | ||
| ``` | ||
|
|
||
| The operator public key is **not** committed: this repository is public, and | ||
| publishing which key is authorized as Administrator on the acceptance host is | ||
| needless disclosure. Pass it at build time (or via | ||
| `HELM_ACCEPTANCE_AUTHORIZED_KEY`); the build stages it as `authorized_key.pub` | ||
| on the ISO and `setup.ps1` refuses to continue without it. `.gitignore` keeps a | ||
| local copy out of git. | ||
|
|
||
| Two constraints are load-bearing: | ||
|
|
||
| - `-iso-level 4` — at genisoimage's default level the ISO9660 namespace | ||
| truncates `Autounattend.xml` to `AUTOUNAT.XML`, which Windows Setup does not | ||
| recognize as an answer file. | ||
| - Volume label `ONEHELM` — the `auditUser` pass locates `setup.ps1` with | ||
| `Get-Volume -FileSystemLabel ONEHELM`. | ||
|
|
||
| ## Host VM shape | ||
|
|
||
| The acceptance workflow restores an accepted clean snapshot before every job, so | ||
| the VM must actually be able to snapshot. Proxmox always creates the **TPM state | ||
| volume as raw**, and a raw volume on directory storage blocks snapshots for the | ||
| whole VM even when every other disk is qcow2. Place the disks as qcow2 and put | ||
| the small `tpmstate0` volume on snapshot-capable storage (thin-LVM), which keeps | ||
| TPM 2.0 and Secure Boot intact so no Windows 11 requirement bypass is needed. | ||
|
|
||
| Verify before installing anything: | ||
|
|
||
| ```sh | ||
| qm snapshot <vmid> probe && qm delsnapshot <vmid> probe | ||
| ``` | ||
|
|
||
| ## Windows 11 25H2 answer-file caveat | ||
|
|
||
| On build 26200 (25H2) the new setup engine (`setuphost.exe`) does **not** | ||
| auto-apply `Autounattend.xml` from a secondary disc, and `setup.exe /unattend:` | ||
| is ignored. The answer file is readable from WinPE — it simply is not consumed, | ||
| so setup falls through to the interactive product-key page. | ||
|
|
||
| Working alternative on affected media: from the WinPE shell (Shift+F10), | ||
| partition with `diskpart`, apply the image with | ||
| `dism /apply-image /imagefile:<media>:\sources\install.wim /index:6 /applydir:W:\`, | ||
| copy `Autounattend.xml` to `W:\Windows\Panther\unattend.xml`, then | ||
| `bcdboot W:\Windows /s S: /f UEFI`. First boot still runs `specialize`, | ||
| `oobeSystem` and `auditUser`, so the computer name, audit reseal and | ||
| `setup.ps1` all still apply. | ||
|
|
||
| Note that WinPE on this media has no `curl`, no `taskkill`, and no configured | ||
| network, so stage anything you need on the bootstrap ISO itself. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| #!/usr/bin/env bash | ||
| # Build the retained Windows acceptance-host bootstrap ISO. | ||
| # | ||
| # Attach the result as a second CD-ROM alongside the Windows installation media | ||
| # on the dedicated Phase 4 acceptance VM. It carries the answer file and the | ||
| # first-boot bootstrap; it publishes nothing and contains no credentials beyond | ||
| # the operator's own SSH public key in setup.ps1. | ||
| set -euo pipefail | ||
|
|
||
| here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| out="${1:-1helm-windows-unattend.iso}" | ||
| key="${2:-${HELM_ACCEPTANCE_AUTHORIZED_KEY:-}}" | ||
|
|
||
| if [ -z "$key" ] || [ ! -f "$key" ]; then | ||
| echo "usage: build-unattend-iso.sh [out.iso] <path-to-authorized-key.pub>" >&2 | ||
| echo " or: HELM_ACCEPTANCE_AUTHORIZED_KEY=/path/to/key.pub build-unattend-iso.sh [out.iso]" >&2 | ||
| echo "The operator public key is deliberately not committed to this public repository." >&2 | ||
| exit 2 | ||
| fi | ||
|
|
||
| stage="$(mktemp -d)" | ||
| trap 'rm -rf "$stage"' EXIT | ||
|
|
||
| cp "$here/Autounattend.xml" "$here/setup.ps1" "$stage/" | ||
| printf 'Retained Windows acceptance bootstrap for 1Helm.\n' > "$stage/1helm-acceptance.txt" | ||
| install -m 0644 "$key" "$stage/authorized_key.pub" | ||
|
|
||
| # -iso-level 4 keeps long file names. At genisoimage's default level the | ||
| # ISO9660 namespace truncates Autounattend.xml to AUTOUNAT.XML, which Windows | ||
| # Setup does not recognize as an answer file. | ||
| # | ||
| # The volume label MUST remain ONEHELM: the auditUser pass in Autounattend.xml | ||
| # locates setup.ps1 via Get-Volume -FileSystemLabel ONEHELM. | ||
| genisoimage -quiet -iso-level 4 -J -r -V ONEHELM -o "$out" "$stage" | ||
|
|
||
| echo "wrote $out" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| $ErrorActionPreference = "Stop" | ||
| $root = "C:\1HelmAcceptance" | ||
| New-Item -ItemType Directory -Force -Path $root | Out-Null | ||
| $log = Join-Path $root "bootstrap.log" | ||
| Start-Transcript -Path $log -Append | ||
| try { | ||
| if (Test-Path (Join-Path $root "ready.json")) { exit 0 } | ||
|
|
||
| $virtio = Get-Volume | Where-Object { $_.DriveLetter -and (Test-Path ("{0}:\guest-agent\qemu-ga-x86_64.msi" -f $_.DriveLetter)) } | Select-Object -First 1 | ||
| if (-not $virtio) { throw "VirtIO 0.1.271 media was not found." } | ||
| $drive = "{0}:" -f $virtio.DriveLetter | ||
| & pnputil.exe /add-driver "$drive\NetKVM\w11\amd64\*.inf" /subdirs /install | ||
| if ($LASTEXITCODE -notin 0, 3010) { throw "NetKVM driver install failed: $LASTEXITCODE" } | ||
| # The QEMU guest agent reaches the host over a VirtIO serial port. Without | ||
| # this driver the QEMU-GA service still starts and reports Running, while the | ||
| # host side ("qm agent <vmid> ping") stays dead and there is no guest-exec | ||
| # channel to provision the host with. | ||
| & pnputil.exe /add-driver "$drive\vioserial\w11\amd64\*.inf" /subdirs /install | ||
| if ($LASTEXITCODE -notin 0, 3010) { throw "VirtIO serial driver install failed: $LASTEXITCODE" } | ||
| & msiexec.exe /i "$drive\guest-agent\qemu-ga-x86_64.msi" /qn /norestart | ||
| if ($LASTEXITCODE -notin 0, 3010) { throw "QEMU guest agent install failed: $LASTEXITCODE" } | ||
|
|
||
| $capability = Get-WindowsCapability -Online | Where-Object Name -Like "OpenSSH.Server*" | Select-Object -First 1 | ||
| if (-not $capability) { throw "Windows did not expose the OpenSSH Server capability." } | ||
| if ($capability.State -ne "Installed") { Add-WindowsCapability -Online -Name $capability.Name | Out-Null } | ||
|
|
||
| New-Item -ItemType Directory -Force -Path "C:\ProgramData\ssh" | Out-Null | ||
| # The authorized key is supplied per site on the bootstrap media rather than | ||
| # committed to this public repository. build-unattend-iso.sh stages it. | ||
| $keySource = Join-Path $PSScriptRoot "authorized_key.pub" | ||
| if (-not (Test-Path $keySource)) { throw "authorized_key.pub is missing from the bootstrap media; see ops/platform-acceptance/windows-host/README.md" } | ||
| $authorizedKey = (Get-Content -Raw $keySource).Trim() | ||
| if ($authorizedKey -notmatch '^(ssh-ed25519|ssh-rsa|ecdsa-sha2-nistp[0-9]+) ') { throw "authorized_key.pub is not an OpenSSH public key" } | ||
| Set-Content -Encoding ascii -Path "C:\ProgramData\ssh\administrators_authorized_keys" -Value $authorizedKey | ||
| & icacls.exe "C:\ProgramData\ssh\administrators_authorized_keys" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F" | Out-Null | ||
| $config = "C:\ProgramData\ssh\sshd_config" | ||
| if (Test-Path $config) { | ||
| $text = Get-Content -Raw $config | ||
| $text = [regex]::Replace($text, '(?m)^\s*#?\s*PasswordAuthentication\s+.*$', 'PasswordAuthentication no') | ||
| $text = [regex]::Replace($text, '(?m)^\s*#?\s*PubkeyAuthentication\s+.*$', 'PubkeyAuthentication yes') | ||
| Set-Content -Encoding ascii -Path $config -Value $text | ||
| } | ||
| Set-Service sshd -StartupType Automatic | ||
| Start-Service sshd | ||
| # Add-WindowsCapability already creates OpenSSH-Server-In-TCP, but scoped to | ||
| # the Private profile only. A freshly bridged VM is categorized Public, so a | ||
| # bare existence check short-circuits and leaves port 22 unreachable even | ||
| # though sshd reports Running. Ensure the rule exists AND covers every profile. | ||
| if (Get-NetFirewallRule -Name OpenSSH-Server-In-TCP -ErrorAction SilentlyContinue) { | ||
| Set-NetFirewallRule -Name OpenSSH-Server-In-TCP -Enabled True -Profile Any | ||
| } else { | ||
| New-NetFirewallRule -Name OpenSSH-Server-In-TCP -DisplayName "OpenSSH Server (sshd)" -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 -Profile Any | Out-Null | ||
| } | ||
| Set-Service QEMU-GA -StartupType Automatic | ||
| Start-Service QEMU-GA | ||
| powercfg.exe /change standby-timeout-ac 0 | Out-Null | ||
| powercfg.exe /change hibernate-timeout-ac 0 | Out-Null | ||
| $record = [ordered]@{ ready = $true; computer = $env:COMPUTERNAME; build = [Environment]::OSVersion.Version.ToString(); at = (Get-Date).ToUniversalTime().ToString("o") } | ||
| Set-Content -Encoding utf8 -Path (Join-Path $root "ready.json") -Value ($record | ConvertTo-Json -Compress) | ||
| } finally { | ||
| Stop-Transcript | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: gitcommit90/1Helm
Length of output: 12552
🏁 Script executed:
Repository: gitcommit90/1Helm
Length of output: 226
🏁 Script executed:
Repository: gitcommit90/1Helm
Length of output: 263
Bound each health probe and enforce the polling deadline.
Line 40 calls
curlwithout--connect-timeoutor--max-time. A listening but unresponsive process can block indefinitely and prevent the function from reaching its timeout. Use a finite per-port timeout and an absolute deadline.🤖 Prompt for AI Agents