Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Actions/Github-Helper.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,17 @@ function DownloadRelease {
$assetPattern2 = "^$escapedProject-$escapedMask-.+\.zip$"
Write-Host "AssetPatterns: '$assetPattern1' | '$assetPattern2'"
$assets = @($release.assets | Where-Object { $_.name -match $assetPattern1 -or $_.name -match $assetPattern2 })
# Warn when other release assets share the same project name prefix but were excluded by strict matching.
# A loose pattern (using .+ instead of [^-]+) also matches assets whose names look like a longer project name
# sharing the same prefix (e.g. 'logis-interface-2-core-library' when project is 'logis-interface').
if ($project -ne '*') {
$loosePattern = "^$escapedProject-.+-$escapedMask-.+\.zip$"
$assetIds = @($assets | ForEach-Object { $_.id })
$excludedPrefixAssets = @($release.assets | Where-Object { $_.name -match $loosePattern -and $_.id -notin $assetIds })
if ($excludedPrefixAssets) {
OutputWarning -message "Found $($excludedPrefixAssets.Count) release asset(s) sharing the '$project' name prefix that were excluded because they appear to belong to a different project: $($excludedPrefixAssets.name -join ', '). Only assets matching project '$project' exactly have been included. If this is unexpected, check for projects with similar names in your repository."
}
}
foreach($asset in $assets) {
$uri = "$api_url/repos/$repository/releases/assets/$($asset.id)"
Write-Host $uri
Expand Down
153 changes: 153 additions & 0 deletions Tests/GitHub-Helper.Test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,156 @@ Describe "GitHub-Helper Tests" {
}
}
}

