Skip to content

Commit 08fdd67

Browse files
committed
ci(defender): depend on shared build-package; download single opencode.zip; scan extracted directory; upload detections
1 parent 23e364e commit 08fdd67

1 file changed

Lines changed: 38 additions & 112 deletions

File tree

Lines changed: 38 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,66 @@
11
name: av-windows-defender
22
on:
3-
workflow_dispatch:
4-
inputs:
5-
tag:
6-
description: 'Release tag to scan (e.g., v0.15.16)'
7-
required: false
3+
pull_request:
84
release:
95
types: [published]
10-
pull_request:
11-
branches: [dev]
12-
schedule:
13-
- cron: "0 4 * * 1"
6+
workflow_dispatch:
147

158
permissions:
169
contents: read
1710

1811
jobs:
19-
defender-pr:
20-
if: github.event_name == 'pull_request' || github.event_name == 'push'
21-
runs-on: windows-latest
12+
build:
13+
runs-on: ubuntu-latest
2214
steps:
23-
- uses: actions/checkout@v4
24-
- name: Prepare PR scan payload
25-
id: prep
26-
shell: pwsh
27-
run: |
28-
New-Item -ItemType Directory -Force -Path dist-pr | Out-Null
29-
$zipName = "scan_$env:GITHUB_RUN_ID`_$env:GITHUB_RUN_ATTEMPT.zip"
30-
$zip = Join-Path (Resolve-Path 'dist-pr') $zipName
31-
$srcRoot = if (Test-Path dist) { 'dist' } elseif (Test-Path build) { 'build' } else { '.' }
32-
$scanRoot = (Resolve-Path $srcRoot).Path
33-
$tempZip = Join-Path $env:RUNNER_TEMP ("scan_" + [guid]::NewGuid().ToString() + ".zip")
34-
function Invoke-WithRetry([scriptblock]$Script, [int]$Attempts = 10, [int]$Delay = 2) {
35-
for ($i=1; $i -le $Attempts; $i++) {
36-
try { & $Script; return } catch { if ($i -eq $Attempts) { throw }; Start-Sleep -Seconds $Delay }
37-
}
38-
}
39-
# Create the zip in temp using bsdtar (avoids Compress-Archive locking issues)
40-
Invoke-WithRetry {
41-
if (Test-Path $tempZip) { Remove-Item -Force $tempZip }
42-
if ($srcRoot -eq '.') {
43-
tar -a -c -f $tempZip --exclude=.git --exclude=.github *
44-
} else {
45-
tar -a -c -f $tempZip -C $srcRoot .
46-
}
47-
}
48-
# Move into working dir with retries in case Defender holds the handle
49-
Invoke-WithRetry { Move-Item -Force $tempZip $zip }
50-
"zip=$zip" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
51-
"scan_root=$scanRoot" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
52-
Write-Host "Created payload: $zip | scan_root: $scanRoot"
53-
- name: Windows Defender scan (PR; scan directory to avoid archive skip)
54-
shell: pwsh
55-
run: |
56-
$mp = (Get-Command MpCmdRun.exe -ErrorAction SilentlyContinue).Source
57-
if (-not $mp) { $mp = "$env:ProgramFiles\Windows Defender\MpCmdRun.exe" }
58-
if (-not (Test-Path $mp)) { throw 'MpCmdRun.exe not found' }
59-
$scanRoot = "${{ steps.prep.outputs.scan_root }}"
60-
if (-not $scanRoot) { throw 'scan_root output missing from prep step' }
61-
& $mp -Scan -ScanType 3 -File $scanRoot
62-
- name: Collect Defender detections (PR)
63-
shell: pwsh
64-
run: |
65-
$since = (Get-Date).AddMinutes(-30)
66-
$scanRoot = "${{ steps.prep.outputs.scan_root }}"
67-
$re = [Regex]::Escape($scanRoot)
68-
$recent = Get-MpThreatDetection | Where-Object { $_.InitialDetectionTime -ge $since -and $_.Resources -and ($_.Resources.Resource -match $re) }
69-
if ($recent) {
70-
$recent | ConvertTo-Json -Depth 5 | Out-File dist-pr\defender-pr-detections.json -Encoding UTF8
71-
Write-Host 'Detections found.'
72-
} else { '{"status":"clean"}' | Out-File dist-pr\defender-pr-detections.json -Encoding UTF8 }
73-
- name: Upload PR scan payload & results
15+
- name: Checkout (release tag)
16+
if: github.event_name == 'release'
17+
uses: actions/checkout@v4
18+
with:
19+
ref: ${{ github.event.release.tag_name }}
20+
- name: Checkout (PR/default)
21+
if: github.event_name != 'release'
22+
uses: actions/checkout@v4
23+
- name: Build and package
24+
uses: ./.github/actions/build-package
25+
- name: Upload build bundle
7426
uses: actions/upload-artifact@v4
7527
with:
76-
name: defender-pr-results
77-
path: |
78-
dist-pr/*.zip
79-
dist-pr/defender-pr-detections.json
28+
name: opencode-bundle
29+
path: bundle/opencode.zip
8030

81-
defender-scan:
82-
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule'
83-
name: Windows Defender scan (release assets)
31+
defender:
32+
needs: build
8433
runs-on: windows-latest
85-
permissions:
86-
contents: read
87-
actions: read
8834
steps:
89-
- name: Prepare download dir
90-
shell: pwsh
91-
run: New-Item -ItemType Directory -Force -Path dist-release | Out-Null
92-
- name: Resolve release tag
93-
id: resolve_tag
94-
shell: pwsh
95-
env:
96-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
97-
run: |
98-
$tag = "${{ github.event.release.tag_name }}"
99-
if (-not $tag) { $tag = "${{ github.event.inputs.tag }}" }
100-
if (-not $tag) { $tag = (gh release list --limit 1 --json tagName -q ".[0].tagName") }
101-
if (-not $tag) { throw 'No release tag found' }
102-
"tag=$tag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
103-
- name: Download assets for this release
35+
- name: Download build bundle
36+
uses: actions/download-artifact@v4
37+
with:
38+
name: opencode-bundle
39+
path: bundle
40+
- name: Prepare scan dir
10441
shell: pwsh
105-
env:
106-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
10742
run: |
108-
gh release download "${{ steps.resolve_tag.outputs.tag }}" --dir dist-release --clobber
109-
- name: List assets
110-
shell: pwsh
111-
run: Get-ChildItem -File dist-release | Select-Object FullName, Length | Format-Table | Out-String | Tee-Object -FilePath dist-release\asset-list.txt
112-
- name: Scan each asset with Defender
43+
New-Item -ItemType Directory -Force -Path scan | Out-Null
44+
Expand-Archive -Path bundle/opencode.zip -DestinationPath scan -Force
45+
- name: Windows Defender scan (directory)
11346
shell: pwsh
11447
run: |
11548
$mp = (Get-Command MpCmdRun.exe -ErrorAction SilentlyContinue).Source
11649
if (-not $mp) { $mp = "$env:ProgramFiles\Windows Defender\MpCmdRun.exe" }
11750
if (-not (Test-Path $mp)) { throw 'MpCmdRun.exe not found' }
118-
Get-ChildItem -File dist-release | ForEach-Object {
119-
Write-Host "Scanning $($_.FullName)"
120-
& $mp -Scan -ScanType 3 -File $_.FullName
121-
Start-Sleep -Seconds 3
122-
}
51+
& $mp -Scan -ScanType 3 -File (Resolve-Path 'scan')
52+
- name: Collect Defender detections
53+
shell: pwsh
54+
run: |
12355
$since = (Get-Date).AddMinutes(-30)
124-
$recent = Get-MpThreatDetection | Where-Object {
125-
$_.InitialDetectionTime -ge $since -and
126-
$_.Resources -and ($_.Resources.Resource -match [Regex]::Escape((Resolve-Path "dist-release").Path))
127-
}
56+
$re = [Regex]::Escape((Resolve-Path 'scan').Path)
57+
$recent = Get-MpThreatDetection | Where-Object { $_.InitialDetectionTime -ge $since -and $_.Resources -and ($_.Resources.Resource -match $re) }
12858
if ($recent) {
129-
$recent | ConvertTo-Json -Depth 5 | Out-File dist-release\defender-detections.json -Encoding UTF8
130-
Write-Error "Windows Defender found detections. See artifact."
131-
} else {
132-
'{\"status\":\"clean\"}' | Out-File dist-release\defender-detections.json -Encoding UTF8
133-
}
59+
$recent | ConvertTo-Json -Depth 5 | Out-File defender-detections.json -Encoding UTF8
60+
Write-Error 'Windows Defender found detections. See artifact.'
61+
} else { '{"status":"clean"}' | Out-File defender-detections.json -Encoding UTF8 }
13462
- name: Upload scan results
13563
uses: actions/upload-artifact@v4
13664
with:
13765
name: defender-scan-results
138-
path: |
139-
dist-release/asset-list.txt
140-
dist-release/defender-detections.json
66+
path: defender-detections.json

0 commit comments

Comments
 (0)