# Installer Studio — 구현 시작 버전 기존 MSIX 우선 설계를 실행 가능한 Rust/Tauri 프로그램으로 옮긴 0.1 개발 버전이다. 모든 소스와 잠금 파일은 이 디렉터리에 있다. **미서명 또는 개발자 자체 서명 MSIX를 생성하며 일반 배포 준비 상태를 부여하지 않는다.** ## 실행 Windows, Rust 1.94.0/MSVC 빌드 도구, Node.js 22.12 이상, WebView2가 필요하다. 실제 패키징에는 Windows SDK의 MakeAppx.exe가 필요하다. SDK·인증서는 프로그램이 자동 설치하지 않는다. ```powershell cd D:\networkSetup\src\apps\desktop npm.cmd ci npm.cmd run tauri dev ``` 새 프로젝트를 만들거나 `.isproj` 파일을 연 뒤 앱 정보 → 파일 구성에서 소스 폴더 연결 → 패키지 설정 → 검증·빌드에서 SDK 도구 선택 → 입력 검사 → 빌드 계획 생성 → MSIX 빌드 순서로 사용한다. 포함/제외 규칙과 의존성은 프로젝트 JSON 편집에서 수정한다. 기본 프로젝트의 Publisher는 예시이며 자신의 패키지 identity에 맞게 바꿔야 한다. 시작 화면은 왼쪽 **최근 프로젝트 목록**, 오른쪽 **프로젝트 열기 / 새 프로젝트 만들기** 버튼으로 구성한다. 최근 목록은 이 버전의 GUI에서 열거나 만든 프로젝트를 최대 20개 보관하며 앱을 다시 실행해도 유지된다. 이름·경로 검색과 오늘/이번 주/이번 달/이전 그룹을 제공한다. 목록의 `×`는 기록만 제거하며 프로젝트 파일을 삭제하지 않는다. 이동·삭제된 파일은 위치 확인 안내를 표시한다. 편집 화면 상단의 **프로젝트 닫기**로 시작 화면에 돌아간다. 미저장 변경이 있으면 **저장 후 닫기 / 저장 안 함 / 취소**를 선택하며, 저장 오류가 발생하면 프로젝트와 편집 내용을 유지한다. 다른 프로젝트 열기·새로 만들기에도 같은 보호 절차를 적용한다. 빌드 중에는 프로젝트를 닫을 수 없다. 최근 목록은 Tauri의 앱 데이터 폴더(기본 Windows 경로 `%APPDATA%\dev.networksetup.msixstudio\recent-projects.json`)에 저장한다. 프로젝트 경로·표시명·최근 열기 시각만 기록한다. 목록 저장 실패가 프로젝트 열기 자체를 차단하지는 않는다. 프런트엔드만 `npm.cmd run dev`로 실행하면 UI를 볼 수 있지만 파일 작업은 할 수 없다. 데스크톱은 임의 경로를 받는 파일/셸 플러그인 없이 Rust의 파일 선택 대화상자와 현재 프로젝트 세션을 사용한다. 실행 파일을 빌드하려면: ```powershell # src/apps/desktop npm.cmd run build cd ../.. cargo build --locked -p msix-studio --features custom-protocol # src/target/debug/msix-studio.exe ``` ## VS Code 실행·디버깅 저장소 최상위 **`D:\networkSetup` 폴더**를 VS Code로 연다. 루트 `.vscode` 설정은 `src`의 Rust workspace를 연결한다. 확장 탭의 권장 확장인 **C/C++ (`ms-vscode.cpptools`)**와 **rust-analyzer**를 설치한다. Windows/MSVC용 `cppvsdbg` 구성은 [Tauri 공식 디버깅 안내](https://v2.tauri.app/develop/debug/vscode/)를 따른다. 1. `실행 및 디버그` (`Ctrl+Shift+D`)에서 **Installer Studio: Desktop (Rust)**를 선택한다. 2. `src/apps/desktop/src-tauri/src/main.rs` 또는 `src/crates`의 Rust 코드에 중단점을 설정하고 **F5**를 누른다. 3. 프런트엔드 의존성 설치 → TypeScript/Vite 빌드 → Rust debug 빌드 후 앱이 디버거에서 실행된다. 빌드된 UI를 포함하므로 Vite 서버는 시작하지 않는다. UI 변경도 F5로 다시 빌드하여 반영한다. 데스크톱 F5는 잠금 파일 기준으로 `npm ci`를 실행하므로 기존 Vite/Tauri 개발 서버를 먼저 종료한다. Rust 코드를 변경하고 재실행할 때도 이전 디버그 세션을 종료한다. `Ctrl+F5`는 디버거 없이 실행하고, `Ctrl+Shift+B`는 데스크톱 빌드만 수행한다. 이 구성의 중단점 대상은 Rust이며 TypeScript/WebView 디버깅은 별도다. VS Code 빌드/시험 산출물은 `src/target/vscode`에 분리한다. 기존 `src/target/debug/msix-studio.exe`를 실행 중이어도 디버그 빌드와 충돌하지 않는다. 최초 VS Code 빌드는 의존성을 별도로 컴파일하므로 시간이 더 걸릴 수 있다. | 실행 구성 | 동작 | | --- | --- | | `Installer Studio: Desktop (Rust)` | MSIX 제작기 GUI와 Rust 공통 엔진 디버깅 | | `MSIX CLI: Schema` | 추가 입력 없이 JSON Schema 출력; CLI 중단점 확인용 | | `MSIX CLI: Validate project` | 입력한 JSON 프로젝트 검사 | | `MSIX CLI: Plan release` | 프로젝트 경로와 대상 ID를 받아 계획 생성 | | `MSIX CLI: Build plan` | 프로젝트 경로와 새 계획 UUID를 받아 실제 MSIX 생성 | CLI 입력 경로는 절대 경로나 `src` 기준 상대 경로를 따옴표 없이 입력한다. 기본값 `fixtures/InstallerProject.isproj`은 Publisher가 미확정인 초안이므로 검증 오류를 확인하는 용도다. 실제 빌드는 소스/SDK가 연결된 프로젝트를 사용한다. 시험 앱을 생성했다면 `.work/demo/FixtureAlpha/InstallerProject.isproj`을 입력할 수 있다. 계획 ID는 `Plan release` 결과의 `id`를 사용한다. 명령 팔레트의 `Tasks: Run Task`에서 `MSIX: test Rust`를 실행할 수 있다. MakeAppx 통합 시험은 기존 `scripts/Check.ps1 -MakeAppx ...`로 명시 실행한다. ## 레지스트리 설정 **레지스트리** 탭에서 값을 추가·수정·삭제한 뒤 저장하고 새 빌드 계획을 생성한다. `HKLM\Software` 아래 앱 전용 설정, 기본값, 32/64비트 뷰, `REG_SZ`/`REG_EXPAND_SZ`/`REG_DWORD`/`REG_QWORD`/`REG_MULTI_SZ`/`REG_BINARY`를 지원한다. QWORD를 포함한 모든 데이터는 프로젝트 JSON의 문자열로 보관한다. 빌드 엔진은 Windows의 `offreg.dll`로 실제 `registry.dat`를 생성하고, 패키지 역추출 후 해시와 각 값을 다시 검증한다. 빌드 PC의 일반 레지스트리는 변경하지 않는다. 릴리스와 내보내기에 `registry-report.json`을 포함한다. 이전 v2 프로젝트에 `registry` 필드가 없어도 빈 설정으로 열린다. HKCU 초기화·COM/파일 연결·ISM 가져오기와 MSI 속성 치환은 아직 지원하지 않는다. 기존 EG-BIM 샘플에 레지스트리 설정을 자동 추가하지 않았으며, 새 기능을 사용한 프로젝트는 다시 빌드해야 한다. [설정 예시와 실제 실행 시험 기록](../docs/changes/2026-10-22-msix-registry-editor.md) ## CLI 아래 명령은 `src`에서 실행한다. stdout은 JSON, 오류는 stderr JSON이다. 개발자 서명 모드는 실제 MSIX 서명을 수행한다. 앱 설치와 PC의 인증서 신뢰 등록은 자동 수행하지 않는다. ```powershell cargo run -p package-builder -- init --project D:\packages\demo\InstallerProject.isproj cargo run -p package-builder -- validate --project D:\packages\demo\InstallerProject.isproj cargo run -p package-builder -- plan release --project D:\packages\demo\InstallerProject.isproj --target msix-direct cargo run -p package-builder -- build --project D:\packages\demo\InstallerProject.isproj --plan-id <계획의-id> cargo run -p package-builder -- job status --project D:\packages\demo\InstallerProject.isproj --id <계획의-id> cargo run -p package-builder -- export --project D:\packages\demo\InstallerProject.isproj --release <계획의-id> --output D:\exports\new-folder cargo run -p package-builder -- schema ``` 프로젝트는 `.isproj`만 지원하며 내부 내용은 UTF-8 JSON v2다. 새 프로젝트의 기본 이름은 `InstallerProject.isproj`이고, 확장자를 생략하면 `.isproj`를 붙인다. 기존 `.json` 프로젝트의 열기·호환·변환은 제공하지 않는다. 기존 JSON 항목은 최근 목록에서도 숨긴다. 별도의 프로젝트 ID는 사용하지 않는다. MSIX 앱 계열은 패키지 설정의 Identity Name과 Publisher로 관리한다. 기존 `projectId` 필드가 포함된 개발용 파일은 자동 변환하지 않고 알 수 없는 필드로 거부한다. 현재 fixture와 샘플 생성 스크립트는 해당 필드 없이 프로젝트를 만든다. 프로젝트 옆 `<프로젝트 파일명>.local.json`에서 소스 alias와 SDK를 연결한다. 예를 들어 `InstallerProject.isproj.local.json`이다. 상대 소스 경로는 프로젝트 폴더 기준이다. 기존 `package-project.local.json`은 읽지 않으며 local 파일은 Git에 넣지 않는다. 저장 시 이전 프로젝트는 `.isproj.bak`, 이전 로컬 설정은 `.isproj.local.json.bak`으로 보관한다. ```json { "sources": { "appPayload": "payload" }, "makeAppx": "C:/Program Files (x86)/Windows Kits/10/bin/10.0.26100.0/x64/makeappx.exe" } ``` 소스는 `.work`, `releases`를 포함하거나 그 아래에 위치할 수 없다. 예를 들어 프로젝트 폴더 전체 대신 그 안의 `payload` 폴더를 연결한다. 실행 항목은 x86/x64/arm64 PE이며 패키지 아키텍처와 같아야 한다. 이 버전의 로고는 scale-100 기준 44×44, 150×150 PNG만 지원한다. 생성물은 `.work/plans/.json`, `.work/jobs//`, `releases//`에 보존된다. 계획에는 프로젝트/local revision, 소스별 SHA-256, MakeAppx 경로·해시를 저장하고 실행 전에 재검사한다. 같은 계획은 다시 실행하지 않으며 실패 후에는 새 계획을 만든다. `Ctrl+C`로 CLI 빌드를 취소할 수 있다. 종료된 작업의 `Running` 상태는 `job status`에서 잠금 소유자가 없을 때 `Interrupted`로 복구한다. 종료 코드: 0 명령 성공, 2 입력/계획 오류, 4 도구 오류, 5 아티팩트/identity 오류, 6 잠금 충돌, 130 취소. 빌드 성공은 배포 가능 판정이 아니다. ## 개발자 서명 모드 **서명 → 개발자 서명 · 테스트용 자체 서명**을 선택하고 **테스트 인증서 생성**을 누른다. 기존 인증서를 사용할 때는 **인증서 목록 새로고침 → 인증서 선택 → 선택한 인증서 사용** 순서로 진행한다. `Publisher`와 정확히 일치하는 Subject, 유효 기간, 코드 서명 용도, 개인 키를 검사한다. MakeAppx.exe와 같은 폴더의 SignTool.exe가 필요하다. 프로젝트에는 `"signing": { "mode": "development" }`, 로컬 설정에는 `developerCertificateThumbprint`를 저장한다. 기존 프로젝트의 기본값은 `unsigned`다. 인증서를 선택하지 않은 개발자 서명 빌드는 오류로 중단하며 미서명으로 대체하지 않는다. CLI에서는 `certificate --project <경로> --create`, 기존 인증서 선택은 `--thumbprint <지문>`, 목록은 추가 옵션 없이 실행한다. 인증서는 현재 사용자 개인 저장소에 생성하고 3개월간 유효하다. 개인 키는 내보내지 않으며 다음 빌드에서 선택한 인증서를 재사용한다. 패키징 → MSIX 서명 → 서명 및 신뢰 검사 → 역추출·내용 검사 순서로 처리한다. 결과에 공개 인증서 `development-signing.cer`, `signing-report.json`, `sign.log`, 관리자용 `Install-TestCertificate.ps1`을 함께 출력한다. 설치할 테스트 PC에서 공개 인증서를 확인한 뒤 스크립트를 관리자 권한으로 실행하면 해당 인증서만 `LocalMachine\TrustedPeople`에 등록한다. 제작기는 이 스크립트를 자동 실행하지 않는다. 서명 성공과 PC 신뢰 여부는 별도로 표시한다. 자체 서명은 Microsoft의 게시자 신원 보증이 아니며 Windows 개발자 모드와도 별개다. 내부 EXE/DLL 개별 서명, 공인 서명 서비스, 타임스탬프, 자동 설치 시험은 아직 제공하지 않는다. [구현 및 검증 기록](../docs/changes/2026-10-23-developer-signing.md) ## EG-BIM 샘플의 개발용 서명 후처리 기존 미서명 릴리스에는 `0x800B010A` 설치 오류에 대응하여 추가했던 `scripts/Sign-DevelopmentMsix.ps1`을 계속 사용할 수 있다. **제작기로 만든 검증된 미서명 릴리스**의 해시를 확인하고 복사본에 Windows SDK SignTool로 서명한다. 새 빌드에는 위의 통합 개발자 서명 모드를 사용하며, 이미 서명된 릴리스에 후처리를 중복 적용하지 않는다. ```powershell .\scripts\Sign-DevelopmentMsix.ps1 -Release '<프로젝트 폴더>\releases\<빌드 ID>\release.json' -Output '<새 서명 출력 폴더>' # 기존 개발용 인증서를 재사용하려면 -CertificateThumbprint <지문> 추가 # 새 빌드부터 이어서 서명하려면 Build-EgbimMsixSample.ps1에 -SignDevelopment 추가 ``` Publisher와 같은 Subject의 단기 개발용 인증서를 현재 사용자의 개인 저장소에 생성한다. 개인 키는 내보내지 않고 공개 CER만 출력한다. 출력에는 서명본, SignTool 로그, CMS 서명 검사 및 신뢰 검사 결과를 기록한다. 신뢰되지 않은 자체 서명 인증서는 SignTool verify가 실패하며 설치 가능한 상태로 표시하지 않는다. 설치하려면 테스트 PC의 관리자가 공개 CER를 `LocalMachine\TrustedPeople`에 등록해야 한다. 스크립트는 인증서 신뢰 등록이나 앱 설치를 수행하지 않는다. ## 구조 | 경로 | 역할 | | --- | --- | | `crates/package-domain` | 엄격한 v2 DTO, 진단, 경로/버전/대상 검증, manifest 생성 | | `crates/package-engine` | 검증/계획 계약, 백엔드 포트, 파일·도구 스냅샷 | | `crates/package-infra` | 스트림 해시/복사, 파일 수집, OS 잠금, 원자적 JSON 저장, MakeAppx, 패키지 재검사, 결과 내보내기 | | `apps/cli` | 공통 엔진 CLI | | `apps/desktop` | TypeScript UI와 Tauri 명령·capabilities | | `fixtures`, `scripts` | 기본 프로젝트, 두 Win32 시험 앱 생성, 재현 가능한 검증 명령 | Rust DTO에서 생성하는 JSON Schema는 구조와 알 수 없는 필드를 검증하는 용도다. 버전·대상·경로·파일 등의 의미 검증은 공통 엔진이 추가 수행한다. 실제 manifest XML은 [MakeAppx의 기본 검증](https://learn.microsoft.com/en-us/windows/msix/package/create-app-package-with-makeappx-tool)을 끄지 않고 검사한다. Tauri 명령은 [AppManifest와 capability 권한](https://v2.tauri.app/security/capabilities/)으로 main 창에 한정한다. ## 검사와 시험 앱 ```powershell # src에서 실행. 기존 폴더는 덮어쓰지 않는다. .\scripts\New-Fixtures.ps1 -MakeAppx 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\makeappx.exe' # .work/demo/FixtureAlpha와 FixtureBeta의 프로젝트를 앱에서 열 수 있다. .\scripts\Check.ps1 -MakeAppx 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\makeappx.exe' ``` 검사 스크립트는 `npm ci`로 의존성을 재설치하므로 먼저 실행 중인 Vite/Tauri 개발 서버를 종료한다. Windows에서 실행 중인 esbuild 파일은 교체할 수 없다. `cargo test`는 일반 단위/통합 테스트를 수행한다. SDK 통합 테스트는 기본적으로 ignored이며 `MSIX_TEST_MAKEAPPX`를 지정하고 `--ignored`로 명시 실행한다. 이 테스트는 두 identity, 실제 MakeAppx pack/unpack, 원본 변경 후 계획 거부, 중복 빌드, 내보내기 무결성 및 취소를 확인한다. 설치 시험으로 취급하지 않는다. 프로젝트 닫기와 최근 목록 저장 테스트는 `cargo test --workspace`에 포함된다. 시작 화면의 날짜 그룹·검색·HTML 이스케이프와 미저장 변경 처리 테스트는 `apps/desktop`에서 `npm.cmd test`로 실행한다. `scripts/Check.ps1`도 두 검사를 모두 수행한다. [2026-10-19 검증 기록](tests/verification-2026-10-19.json)에 실제 도구 해시, 시험 결과, 로컬 생성물 해시와 미실행 항목을 보관한다. GUI 컴파일은 통과했지만 현재 자동화 연결을 사용할 수 없어 화면 클릭·시각 검사는 `notRun`이다. ## 현재 구현 범위와 다음 작업 - 구현: workspace/공통 엔진/CLI/GUI, v2 열기·저장·백업·revision 충돌, 파일 포함/제외·정렬·충돌·위험 경로/reparse 차단, PE 아키텍처/PNG 확인, XML 이스케이프, 계획 고정, OS 잠금, Windows Job Object, 도구 타임아웃·취소, MSIX pack/unpack 및 identity/파일 해시 대조, 덮어쓰기 없는 개발 결과와 보고서 내보내기. - 다음: 운영 서명 프로필·타임스탬프, App Installer, 승인 SDK 버전 정책, 다중 대상 일괄 작업, 작업 이력/재연결 화면, 파일 목록 서버 페이지 처리, 접근성/DPI 전체 시험, Windows VM 설치·실행·업데이트·제거·사용자 데이터 보존 증빙. - EXE/MSI/MSP, Store, bundle, extension은 명시적으로 거부한다. 운영 서명 프로필/App Installer 요청도 구현 완료 전에는 차단한다. - 로컬 검증을 통과한 아키텍처/OS 값은 지원 인증을 의미하지 않는다. 도구 해시는 계획 시 고정하지만 승인된 SDK 목록/도구 버전 메타데이터 정책은 아직 없다. - 프로젝트와 local JSON은 각각 원자적으로 저장하고 이전 파일을 `.bak`으로 보관한다. 두 파일을 한 번에 교체하는 트랜잭션은 아니다. 작업 로그에는 로컬 경로가 포함되므로 결과 공유 시 검토한다. - 결과는 애플리케이션에서 덮어쓰지 않지만 OS 파일 권한으로 불변성을 강제하지는 않는다. 내보내기 전 MSIX 해시를 다시 검증한다. 백로그 BL-09/10/11/14/16/29/47/48/49/50의 일부를 구현한 상태다. 서명·VM 증빙을 포함한 원래 인수 기준이 남아 있으므로 해당 백로그와 MS6를 완료로 표시하지 않는다.