Add ZScaler root certificate propagation option for Windows Sandbox#297
Conversation
|
|
리뷰에서 지적된 잔여 개선 사항 반영: - SandboxBuilder(호스트): LocalMachine\Root 열거 인증서 중 미매칭은 즉시, 매칭분은 PEM 추출 후 finally에서 Dispose (X509Certificate2 키 핸들 누수 방지). - SandboxBootstrap(게스트): CurrentUser\Root 등록 후 X509Certificate2Collection 항목을 finally에서 Dispose (Store.Add는 복제하므로 원본 해제 안전). - git SChannel 구성: WaitForExit 타임아웃(5s) 시 Kill(entireProcessTree)로 좀비 프로세스 방지. 동작 변화 없음(정리 전용). 빌드 경고 0, TableCloth.Test 46 + Spork.Test 3 통과. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
호스트 보안 프로그램 대응 등으로 호환성 설정이 계속 늘어날 것을 대비해, 하드코딩된 체크박스 3개를 데이터 기반 구조로 전환한다. - CompatibilityOptionItem: 기존 [ObservableProperty] bool을 그대로 읽고 쓰는 얇은 어댑터. 이름·설명(한/영)을 합친 검색 인덱스와 MatchesFilter를 보유. 저장 파이프라인(OnViewModelPropertyChangedAsync)은 변경 없이 재사용된다. - OptionsWindowViewModel: CompatibilityOptions 컬렉션 + 검색어 + 필터. BuildSearchText가 한국어·중립(영어) 리소스를 모두 색인해, 현재 UI 언어와 무관하게 한/영 어느 쪽으로도 검색된다. 검색어 등 UI 전용 속성은 저장 핸들러에서 조기 반환해 키 입력마다의 preferences 로드를 막는다. - OptionsWindow.xaml: 검색 TextBox(카탈로그와 동일한 CueBannerBrush 워터마크) + 수직 전용 ScrollViewer(가로 스크롤 비활성) + ItemsControl. 결과 없음 안내 포함. - 리소스: Option_Compatibility_SearchPlaceholder / _NoSearchResults (한/영). - 테스트: 검색/필터/대소문자·한영 매칭/결과 없음/양방향 바인딩 및 로드 시점 IsChecked 알림까지 검증(8건). 빌드 경고 0, 테스트 54건 통과. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds an opt-in “ZScaler root certificate propagation” compatibility setting to restore HTTPS connectivity inside Windows Sandbox environments that perform SSL inspection, by extracting the host’s ZScaler root cert(s) and importing them into the sandbox trust store during bootstrap.
Changes:
- Introduces
EnableZScalerRootCertPropagationpreference + host→guest transport viaSporkAnswers. - Implements host-side cert extraction/staging (
SandboxBuilder) and guest-side import + environment/tooling tweaks (SandboxBootstrap). - Adds a searchable Compatibility options UI, localized strings, docs entry, and unit tests for the new preference/flag and UI filtering behavior.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/TableCloth.Test/SporkAnswersTests.cs | Adds tests for new SporkAnswers.EnableZScalerRootCertPropagation default/set behavior. |
| src/TableCloth.Test/PreferenceSettingsTests.cs | Adds tests for new preference default/set behavior (and existing DNS fallback default). |
| src/TableCloth.Test/CompatibilityOptionSearchTests.cs | Adds tests for Compatibility tab search/filter and viewmodel↔item roundtripping. |
| src/TableCloth.Core/Resources/UIStringResources.resx | Adds EN strings for ZScaler option + compatibility search UI strings. |
| src/TableCloth.Core/Resources/UIStringResources.ko.resx | Adds KO strings for ZScaler option + compatibility search UI strings. |
| src/TableCloth.Core/Resources/UIStringResources.Designer.cs | Regenerates strongly-typed accessors for the new resource keys. |
| src/TableCloth.Core/Models/Configuration/PreferenceSettings.cs | Adds EnableZScalerRootCertPropagation preference (default off) with documentation. |
| src/TableCloth.Core/Models/Answers/SporkAnswers.cs | Adds EnableZScalerRootCertPropagation answer flag (default off) with documentation. |
| src/TableCloth.App/ViewModels/OptionsWindowViewModel.cs | Wires preference load/save for the new flag; builds a searchable Compatibility options list. |
| src/TableCloth.App/ViewModels/CompatibilityOptionItem.cs | Introduces an adapter item for searchable compatibility toggles. |
| src/TableCloth.App/Dialogs/OptionsWindow.xaml | Reworks Compatibility tab UI into searchable, scrollable list with empty-results indicator. |
| src/TableCloth.App/Components/Implementations/SandboxBuilder.cs | Stages ZScaler cert PEM into App\\zscaler\\zscaler.pem when enabled. |
| src/Spork.Sandbox/SandboxBootstrap.cs | Imports staged PEM into CurrentUser\\Root, sets NODE_EXTRA_CA_CERTS, configures git SChannel. |
| docs/PARAMETERIZED_WSB_SPEC.md | Documents the new option and Mode-1-only scope in the spec changelog. |
Files not reviewed (1)
- src/TableCloth.Core/Resources/UIStringResources.Designer.cs: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private static void StageZScalerRootCerts(string appDirectory, bool enabled) | ||
| { | ||
| if (!enabled) | ||
| return; | ||
|
|
||
| try | ||
| { | ||
| // X509Certificate2는 IDisposable(키 핸들 보유)이므로, 매칭되지 않은 인증서는 즉시, | ||
| // 매칭된 인증서는 PEM 추출 후 finally에서 정리한다. | ||
| var matchingCerts = new List<X509Certificate2>(); | ||
| try | ||
| { | ||
| using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine)) | ||
| { | ||
| store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); | ||
| foreach (var cert in store.Certificates) | ||
| { | ||
| if (cert.Subject.IndexOf("Zscaler", StringComparison.OrdinalIgnoreCase) >= 0) | ||
| matchingCerts.Add(cert); | ||
| else | ||
| cert.Dispose(); | ||
| } | ||
| } | ||
|
|
||
| var zscalerStagingDirectoryPath = Path.Combine(appDirectory, "zscaler"); |
In ZScaler (SSL-inspection endpoint-control) environments, the host's ZScaler root certificate isn't automatically trusted inside Windows Sandbox, so all HTTPS from the sandbox is blocked. This adds an opt-in preference that extracts the host's ZScaler root cert and registers it inside the sandbox to restore connectivity. The option is Mode-1 only and unsupported in the no-install (portable) build.
Changes
PreferenceSettings.EnableZScalerRootCertPropagation(default off), mirrored ontoSporkAnswersfor host→guest delivery.SandboxBuilder) — when enabled, extracts certs whose Subject containsZscalerfromLocalMachine\Rootand writes them as PEM toApp\zscaler\zscaler.pem. Best-effort: cleans up / skips silently when disabled or no matching cert exists.SandboxBootstrap) — when enabled and the PEM is present: imports intoCurrentUser\Root, setsNODE_EXTRA_CA_CERTS(User + Process), and sets githttp.sslBackend=schannel. All failures are non-fatal to boot.OptionsWindowViewModel, with EN/KO resource strings; the description states the no-install limitation.PARAMETERIZED_WSB_SPEC.mdchangelog entry noting the Mode-1-only scope.Guest-side propagation mirrors the manual
setup.ps1from the issue:Note: certs are read from
LocalMachine\Root; reading the host's machine-wide root store may require the certs to already be present there (ZScaler typically installs them machine-wide).