@@ -155,6 +155,9 @@ jobs:
155155 needs : package
156156 runs-on : windows-latest
157157 steps :
158+ - name : Checkout code
159+ uses : actions/checkout@v5
160+
158161 - name : Install MSI
159162 uses : actions/download-artifact@v4
160163 with :
@@ -164,11 +167,131 @@ jobs:
164167 - name : Install MSI
165168 shell : pwsh
166169 run : |
167- msiexec /i modsecurityiis.msi /qn /norestart
168- Restart-Service W3SVC
170+ $msiPath = "${{ github.workspace }}\modsecurityiis.msi"
171+ if (-not (Test-Path $msiPath)) {
172+ Write-Error "MSI file not found at $msiPath"
173+ exit 1
174+ }
175+
176+ # Install with logging for debugging
177+ $installLog = "${{ github.workspace }}\install.log"
178+ $installResult = Start-Process -FilePath "msiexec.exe" -ArgumentList @(
179+ "/i", "`"$msiPath`"",
180+ "/qn",
181+ "/norestart",
182+ "/l*", "`"$installLog`""
183+ ) -Wait -PassThru
169184
185+ if ($installResult.ExitCode -ne 0) {
186+ Write-Error "MSI installation failed with exit code $($installResult.ExitCode)"
187+ Get-Content $installLog | Write-Host
188+ exit 1
189+ }
190+
191+ $installDir = "C:\Program Files\ModSecurity IIS"
192+ $requiredFiles = @(
193+ "modsecurity.conf",
194+ "modsecurity_iis.conf"
195+ )
196+
197+ foreach ($file in $requiredFiles) {
198+ $filePath = Join-Path $installDir $file
199+ if (-not (Test-Path $filePath)) {
200+ Write-Error "Required file $file not found in installation directory"
201+ exit 1
202+ }
203+ }
204+
205+ - name : Install OWASP Core Rules
206+ shell : pwsh
207+ run : |
208+ $crsVersion = "v4.18.0"
209+ $crsUrl = "https://github.com/coreruleset/coreruleset/archive/refs/tags/$crsVersion.tar.gz"
210+ $crsDir = "C:\Program Files\ModSecurity IIS\coreruleset"
211+ $modSecurityConfigDir = "C:\Program Files\ModSecurity IIS"
212+
213+ try {
214+ New-Item -ItemType Directory -Path $crsDir -Force
215+ Invoke-WebRequest -Uri $crsUrl -OutFile "$crsDir\$crsVersion.tar.gz"
216+ tar -xzf "$crsDir\$crsVersion.tar.gz" -C $crsDir --strip-components=1
217+
218+ Get-ChildItem "$crsDir" -Recurse -Filter "*.example" | ForEach-Object {
219+ $newName = $_.Name.Replace(".example", "")
220+ Rename-Item -Path $_.FullName -NewName $newName
221+ }
222+
223+ $modSecurityConfigFile = "$modSecurityConfigDir\modsecurity_iis.conf"
224+
225+ $crsRules = @(
226+ "Include coreruleset/crs-setup.conf",
227+ "Include coreruleset/rules/*.conf",
228+ "Include coreruleset/plugins/*-config.conf",
229+ "Include coreruleset/plugins/*-before.conf",
230+ "Include coreruleset/rules/*.conf",
231+ "Include coreruleset/plugins/*-after.conf"
232+ )
233+
234+ Add-Content -Path $modSecurityConfigFile -Value $crsRules
235+
236+ (Get-Content -Path $modSecurityConfigDir\modsecurity.conf) -replace 'SecRuleEngine DetectionOnly', 'SecRuleEngine On' | Set-Content -Path $modSecurityConfigDir\modsecurity.conf
237+
238+ }
239+ catch {
240+ Write-Error "Failed to install OWASP Core Rules: $($_.Exception.Message)"
241+ exit 1
242+ }
243+
170244 - name : Test IIS Module
171245 shell : pwsh
172246 run : |
173- curl -I http://localhost/
174- Get-EventLog -LogName Application -Newest 10
247+ $iisConfigDir = "C:\Program Files\ModSecurity IIS\"
248+
249+ Restart-Service W3SVC -Force
250+
251+ $modules = & "$env:SystemRoot\system32\inetsrv\appcmd.exe" list modules
252+ if ($LASTEXITCODE -ne 0) {
253+ Write-Error "appcmd failed with exit code $LASTEXITCODE"
254+ exit 1
255+ }
256+
257+ if (-not ($modules -match "ModSecurity")) {
258+ Write-Error "ModSecurity module not found in IIS modules"
259+ Write-Host "IIS modules: $modules"
260+ exit 1
261+ }
262+
263+ $testCases = @(
264+ @{Url = "http://localhost/"; Description = "Normal request"; ExpectedCode = 200},
265+ @{Url = "http://localhost/?id=1' OR '1'='1"; Description = "SQL injection attempt"; ExpectedCode = 403},
266+ @{Url = "http://localhost/?q=<script>alert('test')</script>"; Description = "XSS attempt"; ExpectedCode = 403}
267+ )
268+
269+ foreach ($test in $testCases) {
270+ try {
271+ $response = Invoke-WebRequest $test.Url -UseBasicParsing -SkipHttpErrorCheck -TimeoutSec 30
272+
273+ if ($response.StatusCode -eq $test.ExpectedCode) {
274+ Write-Host "PASS: $($test.Description) - returned $($response.StatusCode)"
275+ }
276+ else {
277+ Write-Host "FAIL: $($test.Description) - expected $($test.ExpectedCode) but got $($response.StatusCode)"
278+ }
279+ }
280+ catch {
281+ Write-Host "ERROR: $($test.Description) - request failed: $($_.Exception.Message)"
282+ }
283+ }
284+
285+
286+ # Check event log
287+ $badMessagePattern = 'Failed to find the RegisterModule entrypoint|The description for Event ID|The data is the error|dll failed to load'
288+
289+ $events = Get-EventLog -LogName Application -Newest 100 |
290+ Where-Object { $_.Message -match $badMessagePattern } |
291+ Where-Object { $_.Source -match 'IIS|W3SVC|mscor|IIS-W3SVC|IIS-W3WP|ModSecurity' }
292+
293+ if ($events -and $events.Count -gt 0) {
294+ Write-Host '::error:: Found errors in event log'
295+ $events | Select-Object TimeGenerated, Source, EntryType, EventID, Message | Format-List
296+ Exit 1
297+ }
0 commit comments