Examples/SecurityIncidentTriage.ps1

#requires -Version 7.0

# Inspired by TypeSafe's Security Incidents workflow:
# https://evals.typesafe.ai/security_incidents
# Set TYPESAFE_API_KEY before running this example.

Import-Module (Join-Path $PSScriptRoot '..' 'Jev.psd1') -Force

$state = [ordered]@{
    alert = 'A PowerShell process read LSASS memory using comsvcs.dll on a production server.'
    asset = [ordered]@{
        environment = 'production'
        tier        = 'critical'
        owner       = 'platform operations'
    }
    open_tickets = @(
        'INC-1042: investigate unusual PowerShell activity on the production server'
    )
    registered_devices = @(
        'The owner normally uses a managed Windows laptop from the corporate network.'
    )
    scheduled_maintenance = @(
        'No maintenance window is scheduled.'
    )
    standing_authorizations = @(
        'Platform operations may run approved diagnostics during an incident.'
    )
}

$questions = @(
    New-JevQuestion `
        -Name unauthorized_activity `
        -Type Noul `
        -Instructions 'Does `alert` describe unauthorized activity given `standing_authorizations` and `scheduled_maintenance`?' `
        -Criteria @{ `
            true  = 'The activity is not explained by an authorization or maintenance window.'
            false = 'The activity is explained by an approved authorization or maintenance window.'
        }

    New-JevQuestion `
        -Name evidence_strength `
        -Type Score `
        -Instructions 'How strong is the evidence that the activity in `alert` is harmful, given the asset and incident records?' `
        -Criteria @(
            'Weak: an unusual event with a plausible benign explanation.'
            'Moderate: suspicious activity with incomplete supporting evidence.'
            'Strong: a high impact asset and a clear malicious technique.'
        )

    New-JevQuestion `
        -Name response `
        -Type Choice `
        -Instructions 'What immediate response best fits this alert and the available records?' `
        -Criteria @{ `
            notify_user    = 'Notify the asset owner and continue monitoring.'
            escalate_tier2 = 'Queue the alert for a security analyst.'
            kill_process   = 'Stop the suspicious process while preserving the account.'
            disable_account = 'Disable the suspected account because identity misuse is likely.'
            escalate_urgent = 'Escalate urgently because the production impact is severe or expanding.'
        }
)

$response = Invoke-Jev -State $state -Question $questions

'Merged Jev response:'
$response | ConvertTo-Json -Depth 10

# Add -Raw to the Invoke-Jev call when you need only the API response.

$summary = foreach ($answerProperty in $response.answers.PSObject.Properties) {
    $answer = $answerProperty.Value
    $decision = $null
    $probability = $null
    $confidence = $null

    switch ($answer.type.ToLowerInvariant()) {
        'noul' {
            $decision = if ($answer.noul -ge 0.5) { 'True' } else { 'False' }
            $probability = [math]::Round($answer.noul, 3)
        }
        'choice' {
            $decision = $answer.choice
            $confidence = [math]::Round($answer.confidence, 3)
        }
        'score' {
            $decision = $answer.score
            $confidence = [math]::Round($answer.confidence, 3)
        }
    }

    [pscustomobject]@{
        Question    = $answerProperty.Name
        Type        = $answer.type
        Decision    = $decision
        Probability = $probability
        Confidence  = $confidence
    }
}

'Readable decisions:'
$summary | Format-Table -AutoSize -Wrap