microsoft/hve-core

Public

mirrored fromhttps://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
hve-core-v3.2.1

Branches

Tags

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

Clone

HTTPS

Download ZIP

scripts/tests/security/SecurityClasses.Tests.ps1

203lines · modecode

1#Requires -Modules Pester
2# Copyright (c) Microsoft Corporation.
3# SPDX-License-Identifier: MIT
4using module ..\..\security\Modules\SecurityClasses.psm1
5
6Describe 'DependencyViolation' -Tag 'Unit' {
7 Context 'Default constructor' {
8 It 'Initializes with empty Metadata hashtable' {
9 $v = [DependencyViolation]::new()
10 $v.Metadata | Should -BeOfType [hashtable]
11 $v.Metadata.Count | Should -Be 0
12 }
13
14 It 'Has null/default string properties' {
15 $v = [DependencyViolation]::new()
16 $v.File | Should -BeNullOrEmpty
17 $v.Name | Should -BeNullOrEmpty
18 $v.Line | Should -Be 0
19 }
20 }
21
22 Context 'Parameterized constructor' {
23 BeforeAll {
24 $script:violation = [DependencyViolation]::new(
25 'workflow.yml', 10, 'github-actions', 'actions/checkout', 'High', 'Not pinned'
26 )
27 }
28
29 It 'Sets File property' {
30 $script:violation.File | Should -Be 'workflow.yml'
31 }
32
33 It 'Sets Line property' {
34 $script:violation.Line | Should -Be 10
35 }
36
37 It 'Sets Type property' {
38 $script:violation.Type | Should -Be 'github-actions'
39 }
40
41 It 'Sets Name property' {
42 $script:violation.Name | Should -Be 'actions/checkout'
43 }
44
45 It 'Sets Severity property' {
46 $script:violation.Severity | Should -Be 'High'
47 }
48
49 It 'Sets Description property' {
50 $script:violation.Description | Should -Be 'Not pinned'
51 }
52
53 It 'Initializes Metadata as empty hashtable' {
54 $script:violation.Metadata | Should -BeOfType [hashtable]
55 $script:violation.Metadata.Count | Should -Be 0
56 }
57 }
58
59 Context 'ViolationType ValidateSet' {
60 It 'Accepts valid ViolationType values' -ForEach @(
61 @{ Value = 'Unpinned' }
62 @{ Value = 'Stale' }
63 @{ Value = 'VersionMismatch' }
64 @{ Value = 'MissingVersionComment' }
65 @{ Value = 'MissingPermissions' }
66 @{ Value = '' }
67 ) {
68 $v = [DependencyViolation]::new()
69 $v.ViolationType = $Value
70 $v.ViolationType | Should -Be $Value
71 }
72
73 It 'Rejects invalid ViolationType' {
74 $v = [DependencyViolation]::new()
75 { $v.ViolationType = 'InvalidType' } | Should -Throw
76 }
77 }
78}
79
80Describe 'ComplianceReport' -Tag 'Unit' {
81 Context 'Default constructor' {
82 BeforeAll {
83 $script:report = [ComplianceReport]::new()
84 }
85
86 It 'Sets Timestamp to current time' {
87 $script:report.Timestamp | Should -BeOfType [datetime]
88 ($script:report.Timestamp - (Get-Date)).TotalSeconds | Should -BeLessThan 5
89 }
90
91 It 'Initializes empty Violations array' {
92 $script:report.Violations | Should -HaveCount 0
93 }
94
95 It 'Initializes empty Summary hashtable' {
96 $script:report.Summary | Should -BeOfType [hashtable]
97 }
98
99 It 'Initializes empty Metadata hashtable' {
100 $script:report.Metadata | Should -BeOfType [hashtable]
101 }
102 }
103
104 Context 'Parameterized constructor' {
105 It 'Sets ScanPath' {
106 $report = [ComplianceReport]::new('/repo')
107 $report.ScanPath | Should -Be '/repo'
108 }
109
110 It 'Initializes collections' {
111 $report = [ComplianceReport]::new('/repo')
112 $report.Violations | Should -HaveCount 0
113 $report.Summary | Should -BeOfType [hashtable]
114 $report.Metadata | Should -BeOfType [hashtable]
115 }
116 }
117
118 Context 'AddViolation' {
119 It 'Appends violation and updates UnpinnedDependencies count' {
120 $report = [ComplianceReport]::new('/repo')
121 $v = [DependencyViolation]::new('f.yml', 1, 'github-actions', 'a/b', 'High', 'desc')
122 $report.AddViolation($v)
123 $report.Violations | Should -HaveCount 1
124 $report.UnpinnedDependencies | Should -Be 1
125 }
126
127 It 'Tracks multiple violations' {
128 $report = [ComplianceReport]::new('/repo')
129 $report.AddViolation([DependencyViolation]::new('a.yml', 1, 't', 'n1', 'High', 'd'))
130 $report.AddViolation([DependencyViolation]::new('b.yml', 2, 't', 'n2', 'Low', 'd'))
131 $report.Violations | Should -HaveCount 2
132 $report.UnpinnedDependencies | Should -Be 2
133 }
134 }
135
136 Context 'CalculateScore' {
137 It 'Computes percentage when TotalDependencies > 0' {
138 $report = [ComplianceReport]::new('/repo')
139 $report.TotalDependencies = 10
140 $report.PinnedDependencies = 8
141 $report.CalculateScore()
142 $report.ComplianceScore | Should -Be 80.0
143 }
144
145 It 'Returns 100 when TotalDependencies is zero' {
146 $report = [ComplianceReport]::new('/repo')
147 $report.TotalDependencies = 0
148 $report.CalculateScore()
149 $report.ComplianceScore | Should -Be 100.0
150 }
151
152 It 'Rounds to two decimal places' {
153 $report = [ComplianceReport]::new('/repo')
154 $report.TotalDependencies = 3
155 $report.PinnedDependencies = 1
156 $report.CalculateScore()
157 $report.ComplianceScore | Should -Be 33.33
158 }
159 }
160
161 Context 'ToHashtable' {
162 BeforeAll {
163 $script:report = [ComplianceReport]::new('/repo')
164 $script:report.TotalFiles = 5
165 $script:report.ScannedFiles = 3
166 $script:report.TotalDependencies = 10
167 $script:report.PinnedDependencies = 8
168 $script:report.UnpinnedDependencies = 2
169 $script:report.ComplianceScore = 80.0
170 $script:ht = $script:report.ToHashtable()
171 }
172
173 It 'Returns hashtable with 11 keys' {
174 $script:ht | Should -BeOfType [hashtable]
175 $script:ht.Keys.Count | Should -Be 11
176 }
177
178 It 'Includes all expected keys' -ForEach @(
179 @{ Key = 'ScanPath' }
180 @{ Key = 'Timestamp' }
181 @{ Key = 'TotalFiles' }
182 @{ Key = 'ScannedFiles' }
183 @{ Key = 'TotalDependencies' }
184 @{ Key = 'PinnedDependencies' }
185 @{ Key = 'UnpinnedDependencies' }
186 @{ Key = 'ComplianceScore' }
187 @{ Key = 'Violations' }
188 @{ Key = 'Summary' }
189 @{ Key = 'Metadata' }
190 ) {
191 $script:ht.ContainsKey($Key) | Should -BeTrue
192 }
193
194 It 'Formats Timestamp as ISO 8601 string' {
195 $script:ht['Timestamp'] | Should -Match '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$'
196 }
197
198 It 'Preserves numeric values' {
199 $script:ht['TotalFiles'] | Should -Be 5
200 $script:ht['ComplianceScore'] | Should -Be 80.0
201 }
202 }
203}
204