Add negative Android provenance checks and short tap exercise

This commit is contained in:
NINI
2026-10-05 03:51:27 +09:00
parent 92cbb52b73
commit f3f1f14fb1
3 changed files with 31 additions and 3 deletions
+3 -3
View File
@@ -39,7 +39,7 @@ try {
Step 'final-02-selection' @('shell','input','tap','1200','616')
Start-Audio 'audio-online-guidecollect' 8
Step 'final-03-stage' @('shell','input','tap','1200','560') 2500
Step 'final-04-precollect-tap' @('shell','input','swipe','930','510','930','510','200')
Step 'final-04-precollect-tap' @('shell','input','tap','930','510')
$uncollected=Save-State 'final-04-uncollected'
Assert-State 'direct-collection-required' ($uncollected.puzzleStates[0].collectedBallIds.Count -eq 0 -and $uncollected.puzzleStates[0].countedBallIds.Count -eq 0 -and $uncollected.completedStageIds.Count -eq 0) ($uncollected | ConvertTo-Json -Depth 8 -Compress)
Start-Audio 'audio-online-guidecount' 8
@@ -53,7 +53,7 @@ try {
$after=Save-State 'final-07-incomplete-after'
Assert-State 'incomplete-json-restored' (($before | ConvertTo-Json -Depth 8 -Compress) -eq ($after | ConvertTo-Json -Depth 8 -Compress)) '배치/카메라/그룹/수집/빈 계수 전체 JSON 동일'
Start-Audio 'audio-online-count01' 8
Step 'final-08-success-same-board' @('shell','input','swipe','1182','514','1182','514','200') 1500
Step 'final-08-success-same-board' @('shell','input','tap','1182','514') 1500
$success=Save-State 'final-08-success'
Assert-State 'completion-atomic-state' ($success.completedStageIds.Count -eq 1 -and $success.completedStageIds[0] -eq 1 -and $success.puzzleStates.Count -eq 0 -and $success.latestFreePlay.sourceStageId -eq 1) ($success | ConvertTo-Json -Depth 8 -Compress)
Assert-State 'success-preserves-board-camera' (($before.puzzleStates[0].balls | ConvertTo-Json -Depth 6 -Compress) -eq ($success.latestFreePlay.balls | ConvertTo-Json -Depth 6 -Compress) -and ($before.puzzleStates[0].camera | ConvertTo-Json -Depth 6 -Compress) -eq ($success.latestFreePlay.camera | ConvertTo-Json -Depth 6 -Compress)) '성공 전후 balls/camera 동일'
@@ -88,7 +88,7 @@ try {
Step 'final-12-offline-collect' @('shell','input','swipe','930','510','1200','510','800') 4500
$offlineCollected=Save-State 'final-12-offline-collected'
Assert-State 'offline-collected-unfinished' ($offlineCollected.puzzleStates.Count -eq 1 -and $offlineCollected.puzzleStates[0].collectedBallIds.Count -eq 1 -and $offlineCollected.puzzleStates[0].countedBallIds.Count -eq 0) '오프라인 실제 수집됨/계수 전 0'
Step 'final-12-offline-count-success' @('shell','input','swipe','1182','510','1182','510','200') 1500
Step 'final-12-offline-count-success' @('shell','input','tap','1182','510') 1500
$offlineSuccess=Save-State 'final-12-offline-success'
Assert-State 'offline-collection-count-actually-success' ($offlineSuccess.completedStageIds.Count -eq 1 -and $offlineSuccess.completedStageIds[0] -eq 1 -and $offlineSuccess.puzzleStates.Count -eq 0 -and $offlineSuccess.latestFreePlay.sourceStageId -eq 1 -and ($offlineCollected.puzzleStates[0].balls | ConvertTo-Json -Depth 6 -Compress) -eq ($offlineSuccess.latestFreePlay.balls | ConvertTo-Json -Depth 6 -Compress)) '완료1/미완료없음/수집 전후 같은 IDs와 배치 자유 전이'
Step 'final-13-offline-free-move' @('shell','input','swipe','1182','510','1350','450','800')
+26
View File
@@ -0,0 +1,26 @@
param([string]$EvidenceDir='artifacts/verification/FirstSlice')
$ErrorActionPreference='Stop'
$EvidenceDir=(Resolve-Path -LiteralPath $EvidenceDir).Path
$apkPath=(Resolve-Path -LiteralPath 'artifacts/android/FirstSlice/MagnetismHeroes.apk').Path
$source=& git rev-parse HEAD
$build=Get-Content -LiteralPath (Join-Path $EvidenceDir 'androidbuild-evidence.json') -Raw | ConvertFrom-Json
if ($build.sourceCommit -ne $source -or $build.sourceDirty -ne $false -or $build.sourceDirtyEnd -ne $false -or $build.apkSha256 -ne (Get-FileHash -LiteralPath $apkPath).Hash) { throw '현재 clean 소스의 실제 Build 근거가 있어야 부정 검사를 실행할 수 있습니다.' }
$results=@()
foreach ($field in @('sourceCommit','apkSha256')) {
$caseDir=Join-Path $EvidenceDir "red/provenance-$field"
New-Item -ItemType Directory -Path $caseDir -Force | Out-Null
$copy=Get-Content -LiteralPath (Join-Path $EvidenceDir 'androidbuild-evidence.json') -Raw | ConvertFrom-Json
$copy.$field='deliberately-invalid-verification-copy'
$copy | ConvertTo-Json -Depth 10 | Set-Content -LiteralPath (Join-Path $caseDir 'androidbuild-evidence.json') -Encoding utf8
Copy-Item -LiteralPath (Join-Path $EvidenceDir 'apk-metadata.json') -Destination (Join-Path $caseDir 'apk-metadata.json')
$log=Join-Path $caseDir 'negative-smoke.log'
$smoke=Join-Path $PSScriptRoot 'smoke.ps1'
& pwsh -NoProfile -File $smoke -ApkPath $apkPath -Milestone FirstSlice -EvidenceDir $caseDir *> $log
$code=$LASTEXITCODE
$outcome=Get-Content -LiteralPath (Join-Path $caseDir 'android-device-evidence.json') -Raw | ConvertFrom-Json
$passed=$code -eq 1 -and $outcome.status -eq 'failed' -and @($outcome.commands).Count -eq 0 -and $outcome.checks[-1].criterion -eq 'verified-build-provenance' -and $outcome.checks[-1].passed -eq $false
$results += [ordered]@{ field=$field; command="pwsh -NoProfile -File $smoke -ApkPath $apkPath -Milestone FirstSlice -EvidenceDir $caseDir"; actualExitCode=$code; deviceCommandCount=@($outcome.commands).Count; passed=$passed; log=$log }
}
[ordered]@{ sourceCommit=$source; apkSha256=$build.apkSha256; cases=$results } | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $EvidenceDir 'negative-provenance-results.json') -Encoding utf8
if (@($results | Where-Object passed -ne $true).Count) { throw '출처가 틀린 검사 복사본을 기기 조작 전에 거부하지 못했습니다.' }
Write-Host '소스 SHA/APK hash 손상 복사본 2개를 실제 종료 코드 1로 기기 조작 전 거부했습니다.'