@@ -404,6 +404,97 @@ jobs:
404404 exit "${code}"
405405 fi
406406
407+ - name : Windows runtime smoke test
408+ if : matrix.os == 'windows-latest'
409+ shell : pwsh
410+ run : |
411+ $ErrorActionPreference = "Stop"
412+ $binary = "src-tauri/target/release/lessai.exe"
413+ if (-not (Test-Path $binary)) {
414+ throw "[ERROR] Windows smoke binary not found: $binary"
415+ }
416+
417+ $stdoutLog = Join-Path $env:RUNNER_TEMP "lessai-win-smoke.stdout.log"
418+ $stderrLog = Join-Path $env:RUNNER_TEMP "lessai-win-smoke.stderr.log"
419+ Write-Host "[INFO] Smoke testing $binary"
420+
421+ $proc = Start-Process -FilePath $binary -PassThru -WindowStyle Hidden -RedirectStandardOutput $stdoutLog -RedirectStandardError $stderrLog
422+ Start-Sleep -Seconds 18
423+
424+ $exitCode = 124
425+ if ($proc.HasExited) {
426+ $exitCode = $proc.ExitCode
427+ } else {
428+ Stop-Process -Id $proc.Id -Force
429+ Wait-Process -Id $proc.Id -Timeout 5 -ErrorAction SilentlyContinue
430+ }
431+
432+ if (Test-Path $stdoutLog) { Get-Content $stdoutLog -Tail 200 }
433+ if (Test-Path $stderrLog) { Get-Content $stderrLog -Tail 200 }
434+
435+ $combined = ""
436+ if (Test-Path $stdoutLog) { $combined += (Get-Content $stdoutLog -Raw) }
437+ if (Test-Path $stderrLog) { $combined += "`n" + (Get-Content $stderrLog -Raw) }
438+
439+ if ($combined -match "(segmentation fault|core dumped|access violation|fatal error|panic)") {
440+ throw "[ERROR] Windows smoke test detected fatal runtime signature."
441+ }
442+
443+ if ($exitCode -ne 124 -and $exitCode -ne 0) {
444+ throw "[ERROR] Windows smoke test failed with exit code $exitCode."
445+ }
446+
447+ - name : macOS runtime smoke test
448+ if : matrix.os == 'macos-latest'
449+ shell : bash
450+ run : |
451+ set -euo pipefail
452+
453+ app_bin="$(find src-tauri/target/release/bundle/macos -type f -path '*.app/Contents/MacOS/*' | head -n 1 || true)"
454+ if [[ -z "${app_bin}" && -x src-tauri/target/release/lessai ]]; then
455+ app_bin="src-tauri/target/release/lessai"
456+ fi
457+ if [[ -z "${app_bin}" ]]; then
458+ echo "[ERROR] macOS smoke binary not found." >&2
459+ exit 1
460+ fi
461+
462+ echo "[INFO] Smoke testing ${app_bin}"
463+ export LESSAI_LINUX_GRAPHICS_MODE=auto
464+
465+ python3 - "$app_bin" <<'PY'
466+ import pathlib
467+ import re
468+ import signal
469+ import subprocess
470+ import sys
471+ import tempfile
472+ import time
473+
474+ binary = sys.argv[1]
475+ log_path = pathlib.Path(tempfile.gettempdir()) / "lessai-macos-smoke.log"
476+ with log_path.open("wb") as log_file:
477+ proc = subprocess.Popen([binary], stdout=log_file, stderr=subprocess.STDOUT)
478+ exit_code = 124
479+ try:
480+ proc.wait(timeout=18)
481+ exit_code = proc.returncode
482+ except subprocess.TimeoutExpired:
483+ proc.terminate()
484+ try:
485+ proc.wait(timeout=4)
486+ except subprocess.TimeoutExpired:
487+ proc.kill()
488+ proc.wait(timeout=4)
489+
490+ content = log_path.read_text("utf-8", errors="ignore")
491+ print(content[-8000:])
492+ if re.search(r"(segmentation fault|abort trap|core dumped|fatal error|panic)", content, re.IGNORECASE):
493+ raise SystemExit("[ERROR] macOS smoke test detected fatal runtime signature.")
494+ if exit_code not in (0, 124):
495+ raise SystemExit(f"[ERROR] macOS smoke test failed with exit code {exit_code}.")
496+ PY
497+
407498 - name : Re-sign patched Linux AppImage
408499 if : matrix.os == 'ubuntu-latest' && env.TAURI_SIGNING_PRIVATE_KEY != ''
409500 shell : bash
@@ -465,6 +556,8 @@ jobs:
465556 env :
466557 RELEASE_TAG : ${{ needs.preflight.outputs.release_tag }}
467558 RELEASE_VERSION : ${{ needs.preflight.outputs.release_version }}
559+ TAURI_SIGNING_PRIVATE_KEY : ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
560+ TAURI_SIGNING_PRIVATE_KEY_PASSWORD : ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
468561 permissions :
469562 contents : write
470563
@@ -486,6 +579,21 @@ jobs:
486579 path : artifacts
487580 pattern : bundles-*
488581
582+ - name : Setup pnpm
583+ uses : pnpm/action-setup@v4
584+ with :
585+ version : 10
586+ run_install : false
587+
588+ - name : Setup Node
589+ uses : actions/setup-node@v4
590+ with :
591+ node-version-file : .nvmrc
592+ cache : pnpm
593+
594+ - name : Install dependencies
595+ run : pnpm install --frozen-lockfile
596+
489597 - name : Prepare release assets
490598 shell : bash
491599 run : |
@@ -767,6 +875,16 @@ jobs:
767875 print(f"[INFO] system-packages entries: {len(packages)}")
768876 PY
769877
878+ if [[ -z "${TAURI_SIGNING_PRIVATE_KEY}" ]]; then
879+ echo "[ERROR] Missing TAURI_SIGNING_PRIVATE_KEY for system-packages manifest signing." >&2
880+ exit 1
881+ fi
882+ pnpm exec tauri signer sign release-assets/system-packages.json
883+ if [[ ! -f release-assets/system-packages.json.sig ]]; then
884+ echo "[ERROR] Missing generated signature: release-assets/system-packages.json.sig" >&2
885+ exit 1
886+ fi
887+
770888 (cd release-assets && sha256sum * > checksums.sha256)
771889
772890 echo "[INFO] Release assets:"
@@ -799,4 +917,5 @@ jobs:
799917 - 能导入并查看,不等于一定允许写回原文件。
800918 - 检测到结构歧义、锁定区变化或文本层定位不稳定时,会主动拒绝写回以保护原文。
801919 - 如遇写回阻断,可先导出为新文件继续处理。
920+ - 详细口径见:`docs/release-writeback-compatibility.md`
802921 generate_release_notes : true
0 commit comments