- EXE versions: prerequisite list with the built-in catalog, custom installers, download link checks and install file analysis; entries are added by the user (no automatic adding), one "추가" dialog with 기본 목록 / 직접 추가 tabs - offline prerequisite setup: single exe made from PrerequisiteSetup.exe (Windows task dialog, no prerequisites) plus every installer, hash checked before, while and after appending; optional WebView2 Runtime chosen in the save dialog; replaces an existing file only after the user agrees (CLI --replace) - desktop: progress popup with 생성위치 열기, save dialog fix for verbatim paths, EXE 서명 and 설치파일 생성 as version tabs, start screen 도구 › 서명하기 placeholder - CLAUDE.md: results are overwritten only with the user's consent - test kit and scripts for Windows Sandbox and Hyper-V checks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
10 KiB
10 KiB
선행 설치 오프라인 설치기
2026-11-12. EXE 버전의 선행 설치 탭에 오프라인용 설치기 생성을 추가했다. 선행 설치 목록의 설치 프로그램을 모두 담은 실행 파일 하나를 만들고, 그 파일을 대상 PC에서 실행하면 목록을 위에서부터 감지·설치하며 진행 과정을 HTML 화면으로 보여 준다. 제품 파일을 포함한 EXE 빌드, 서명, 대상 PC 설치 시험은 범위 밖이다.
사용
- 설치 구성에서 버전을 열고 선행 설치 탭에서 오프라인용 설치기 생성을 누른다. 버전을 읽기만 하므로 잠긴 버전에서도 된다.
- 저장 위치를 고른다. 기본 이름은
<제품>-<버전>-Prerequisites.exe이고 같은 이름의 파일이 있으면 만들지 않는다. - 팝업 창이 열려 전체 진행(설치 프로그램 확인 → 설치기에 넣기 → 다시 읽어 확인)과 항목마다의 단계를 보여 준다. 실행 중에는 취소 요청만 누를 수 있다.
- 끝나면 같은 팝업에 경로, 크기, SHA-256, 항목별 출처(지정한 파일·제작기 기본 제공 파일·이번에 다운로드)와
설치 시험: notRun, 또는 실패·취소 이유가 표시되고 닫기로 닫는다(2026-11-13, 처음의 탭 아래 패널을 사용자 요청으로 팝업으로 바꿈). - 대상 PC에서 실행하면 관리자 권한을 요청하고, 항목별 상태(설치 필요·이미 설치됨·해당 없음)를 보여 준 뒤 설치로 차례로 설치한다.
CLI: cargo run -p package-builder -- offline-setup --project <.isproj> --version <버전> --output <새 .exe>.
결정
- 사용자 결정(2026-11-12): 설치기 UI는 Rust + Tauri(WebView2)의 HTML 화면으로 만들고 WebView2 Runtime은 대상 PC에 있다고 가정한다. 없으면 설치기가
MissingWebView2안내를 띄우고 종료하며 WebView2를 대신 설치하지 않는다. - 결과물은 단일 파일 설치 결정(4GB 미만)을 따른다. 설치기 원본
PrerequisiteSetup.exe뒤에 설치 프로그램을 붙이는 형식이며, 폴더나 여러 파일로 나누지 않는다. - 오프라인용이므로
download방식 항목도 설치기 안에 넣는다. 설치 프로그램은 지정한 파일 → 제작기의SetupPrerequisites→ 다운로드 주소 순으로 찾는다.bundled항목의 파일이 없을 때 다운로드로 대신하지 않는다. - 실행 중인 설치 프로그램은 중단하지 않는다(절반 설치 방지). 중단 요청은 다음 항목 전에 적용하고, 실패한 항목 뒤의 항목은 설치하지 않는다. 재부팅은 안내만 한다.
- 대상 PC의 감지는 레지스트리 값만 읽는다. 파일 버전 감지(
fileVersion)는 설치기를 만들 때UnsupportedPrerequisiteDetection으로 거부한다. - 설치기의 종료 코드는 Windows Installer 관례를 따른다: 0 성공(설치할 항목 없음 포함), 3010 재시작 필요, 1603 실패·시작 불가, 1602 사용자 취소·중단.
모델과 실행
- 형식(
package-domain::setup_bundle):[설치기 원본][설치 프로그램 1..n][manifest JSON][0 채움][꼬리 32바이트]. 꼬리는 원본 끝(설치 프로그램 시작), manifest 위치, manifest 길이(각u64LE)와ISPRQ001이다. 파일은 8바이트 경계로 끝나며, 서명된 파일은 PE 보안 디렉터리의 인증서 표 앞까지 읽는다. manifest는{format: 1, product: {name, version, manufacturer}, items: [{id, name, architecture, fileName, arguments, detect, rebootCodes, sha256, bytes, offset}]}이고 알 수 없는 필드를 거부한다. 항목은 원본 바로 뒤부터 빈틈없이 이어져 manifest 앞에서 끝나야 한다(DamagedSetup). - 만들기(
package-infra::build_offline_setup): 입력 검사(NoPrerequisites,InvalidPrerequisites,UnsupportedPrerequisiteDetection) → 출력 검사(InvalidSetupOutput,OutputExists,MissingOutputFolder) → 원본 검사(MissingSetupStub,InvalidSetupStub: MZ가 아님·서명됨·이미 목록 있음) → 4GB 검사(SetupTooLarge) → 설치 프로그램 확보와 SHA-256·크기 확인(MissingPrerequisiteFile,PrerequisiteChanged,DownloadFailed,DownloadMismatch) → 출력 폴더의 임시 파일에 원본·설치 프로그램을 스트림 해시하며 쓰기(InputChanged) → manifest·꼬리 → 같은 리더로 다시 읽어 manifest와 원본·항목 해시 확인(ArtifactMismatch) →persist_noclobber. 다운로드는 시스템 임시 폴더에 받고 끝나면 지운다. 진행은OfflineSetupProgress {stage, index, name, done, total}(바이트 수는 10진 문자열)로 알린다. - 다운로드(
download_installer):check_download_link와 같은 WinHTTP 요청을 함수로 나눠 본문까지 받는다. HTTPS 이외로 이동하면 거부하고,Content-Length가 기록과 다르거나 받은 크기가 넘치면 즉시 멈추며, 실패·취소 시 받던 파일을 지운다. 기존 파일은 덮어쓰지 않는다. - 설치기(
apps/prerequisite-setup, 실행 파일PrerequisiteSetup.exe): 매니페스트requireAdministrator,withGlobalTauri, 명령setup_overview·start_install·cancel_install·finish_setup, 이벤트setup-item·setup-finished·setup-close-blocked. 시작할 때 WebView2(HKLM32비트 보기 또는HKCU의EdgeUpdate\Clients\{F3017226-…}pv) → 자기 파일의 목록 → Windows 아키텍처(IsWow64Process2)를 확인하고 실패하면 메시지 상자 후 1603으로 끝낸다. 작업 폴더(%TEMP%\PrerequisiteSetup-*)에 항목마다<번호>\<파일 이름>으로 꺼내고, 공유 읽기만 허용한 핸들로 SHA-256을 다시 확인해 실행이 끝날 때까지 쓰기·삭제를 막는다..exe는 직접,.msi는System32\msiexec.exe /i,.msu는System32\wusa.exe로 실행하며 실행 인수는 셸 없이 그대로 넘긴다. WebView2 데이터도 작업 폴더에 두고 종료할 때 지운다. 로그는%TEMP%\PrerequisiteSetup-<UNIX 초>.log. - 데스크톱: Tauri 명령
build_offline_setup(version)(저장 대화상자 →session.busy→ 진행 이벤트offline-setup-progress, 단계·항목·퍼센트가 바뀔 때만 보냄), 취소는 기존cancel_build. 화면 모듈offline-setup.ts(팝업renderOfflineSetupDialog, 전체 진행offlineOverall). - 빌드:
apps/prerequisite-setup은 컴파일할 때ui/dist를 넣으므로npm.cmd run build(새build:setup포함)가 cargo보다 먼저다.Check.ps1과check스킬의 순서를 fmt → 프런트엔드 → test → clippy → 실행 파일 빌드로 바꿨다. 관리자 권한 프로그램이라 테스트 빌드를 만들지 않는다(test = false).Publish-Desktop.ps1은PrerequisiteSetup.exe를InstallerStudio.exe옆에 복사한다. 제작기는 원본을 실행 파일 옆에서만 찾는다(다른 폴더로 대신 찾지 않음). 개발 빌드는 제작기와 같은--target-dir에 있어야 하므로 VS Code 빌드 작업(target/vscode)도prerequisite-setup을 함께 빌드한다(2026-11-13, VS Code에서 띄운 제작기가MissingSetupStub을 낸 문제 수정).
확인 결과
scripts/Check.ps1전체 통과(fmt → npm ci·test·build → cargo test → clippy → 두 실행 파일 빌드). Rust 테스트 122개 통과, 6개 무시. 새 테스트는 도메인 8개(꼬리 왕복·손상 거부, 8바이트 채움, 인증서 표 위치, 항목 배치 검사, 파일 이름, 아키텍처 적용, 버전 비교, 종료 코드 판정), 인프라 단위 8개(추출·잠금·변조·손상·취소, 설치 프로그램 실행 방식, 감지 입력 거부, 다운로드 주소 거부와 기존 파일 보존, 기본 파일 이름), 통합 6개(지정 파일+기본 제공 파일로 만들고 다시 읽어 추출, 기존 출력 보존, 변경·누락 파일, 거부되는 목록, 원본 검사, 취소 시 잔여물 없음).- 무시 테스트 직접 실행: 레지스트리 읽기(이 PC의
CurrentBuild·DWORD·없는 키/값, 쓰기 없음), 기본 목록에서 가장 작은 설치 프로그램 실제 다운로드와 해시 일치·틀린 해시 거부, 다운로드 항목을 받아 설치기에 넣기. 모두 통과. - 프런트엔드 테스트 154개 통과(설치기 화면 8개, 오프라인 설치기 팝업 8개 포함). 팝업은 브라우저에서 앱 스타일로 진행·완료·실패 상태를 렌더링해 확인했다(실제 Tauri 창에서 버튼으로 연 시험은 아님). 데스크톱과 설치기 화면의
tsc·Vite 빌드 통과. - 실제 프로젝트로 생성:
D:\egbim-setup\egbimExe.isproj1.0.0(6개 항목, 모두 기본 제공 파일)을 CLI로 임시 폴더에 만들었다. 243,683,008바이트, SHA-25622a9a63e5c8a3d82efb24af843785c98d45bec1683763df9e69971c61e8535a6, 약 23초. 프로젝트와 버전 파일의 해시는 생성 전후로 같았다. 시험 파일은 지웠다. - 관리자 권한 요구: 원본과 만든 설치기 모두 일반 권한 셸에서 시작하면 "requires elevation"으로 거부되어 매니페스트와 PE가 유효함을 확인했다. 서명 상태는
NotSigned. - 설치기 화면: 브라우저에서 Tauri 연결을 흉내 내 대기·진행·재시작 필요·실패 상태를 렌더링해 확인했고, 목록이 창 안에서 스크롤되도록 고쳤다. 실제 WebView2 창은 띄우지 않았다.
- 실행하지 않음: 만든 설치기를 관리자 권한으로 실행(실제 설치), 대상 PC·VM 설치 시험, WebView2가 없는 PC, Arm64·x86 Windows, 데스크톱 앱에서 버튼을 눌러 보는 GUI 시험, 배포본(
Publish-Desktop.ps1)으로 만든 설치기, 서명한 설치기 읽기.
증빙: 시험 결과 JSON
근거
- Microsoft Learn: Distribute your app and the WebView2 Runtime
- Microsoft Learn: Standard installer command-line options (msiexec)
- Microsoft Learn: MsiExec.exe and InstMsi.exe error messages (1602, 1603, 3010)
- Microsoft Learn: PE format — the attribute certificate table
- Microsoft Learn: IsWow64Process2