7.1 KiB
원본 one-time importer 안전 감사
기준일은 2026-07-12이며, 설치된 패키지는
Wickedness.MBNStockWebView_1.0.3.0_x64__qbv3jkvsn3aj0이다. 이 감사에서는
원본 Data를 읽기 전용으로 사용했고 Oracle/MariaDB에는 SELECT만 실행했다.
운영 %LOCALAPPDATA%\MBN_STOCK_WEBVIEW\OperatorData와 Tornado2에는 쓰기나
명령을 보내지 않았다. 비교쌍에 한해서는 설치된 signed package의 명시적
버튼을 한 번 눌러 WebView2 localStorage에 8쌍과 one-time marker를 같은
envelope로 저장했다.
감사 시점 운영 profile 분류
FSell/VI 저장소에는 marker와 intent 없이 원본과 byte 단위로 같은 네 파일이 이미 있다.
| 파일 | 길이 | SHA-256 | 고정 원본과 일치 |
|---|---|---|---|
개인.dat |
56 | F953366A5D9F940CBE54F05C256F8BFB0AF4674C8F4D46CCBF839A63113342FA |
예 |
외국인.dat |
58 | 45F62038E3216E80FCF22F4E923056858E9C3537BF0DC46BC359148E82DD7CD8 |
예 |
기관.dat |
27 | BC4D62D734E701744E10DD830A2D6B9AEBEBEB795BB4DABC77CDE6577F016EB7 |
예 |
VI발동.dat |
276 | 46AFBA07D2C4AF50717450582DEB10EC10367701D09161BECF5E32342AD4AA45 |
예 |
.legacy-manual-operator-import.v1.json: 없음.legacy-manual-operator-import.v1.in-progress.json: 없음- importer staging 파일: 없음
- startup 상태: marker가 없는 기존 원본 파일을 그대로 쓰는
ReadyLegacyData - 현재 버튼 실행 판정:
DestinationNotEmpty,OutcomeUnknown=false
따라서 현재 profile에서 원본 데이터 가져오기를 누르면 네 파일을 덮어쓰지
않고 source read 전에 전체 import가 중단된다. marker를 임의로 만들어
AlreadyImported로 바꾸거나 파일을 지워 import를 재현하면 안 된다.
다음 명령은 운영 profile을 쓰지 않고 이 판정을 다시 출력한다.
dotnet run --project .\tools\MBN_STOCK_WEBVIEW.DbSmoke\MBN_STOCK_WEBVIEW.DbSmoke.csproj `
-c Release -p:Platform=x64 -- --manual-import-audit
현재 결과:
MANUAL_IMPORT_AUDIT: PASS sourceFiles=4/4 operatingFiles=4/4 sourceByteIdentical=true marker=false intent=false staged=false runtime=ReadyLegacyData decision=DestinationNotEmpty outcomeUnknown=false writesAttempted=false
격리 FSell/VI 실제 원본 import
--manual-import-fixture는 사용자가 destination을 지정할 수 없게 닫혀 있다.
고정 원본을 읽고 %TEMP%\MBN_STOCK_WEBVIEW-manual-import-fixture-<GUID>에만
쓴다. 전체 실행은 1분 timeout으로 제한되며 timeout/cancel 뒤 자동 재시도하지
않는다. 다음 항목을 모두 확인한 뒤 자신이 만든 prefix의 non-reparse directory만
삭제한다.
- 4파일 stage 및 no-overwrite commit
- production parser read-back
- marker-last commit과 intent 제거
- 재시작 guard의
ReadyImportedData - 같은 fixture의 두 번째 실행
AlreadyImported,OutcomeUnknown=false - 원본 4파일과 운영 import 대상 6항목의 실행 전후 SHA-256 불변
- 원본 aggregate SHA-256
fd39a363…a2114, FSell 15행과 VI 9건 고정
dotnet run --project .\tools\MBN_STOCK_WEBVIEW.DbSmoke\MBN_STOCK_WEBVIEW.DbSmoke.csproj `
-c Release -p:Platform=x64 -- --manual-import-fixture
실제 결과:
MANUAL_IMPORT_FIXTURE: PASS rows=15 vi=9 sourceSha256=fd39a3639e574a19f174225e8e65234d6bdd4c58700bb5d10230a779a03a2114 state=ReadyImportedData secondAttempt=AlreadyImported outcomeUnknown=false sourceUnchanged=true operatingImportSetUnchanged=true
종목비교.dat 분류
- 고정 원본: 358바이트, 8행
- SHA-256:
1EE76BC464FB1C44C8B6546E99CDC21C726C0E2C24AD344F5C19AE41BFC0D2F2 - 실제 Oracle/MariaDB read-only 재검증: 8/8 identity 해소
- 실행 경로:
비교화면의원본 비교쌍 가져오기 - 성공 저장 위치: package WebView2
localStorage의 단일 comparison envelope
감사 초기에 package WebView2가 닫힌 상태에서 LevelDB에는 87바이트
VERSION=1 log 외 comparison key byte가 없었고 비교 화면은 0 PAIRS였다.
signed 1.0.3 패키지에서 원본 비교쌍 가져오기를 명시적으로 한 번 실행한
결과, native가 고정 원본의 SHA-256과 8행을 다시 읽고 현재 DB에서 모든
identity를 해소한 뒤 화면이 8 PAIRS와 원본 8쌍 가져옴으로 바뀌었다.
부분 저장이나 복구 필요 상태는 발생하지 않았다.
이 성공은 같은 package profile의 단일 comparison envelope에 pair list와 marker를 함께 기록한 결과다. 앱을 정상 종료한 뒤 설치된 signed 1.0.3을 다시 실행해 다음 상태를 확인했다.
- 비교 화면:
8 PAIRS - 저장 비교쌍: 원본 순서의 8개 항목 유지
- one-time gate: 완료형
원본 8쌍 가져옴, 다시 실행할 수 없는 상태 - 고정 원본 SHA-256:
1EE76BC464FB1C44C8B6546E99CDC21C726C0E2C24AD344F5C19AE41BFC0D2F2로 불변
따라서 package UI 저장과 재시작 marker 영속성은 PASS다. 실행 중 LevelDB는 process lock 상태이므로 raw 파일 검색으로 live logical state를 단정하거나 파일을 복사·수정하지 않았다.
정규 DB smoke에는 실제 importer를 추가했다. 아래 명령은 원본을 읽고 8개
identity를 fresh SELECT로 해소하지만 package localStorage에는 쓰지 않는다.
dotnet run --project .\tools\MBN_STOCK_WEBVIEW.DbSmoke\MBN_STOCK_WEBVIEW.DbSmoke.csproj `
-c Release -p:Platform=x64 --no-build
확인 결과는 다음과 같다.
LegacyComparisonImport: rows=8, sha256=1EE76BC464FB1C44C8B6546E99CDC21C726C0E2C24AD344F5C19AE41BFC0D2F2, identities=fresh-read-only
REAL_DB_SMOKE: PASS
현재 package profile에서는 실제 0→8 import와 정상 종료 후 재시작 marker
검증을 완료했으므로 이를 재현하려고 package family 데이터를 초기화하지
않는다. 빈 profile의 실패 fixture가 추가로 필요하면 별도 test package
identity를 사용한다. 운영 identity에서 Remove-AppxPackage, app data reset,
LevelDB 파일 복사·삭제로 빈 profile을 만들지 않는다.
차단 판정표
| 상태 | FSell/VI 판정 | 비교쌍 판정 | 자동 재시도 |
|---|---|---|---|
| 대상 파일 없음, source 정상 | import 가능 | marker 없고 envelope 정상일 때 가능 | 명시적 버튼만 |
| 기존 4파일, marker 없음 | DestinationNotEmpty |
해당 없음 | 금지 |
| 유효 marker 있음 | AlreadyImported |
버튼이 원본 N쌍 가져옴으로 비활성 |
금지 |
| intent 있음 | InterruptedImport, OutcomeUnknown=true |
해당 없음 | 금지, 수동 대조 |
| marker/4파일 불일치 | InvalidImportedState |
해당 없음 | 금지, 수동 대조 |
| split/손상 envelope | 해당 없음 | 복구 필요, 전체 차단 |
금지, local state 대조 |
| DB timeout/identity 오류 | 해당 없음 | 저장 전 전체 취소 | 금지 |
FSell/VI 전용 화면은 원본 운영 항목의 개인·외국인·기관 또는 VI 수동 항목을
열어 진입하며, header의 원본 데이터 가져오기가 importer 버튼이다. 비교쌍은
상단 비교 업무 탭 안의 원본 비교쌍 가져오기 버튼으로 진입한다.