microsoft/hve-core

Public

mirrored from https://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/research-single-dynamic-rewrite

Branches

Tags

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

Clone

HTTPS

Download ZIP

scripts/tests/lib/Get-VerifiedDownload.Tests.ps1

535lines · modecode

1#Requires -Modules Pester
2# Copyright (c) Microsoft Corporation.
3# SPDX-License-Identifier: MIT
4
5BeforeAll {
6 . $PSScriptRoot/../../lib/Get-VerifiedDownload.ps1
7}
8
9Describe 'Get-FileHashValue' {
10 It 'Returns uppercase hash string for valid file' {
11 $tempFile = New-TemporaryFile
12 try {
13 'test content' | Set-Content -Path $tempFile.FullName -NoNewline
14 $result = Get-FileHashValue -Path $tempFile.FullName -Algorithm 'SHA256'
15 $result | Should -BeOfType [string]
16 $result | Should -Match '^[A-F0-9]{64}$'
17 } finally {
18 Remove-Item -Path $tempFile.FullName -Force -ErrorAction SilentlyContinue
19 }
20 }
21
22 It 'Supports SHA384 algorithm' {
23 $tempFile = New-TemporaryFile
24 try {
25 'test' | Set-Content -Path $tempFile.FullName -NoNewline
26 $result = Get-FileHashValue -Path $tempFile.FullName -Algorithm 'SHA384'
27 $result | Should -Match '^[A-F0-9]{96}$'
28 } finally {
29 Remove-Item -Path $tempFile.FullName -Force -ErrorAction SilentlyContinue
30 }
31 }
32
33 It 'Supports SHA512 algorithm' {
34 $tempFile = New-TemporaryFile
35 try {
36 'test' | Set-Content -Path $tempFile.FullName -NoNewline
37 $result = Get-FileHashValue -Path $tempFile.FullName -Algorithm 'SHA512'
38 $result | Should -Match '^[A-F0-9]{128}$'
39 } finally {
40 Remove-Item -Path $tempFile.FullName -Force -ErrorAction SilentlyContinue
41 }
42 }
43}
44
45Describe 'Test-HashMatch' {
46 It 'Returns true when hashes match (case-insensitive)' {
47 $result = Test-HashMatch -ComputedHash 'ABC123' -ExpectedHash 'abc123'
48 $result | Should -BeTrue
49 }
50
51 It 'Returns false when hashes do not match' {
52 $result = Test-HashMatch -ComputedHash 'ABC123' -ExpectedHash 'DEF456'
53 $result | Should -BeFalse
54 }
55
56 It 'Returns true when hashes match exactly' {
57 $result = Test-HashMatch -ComputedHash 'ABC123DEF456' -ExpectedHash 'ABC123DEF456'
58 $result | Should -BeTrue
59 }
60}
61
62Describe 'Get-DownloadTargetPath' {
63 BeforeAll {
64 $script:testDir = [System.IO.Path]::GetTempPath().TrimEnd([System.IO.Path]::DirectorySeparatorChar)
65 }
66
67 It 'Uses filename from URL when FileName not specified' {
68 $result = Get-DownloadTargetPath -Url 'https://example.com/file.zip' -DestinationDirectory $script:testDir
69 $expected = [System.IO.Path]::Combine($script:testDir, 'file.zip')
70 $result | Should -Be $expected
71 }
72
73 It 'Uses explicit FileName when specified' {
74 $result = Get-DownloadTargetPath -Url 'https://example.com/file.zip' -DestinationDirectory $script:testDir -FileName 'custom.zip'
75 $expected = [System.IO.Path]::Combine($script:testDir, 'custom.zip')
76 $result | Should -Be $expected
77 }
78
79 It 'Handles URL with query parameters' {
80 $result = Get-DownloadTargetPath -Url 'https://example.com/file.zip?token=abc' -DestinationDirectory $script:testDir
81 $expected = [System.IO.Path]::Combine($script:testDir, 'file.zip')
82 $result | Should -Be $expected
83 }
84}
85
86Describe 'Test-ExistingFileValid' {
87 It 'Returns true when file exists with matching hash' {
88 $tempFile = New-TemporaryFile
89 try {
90 'known content' | Set-Content -Path $tempFile.FullName -NoNewline
91 $expectedHash = (Get-FileHash -Path $tempFile.FullName -Algorithm SHA256).Hash
92 $result = Test-ExistingFileValid -Path $tempFile.FullName -ExpectedHash $expectedHash -Algorithm 'SHA256'
93 $result | Should -BeTrue
94 } finally {
95 Remove-Item -Path $tempFile.FullName -Force -ErrorAction SilentlyContinue
96 }
97 }
98
99 It 'Returns false when file exists with non-matching hash' {
100 $tempFile = New-TemporaryFile
101 try {
102 'some content' | Set-Content -Path $tempFile.FullName -NoNewline
103 $result = Test-ExistingFileValid -Path $tempFile.FullName -ExpectedHash 'INVALID_HASH' -Algorithm 'SHA256'
104 $result | Should -BeFalse
105 } finally {
106 Remove-Item -Path $tempFile.FullName -Force -ErrorAction SilentlyContinue
107 }
108 }
109
110 It 'Returns false when file does not exist' {
111 $nonexistentPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), 'nonexistent-dir-12345', 'file.txt')
112 $result = Test-ExistingFileValid -Path $nonexistentPath -ExpectedHash 'ABC123' -Algorithm 'SHA256'
113 $result | Should -BeFalse
114 }
115}
116
117Describe 'New-DownloadResult' {
118 It 'Creates hashtable with all properties' {
119 $result = New-DownloadResult -Path 'C:\file.zip' -WasDownloaded $true -HashVerified $true
120 $result | Should -BeOfType [hashtable]
121 $result.Path | Should -Be 'C:\file.zip'
122 $result.WasDownloaded | Should -BeTrue
123 $result.HashVerified | Should -BeTrue
124 }
125
126 It 'Handles false values correctly' {
127 $result = New-DownloadResult -Path 'C:\cached.zip' -WasDownloaded $false -HashVerified $true
128 $result.WasDownloaded | Should -BeFalse
129 $result.HashVerified | Should -BeTrue
130 }
131}
132
133Describe 'Get-ArchiveType' {
134 It 'Returns tar.gz for .tar.gz files' {
135 $result = Get-ArchiveType -Path 'archive.tar.gz'
136 $result | Should -Be 'tar.gz'
137 }
138
139 It 'Returns tar.gz for .tgz files' {
140 $result = Get-ArchiveType -Path 'archive.tgz'
141 $result | Should -Be 'tar.gz'
142 }
143
144 It 'Returns tar for plain .tar files' {
145 $result = Get-ArchiveType -Path 'archive.tar'
146 $result | Should -Be 'tar'
147 }
148
149 It 'Returns zip for .zip files' {
150 $result = Get-ArchiveType -Path 'archive.zip'
151 $result | Should -Be 'zip'
152 }
153
154 It 'Returns unknown for unrecognized extensions' {
155 $result = Get-ArchiveType -Path 'file.txt'
156 $result | Should -Be 'unknown'
157 }
158
159 It 'Handles paths with directories' {
160 $result = Get-ArchiveType -Path 'C:\downloads\archive.tar.gz'
161 $result | Should -Be 'tar.gz'
162 }
163}
164
165Describe 'Test-TarAvailable' {
166 It 'Returns boolean indicating tar availability' {
167 $result = Test-TarAvailable
168 $result | Should -BeOfType [bool]
169 }
170}
171
172Describe 'Invoke-VerifiedDownload' {
173 BeforeAll {
174 $script:testDestDir = Join-Path $TestDrive 'downloads'
175 $script:testUrl = 'https://example.com/tool.zip'
176 $script:testHash = 'ABC123DEF456ABC123DEF456ABC123DEF456ABC123DEF456ABC123DEF456ABCD'
177 }
178
179 BeforeEach {
180 # Clean test directory before each test
181 if (Test-Path $script:testDestDir) {
182 Remove-Item -Path $script:testDestDir -Recurse -Force
183 }
184 }
185
186 Context 'Skip when valid file exists' {
187 BeforeAll {
188 Mock Write-Verbose { }
189 }
190
191 It 'Skips download when existing file hash matches' {
192 # Create a pre-existing file with matching hash
193 New-Item -ItemType Directory -Path $script:testDestDir -Force | Out-Null
194 $prePath = Join-Path $script:testDestDir 'tool.zip'
195 'existing content' | Set-Content -Path $prePath -NoNewline
196 $actualHash = (Get-FileHash -Path $prePath -Algorithm SHA256).Hash
197
198 $result = Invoke-VerifiedDownload `
199 -Url $script:testUrl `
200 -DestinationDirectory $script:testDestDir `
201 -ExpectedHash $actualHash
202
203 $result.WasDownloaded | Should -BeFalse
204 $result.HashVerified | Should -BeTrue
205 $result.Path | Should -Be $prePath
206 }
207
208 It 'Returns existing file path in result' {
209 New-Item -ItemType Directory -Path $script:testDestDir -Force | Out-Null
210 $prePath = Join-Path $script:testDestDir 'tool.zip'
211 'existing content' | Set-Content -Path $prePath -NoNewline
212 $actualHash = (Get-FileHash -Path $prePath -Algorithm SHA256).Hash
213
214 $result = Invoke-VerifiedDownload `
215 -Url $script:testUrl `
216 -DestinationDirectory $script:testDestDir `
217 -ExpectedHash $actualHash
218
219 $result.Path | Should -Not -BeNullOrEmpty
220 $result.Path | Should -Exist
221 }
222 }
223
224 Context 'Successful download with valid hash' {
225 BeforeAll {
226 Mock Write-Host { }
227 }
228
229 It 'Downloads file and returns success result' {
230 $expectedHash = '2D8C2F6D7A37F9F6E8C5A4B3D2E1F0A9B8C7D6E5F4A3B2C1D0E9F8A7B6C5D4E3'
231
232 Mock Invoke-WebRequest {
233 param($OutFile)
234 Set-Content -Path $OutFile -Value 'mock downloaded content' -NoNewline
235 }
236 Mock Get-FileHashValue { return '2D8C2F6D7A37F9F6E8C5A4B3D2E1F0A9B8C7D6E5F4A3B2C1D0E9F8A7B6C5D4E3' }
237
238 $result = Invoke-VerifiedDownload `
239 -Url $script:testUrl `
240 -DestinationDirectory $script:testDestDir `
241 -ExpectedHash $expectedHash
242
243 $result.WasDownloaded | Should -BeTrue
244 $result.HashVerified | Should -BeTrue
245 $result.Path | Should -Exist
246 Should -Invoke -CommandName Invoke-WebRequest -Times 1 -Exactly
247 Should -Invoke -CommandName Get-FileHashValue -Times 1
248 }
249
250 It 'Creates destination directory if not exists' {
251 $expectedHash = 'AABBCC11223344556677889900AABBCC11223344556677889900AABBCC112233'
252
253 Mock Invoke-WebRequest {
254 param($OutFile)
255 Set-Content -Path $OutFile -Value 'mock content' -NoNewline
256 }
257 Mock Get-FileHashValue { return 'AABBCC11223344556677889900AABBCC11223344556677889900AABBCC112233' }
258
259 $newDir = Join-Path $TestDrive 'new-subdir'
260 $result = Invoke-VerifiedDownload `
261 -Url $script:testUrl `
262 -DestinationDirectory $newDir `
263 -ExpectedHash $expectedHash
264
265 $newDir | Should -Exist
266 $result.WasDownloaded | Should -BeTrue
267 }
268 }
269
270 Context 'Successful download with extraction' {
271 BeforeAll {
272 Mock Write-Host { }
273 Mock Write-Verbose { }
274 }
275
276 It 'Extracts ZIP archive to target path' {
277 $downloadedContent = 'mock zip content'
278 $expectedHash = 'ZIPARCHIVEHASH123456789012345678901234567890123456789012345678'
279
280 Mock Invoke-WebRequest {
281 param($OutFile)
282 Set-Content -Path $OutFile -Value $downloadedContent -NoNewline
283 }
284 Mock Get-FileHashValue { return $expectedHash }
285 Mock Expand-Archive { }
286 Mock Get-ArchiveType { return 'zip' }
287
288 $extractDir = Join-Path $TestDrive 'extracted'
289 $result = Invoke-VerifiedDownload `
290 -Url 'https://example.com/archive.zip' `
291 -DestinationDirectory $script:testDestDir `
292 -ExpectedHash $expectedHash `
293 -Extract `
294 -ExtractPath $extractDir
295
296 $result.HashVerified | Should -BeTrue
297 Should -Invoke -CommandName Expand-Archive -Times 1 -Exactly
298 }
299 }
300
301 Context 'Hash mismatch' {
302 BeforeAll {
303 Mock Write-Host { }
304 }
305
306 It 'Throws on hash verification failure' {
307 Mock Invoke-WebRequest {
308 param($OutFile)
309 Set-Content -Path $OutFile -Value 'bad content' -NoNewline
310 }
311 Mock Get-FileHashValue { return 'WRONGHASH123456789012345678901234567890123456789012345678901234' }
312
313 { Invoke-VerifiedDownload `
314 -Url $script:testUrl `
315 -DestinationDirectory $script:testDestDir `
316 -ExpectedHash 'EXPECTEDHASH567890123456789012345678901234567890123456789012345'
317 } | Should -Throw '*Checksum verification failed*'
318 }
319
320 It 'Cleans up temp file on hash failure' {
321 Mock Invoke-WebRequest {
322 param($OutFile)
323 Set-Content -Path $OutFile -Value 'bad content' -NoNewline
324 }
325 Mock Get-FileHashValue { return 'MISMATCHHASH23456789012345678901234567890123456789012345678901' }
326 Mock Remove-Item { } -Verifiable
327
328 { Invoke-VerifiedDownload `
329 -Url $script:testUrl `
330 -DestinationDirectory $script:testDestDir `
331 -ExpectedHash 'EXPECTEDHASH567890123456789012345678901234567890123456789012345'
332 } | Should -Throw
333
334 # The finally block should clean up temp files
335 Should -InvokeVerifiable
336 }
337 }
338
339 Context 'Network error' {
340 It 'Propagates network errors' {
341 Mock Invoke-WebRequest { throw 'Network unreachable' }
342
343 { Invoke-VerifiedDownload `
344 -Url $script:testUrl `
345 -DestinationDirectory $script:testDestDir `
346 -ExpectedHash $script:testHash
347 } | Should -Throw '*Network unreachable*'
348 }
349 }
350
351 Context 'Extraction error' {
352 BeforeAll {
353 Mock Write-Host { }
354 Mock Write-Verbose { }
355 }
356
357 It 'Propagates ZIP extraction errors' {
358 $downloadedContent = 'mock content'
359 $expectedHash = 'VALIDHASH1234567890123456789012345678901234567890123456789012'
360
361 Mock Invoke-WebRequest {
362 param($OutFile)
363 Set-Content -Path $OutFile -Value $downloadedContent -NoNewline
364 }
365 Mock Get-FileHashValue { return $expectedHash }
366 Mock Expand-Archive { throw 'Invalid archive format' }
367 Mock Get-ArchiveType { return 'zip' }
368
369 { Invoke-VerifiedDownload `
370 -Url 'https://example.com/archive.zip' `
371 -DestinationDirectory $script:testDestDir `
372 -ExpectedHash $expectedHash `
373 -Extract
374 } | Should -Throw '*Invalid archive format*'
375 }
376
377 It 'Throws for unsupported archive format' {
378 $downloadedContent = 'mock content'
379 $expectedHash = 'UNSUPPORTEDHASH89012345678901234567890123456789012345678901234'
380
381 Mock Invoke-WebRequest {
382 param($OutFile)
383 Set-Content -Path $OutFile -Value $downloadedContent -NoNewline
384 }
385 Mock Get-FileHashValue { return $expectedHash }
386 Mock Get-ArchiveType { return 'unknown' }
387
388 { Invoke-VerifiedDownload `
389 -Url 'https://example.com/file.xyz' `
390 -DestinationDirectory $script:testDestDir `
391 -ExpectedHash $expectedHash `
392 -Extract
393 } | Should -Throw '*Unsupported archive format*'
394 }
395 }
396
397 Context 'Tar extraction' {
398 BeforeAll {
399 Mock Write-Host { }
400 Mock Write-Verbose { }
401 }
402
403 It 'Throws when tar not available for tar.gz extraction' {
404 $downloadedContent = 'mock content'
405 $expectedHash = 'TARHASH123456789012345678901234567890123456789012345678901234'
406
407 Mock Invoke-WebRequest {
408 param($OutFile)
409 Set-Content -Path $OutFile -Value $downloadedContent -NoNewline
410 }
411 Mock Get-FileHashValue { return $expectedHash }
412 Mock Get-ArchiveType { return 'tar.gz' }
413 Mock Test-TarAvailable { return $false }
414
415 { Invoke-VerifiedDownload `
416 -Url 'https://example.com/archive.tar.gz' `
417 -DestinationDirectory $script:testDestDir `
418 -ExpectedHash $expectedHash `
419 -Extract
420 } | Should -Throw '*tar command not available*'
421 }
422
423 It 'Extracts tar.gz archive when tar is available' {
424 $downloadedContent = 'mock tar.gz content'
425 $expectedHash = 'TARGZHASH23456789012345678901234567890123456789012345678901234'
426
427 Mock Invoke-WebRequest {
428 param($OutFile)
429 Set-Content -Path $OutFile -Value $downloadedContent -NoNewline
430 }
431 Mock Get-FileHashValue { return $expectedHash }
432 Mock Get-ArchiveType { return 'tar.gz' }
433 Mock Test-TarAvailable { return $true }
434 Mock tar { $global:LASTEXITCODE = 0 }
435
436 $extractDir = Join-Path $TestDrive 'tar-gz-extracted'
437 $result = Invoke-VerifiedDownload `
438 -Url 'https://example.com/archive.tar.gz' `
439 -DestinationDirectory $script:testDestDir `
440 -ExpectedHash $expectedHash `
441 -Extract `
442 -ExtractPath $extractDir
443
444 $result.HashVerified | Should -BeTrue
445 Should -Invoke -CommandName tar -Times 1 -Exactly
446 }
447
448 It 'Extracts plain tar archive when tar is available' {
449 $downloadedContent = 'mock tar content'
450 $expectedHash = 'PLAINTARHASH456789012345678901234567890123456789012345678901234'
451
452 Mock Invoke-WebRequest {
453 param($OutFile)
454 Set-Content -Path $OutFile -Value $downloadedContent -NoNewline
455 }
456 Mock Get-FileHashValue { return $expectedHash }
457 Mock Get-ArchiveType { return 'tar' }
458 Mock Test-TarAvailable { return $true }
459 Mock tar { $global:LASTEXITCODE = 0 }
460
461 $extractDir = Join-Path $TestDrive 'tar-extracted'
462 $result = Invoke-VerifiedDownload `
463 -Url 'https://example.com/archive.tar' `
464 -DestinationDirectory $script:testDestDir `
465 -ExpectedHash $expectedHash `
466 -Extract `
467 -ExtractPath $extractDir
468
469 $result.HashVerified | Should -BeTrue
470 Should -Invoke -CommandName tar -Times 1 -Exactly
471 }
472
473 It 'Throws when tar not available for plain tar extraction' {
474 $downloadedContent = 'mock content'
475 $expectedHash = 'NOTARHASH789012345678901234567890123456789012345678901234567890'
476
477 Mock Invoke-WebRequest {
478 param($OutFile)
479 Set-Content -Path $OutFile -Value $downloadedContent -NoNewline
480 }
481 Mock Get-FileHashValue { return $expectedHash }
482 Mock Get-ArchiveType { return 'tar' }
483 Mock Test-TarAvailable { return $false }
484
485 { Invoke-VerifiedDownload `
486 -Url 'https://example.com/archive.tar' `
487 -DestinationDirectory $script:testDestDir `
488 -ExpectedHash $expectedHash `
489 -Extract
490 } | Should -Throw '*tar command not available*'
491 }
492
493 It 'Throws when tar.gz extraction fails with non-zero exit code' {
494 $downloadedContent = 'mock content'
495 $expectedHash = 'TARFAILHASH9012345678901234567890123456789012345678901234567890'
496
497 Mock Invoke-WebRequest {
498 param($OutFile)
499 Set-Content -Path $OutFile -Value $downloadedContent -NoNewline
500 }
501 Mock Get-FileHashValue { return $expectedHash }
502 Mock Get-ArchiveType { return 'tar.gz' }
503 Mock Test-TarAvailable { return $true }
504 Mock tar { $global:LASTEXITCODE = 1 }
505
506 { Invoke-VerifiedDownload `
507 -Url 'https://example.com/archive.tar.gz' `
508 -DestinationDirectory $script:testDestDir `
509 -ExpectedHash $expectedHash `
510 -Extract
511 } | Should -Throw '*tar extraction failed*'
512 }
513
514 It 'Throws when plain tar extraction fails with non-zero exit code' {
515 $downloadedContent = 'mock content'
516 $expectedHash = 'PLAINTARFAIL012345678901234567890123456789012345678901234567890'
517
518 Mock Invoke-WebRequest {
519 param($OutFile)
520 Set-Content -Path $OutFile -Value $downloadedContent -NoNewline
521 }
522 Mock Get-FileHashValue { return $expectedHash }
523 Mock Get-ArchiveType { return 'tar' }
524 Mock Test-TarAvailable { return $true }
525 Mock tar { $global:LASTEXITCODE = 2 }
526
527 { Invoke-VerifiedDownload `
528 -Url 'https://example.com/archive.tar' `
529 -DestinationDirectory $script:testDestDir `
530 -ExpectedHash $expectedHash `
531 -Extract
532 } | Should -Throw '*tar extraction failed*'
533 }
534 }
535}
536