Skip to content

refactor(scripts): refactor Test-DependencyPinning.ps1 to use CIHelpers module #349

@WilliamBerryiii

Description

@WilliamBerryiii

Summary

Refactor Test-DependencyPinning.ps1 to use the shared CIHelpers.psm1 module, removing 13 inline CI platform detection and output patterns. This is the highest-priority refactoring target due to pattern complexity and coverage across all CIHelpers functions.

Prerequisites

Problem

scripts/security/Test-DependencyPinning.ps1 contains 13 inline CI patterns that duplicate functionality now available in CIHelpers.psm1:

GitHub Actions patterns (inline):

# Output variables
if ($env:GITHUB_OUTPUT) {
    "dependency-report=$ReportPath" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding UTF8
    "compliance-score=$($Report.ComplianceScore)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding UTF8
}

# Step summary
if ($env:GITHUB_STEP_SUMMARY) {
    Copy-Item -Path $summaryPath -Destination $env:GITHUB_STEP_SUMMARY -Force
}

# Error annotations in catch blocks
Write-Output "::error file=$file,line=$line::$message"

Azure DevOps patterns (inline):

# Output variables
if ($env:TF_BUILD -eq 'True' -or $env:AZURE_PIPELINES -eq 'True') {
    Write-Output "##vso[task.setvariable variable=dependencyReport;isOutput=true]$ReportPath"
    Write-Output "##vso[task.setvariable variable=complianceScore;isOutput=true]$($Report.ComplianceScore)"
}

# Artifact upload
Write-Output "##vso[artifact.upload containerfolder=dependency-pinning;artifactname=dependency-pinning-report]$ReportPath"

# Annotations
Write-Output "##vso[task.logissue type=warning;sourcepath=$file]$message"

Pattern inventory (13 total):

Pattern Type Count CIHelpers Function
Environment detection 3 Test-CIEnvironment, Get-CIPlatform
Output variables 4 Set-CIOutput
Step summary 2 Write-CIStepSummary
Artifact upload 2 Publish-CIArtifact
Annotations (catch blocks) 2 Write-CIAnnotation

Solution

Step 1: Add module import

Add after the param() block:

# Import shared CI helpers module
$ciHelpersPath = Join-Path $PSScriptRoot "../lib/Modules/CIHelpers.psm1"
Import-Module $ciHelpersPath -Force

Step 2: Replace inline patterns

Original Pattern Replacement
if ($env:GITHUB_ACTIONS -eq 'true') if ((Get-CIPlatform) -eq 'GitHub')
if ($env:TF_BUILD -eq 'True') if ((Get-CIPlatform) -eq 'AzureDevOps')
$env:GITHUB_OUTPUT writes Set-CIOutput -Name $name -Value $value
##vso[task.setvariable...] Set-CIOutput -Name $name -Value $value -IsOutput
$env:GITHUB_STEP_SUMMARY copy Write-CIStepSummary -Path $summaryPath
##[section] writes Write-CIStepSummary -Content $content
##vso[artifact.upload...] Publish-CIArtifact -Path $path -Name $name -ContainerFolder $folder
::error:: / ::warning:: Write-CIAnnotation -Type error -Message $msg -File $file
##vso[task.logissue...] Write-CIAnnotation -Type warning -Message $msg -File $file

Step 3: Example refactored catch block

# Before
catch {
    if ($env:GITHUB_ACTIONS -eq 'true') {
        Write-Output "::error file=$file::$($_.Exception.Message)"
    }
    elseif ($env:TF_BUILD -eq 'True') {
        Write-Output "##vso[task.logissue type=error;sourcepath=$file]$($_.Exception.Message)"
    }
    throw
}

# After
catch {
    Write-CIAnnotation -Type error -Message $_.Exception.Message -File $file
    throw
}

Step 4: Example output variable refactoring

# Before
if ($env:GITHUB_OUTPUT) {
    "dependency-report=$ReportPath" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding UTF8
    "compliance-score=$($Report.ComplianceScore)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding UTF8
}
if ($env:TF_BUILD -eq 'True') {
    Write-Output "##vso[task.setvariable variable=dependencyReport;isOutput=true]$ReportPath"
    Write-Output "##vso[task.setvariable variable=complianceScore;isOutput=true]$($Report.ComplianceScore)"
}

# After
Set-CIOutput -Name 'dependency-report' -Value $ReportPath -IsOutput
Set-CIOutput -Name 'compliance-score' -Value $Report.ComplianceScore -IsOutput

Testing Requirements

Update existing tests

Modify scripts/tests/security/Test-DependencyPinning.Tests.ps1 to:

  1. Mock CIHelpers functions instead of environment variables:
BeforeAll {
    # Mock CIHelpers module
    Mock -ModuleName Test-DependencyPinning Get-CIPlatform { return 'Local' }
    Mock -ModuleName Test-DependencyPinning Test-CIEnvironment { return $false }
    Mock -ModuleName Test-DependencyPinning Set-CIOutput { }
    Mock -ModuleName Test-DependencyPinning Write-CIStepSummary { }
    Mock -ModuleName Test-DependencyPinning Write-CIAnnotation { }
    Mock -ModuleName Test-DependencyPinning Publish-CIArtifact { }
}
  1. Add CI integration tests:
Describe 'CI Platform Integration' {
    Context 'GitHub Actions environment' {
        BeforeEach {
            Mock Get-CIPlatform { return 'GitHub' }
            Mock Test-CIEnvironment { return $true }
        }

        It 'Sets output variables via CIHelpers' {
            # Test execution
            Should -Invoke Set-CIOutput -Times 2 -Exactly
        }

        It 'Writes step summary via CIHelpers' {
            # Test execution
            Should -Invoke Write-CIStepSummary -Times 1
        }
    }

    Context 'Azure DevOps environment' {
        BeforeEach {
            Mock Get-CIPlatform { return 'AzureDevOps' }
            Mock Test-CIEnvironment { return $true }
        }

        It 'Publishes artifacts via CIHelpers' {
            # Test execution
            Should -Invoke Publish-CIArtifact -Times 1
        }
    }

    Context 'Error handling' {
        It 'Writes annotations on validation failures' {
            # Test with invalid input
            Should -Invoke Write-CIAnnotation -ParameterFilter { $Type -eq 'error' }
        }
    }
}
  1. Target coverage: 80%+ for the script file

Run validation

# Run tests with coverage
Invoke-Pester -Path scripts/tests/security/Test-DependencyPinning.Tests.ps1 -Output Detailed -CodeCoverage scripts/security/Test-DependencyPinning.ps1

# Verify no inline CI patterns remain
Select-String -Path scripts/security/Test-DependencyPinning.ps1 -Pattern '::error|::warning|##vso\[|GITHUB_OUTPUT|GITHUB_STEP_SUMMARY' | Should -BeNullOrEmpty

Acceptance Criteria

  • Script imports CIHelpers.psm1 module
  • All 13 inline CI patterns replaced with CIHelpers function calls
  • No $env:GITHUB_OUTPUT, $env:GITHUB_STEP_SUMMARY, $env:TF_BUILD checks remain
  • No ::error::, ::warning::, ##vso[ string patterns remain
  • Existing tests updated to mock CIHelpers functions
  • New CI integration tests added
  • Test coverage reaches 80%+ for Test-DependencyPinning.ps1
  • Script produces identical output in all formats (json, console)
  • PSScriptAnalyzer passes with no errors

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    maintenanceMaintenance work, no version bump

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions