Public/Test-TriggerFilter.ps1

function Test-TriggerFilter {
    [CmdletBinding()]
    [OutputType([PSCustomObject[]])]
    param(
        [Parameter(Mandatory)]
        [PSCustomObject[]]$WorkflowFiles
    )

    $results = [System.Collections.Generic.List[PSCustomObject]]::new()
    $eventsRequiringTypes = @(
        'discussion',
        'issue_comment',
        'issues',
        'pull_request_review',
        'pull_request_review_comment',
        'project',
        'project_card',
        'project_column'
    )

    foreach ($wf in $WorkflowFiles) {
        $lines = @(($wf.Content -split "`n") | Where-Object { $_ -notmatch '^\s*#' })
        $content = $lines -join "`n"
        $missingTypes = @(Get-MissingTypesEvent -WorkflowContent $content -Events $eventsRequiringTypes)

        if ($missingTypes.Count -eq 0) {
            $results.Add((Format-FylgyrResult `
                -CheckName 'TriggerFilter' `
                -Status 'Pass' `
                -Severity 'Info' `
                -Resource $wf.Path `
                -Detail "Workflow '$($wf.Name)' has no detected trigger events missing types filters." `
                -Remediation 'No action needed.'))
            continue
        }

        $selfHostedRunner = $content -match '(?im)^\s*runs-on\s*:\s*(\[[^\]]*self-hosted[^\]]*\]|.*self-hosted.*)$'
        $runBlocks = @(Get-RunBlock -Content $content)
        $hasUntrustedInterpolation = $false
        foreach ($block in $runBlocks) {
            if ($block.Content -match '(?i)\$\{\{\s*github\.event\.(discussion|issue|issue_comment|comment|review)\.') {
                $hasUntrustedInterpolation = $true
                break
            }
        }

        $escalated = $selfHostedRunner -or $hasUntrustedInterpolation
        $status = if ($escalated) { 'Fail' } else { 'Warning' }
        $severity = if ($escalated) { 'High' } else { 'Medium' }

        $detail = "Workflow '$($wf.Name)' defines trigger(s) without types filters: $($missingTypes -join ', ')."
        if ($escalated) {
            $detail += ' Combined with self-hosted execution or untrusted run interpolation, this increases exposure to obscure event-subtype trigger abuse.'
        }

        $results.Add((Format-FylgyrResult `
            -CheckName 'TriggerFilter' `
            -Status $status `
            -Severity $severity `
            -Resource $wf.Path `
            -Detail $detail `
            -Remediation 'Add explicit types: filters for discussion/comment/review/project events so only intended sub-actions trigger workflow execution.' `
            -AttackMapping @('shai-hulud-runner-backdoor')))
    }

    return $results.ToArray()
}