Describe 'DownloadRelease Asset Pattern Matching Tests' {
BeforeAll {
Mock GetHeaders -ModuleName Github-Helper { return @{ 'Authorization' = 'token dummy' } }
Mock InvokeWebRequest -ModuleName Github-Helper {
param($Headers, $Uri, $OutFile)
if ($Headers -and $Uri) { }
if ($OutFile) {
# Create a minimal valid empty zip file so Expand-Archive doesn't fail if called
$emptyZip = [byte[]](0x50, 0x4B, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
[System.IO.File]::WriteAllBytes($OutFile, $emptyZip)
}
}
}

It 'Downloads only exact project assets and excludes assets from projects with the same name prefix' {
# Regression test for: https://github.com/microsoft/AL-Go/issues/2234
# Project 'logis-interface' should NOT match release assets of 'logis-interface-2-core-library'
$mockRelease = @{
Name = 'v1.0'
assets = @(
[PSCustomObject]@{ id = 1; name = 'logis-interface-main-Apps-1.0.64.0.zip' }
[PSCustomObject]@{ id = 2; name = 'logis-interface-2-core-library-main-Apps-1.0.64.0.zip' }
[PSCustomObject]@{ id = 3; name = 'other-project-main-Apps-1.0.64.0.zip' }
)
}

$tempPath = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
New-Item -ItemType Directory -Path $tempPath | Out-Null
try {
$result = DownloadRelease -token 'dummy' -projects 'logis-interface' -api_url 'https://api.github.com' -repository 'test/repo' -path $tempPath -mask 'Apps' -release $mockRelease

$result | Should -HaveCount 1
$result | Should -Match ([regex]::Escape('logis-interface-main-Apps-1.0.64.0.zip'))
}
finally {
Remove-Item -Path $tempPath -Recurse -Force -ErrorAction SilentlyContinue
}
}
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed

It 'Downloads assets for a project even when another project shares the same root name' {
# Downloads assets for 'logis-interface-2-core-library' without also downloading 'logis-interface' assets
$mockRelease = @{
Name = 'v1.0'
assets = @(
[PSCustomObject]@{ id = 1; name = 'logis-interface-main-Apps-1.0.64.0.zip' }
[PSCustomObject]@{ id = 2; name = 'logis-interface-2-core-library-main-Apps-1.0.64.0.zip' }
)
}

$tempPath = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
New-Item -ItemType Directory -Path $tempPath | Out-Null
try {
$result = DownloadRelease -token 'dummy' -projects 'logis-interface-2-core-library' -api_url 'https://api.github.com' -repository 'test/repo' -path $tempPath -mask 'Apps' -release $mockRelease

$result | Should -HaveCount 1
$result | Should -Match ([regex]::Escape('logis-interface-2-core-library-main-Apps-1.0.64.0.zip'))
}
finally {
Remove-Item -Path $tempPath -Recurse -Force -ErrorAction SilentlyContinue
}
}

It 'Downloads assets for wildcard project (*) matching all projects' {
$mockRelease = @{
Name = 'v1.0'
assets = @(
[PSCustomObject]@{ id = 1; name = 'logis-interface-main-Apps-1.0.64.0.zip' }
[PSCustomObject]@{ id = 2; name = 'logis-interface-2-core-library-main-Apps-1.0.64.0.zip' }
)
}

$tempPath = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
New-Item -ItemType Directory -Path $tempPath | Out-Null
try {
$result = DownloadRelease -token 'dummy' -projects '*' -api_url 'https://api.github.com' -repository 'test/repo' -path $tempPath -mask 'Apps' -release $mockRelease

$result | Should -HaveCount 2
}
finally {
Remove-Item -Path $tempPath -Recurse -Force -ErrorAction SilentlyContinue
}
}

It 'Downloads assets with no-branch pattern (Pattern 2) for legacy releases' {
$mockRelease = @{
Name = 'v1.0'
assets = @(
[PSCustomObject]@{ id = 1; name = 'myproject-Apps-1.0.0.0.zip' }
[PSCustomObject]@{ id = 2; name = 'other-project-Apps-1.0.0.0.zip' }
)
}

$tempPath = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
New-Item -ItemType Directory -Path $tempPath | Out-Null
try {
$result = DownloadRelease -token 'dummy' -projects 'myproject' -api_url 'https://api.github.com' -repository 'test/repo' -path $tempPath -mask 'Apps' -release $mockRelease

$result | Should -HaveCount 1
$result | Should -Match ([regex]::Escape('myproject-Apps-1.0.0.0.zip'))
}
finally {
Remove-Item -Path $tempPath -Recurse -Force -ErrorAction SilentlyContinue
}
}

It 'Emits a warning when similarly-named project assets are present and excluded' {
# When release contains assets from 'logis-interface-2-core-library' alongside 'logis-interface',
# downloading for project 'logis-interface' should emit a warning about the excluded assets.
$mockRelease = @{
Name = 'v1.0'
assets = @(
[PSCustomObject]@{ id = 1; name = 'logis-interface-main-Apps-1.0.64.0.zip' }
[PSCustomObject]@{ id = 2; name = 'logis-interface-2-core-library-main-Apps-1.0.64.0.zip' }
)
}
Mock OutputWarning -ModuleName Github-Helper { }

$tempPath = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
New-Item -ItemType Directory -Path $tempPath | Out-Null
try {
$null = DownloadRelease -token 'dummy' -projects 'logis-interface' -api_url 'https://api.github.com' -repository 'test/repo' -path $tempPath -mask 'Apps' -release $mockRelease

Assert-MockCalled OutputWarning -ModuleName Github-Helper -ParameterFilter { $message -like '*logis-interface-2-core-library*' } -Scope It
}
finally {
Remove-Item -Path $tempPath -Recurse -Force -ErrorAction SilentlyContinue
}
}

It 'Does not emit a warning when no similarly-named project assets are present' {
# When release only contains assets for the exact project, no warning should be emitted.
$mockRelease = @{
Name = 'v1.0'
assets = @(
[PSCustomObject]@{ id = 1; name = 'logis-interface-main-Apps-1.0.64.0.zip' }
[PSCustomObject]@{ id = 2; name = 'other-project-main-Apps-1.0.64.0.zip' }
)
}
Mock OutputWarning -ModuleName Github-Helper { }

$tempPath = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
New-Item -ItemType Directory -Path $tempPath | Out-Null
try {
$null = DownloadRelease -token 'dummy' -projects 'logis-interface' -api_url 'https://api.github.com' -repository 'test/repo' -path $tempPath -mask 'Apps' -release $mockRelease

Assert-MockCalled OutputWarning -ModuleName Github-Helper -Scope It -Times 0
}
finally {
Remove-Item -Path $tempPath -Recurse -Force -ErrorAction SilentlyContinue
}
}
}
Loading