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/Update-ActionSHAPinning.Tests.ps1

222lines · modecode

1#Requires -Modules Pester
2
3BeforeAll {
4 $scriptPath = Join-Path $PSScriptRoot '../../security/Update-ActionSHAPinning.ps1'
5 $scriptContent = Get-Content $scriptPath -Raw
6
7 # Extract function definitions and script-level variables using AST to avoid executing main block
8 $tokens = $null
9 $errors = $null
10 $ast = [System.Management.Automation.Language.Parser]::ParseInput($scriptContent, [ref]$tokens, [ref]$errors)
11
12 # Extract and execute script-level variable assignments (e.g., $ActionSHAMap)
13 # These are direct children of the script block that are assignments
14 $scriptStatements = $ast.EndBlock.Statements
15 foreach ($stmt in $scriptStatements) {
16 if ($stmt -is [System.Management.Automation.Language.AssignmentStatementAst]) {
17 $varCode = $stmt.Extent.Text
18 try {
19 $scriptBlock = [scriptblock]::Create($varCode)
20 . $scriptBlock
21 } catch {
22 # Skip assignments that fail (may depend on other variables)
23 $null = $_
24 }
25 }
26 }
27
28 # Extract and define all function definitions
29 $functionDefs = $ast.FindAll({ $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $true)
30
31 foreach ($func in $functionDefs) {
32 $funcCode = $func.Extent.Text
33 $scriptBlock = [scriptblock]::Create($funcCode)
34 . $scriptBlock
35 }
36
37 $mockPath = Join-Path $PSScriptRoot '../Mocks/GitMocks.psm1'
38 Import-Module $mockPath -Force
39
40 # Save environment before tests
41 Save-GitHubEnvironment
42
43 # Fixture paths
44 $script:FixturesPath = Join-Path $PSScriptRoot '../Fixtures/Workflows'
45}
46
47AfterAll {
48 Restore-GitHubEnvironment
49}
50
51Describe 'Get-ActionReference' -Tag 'Unit' {
52 Context 'Standard action references' {
53 It 'Parses action with tag reference' {
54 $yaml = 'uses: actions/checkout@v4'
55 $result = Get-ActionReference -WorkflowContent $yaml
56 $result | Should -Not -BeNullOrEmpty
57 $result.OriginalRef | Should -Be 'actions/checkout@v4'
58 }
59
60 It 'Parses action with SHA reference' {
61 $yaml = 'uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29'
62 $result = Get-ActionReference -WorkflowContent $yaml
63 $result.OriginalRef | Should -Be 'actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29'
64 }
65
66 It 'Returns LineNumber for reference' {
67 $yaml = "name: Test`njobs:`n test:`n steps:`n - name: Checkout`n uses: actions/checkout@v4"
68 $result = Get-ActionReference -WorkflowContent $yaml
69 $result.LineNumber | Should -BeGreaterThan 0
70 }
71 }
72
73 Context 'Multiple action references' {
74 It 'Finds all action references in workflow' {
75 $yaml = "jobs:`n test:`n steps:`n - name: Checkout`n uses: actions/checkout@v4`n - name: Setup`n uses: actions/setup-node@v4"
76 $result = @(Get-ActionReference -WorkflowContent $yaml)
77 $result.Count | Should -Be 2
78 }
79 }
80
81 Context 'Invalid references' {
82 It 'Returns empty for non-action content' {
83 $yaml = 'run: echo "Hello"'
84 $result = Get-ActionReference -WorkflowContent $yaml
85 $result | Should -BeNullOrEmpty
86 }
87 }
88}
89
90Describe 'Get-SHAForAction' -Tag 'Unit' {
91 BeforeEach {
92 Initialize-MockGitHubEnvironment
93 $env:GITHUB_TOKEN = 'ghp_test123456789'
94 }
95
96 AfterEach {
97 Clear-MockGitHubEnvironment
98 }
99
100 Context 'ActionSHAMap lookup' {
101 It 'Returns action reference with SHA for known action' {
102 $result = Get-SHAForAction -ActionRef 'actions/checkout@v4'
103 $result | Should -Not -BeNullOrEmpty
104 # Function returns full action reference with SHA (e.g., actions/checkout@sha)
105 $result | Should -Match '@[a-f0-9]{40}$'
106 }
107 }
108
109 Context 'Unmapped actions' {
110 It 'Returns null when action not in map and no API call is made' {
111 # Get-SHAForAction returns null for unmapped actions without attempting API
112 $result = Get-SHAForAction -ActionRef 'unknown/action@v1'
113 $result | Should -BeNullOrEmpty
114 }
115
116 It 'Returns null for unmapped actions requiring manual review' {
117 # The function logs a warning and returns null for unmapped actions
118 $result = Get-SHAForAction -ActionRef 'test-org/test-action@v1'
119 $result | Should -BeNullOrEmpty
120 }
121 }
122}
123
124Describe 'Update-WorkflowFile' -Tag 'Unit' {
125 BeforeEach {
126 Initialize-MockGitHubEnvironment
127 $env:GITHUB_TOKEN = 'ghp_test123456789'
128
129 # Copy fixture to TestDrive for modification testing
130 $unpinnedSource = Join-Path $script:FixturesPath 'unpinned-workflow.yml'
131 $script:TestWorkflow = Join-Path $TestDrive 'test-workflow.yml'
132 Copy-Item $unpinnedSource $script:TestWorkflow
133
134 Mock Invoke-RestMethod {
135 return @{
136 object = @{
137 sha = 'newsha123456789012345678901234567890abcd'
138 }
139 }
140 }
141 }
142
143 AfterEach {
144 Clear-MockGitHubEnvironment
145 }
146
147 Context 'Return value structure' {
148 It 'Returns hashtable with FilePath' {
149 $result = Update-WorkflowFile -FilePath $script:TestWorkflow
150 $result | Should -BeOfType [hashtable]
151 $result.FilePath | Should -Be $script:TestWorkflow
152 }
153
154 It 'Returns ActionsProcessed count' {
155 $result = Update-WorkflowFile -FilePath $script:TestWorkflow
156 $result.ActionsProcessed | Should -BeGreaterOrEqual 0
157 }
158
159 It 'Returns ActionsPinned count' {
160 $result = Update-WorkflowFile -FilePath $script:TestWorkflow
161 $result.ContainsKey('ActionsPinned') | Should -BeTrue
162 }
163 }
164
165 Context 'File modification' {
166 It 'Updates unpinned action to SHA' {
167 Update-WorkflowFile -FilePath $script:TestWorkflow
168
169 $content = Get-Content $script:TestWorkflow -Raw
170 # Check that the file was processed (content may or may not change based on mock)
171 $content | Should -Not -BeNullOrEmpty
172 }
173 }
174
175 Context 'Already pinned workflows' {
176 It 'Does not modify already pinned actions' {
177 $pinnedSource = Join-Path $script:FixturesPath 'pinned-workflow.yml'
178 $pinnedTest = Join-Path $TestDrive 'pinned-test.yml'
179 Copy-Item $pinnedSource $pinnedTest
180
181 $originalContent = Get-Content $pinnedTest -Raw
182 Update-WorkflowFile -FilePath $pinnedTest
183 $newContent = Get-Content $pinnedTest -Raw
184
185 $newContent | Should -Be $originalContent
186 }
187 }
188}
189
190Describe 'Update-WorkflowFile -WhatIf' -Tag 'Unit' {
191 BeforeEach {
192 Initialize-MockGitHubEnvironment
193 $env:GITHUB_TOKEN = 'ghp_test123456789'
194
195 $unpinnedSource = Join-Path $script:FixturesPath 'unpinned-workflow.yml'
196 $script:TestWorkflow = Join-Path $TestDrive 'whatif-test.yml'
197 Copy-Item $unpinnedSource $script:TestWorkflow
198
199 Mock Invoke-RestMethod {
200 return @{
201 object = @{
202 sha = 'newsha123456789012345678901234567890abcd'
203 }
204 }
205 }
206 }
207
208 AfterEach {
209 Clear-MockGitHubEnvironment
210 }
211
212 Context 'WhatIf behavior' {
213 It 'Does not modify file when WhatIf is specified' {
214 $originalContent = Get-Content $script:TestWorkflow -Raw
215
216 Update-WorkflowFile -FilePath $script:TestWorkflow -WhatIf
217
218 $newContent = Get-Content $script:TestWorkflow -Raw
219 $newContent | Should -Be $originalContent
220 }
221 }
222}
223