microsoft/hve-core

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
feat/add-pester-code-coverage

Branches

Tags

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

Clone

HTTPS

Download ZIP

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

262lines · modecode

1#Requires -Modules Pester
2
3<#
4.SYNOPSIS
5 Pester tests for Test-SHAStaleness.ps1 functions.
6
7.DESCRIPTION
8 Tests the staleness checking functions without executing the main script.
9 Uses AST function extraction to avoid running main execution block.
10#>
11
12BeforeAll {
13 $scriptPath = Join-Path $PSScriptRoot '../../security/Test-SHAStaleness.ps1'
14 $scriptContent = Get-Content $scriptPath -Raw
15
16 # Extract function definitions from the script without executing main block
17 # Parse the AST to get function definitions
18 $tokens = $null
19 $errors = $null
20 $ast = [System.Management.Automation.Language.Parser]::ParseInput($scriptContent, [ref]$tokens, [ref]$errors)
21
22 # Extract all function definitions
23 $functionDefs = $ast.FindAll({ $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $true)
24
25 # Define each function in the current scope using ScriptBlock
26 foreach ($func in $functionDefs) {
27 $funcCode = $func.Extent.Text
28 $scriptBlock = [scriptblock]::Create($funcCode)
29 . $scriptBlock
30 }
31
32 $mockPath = Join-Path $PSScriptRoot '../Mocks/GitMocks.psm1'
33 Import-Module $mockPath -Force
34
35 # Save environment before tests
36 Save-GitHubEnvironment
37
38 # Fixture paths
39 $script:FixturesPath = Join-Path $PSScriptRoot '../Fixtures/Security'
40}
41
42AfterAll {
43 # Restore environment after tests
44 Restore-GitHubEnvironment
45}
46
47Describe 'Test-GitHubToken' -Tag 'Unit' {
48 BeforeEach {
49 Initialize-MockGitHubEnvironment
50 }
51
52 AfterEach {
53 Clear-MockGitHubEnvironment
54 }
55
56 Context 'No token provided' {
57 It 'Returns hashtable with Valid=false when empty token provided' {
58 $result = Test-GitHubToken -Token ''
59 $result | Should -BeOfType [hashtable]
60 $result.Valid | Should -BeFalse
61 }
62
63 It 'Returns Authenticated=false when no token provided' {
64 $result = Test-GitHubToken -Token ''
65 $result.Authenticated | Should -BeFalse
66 }
67
68 It 'Returns rate limit of 60 when no token provided' {
69 $result = Test-GitHubToken -Token ''
70 $result.RateLimit | Should -Be 60
71 }
72 }
73
74 Context 'Invalid token' {
75 BeforeEach {
76 Mock Invoke-RestMethod {
77 throw 'Bad credentials'
78 }
79 }
80
81 It 'Returns Valid=false for invalid token' {
82 $result = Test-GitHubToken -Token 'invalid-token'
83 $result.Valid | Should -BeFalse
84 }
85 }
86
87 Context 'Valid token' {
88 BeforeEach {
89 Mock Invoke-RestMethod {
90 return @{
91 data = @{
92 viewer = @{ login = 'testuser' }
93 rateLimit = @{ limit = 5000; remaining = 4999; resetAt = '2024-01-01T00:00:00Z' }
94 }
95 }
96 }
97 }
98
99 It 'Returns Valid=true for valid token' {
100 $result = Test-GitHubToken -Token 'ghp_validtoken123456789'
101 $result.Valid | Should -BeTrue
102 }
103
104 It 'Returns user information for valid token' {
105 $result = Test-GitHubToken -Token 'ghp_validtoken123456789'
106 $result.User | Should -Be 'testuser'
107 }
108
109 It 'Returns rate limit information for valid token' {
110 $result = Test-GitHubToken -Token 'ghp_validtoken123456789'
111 $result.RateLimit | Should -Be 5000
112 $result.Remaining | Should -Be 4999
113 }
114 }
115}
116
117Describe 'Invoke-GitHubAPIWithRetry' -Tag 'Unit' {
118 BeforeEach {
119 Initialize-MockGitHubEnvironment
120 }
121
122 AfterEach {
123 Clear-MockGitHubEnvironment
124 }
125
126 Context 'Successful requests' {
127 It 'Returns response on first successful call' {
128 Mock Invoke-RestMethod {
129 return @{ data = 'success' }
130 }
131
132 $headers = @{ 'Authorization' = 'Bearer test' }
133 $result = Invoke-GitHubAPIWithRetry -Uri 'https://api.github.com/graphql' -Method 'POST' -Headers $headers -Body '{}'
134 $result.data | Should -Be 'success'
135 }
136 }
137
138 Context 'Rate limiting' {
139 It 'Throws on non-rate-limit errors' {
140 Mock Invoke-RestMethod {
141 throw [System.Exception]::new('Network error')
142 }
143
144 $headers = @{ 'Authorization' = 'Bearer test' }
145 { Invoke-GitHubAPIWithRetry -Uri 'https://api.github.com/graphql' -Method 'POST' -Headers $headers -Body '{}' } | Should -Throw
146 }
147 }
148}
149
150Describe 'Write-SecurityLog' -Tag 'Unit' {
151 Context 'Log output' {
152 It 'Does not throw for Info level' {
153 { Write-SecurityLog -Message 'Test message' -Level Info } | Should -Not -Throw
154 }
155
156 It 'Does not throw for Warning level' {
157 { Write-SecurityLog -Message 'Warning message' -Level Warning } | Should -Not -Throw
158 }
159
160 It 'Does not throw for Error level' {
161 { Write-SecurityLog -Message 'Error message' -Level Error } | Should -Not -Throw
162 }
163
164 It 'Does not throw for Success level' {
165 { Write-SecurityLog -Message 'Success message' -Level Success } | Should -Not -Throw
166 }
167 }
168}
169
170Describe 'Compare-ToolVersion' -Tag 'Unit' {
171 Context 'Semantic version comparison' {
172 It 'Returns true when latest is newer major version' {
173 Compare-ToolVersion -Current '1.0.0' -Latest '2.0.0' | Should -BeTrue
174 }
175
176 It 'Returns true when latest is newer minor version' {
177 Compare-ToolVersion -Current '1.0.0' -Latest '1.1.0' | Should -BeTrue
178 }
179
180 It 'Returns true when latest is newer patch version' {
181 Compare-ToolVersion -Current '1.0.0' -Latest '1.0.1' | Should -BeTrue
182 }
183
184 It 'Returns false when current equals latest' {
185 Compare-ToolVersion -Current '1.0.0' -Latest '1.0.0' | Should -BeFalse
186 }
187
188 It 'Returns false when current is newer than latest' {
189 Compare-ToolVersion -Current '2.0.0' -Latest '1.0.0' | Should -BeFalse
190 }
191
192 It 'Handles major version differences correctly' {
193 Compare-ToolVersion -Current '7.0.0' -Latest '8.0.0' | Should -BeTrue
194 }
195
196 It 'Handles minor version differences correctly' {
197 Compare-ToolVersion -Current '8.17.0' -Latest '8.18.0' | Should -BeTrue
198 }
199
200 It 'Handles patch version differences correctly' {
201 Compare-ToolVersion -Current '8.18.1' -Latest '8.18.2' | Should -BeTrue
202 }
203 }
204
205 Context 'Version with v prefix' {
206 It 'Handles v-prefixed versions' {
207 Compare-ToolVersion -Current 'v1.0.0' -Latest 'v2.0.0' | Should -BeTrue
208 }
209
210 It 'Handles mixed v-prefix versions' {
211 Compare-ToolVersion -Current '1.0.0' -Latest 'v2.0.0' | Should -BeTrue
212 }
213
214 It 'Returns false for equal v-prefixed versions' {
215 Compare-ToolVersion -Current 'v1.0.0' -Latest 'v1.0.0' | Should -BeFalse
216 }
217 }
218
219 Context 'Pre-release versions' {
220 It 'Strips pre-release metadata for comparison' {
221 Compare-ToolVersion -Current '1.0.0-alpha' -Latest '1.0.0' | Should -BeFalse
222 }
223
224 It 'Handles build metadata' {
225 Compare-ToolVersion -Current '1.0.0+build123' -Latest '2.0.0' | Should -BeTrue
226 }
227 }
228}
229
230Describe 'Get-ToolStaleness' -Tag 'Integration', 'RequiresNetwork' {
231 Context 'With mock manifest' {
232 BeforeEach {
233 # Create a temporary manifest file
234 $script:TempManifest = Join-Path $TestDrive 'tool-checksums.json'
235 $manifestContent = @{
236 tools = @(
237 @{
238 name = 'test-tool'
239 repo = 'test-org/test-repo'
240 version = '1.0.0'
241 sha256 = 'abc123'
242 notes = 'Test tool'
243 }
244 )
245 } | ConvertTo-Json -Depth 10
246 Set-Content -Path $script:TempManifest -Value $manifestContent
247 }
248
249 It 'Returns results array' -Skip:$true {
250 # Skip by default - requires actual GitHub API access
251 $result = Get-ToolStaleness -ManifestPath $script:TempManifest
252 $result | Should -BeOfType [System.Object[]]
253 }
254 }
255
256 Context 'Missing manifest' {
257 It 'Handles missing manifest gracefully' {
258 $result = Get-ToolStaleness -ManifestPath 'TestDrive:/nonexistent/manifest.json'
259 $result | Should -BeNullOrEmpty
260 }
261 }
262}
263