microsoft/hve-core

Public

mirrored fromhttps://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
feat-ds-agent

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

scripts/tests/security/Test-ActionVersionConsistency.Tests.ps1

558lines · modecode

1#Requires -Modules Pester
2# Copyright (c) Microsoft Corporation.
3# SPDX-License-Identifier: MIT
4
5using module ../../security/Modules/SecurityClasses.psm1
6
7<#
8.SYNOPSIS
9 Pester tests for Test-ActionVersionConsistency.ps1 functions.
10
11.DESCRIPTION
12 Tests version consistency checking functions without executing the main script.
13 Uses dot-source guard pattern for function isolation.
14#>
15
16BeforeAll {
17 $scriptPath = Join-Path $PSScriptRoot '../../security/Test-ActionVersionConsistency.ps1'
18 . $scriptPath
19
20 $mockPath = Join-Path $PSScriptRoot '../Mocks/GitMocks.psm1'
21 Import-Module $mockPath -Force
22
23 Save-CIEnvironment
24
25 $script:FixturesPath = Join-Path $PSScriptRoot '../Fixtures/Workflows'
26}
27
28AfterAll {
29 Restore-CIEnvironment
30 Remove-Module CIHelpers -Force -ErrorAction SilentlyContinue
31}
32
33Describe 'Write-ConsistencyLog' -Tag 'Unit' {
34 Context 'Log output' {
35 It 'Does not throw for Info level' {
36 { Write-ConsistencyLog -Message 'Test message' -Level Info } | Should -Not -Throw
37 }
38
39 It 'Does not throw for Warning level' {
40 { Write-ConsistencyLog -Message 'Warning message' -Level Warning } | Should -Not -Throw
41 }
42
43 It 'Does not throw for Error level' {
44 { Write-ConsistencyLog -Message 'Error message' -Level Error } | Should -Not -Throw
45 }
46
47 It 'Does not throw for Success level' {
48 { Write-ConsistencyLog -Message 'Success message' -Level Success } | Should -Not -Throw
49 }
50
51 It 'Defaults to Info level when not specified' {
52 { Write-ConsistencyLog -Message 'Default level test' } | Should -Not -Throw
53 }
54 }
55}
56
57Describe 'Get-ActionVersionViolations' -Tag 'Unit' {
58 Context 'Clean workflow (no violations)' {
59 It 'Returns zero violations for fully commented workflow' {
60 $testPath = Join-Path $TestDrive 'clean-workflow-test'
61 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
62 Copy-Item -Path (Join-Path $script:FixturesPath 'consistent-versions.yml') -Destination $testPath
63
64 $result = Get-ActionVersionViolations -WorkflowPath $testPath
65 $result.Violations | Should -BeNullOrEmpty
66 }
67
68 It 'Returns correct TotalActions count' {
69 $testPath = Join-Path $TestDrive 'consistent-test'
70 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
71 Copy-Item -Path (Join-Path $script:FixturesPath 'consistent-versions.yml') -Destination $testPath
72
73 $result = Get-ActionVersionViolations -WorkflowPath $testPath
74 $result.TotalActions | Should -Be 3
75 }
76
77 It 'Returns empty violations array for pinned-workflow.yml' {
78 $testPath = Join-Path $TestDrive 'pinned-test'
79 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
80 Copy-Item -Path (Join-Path $script:FixturesPath 'pinned-workflow.yml') -Destination $testPath
81
82 $result = Get-ActionVersionViolations -WorkflowPath $testPath
83 $result.Violations.Count | Should -Be 0
84 }
85 }
86
87 Context 'Missing version comment (single)' {
88 It 'Detects SHA without version comment' {
89 $testPath = Join-Path $TestDrive 'missing-single'
90 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
91 Copy-Item -Path (Join-Path $script:FixturesPath 'missing-version-comment.yml') -Destination $testPath
92
93 $result = Get-ActionVersionViolations -WorkflowPath $testPath
94 $missingComments = $result.Violations | Where-Object { $_.ViolationType -eq 'MissingVersionComment' }
95 $missingComments.Count | Should -Be 1
96 }
97
98 It 'Returns correct violation properties for missing comment' {
99 $testPath = Join-Path $TestDrive 'missing-props'
100 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
101 Copy-Item -Path (Join-Path $script:FixturesPath 'missing-version-comment.yml') -Destination $testPath
102
103 $result = Get-ActionVersionViolations -WorkflowPath $testPath
104 $violation = $result.Violations | Where-Object { $_.ViolationType -eq 'MissingVersionComment' } | Select-Object -First 1
105
106 $violation.Type | Should -Be 'github-actions'
107 $violation.Severity | Should -Be 'Medium'
108 $violation.Name | Should -Be 'actions/checkout'
109 $violation.Description | Should -Match 'missing version comment'
110 }
111
112 It 'Includes FullSha in violation Metadata' {
113 $testPath = Join-Path $TestDrive 'missing-meta'
114 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
115 Copy-Item -Path (Join-Path $script:FixturesPath 'missing-version-comment.yml') -Destination $testPath
116
117 $result = Get-ActionVersionViolations -WorkflowPath $testPath
118 $violation = $result.Violations | Where-Object { $_.ViolationType -eq 'MissingVersionComment' } | Select-Object -First 1
119
120 $violation.Metadata.FullSha | Should -Be 'a5ac7e51b41094c92402da3b24376905380afc29'
121 }
122 }
123
124 Context 'Missing version comments (multiple)' {
125 It 'Detects all missing version comments' {
126 $testPath = Join-Path $TestDrive 'missing-multiple'
127 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
128 Copy-Item -Path (Join-Path $script:FixturesPath 'multiple-missing-comments.yml') -Destination $testPath
129
130 $result = Get-ActionVersionViolations -WorkflowPath $testPath
131 $missingComments = $result.Violations | Where-Object { $_.ViolationType -eq 'MissingVersionComment' }
132 $missingComments.Count | Should -Be 3
133 }
134
135 It 'Returns unique line numbers for each violation' {
136 $testPath = Join-Path $TestDrive 'missing-lines'
137 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
138 Copy-Item -Path (Join-Path $script:FixturesPath 'multiple-missing-comments.yml') -Destination $testPath
139
140 $result = Get-ActionVersionViolations -WorkflowPath $testPath
141 $lines = $result.Violations | ForEach-Object { $_.Line } | Sort-Object -Unique
142 $lines.Count | Should -Be $result.Violations.Count
143 }
144 }
145
146 Context 'Version mismatch detection' {
147 It 'Detects version mismatch for same SHA across files' {
148 $testPath = Join-Path $TestDrive 'mismatch-test'
149 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
150 Copy-Item -Path (Join-Path $script:FixturesPath 'version-mismatch-a.yml') -Destination $testPath
151 Copy-Item -Path (Join-Path $script:FixturesPath 'version-mismatch-b.yml') -Destination $testPath
152
153 $result = Get-ActionVersionViolations -WorkflowPath $testPath
154 $mismatches = $result.Violations | Where-Object { $_.ViolationType -eq 'VersionMismatch' }
155 $mismatches.Count | Should -Be 1
156 }
157
158 It 'Returns High severity for version mismatch' {
159 $testPath = Join-Path $TestDrive 'mismatch-severity'
160 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
161 Copy-Item -Path (Join-Path $script:FixturesPath 'version-mismatch-a.yml') -Destination $testPath
162 Copy-Item -Path (Join-Path $script:FixturesPath 'version-mismatch-b.yml') -Destination $testPath
163
164 $result = Get-ActionVersionViolations -WorkflowPath $testPath
165 $mismatch = $result.Violations | Where-Object { $_.ViolationType -eq 'VersionMismatch' } | Select-Object -First 1
166 $mismatch.Severity | Should -Be 'High'
167 }
168
169 It 'Includes conflicting versions in Metadata' {
170 $testPath = Join-Path $TestDrive 'mismatch-meta'
171 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
172 Copy-Item -Path (Join-Path $script:FixturesPath 'version-mismatch-a.yml') -Destination $testPath
173 Copy-Item -Path (Join-Path $script:FixturesPath 'version-mismatch-b.yml') -Destination $testPath
174
175 $result = Get-ActionVersionViolations -WorkflowPath $testPath
176 $mismatch = $result.Violations | Where-Object { $_.ViolationType -eq 'VersionMismatch' } | Select-Object -First 1
177 $mismatch.Metadata.ConflictingVersions | Should -Match 'v4\.1\.0'
178 $mismatch.Metadata.ConflictingVersions | Should -Match 'v4\.1\.6'
179 }
180
181 It 'Includes affected locations in Metadata' {
182 $testPath = Join-Path $TestDrive 'mismatch-locations'
183 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
184 Copy-Item -Path (Join-Path $script:FixturesPath 'version-mismatch-a.yml') -Destination $testPath
185 Copy-Item -Path (Join-Path $script:FixturesPath 'version-mismatch-b.yml') -Destination $testPath
186
187 $result = Get-ActionVersionViolations -WorkflowPath $testPath
188 $mismatch = $result.Violations | Where-Object { $_.ViolationType -eq 'VersionMismatch' } | Select-Object -First 1
189 $mismatch.Metadata.AffectedLocations.Count | Should -Be 2
190 }
191 }
192
193 Context 'Non-existent path handling' {
194 BeforeAll {
195 # Use platform-agnostic path that guaranteed doesn't exist
196 $script:NonExistentPath = Join-Path ([System.IO.Path]::GetTempPath()) "nonexistent-$(New-Guid)"
197 }
198
199 It 'Returns empty violations for non-existent path' {
200 $result = Get-ActionVersionViolations -WorkflowPath $script:NonExistentPath
201 $result.Violations | Should -BeNullOrEmpty
202 }
203
204 It 'Returns zero TotalActions for non-existent path' {
205 $result = Get-ActionVersionViolations -WorkflowPath $script:NonExistentPath
206 $result.TotalActions | Should -Be 0
207 }
208
209 It 'Returns empty ShaVersionMap for non-existent path' {
210 $result = Get-ActionVersionViolations -WorkflowPath $script:NonExistentPath
211 $result.ShaVersionMap.Count | Should -Be 0
212 }
213 }
214
215 Context 'Empty directory handling' {
216 It 'Returns empty violations for empty directory' {
217 $emptyPath = Join-Path $TestDrive 'empty-workflows'
218 New-Item -ItemType Directory -Path $emptyPath -Force | Out-Null
219
220 $result = Get-ActionVersionViolations -WorkflowPath $emptyPath
221 $result.Violations | Should -BeNullOrEmpty
222 }
223
224 It 'Returns zero TotalActions for empty directory' {
225 $emptyPath = Join-Path $TestDrive 'empty-workflows-count'
226 New-Item -ItemType Directory -Path $emptyPath -Force | Out-Null
227
228 $result = Get-ActionVersionViolations -WorkflowPath $emptyPath
229 $result.TotalActions | Should -Be 0
230 }
231 }
232
233 Context 'Mixed violations (both types in one scan)' {
234 It 'Detects both mismatch and missing comment violations' {
235 $testPath = Join-Path $TestDrive 'mixed-violations'
236 New-Item -ItemType Directory -Path $testPath -Force | Out-Null
237 Copy-Item -Path (Join-Path $script:FixturesPath 'version-mismatch-a.yml') -Destination $testPath
238 Copy-Item -Path (Join-Path $script:FixturesPath 'version-mismatch-b.yml') -Destination $testPath
239 Copy-Item -Path (Join-Path $script:FixturesPath 'missing-version-comment.yml') -Destination $testPath
240
241 $result = Get-ActionVersionViolations -WorkflowPath $testPath
242 $mismatches = @($result.Violations | Where-Object { $_.ViolationType -eq 'VersionMismatch' })
243 $missingComments = @($result.Violations | Where-Object { $_.ViolationType -eq 'MissingVersionComment' })
244
245 $mismatches.Count | Should -BeGreaterThan 0
246 $missingComments.Count | Should -BeGreaterThan 0
247 }
248 }
249}
250
251Describe 'Export-ConsistencyReport' -Tag 'Unit' {
252 BeforeEach {
253 $script:TestOutputPath = Join-Path $TestDrive 'report'
254 New-Item -ItemType Directory -Path $script:TestOutputPath -Force | Out-Null
255
256 # Create mock violations
257 $script:MockViolations = @()
258
259 $v1 = [DependencyViolation]::new()
260 $v1.File = 'workflow.yml'
261 $v1.Line = 10
262 $v1.Type = 'github-actions'
263 $v1.Name = 'actions/checkout'
264 $v1.Version = 'a5ac7e5'
265 $v1.Severity = 'Medium'
266 $v1.ViolationType = 'MissingVersionComment'
267 $v1.Description = 'SHA-pinned action missing version comment'
268 $v1.Remediation = 'Add version comment'
269 $v1.Metadata = @{ FullSha = 'a5ac7e51b41094c92402da3b24376905380afc29' }
270 $script:MockViolations += $v1
271
272 $v2 = [DependencyViolation]::new()
273 $v2.File = 'other.yml'
274 $v2.Line = 15
275 $v2.Type = 'github-actions'
276 $v2.Name = 'actions/setup-node'
277 $v2.Version = '60edb5d'
278 $v2.Severity = 'High'
279 $v2.ViolationType = 'VersionMismatch'
280 $v2.Description = 'Same SHA has conflicting version comments'
281 $v2.Remediation = 'Standardize version comment'
282 $v2.Metadata = @{ ConflictingVersions = 'v4.0.0, v4.0.2' }
283 $script:MockViolations += $v2
284 }
285
286 Context 'Table format output' {
287 It 'Does not throw for Table format' {
288 { Export-ConsistencyReport -Violations $script:MockViolations -Format Table -TotalActions 5 } | Should -Not -Throw
289 }
290
291 It 'Writes file when OutputPath specified' {
292 $outputFile = Join-Path $script:TestOutputPath 'report.txt'
293 Export-ConsistencyReport -Violations $script:MockViolations -Format Table -OutputPath $outputFile -TotalActions 5
294 Test-Path $outputFile | Should -BeTrue
295 }
296
297 It 'Reports success message when no violations' {
298 # Capture Host output
299 $output = Export-ConsistencyReport -Violations @() -Format Table -TotalActions 0 6>&1
300 ($output -join ' ') | Should -Match 'No version consistency violations found'
301 }
302 }
303
304 Context 'JSON format with OutputPath' {
305 It 'Generates valid JSON' {
306 $outputFile = Join-Path $script:TestOutputPath 'report.json'
307 Export-ConsistencyReport -Violations $script:MockViolations -Format Json -OutputPath $outputFile -TotalActions 5
308
309 Test-Path $outputFile | Should -BeTrue
310 $content = Get-Content $outputFile -Raw
311 { $content | ConvertFrom-Json } | Should -Not -Throw
312 }
313
314 It 'Includes Timestamp field' {
315 $outputFile = Join-Path $script:TestOutputPath 'report-ts.json'
316 Export-ConsistencyReport -Violations $script:MockViolations -Format Json -OutputPath $outputFile -TotalActions 5
317
318 $rawContent = Get-Content $outputFile -Raw
319 $rawContent | Should -Match '"Timestamp":\s*"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}'
320 }
321
322 It 'Includes TotalActions count' {
323 $outputFile = Join-Path $script:TestOutputPath 'report-total.json'
324 Export-ConsistencyReport -Violations $script:MockViolations -Format Json -OutputPath $outputFile -TotalActions 10
325
326 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
327 $content.TotalActions | Should -Be 10
328 }
329
330 It 'Includes MismatchCount' {
331 $outputFile = Join-Path $script:TestOutputPath 'report-mismatch.json'
332 Export-ConsistencyReport -Violations $script:MockViolations -Format Json -OutputPath $outputFile -TotalActions 5
333
334 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
335 $content.MismatchCount | Should -Be 1
336 }
337
338 It 'Includes MissingComments count' {
339 $outputFile = Join-Path $script:TestOutputPath 'report-missing.json'
340 Export-ConsistencyReport -Violations $script:MockViolations -Format Json -OutputPath $outputFile -TotalActions 5
341
342 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
343 $content.MissingComments | Should -Be 1
344 }
345
346 It 'Includes Violations array' {
347 $outputFile = Join-Path $script:TestOutputPath 'report-violations.json'
348 Export-ConsistencyReport -Violations $script:MockViolations -Format Json -OutputPath $outputFile -TotalActions 5
349
350 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
351 $content.Violations.Count | Should -Be 2
352 }
353 }
354
355 Context 'SARIF format schema validation' {
356 It 'Generates valid SARIF structure' {
357 $outputFile = Join-Path $script:TestOutputPath 'report.sarif'
358 Export-ConsistencyReport -Violations $script:MockViolations -Format Sarif -OutputPath $outputFile -TotalActions 5
359
360 Test-Path $outputFile | Should -BeTrue
361 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
362 $content.version | Should -Be '2.1.0'
363 }
364
365 It 'Includes schema reference' {
366 $outputFile = Join-Path $script:TestOutputPath 'report-schema.sarif'
367 Export-ConsistencyReport -Violations $script:MockViolations -Format Sarif -OutputPath $outputFile -TotalActions 5
368
369 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
370 $content.'$schema' | Should -Match 'sarif-2\.1\.0\.json'
371 }
372
373 It 'Includes tool driver information' {
374 $outputFile = Join-Path $script:TestOutputPath 'report-tool.sarif'
375 Export-ConsistencyReport -Violations $script:MockViolations -Format Sarif -OutputPath $outputFile -TotalActions 5
376
377 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
378 $content.runs[0].tool.driver.name | Should -Be 'action-version-consistency'
379 }
380
381 It 'Maps violations to SARIF results' {
382 $outputFile = Join-Path $script:TestOutputPath 'report-results.sarif'
383 Export-ConsistencyReport -Violations $script:MockViolations -Format Sarif -OutputPath $outputFile -TotalActions 5
384
385 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
386 $content.runs[0].results.Count | Should -Be 2
387 }
388
389 It 'Maps MissingVersionComment to warning level' {
390 $outputFile = Join-Path $script:TestOutputPath 'report-warning.sarif'
391 Export-ConsistencyReport -Violations $script:MockViolations -Format Sarif -OutputPath $outputFile -TotalActions 5
392
393 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
394 $warningResult = $content.runs[0].results | Where-Object { $_.ruleId -eq 'missing-version-comment' }
395 $warningResult.level | Should -Be 'warning'
396 }
397
398 It 'Maps VersionMismatch to error level' {
399 $outputFile = Join-Path $script:TestOutputPath 'report-error.sarif'
400 Export-ConsistencyReport -Violations $script:MockViolations -Format Sarif -OutputPath $outputFile -TotalActions 5
401
402 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
403 $errorResult = $content.runs[0].results | Where-Object { $_.ruleId -eq 'version-mismatch' }
404 $errorResult.level | Should -Be 'error'
405 }
406
407 It 'Includes locations with file and line' {
408 $outputFile = Join-Path $script:TestOutputPath 'report-locations.sarif'
409 Export-ConsistencyReport -Violations $script:MockViolations -Format Sarif -OutputPath $outputFile -TotalActions 5
410
411 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
412 $result = $content.runs[0].results[0]
413 $result.locations[0].physicalLocation.artifactLocation.uri | Should -Not -BeNullOrEmpty
414 $result.locations[0].physicalLocation.region.startLine | Should -BeGreaterThan 0
415 }
416 }
417
418 Context 'Empty violations array' {
419 It 'Handles empty violations for JSON format' {
420 $outputFile = Join-Path $script:TestOutputPath 'empty.json'
421 Export-ConsistencyReport -Violations @() -Format Json -OutputPath $outputFile -TotalActions 0
422
423 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
424 $content.Violations.Count | Should -Be 0
425 $content.MismatchCount | Should -Be 0
426 $content.MissingComments | Should -Be 0
427 }
428
429 It 'Handles empty violations for SARIF format' {
430 $outputFile = Join-Path $script:TestOutputPath 'empty.sarif'
431 Export-ConsistencyReport -Violations @() -Format Sarif -OutputPath $outputFile -TotalActions 0
432
433 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
434 $content.runs[0].results.Count | Should -Be 0
435 }
436 }
437
438 Context 'Multiple violations of each type' {
439 BeforeEach {
440 $script:MultipleViolations = @()
441
442 # Add 3 MissingVersionComment violations
443 for ($i = 1; $i -le 3; $i++) {
444 $v = [DependencyViolation]::new()
445 $v.File = "workflow$i.yml"
446 $v.Line = $i * 10
447 $v.Type = 'github-actions'
448 $v.Name = "actions/action$i"
449 $v.Version = "sha$i"
450 $v.Severity = 'Medium'
451 $v.ViolationType = 'MissingVersionComment'
452 $v.Description = 'Missing comment'
453 $script:MultipleViolations += $v
454 }
455
456 # Add 2 VersionMismatch violations
457 for ($i = 1; $i -le 2; $i++) {
458 $v = [DependencyViolation]::new()
459 $v.File = "mismatch$i.yml"
460 $v.Line = $i * 5
461 $v.Type = 'github-actions'
462 $v.Name = "actions/mismatch$i"
463 $v.Version = "msha$i"
464 $v.Severity = 'High'
465 $v.ViolationType = 'VersionMismatch'
466 $v.Description = 'Version mismatch'
467 $script:MultipleViolations += $v
468 }
469 }
470
471 It 'Counts multiple MissingVersionComment violations correctly' {
472 $outputFile = Join-Path $script:TestOutputPath 'multiple.json'
473 Export-ConsistencyReport -Violations $script:MultipleViolations -Format Json -OutputPath $outputFile -TotalActions 10
474
475 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
476 $content.MissingComments | Should -Be 3
477 }
478
479 It 'Counts multiple VersionMismatch violations correctly' {
480 $outputFile = Join-Path $script:TestOutputPath 'multiple-mismatch.json'
481 Export-ConsistencyReport -Violations $script:MultipleViolations -Format Json -OutputPath $outputFile -TotalActions 10
482
483 $content = Get-Content $outputFile -Raw | ConvertFrom-Json
484 $content.MismatchCount | Should -Be 2
485 }
486 }
487}
488
489Describe 'Main Script Execution' -Tag 'Unit' {
490 BeforeAll {
491 $script:TestScript = (Resolve-Path (Join-Path $PSScriptRoot '../../security/Test-ActionVersionConsistency.ps1')).Path
492 $script:FixturesPath = Join-Path $PSScriptRoot '../Fixtures/Workflows'
493 # Use cross-platform temp directory (accessible from child process, unlike $TestDrive)
494 $tempBase = [System.IO.Path]::GetTempPath()
495 $script:MainTestRoot = Join-Path $tempBase "pester-main-$(Get-Random)"
496 New-Item -ItemType Directory -Path $script:MainTestRoot -Force | Out-Null
497 }
498
499 AfterAll {
500 if ($script:MainTestRoot -and (Test-Path $script:MainTestRoot)) {
501 Remove-Item -Path $script:MainTestRoot -Recurse -Force -ErrorAction SilentlyContinue
502 }
503 }
504
505 Context 'Exit code handling' {
506 BeforeEach {
507 $script:TestWorkspace = Join-Path $script:MainTestRoot "test-$(Get-Random)"
508 New-Item -ItemType Directory -Path $script:TestWorkspace -Force | Out-Null
509 }
510
511 AfterEach {
512 if ($script:TestWorkspace -and (Test-Path $script:TestWorkspace)) {
513 Remove-Item -Path $script:TestWorkspace -Recurse -Force -ErrorAction SilentlyContinue
514 }
515 }
516
517 It 'Returns exit code 0 when no violations and no fail flags' {
518 Copy-Item -Path (Join-Path $script:FixturesPath 'pinned-workflow.yml') -Destination $script:TestWorkspace
519
520 $null = pwsh -NoProfile -Command "& '$script:TestScript' -Path '$script:TestWorkspace' -Format Json" 2>&1
521 $LASTEXITCODE | Should -Be 0
522 }
523
524 It 'Returns exit code 1 when FailOnMismatch and mismatches exist' {
525 Copy-Item -Path (Join-Path $script:FixturesPath 'version-mismatch-a.yml') -Destination $script:TestWorkspace
526 Copy-Item -Path (Join-Path $script:FixturesPath 'version-mismatch-b.yml') -Destination $script:TestWorkspace
527
528 $tempScript = Join-Path $script:TestWorkspace 'run-test.ps1'
529 $scriptContent = @"
530& '$($script:TestScript)' -Path '$($script:TestWorkspace)' -Format Json -FailOnMismatch
531exit `$LASTEXITCODE
532"@
533 Set-Content -Path $tempScript -Value $scriptContent
534 $proc = Start-Process -FilePath 'pwsh' -ArgumentList @('-NoProfile', '-File', $tempScript) -Wait -PassThru -NoNewWindow
535 $proc.ExitCode | Should -Be 1
536 }
537
538 It 'Returns exit code 1 when FailOnMissingComment and missing comments exist' {
539 Copy-Item -Path (Join-Path $script:FixturesPath 'missing-version-comment.yml') -Destination $script:TestWorkspace
540
541 $tempScript = Join-Path $script:TestWorkspace 'run-test.ps1'
542 $scriptContent = @"
543& '$($script:TestScript)' -Path '$($script:TestWorkspace)' -Format Json -FailOnMissingComment
544exit `$LASTEXITCODE
545"@
546 Set-Content -Path $tempScript -Value $scriptContent
547 $proc = Start-Process -FilePath 'pwsh' -ArgumentList @('-NoProfile', '-File', $tempScript) -Wait -PassThru -NoNewWindow
548 $proc.ExitCode | Should -Be 1
549 }
550
551 It 'Returns exit code 0 when violations exist but no fail flags set' {
552 Copy-Item -Path (Join-Path $script:FixturesPath 'missing-version-comment.yml') -Destination $script:TestWorkspace
553
554 $null = pwsh -NoProfile -Command "& '$script:TestScript' -Path '$script:TestWorkspace' -Format Json" 2>&1
555 $LASTEXITCODE | Should -Be 0
556 }
557 }
558}
559