Add the shared Rust engine, Tauri UI and CLI, registry authoring, developer signing, branded start screen and .isproj persistence. Remove the unused project ID. Validation: frontend build and tests, Rust workspace tests, native build and real Windows SDK package generation passed. Closes #2 Closes #3 Closes #4 Closes #5 Closes #6 Closes #7
Installer Studio — 구현 시작 버전
기존 MSIX 우선 설계를 실행 가능한 Rust/Tauri 프로그램으로 옮긴 0.1 개발 버전이다. 모든 소스와 잠금 파일은 이 디렉터리에 있다. 미서명 또는 개발자 자체 서명 MSIX를 생성하며 일반 배포 준비 상태를 부여하지 않는다.
실행
Windows, Rust 1.94.0/MSVC 빌드 도구, Node.js 22.12 이상, WebView2가 필요하다. 실제 패키징에는 Windows SDK의 MakeAppx.exe가 필요하다. SDK·인증서는 프로그램이 자동 설치하지 않는다.
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의 파일 선택 대화상자와 현재 프로젝트 세션을 사용한다.
실행 파일을 빌드하려면:
# 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 공식 디버깅 안내를 따른다.
실행 및 디버그(Ctrl+Shift+D)에서 **Installer Studio: Desktop (Rust)**를 선택한다.src/apps/desktop/src-tauri/src/main.rs또는src/crates의 Rust 코드에 중단점을 설정하고 F5를 누른다.- 프런트엔드 의존성 설치 → 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 샘플에 레지스트리 설정을 자동 추가하지 않았으며, 새 기능을 사용한 프로젝트는 다시 빌드해야 한다. 설정 예시와 실제 실행 시험 기록
CLI
아래 명령은 src에서 실행한다. stdout은 JSON, 오류는 stderr JSON이다. 개발자 서명 모드는 실제 MSIX 서명을 수행한다. 앱 설치와 PC의 인증서 신뢰 등록은 자동 수행하지 않는다.
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으로 보관한다.
{
"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/<id>.json, .work/jobs/<id>/, releases/<id>/에 보존된다. 계획에는 프로젝트/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 개별 서명, 공인 서명 서비스, 타임스탬프, 자동 설치 시험은 아직 제공하지 않는다. 구현 및 검증 기록
EG-BIM 샘플의 개발용 서명 후처리
기존 미서명 릴리스에는 0x800B010A 설치 오류에 대응하여 추가했던 scripts/Sign-DevelopmentMsix.ps1을 계속 사용할 수 있다. 제작기로 만든 검증된 미서명 릴리스의 해시를 확인하고 복사본에 Windows SDK SignTool로 서명한다. 새 빌드에는 위의 통합 개발자 서명 모드를 사용하며, 이미 서명된 릴리스에 후처리를 중복 적용하지 않는다.
.\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의 기본 검증을 끄지 않고 검사한다. Tauri 명령은 AppManifest와 capability 권한으로 main 창에 한정한다.
검사와 시험 앱
# 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 검증 기록에 실제 도구 해시, 시험 결과, 로컬 생성물 해시와 미실행 항목을 보관한다. 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를 완료로 표시하지 않는다.