fix(p0): align powershell offline sample case readiness

This commit is contained in:
jhuang-tw
2026-08-17 23:35:27 -07:00
parent fb1124daf9
commit e29bba4b6b
+47 -8
View File
@@ -4,6 +4,9 @@
# Ready-to-act example:
# powershell -File skills/scripts/case-init.ps1 -Hint "web pentest" -CaseName my-case `
# -AuthGranted -TargetUrl "https://app.example/" -NetworkProfile authorized_target_only
# Offline sample ready-to-act example:
# powershell -File skills/scripts/case-init.ps1 -Hint "offline apk" -CaseName my-sample `
# -Preset offline-sample -Sample ".\app.apk"
param(
[string] $Hint = '',
[string] $CaseName = '',
@@ -15,6 +18,8 @@ param(
[string] $AuthBasis = 'own_system',
[string] $EvidenceOfAuth = '',
[string] $TargetUrl = '',
[string] $Sample = '',
[string] $Preset = '',
[string[]] $InScopeAssets = @(),
[string] $NetworkProfile = '',
[switch] $ReadyForAct
@@ -35,6 +40,32 @@ $requestedProjectRoot = if (-not [string]::IsNullOrWhiteSpace($ProjectRoot)) {
}
$projectRoot = Resolve-ReverseProjectRoot -RequestedRoot $requestedProjectRoot
# Cross-platform case presets. Keep semantics aligned with case-init.sh.
$presetNormalized = $Preset.Trim().ToLowerInvariant()
if ($presetNormalized -in @('offline-sample', 'own-sample', 'local-sample')) {
$AuthGranted = $true
$AuthStatus = 'granted'
$AuthBasis = 'own_system'
if ([string]::IsNullOrWhiteSpace($NetworkProfile)) { $NetworkProfile = 'offline' }
if ([string]::IsNullOrWhiteSpace($EvidenceOfAuth)) {
$EvidenceOfAuth = 'preset:offline-sample (owner-operated local file)'
}
} elseif ($presetNormalized -in @('ctf-public', 'ctf')) {
$AuthGranted = $true
$AuthStatus = 'granted'
$AuthBasis = 'ctf_public'
if ([string]::IsNullOrWhiteSpace($NetworkProfile)) { $NetworkProfile = 'authorized_target_only' }
if ([string]::IsNullOrWhiteSpace($EvidenceOfAuth)) { $EvidenceOfAuth = 'preset:ctf-public' }
} elseif ($presetNormalized -in @('own-system', 'lab-only')) {
$AuthGranted = $true
$AuthStatus = 'granted'
$AuthBasis = 'own_system'
if ([string]::IsNullOrWhiteSpace($NetworkProfile)) { $NetworkProfile = 'lab_only' }
if ([string]::IsNullOrWhiteSpace($EvidenceOfAuth)) { $EvidenceOfAuth = 'preset:own-system/lab' }
} elseif (-not [string]::IsNullOrWhiteSpace($Preset)) {
Write-Host ("WARN: unknown -Preset '{0}' (allowed: offline-sample|ctf-public|own-system)" -f $Preset) -ForegroundColor Yellow
}
if (-not $CaseName) {
$slug = if ($Hint) {
($Hint.ToLowerInvariant() -replace '[^a-z0-9]+', '-').Trim('-')
@@ -90,6 +121,9 @@ $evidenceAuth = if (-not [string]::IsNullOrWhiteSpace($EvidenceOfAuth)) {
$assets = New-Object System.Collections.Generic.List[string]
if (-not [string]::IsNullOrWhiteSpace($TargetUrl)) { [void]$assets.Add($TargetUrl.Trim()) }
if (-not [string]::IsNullOrWhiteSpace($Sample) -and -not $assets.Contains($Sample.Trim())) {
[void]$assets.Add($Sample.Trim())
}
foreach ($a in @($InScopeAssets)) {
if (-not [string]::IsNullOrWhiteSpace($a) -and -not $assets.Contains($a.Trim())) {
[void]$assets.Add($a.Trim())
@@ -103,8 +137,8 @@ if ($assets.Count -eq 0 -and $Hint -match 'https?://([^\s/]+)') {
$networkMode = 'offline'
if (-not [string]::IsNullOrWhiteSpace($NetworkProfile)) {
$networkMode = $NetworkProfile.Trim()
} elseif ($assets.Count -gt 0 -and $authStatusResolved -eq 'granted') {
# training labs / intentional vulns often use lab_only; default authorized_target_only
} elseif ($assets.Count -gt 0 -and $authStatusResolved -eq 'granted' -and [string]::IsNullOrWhiteSpace($Sample)) {
# Authorized network targets default to target-only. Explicit local samples remain offline.
$networkMode = 'authorized_target_only'
}
# normalize common aliases
@@ -122,19 +156,21 @@ if ($networkMode -notin $allowedNetworkModes) {
throw "Invalid -NetworkProfile '$NetworkProfile'. Allowed: offline, lab_only, authorized_target_only, unrestricted_lab (aliases: lab, authorized, auth, offline_only)."
}
# ready_for_act requires auth granted + assets + non-offline network.
# -ReadyForAct cannot skip auth (would bypass hard gate).
# ready_for_act requires auth granted + assets. Network targets need a non-offline
# profile; an explicit local sample is valid in offline mode. -ReadyForAct never
# bypasses auth or scope.
$ready = $false
$netAllowsAct = ($networkMode -ne 'offline' -and -not [string]::IsNullOrWhiteSpace($networkMode))
if ($authStatusResolved -eq 'granted' -and $assets.Count -gt 0 -and $netAllowsAct) {
$offlineSampleReady = ($networkMode -eq 'offline' -and -not [string]::IsNullOrWhiteSpace($Sample) -and $assets.Count -gt 0)
if ($authStatusResolved -eq 'granted' -and $assets.Count -gt 0 -and ($netAllowsAct -or $offlineSampleReady)) {
$ready = $true
} elseif ($ReadyForAct) {
if ($authStatusResolved -ne 'granted') {
Write-Host 'WARN: -ReadyForAct ignored because auth.status is not granted' -ForegroundColor Yellow
} elseif ($assets.Count -eq 0) {
Write-Host 'WARN: -ReadyForAct ignored because in_scope.assets is empty' -ForegroundColor Yellow
} elseif (-not $netAllowsAct) {
Write-Host 'WARN: -ReadyForAct ignored because network_profile is offline/empty' -ForegroundColor Yellow
} elseif (-not $netAllowsAct -and -not $offlineSampleReady) {
Write-Host 'WARN: -ReadyForAct ignored because offline mode requires an explicit -Sample' -ForegroundColor Yellow
}
}
@@ -193,6 +229,7 @@ $scope = @"
- lead_role: lead
- specialist_roles: []
- hint: $Hint
- preset: $(if ([string]::IsNullOrWhiteSpace($Preset)) { 'none' } else { $Preset })
## auth
- status: $authStatusResolved
@@ -293,7 +330,9 @@ $readmeNext = if ($ready) {
"@
} else {
@"
1. Edit ``scope.md`` — set auth.status=granted and in_scope (or re-run with -AuthGranted -TargetUrl)
1. Edit ``scope.md`` — set auth.status=granted and in_scope
- network target: re-run with ``-AuthGranted -TargetUrl <url>``
- local sample: re-run with ``-Preset offline-sample -Sample <path>``
2. Set ready_for_act when checklist complete
3. Open primary skill: skills/$primary
4. Append ``timeline.md``; update ``workitems.md``