Skip to content

Commit deafc1e

Browse files
Merge branch 'main' into dependabot/github_actions/actions/checkout-7.0.0
2 parents bb4a92d + 20b9b8c commit deafc1e

4 files changed

Lines changed: 161 additions & 3 deletions

File tree

.github/workflows/Action-Test.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,7 @@ jobs:
3838
} else {
3939
throw "Helpers module not found!"
4040
}
41+
42+
- name: Run Install-PSModule regression tests
43+
shell: pwsh
44+
run: ./tests/Install-PSModule.Tests.ps1

.github/workflows/Linter.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
persist-credentials: false
2626

2727
- name: Lint code base
28-
uses: super-linter/super-linter@9e863354e3ff62e0727d37183162c4a88873df41 # v8.6.0
28+
uses: super-linter/super-linter@4ce20838b8ab83717e78138c5b3a1407148e0918 # v8.7.0
2929
env:
3030
GITHUB_TOKEN: ${{ github.token }}
3131
VALIDATE_BIOME_FORMAT: false

src/Helpers/Helpers.psm1

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,11 +313,33 @@ function Install-PSModule {
313313
Write-Host '::group::Resolving dependencies'
314314
Resolve-PSModuleDependency -ManifestFilePath $manifestFilePath
315315
Write-Host '::endgroup::'
316+
# Install into a version folder that matches the manifest's ModuleVersion so PowerShell
317+
# accepts the module. Fall back to the 999.0.0 placeholder only when the manifest is
318+
# unstamped (e.g. a build that opted out of version resolution). Validate the version as a
319+
# real [version] so a malformed manifest cannot inject path separators/traversal into the
320+
# install path.
321+
$manifestVersion = (Import-PowerShellDataFile -Path $manifestFilePath).ModuleVersion
322+
if ([string]::IsNullOrWhiteSpace($manifestVersion)) {
323+
$moduleVersion = '999.0.0'
324+
} else {
325+
$parsedVersion = $null
326+
if (-not [version]::TryParse($manifestVersion, [ref] $parsedVersion)) {
327+
throw "ModuleVersion '$manifestVersion' in [$manifestFilePath] is not a valid version."
328+
}
329+
$moduleVersion = $parsedVersion.ToString()
330+
}
316331
$PSModulePath = $env:PSModulePath -split [System.IO.Path]::PathSeparator | Select-Object -First 1
317-
$codePath = New-Item -Path "$PSModulePath/$moduleName/999.0.0" -ItemType Directory -Force | Select-Object -ExpandProperty FullName
332+
$moduleInstallRoot = Join-Path -Path $PSModulePath -ChildPath $moduleName
333+
$moduleInstallPath = Join-Path -Path $moduleInstallRoot -ChildPath $moduleVersion
334+
$codePath = New-Item -Path $moduleInstallPath -ItemType Directory -Force |
335+
Select-Object -ExpandProperty FullName
318336
Copy-Item -Path "$Path/*" -Destination $codePath -Recurse -Force
319337
Write-Host '::group::Importing module'
320-
Import-Module -Name $moduleName -Verbose
338+
# Import the freshly-installed copy explicitly by its manifest path (with -Force) so it is
339+
# not shadowed by another version of the same module that may already be loaded or present
340+
# on $env:PSModulePath.
341+
$installedManifestPath = Join-Path -Path $codePath -ChildPath "$moduleName.psd1"
342+
Import-Module -Name $installedManifestPath -Force -Global -Verbose
321343
Write-Host '::endgroup::'
322344
if ($PassThru) {
323345
return $codePath

tests/Install-PSModule.Tests.ps1

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
[CmdletBinding()]
2+
param()
3+
4+
$ErrorActionPreference = 'Stop'
5+
6+
$repoRoot = Split-Path -Path $PSScriptRoot -Parent
7+
$helpersManifestPath = Join-Path -Path $repoRoot -ChildPath 'src/Helpers/Helpers.psd1'
8+
$originalPSModulePath = $env:PSModulePath
9+
$testRoot = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "Install-PSModule-$([guid]::NewGuid())"
10+
11+
$assert = {
12+
param(
13+
[bool] $Condition,
14+
[string] $Message
15+
)
16+
17+
if (-not $Condition) {
18+
throw $Message
19+
}
20+
}
21+
22+
try {
23+
$testPSModulePath = Join-Path -Path $testRoot -ChildPath 'PSModules'
24+
New-Item -Path $testPSModulePath -ItemType Directory -Force | Out-Null
25+
$env:PSModulePath = $testPSModulePath + [System.IO.Path]::PathSeparator + $originalPSModulePath
26+
27+
Remove-Module -Name Helpers -Force -ErrorAction SilentlyContinue
28+
Import-Module -Name $helpersManifestPath -Force
29+
30+
$realVersionSourcePath = Join-Path -Path $testRoot -ChildPath 'RealVersionModule'
31+
New-Item -Path $realVersionSourcePath -ItemType Directory -Force | Out-Null
32+
"function Get-RealVersionValue { 'real-1.2.3' }" |
33+
Set-Content -Path (Join-Path -Path $realVersionSourcePath -ChildPath 'RealVersionModule.psm1')
34+
@'
35+
@{
36+
RootModule = 'RealVersionModule.psm1'
37+
ModuleVersion = '1.2.3'
38+
GUID = '11111111-1111-1111-1111-111111111111'
39+
Author = 'Test'
40+
FunctionsToExport = @('Get-RealVersionValue')
41+
}
42+
'@ | Set-Content -Path (Join-Path -Path $realVersionSourcePath -ChildPath 'RealVersionModule.psd1')
43+
44+
$realVersionInstalledPath = Install-PSModule -Path $realVersionSourcePath -PassThru
45+
$realVersionInstallRoot = Join-Path -Path $testPSModulePath -ChildPath 'RealVersionModule'
46+
$expectedRealVersionPath = Join-Path -Path $realVersionInstallRoot -ChildPath '1.2.3'
47+
$unexpectedPlaceholderPath = Join-Path -Path $realVersionInstallRoot -ChildPath '999.0.0'
48+
$realVersionManifestPath = Join-Path -Path $expectedRealVersionPath -ChildPath 'RealVersionModule.psd1'
49+
$returnedRealVersionPath = [System.IO.Path]::GetFullPath($realVersionInstalledPath)
50+
$expectedRealVersionFullPath = [System.IO.Path]::GetFullPath($expectedRealVersionPath)
51+
52+
& $assert ($returnedRealVersionPath -eq $expectedRealVersionFullPath) 'Expected Install-PSModule to return the real version path.'
53+
& $assert (Test-Path -Path $realVersionManifestPath) 'Expected the module to be installed under version 1.2.3.'
54+
& $assert (-not (Test-Path -Path $unexpectedPlaceholderPath)) 'Did not expect stamped modules to be installed under 999.0.0.'
55+
& $assert ((Get-RealVersionValue) -eq 'real-1.2.3') 'Expected the real-version module command to be imported.'
56+
57+
Remove-Module -Name RealVersionModule -Force -ErrorAction SilentlyContinue
58+
59+
$shadowInstallRoot = Join-Path -Path $testPSModulePath -ChildPath 'ShadowModule'
60+
$oldShadowInstallPath = Join-Path -Path $shadowInstallRoot -ChildPath '999.0.0'
61+
New-Item -Path $oldShadowInstallPath -ItemType Directory -Force | Out-Null
62+
"function Get-ShadowValue { 'old-999' }" |
63+
Set-Content -Path (Join-Path -Path $oldShadowInstallPath -ChildPath 'ShadowModule.psm1')
64+
@'
65+
@{
66+
RootModule = 'ShadowModule.psm1'
67+
ModuleVersion = '999.0.0'
68+
GUID = '22222222-2222-2222-2222-222222222222'
69+
Author = 'Test'
70+
FunctionsToExport = @('Get-ShadowValue')
71+
}
72+
'@ | Set-Content -Path (Join-Path -Path $oldShadowInstallPath -ChildPath 'ShadowModule.psd1')
73+
74+
$shadowSourcePath = Join-Path -Path $testRoot -ChildPath 'ShadowModule'
75+
New-Item -Path $shadowSourcePath -ItemType Directory -Force | Out-Null
76+
"function Get-ShadowValue { 'new-2.0.0' }" |
77+
Set-Content -Path (Join-Path -Path $shadowSourcePath -ChildPath 'ShadowModule.psm1')
78+
@'
79+
@{
80+
RootModule = 'ShadowModule.psm1'
81+
ModuleVersion = '2.0.0'
82+
GUID = '33333333-3333-3333-3333-333333333333'
83+
Author = 'Test'
84+
FunctionsToExport = @('Get-ShadowValue')
85+
}
86+
'@ | Set-Content -Path (Join-Path -Path $shadowSourcePath -ChildPath 'ShadowModule.psd1')
87+
88+
$oldShadowManifestPath = Join-Path -Path $oldShadowInstallPath -ChildPath 'ShadowModule.psd1'
89+
Import-Module -Name $oldShadowManifestPath -Force
90+
& $assert ((Get-ShadowValue) -eq 'old-999') 'Expected the fixture to preload the placeholder module.'
91+
92+
$shadowInstalledPath = Install-PSModule -Path $shadowSourcePath -PassThru
93+
$expectedShadowPath = Join-Path -Path $shadowInstallRoot -ChildPath '2.0.0'
94+
$shadowCommand = Get-Command -Name Get-ShadowValue
95+
$returnedShadowPath = [System.IO.Path]::GetFullPath($shadowInstalledPath)
96+
$expectedShadowFullPath = [System.IO.Path]::GetFullPath($expectedShadowPath)
97+
98+
& $assert ($returnedShadowPath -eq $expectedShadowFullPath) 'Expected the shadowed module under version 2.0.0.'
99+
& $assert ((Get-ShadowValue) -eq 'new-2.0.0') 'Expected the real-version command to replace the preloaded 999.0.0 command.'
100+
& $assert ($shadowCommand.Version.ToString() -eq '2.0.0') 'Expected command resolution to point at version 2.0.0.'
101+
102+
Remove-Module -Name ShadowModule -Force -ErrorAction SilentlyContinue
103+
104+
$badSourcePath = Join-Path -Path $testRoot -ChildPath 'BadModule'
105+
New-Item -Path $badSourcePath -ItemType Directory -Force | Out-Null
106+
"function Get-BadValue { 'bad' }" |
107+
Set-Content -Path (Join-Path -Path $badSourcePath -ChildPath 'BadModule.psm1')
108+
@'
109+
@{
110+
RootModule = 'BadModule.psm1'
111+
ModuleVersion = '1.0/bad'
112+
GUID = '44444444-4444-4444-4444-444444444444'
113+
Author = 'Test'
114+
FunctionsToExport = @('Get-BadValue')
115+
}
116+
'@ | Set-Content -Path (Join-Path -Path $badSourcePath -ChildPath 'BadModule.psd1')
117+
118+
$invalidVersionRejected = $false
119+
try {
120+
Install-PSModule -Path $badSourcePath
121+
} catch {
122+
$invalidVersionRejected = $_.Exception.Message -like '*is not a valid version*'
123+
}
124+
125+
& $assert $invalidVersionRejected 'Expected malformed ModuleVersion values to be rejected.'
126+
} finally {
127+
$env:PSModulePath = $originalPSModulePath
128+
Remove-Module -Name Helpers, RealVersionModule, ShadowModule, BadModule -Force -ErrorAction SilentlyContinue
129+
if (Test-Path -Path $testRoot) {
130+
Remove-Item -Path $testRoot -Recurse -Force
131+
}
132+
}

0 commit comments

Comments
 (0)