1use crate::verdict::Severity;
7
8pub fn short_sha(sha: &str) -> &str {
10 if sha.len() >= 7 { &sha[..7] } else { sha }
11}
12
13pub fn is_approver_independent(is_commit_author: bool, is_pr_author: bool) -> bool {
25 !is_commit_author && !is_pr_author
26}
27
28pub fn signature_severity(unsigned_count: usize) -> Severity {
31 if unsigned_count == 0 {
32 Severity::Pass
33 } else {
34 Severity::Error
35 }
36}
37
38pub fn build_provenance_severity(unverified_count: usize) -> Severity {
41 if unverified_count == 0 {
42 Severity::Pass
43 } else {
44 Severity::Error
45 }
46}
47
48pub fn required_status_checks_severity(fail_count: usize) -> Severity {
53 if fail_count == 0 {
54 Severity::Pass
55 } else {
56 Severity::Error
57 }
58}
59
60pub fn branch_history_severity(unprotected_count: usize) -> Severity {
65 if unprotected_count == 0 {
66 Severity::Pass
67 } else {
68 Severity::Error
69 }
70}
71
72pub fn branch_protection_enforcement_severity(non_enforced_count: usize) -> Severity {
77 if non_enforced_count == 0 {
78 Severity::Pass
79 } else {
80 Severity::Error
81 }
82}
83
84pub fn two_party_review_severity(independent_count: usize) -> Severity {
89 if independent_count >= 2 {
90 Severity::Pass
91 } else {
92 Severity::Error
93 }
94}
95
96pub fn hosted_build_severity(non_hosted_count: usize) -> Severity {
101 if non_hosted_count == 0 {
102 Severity::Pass
103 } else {
104 Severity::Error
105 }
106}
107
108pub fn provenance_authenticity_severity(unauthenticated_count: usize) -> Severity {
113 if unauthenticated_count == 0 {
114 Severity::Pass
115 } else {
116 Severity::Error
117 }
118}
119
120pub fn build_isolation_severity(non_isolated_count: usize) -> Severity {
125 if non_isolated_count == 0 {
126 Severity::Pass
127 } else {
128 Severity::Error
129 }
130}
131
132pub fn dependency_signature_severity(unsigned_count: usize) -> Severity {
137 if unsigned_count == 0 {
138 Severity::Pass
139 } else {
140 Severity::Error
141 }
142}
143
144pub fn container_signature_severity(all_signed: bool, count: u32) -> Severity {
151 if count == 0 {
152 Severity::Warning
153 } else if all_signed {
154 Severity::Pass
155 } else {
156 Severity::Error
157 }
158}
159
160pub fn container_provenance_severity(all_have_provenance: bool, count: u32) -> Severity {
165 if count == 0 {
166 Severity::Warning
167 } else if all_have_provenance {
168 Severity::Pass
169 } else {
170 Severity::Error
171 }
172}
173
174pub fn stale_review_severity(stale_count: usize) -> Severity {
181 if stale_count == 0 {
182 Severity::Pass
183 } else {
184 Severity::Error
185 }
186}
187
188pub fn description_quality_severity(body_length: usize, min_length: usize) -> Severity {
193 if body_length >= min_length {
194 Severity::Pass
195 } else {
196 Severity::Error
197 }
198}
199
200pub fn merge_commit_policy_severity(merge_count: usize) -> Severity {
205 if merge_count == 0 {
206 Severity::Pass
207 } else {
208 Severity::Error
209 }
210}
211
212pub fn conventional_title_severity(is_conventional: bool) -> Severity {
217 if is_conventional {
218 Severity::Pass
219 } else {
220 Severity::Error
221 }
222}
223
224pub fn security_file_change_severity(sensitive_count: usize) -> Severity {
229 if sensitive_count == 0 {
230 Severity::Pass
231 } else {
232 Severity::Error
233 }
234}
235
236pub fn release_traceability_severity(linked_cr_count: usize) -> Severity {
241 if linked_cr_count > 0 {
242 Severity::Pass
243 } else {
244 Severity::Error
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251
252 #[test]
255 fn is_approver_independent_exhaustive_equivalence() {
256 for &ca in &[false, true] {
258 for &pa in &[false, true] {
259 let result = is_approver_independent(ca, pa);
260 let spec = !ca && !pa;
261 assert_eq!(
262 result, spec,
263 "is_approver_independent({ca}, {pa}): got {result}, spec {spec}"
264 );
265 }
266 }
267 }
268
269 #[test]
270 fn signature_severity_equivalence() {
271 assert_eq!(signature_severity(0), Severity::Pass);
272 for count in 1..=100 {
273 assert_eq!(
274 signature_severity(count),
275 Severity::Error,
276 "signature_severity({count}) should be Error"
277 );
278 }
279 }
280
281 #[test]
282 fn build_provenance_severity_equivalence() {
283 assert_eq!(build_provenance_severity(0), Severity::Pass);
284 for count in 1..=100 {
285 assert_eq!(
286 build_provenance_severity(count),
287 Severity::Error,
288 "build_provenance_severity({count}) should be Error"
289 );
290 }
291 }
292
293 #[test]
295 fn classify_scope_exhaustive_equivalence() {
296 use crate::scope::classify_scope;
297 for files in 0..=20usize {
298 for comps in 0..=20usize {
299 let result = classify_scope(files, comps);
300 let spec = if files <= 1 {
301 Severity::Pass
302 } else if comps <= 1 {
303 Severity::Pass
304 } else if comps == 2 {
305 Severity::Warning
306 } else {
307 Severity::Error
308 };
309 assert_eq!(
310 result, spec,
311 "classify_scope({files}, {comps}): got {result:?}, spec {spec:?}"
312 );
313 }
314 }
315 }
316
317 #[test]
318 fn required_status_checks_severity_equivalence() {
319 assert_eq!(required_status_checks_severity(0), Severity::Pass);
320 for count in 1..=10 {
321 assert_eq!(
322 required_status_checks_severity(count),
323 Severity::Error,
324 "required_status_checks_severity({count}) should be Error"
325 );
326 }
327 }
328
329 #[test]
330 fn branch_history_severity_equivalence() {
331 assert_eq!(branch_history_severity(0), Severity::Pass);
332 for count in 1..=10 {
333 assert_eq!(
334 branch_history_severity(count),
335 Severity::Error,
336 "branch_history_severity({count}) should be Error"
337 );
338 }
339 }
340
341 #[test]
342 fn branch_protection_enforcement_severity_equivalence() {
343 assert_eq!(branch_protection_enforcement_severity(0), Severity::Pass);
344 for count in 1..=10 {
345 assert_eq!(
346 branch_protection_enforcement_severity(count),
347 Severity::Error,
348 "branch_protection_enforcement_severity({count}) should be Error"
349 );
350 }
351 }
352
353 #[test]
354 fn two_party_review_severity_equivalence() {
355 assert_eq!(two_party_review_severity(0), Severity::Error);
356 assert_eq!(two_party_review_severity(1), Severity::Error);
357 assert_eq!(two_party_review_severity(2), Severity::Pass);
358 for count in 3..=10 {
359 assert_eq!(
360 two_party_review_severity(count),
361 Severity::Pass,
362 "two_party_review_severity({count}) should be Pass"
363 );
364 }
365 }
366
367 #[test]
368 fn hosted_build_severity_equivalence() {
369 assert_eq!(hosted_build_severity(0), Severity::Pass);
370 for count in 1..=10 {
371 assert_eq!(
372 hosted_build_severity(count),
373 Severity::Error,
374 "hosted_build_severity({count}) should be Error"
375 );
376 }
377 }
378
379 #[test]
380 fn provenance_authenticity_severity_equivalence() {
381 assert_eq!(provenance_authenticity_severity(0), Severity::Pass);
382 for count in 1..=10 {
383 assert_eq!(
384 provenance_authenticity_severity(count),
385 Severity::Error,
386 "provenance_authenticity_severity({count}) should be Error"
387 );
388 }
389 }
390
391 #[test]
392 fn build_isolation_severity_equivalence() {
393 assert_eq!(build_isolation_severity(0), Severity::Pass);
394 for count in 1..=10 {
395 assert_eq!(
396 build_isolation_severity(count),
397 Severity::Error,
398 "build_isolation_severity({count}) should be Error"
399 );
400 }
401 }
402
403 #[test]
406 fn stale_review_severity_equivalence() {
407 assert_eq!(stale_review_severity(0), Severity::Pass);
408 for count in 1..=10 {
409 assert_eq!(
410 stale_review_severity(count),
411 Severity::Error,
412 "stale_review_severity({count}) should be Error"
413 );
414 }
415 }
416
417 #[test]
418 fn description_quality_severity_equivalence() {
419 let min = 10;
420 for len in 0..min {
421 assert_eq!(
422 description_quality_severity(len, min),
423 Severity::Error,
424 "description_quality_severity({len}, {min}) should be Error"
425 );
426 }
427 for len in min..=50 {
428 assert_eq!(
429 description_quality_severity(len, min),
430 Severity::Pass,
431 "description_quality_severity({len}, {min}) should be Pass"
432 );
433 }
434 }
435
436 #[test]
437 fn merge_commit_policy_severity_equivalence() {
438 assert_eq!(merge_commit_policy_severity(0), Severity::Pass);
439 for count in 1..=10 {
440 assert_eq!(
441 merge_commit_policy_severity(count),
442 Severity::Error,
443 "merge_commit_policy_severity({count}) should be Error"
444 );
445 }
446 }
447
448 #[test]
449 fn conventional_title_severity_equivalence() {
450 assert_eq!(conventional_title_severity(true), Severity::Pass);
451 assert_eq!(conventional_title_severity(false), Severity::Error);
452 }
453
454 #[test]
455 fn security_file_change_severity_equivalence() {
456 assert_eq!(security_file_change_severity(0), Severity::Pass);
457 for count in 1..=10 {
458 assert_eq!(
459 security_file_change_severity(count),
460 Severity::Error,
461 "security_file_change_severity({count}) should be Error"
462 );
463 }
464 }
465
466 #[test]
467 fn release_traceability_severity_equivalence() {
468 assert_eq!(release_traceability_severity(0), Severity::Error);
469 for count in 1..=10 {
470 assert_eq!(
471 release_traceability_severity(count),
472 Severity::Pass,
473 "release_traceability_severity({count}) should be Pass"
474 );
475 }
476 }
477
478 #[test]
479 fn dependency_signature_severity_equivalence() {
480 assert_eq!(dependency_signature_severity(0), Severity::Pass);
481 for count in 1..=100 {
482 assert_eq!(
483 dependency_signature_severity(count),
484 Severity::Error,
485 "dependency_signature_severity({count}) should be Error"
486 );
487 }
488 }
489
490 #[test]
493 fn container_signature_severity_equivalence() {
494 assert_eq!(container_signature_severity(true, 0), Severity::Warning);
496 assert_eq!(container_signature_severity(false, 0), Severity::Warning);
497 assert_eq!(container_signature_severity(true, 1), Severity::Pass);
499 assert_eq!(container_signature_severity(true, 5), Severity::Pass);
500 assert_eq!(container_signature_severity(false, 1), Severity::Error);
502 assert_eq!(container_signature_severity(false, 10), Severity::Error);
503 }
504
505 #[test]
506 fn container_provenance_severity_equivalence() {
507 assert_eq!(container_provenance_severity(true, 0), Severity::Warning);
509 assert_eq!(container_provenance_severity(false, 0), Severity::Warning);
510 assert_eq!(container_provenance_severity(true, 1), Severity::Pass);
512 assert_eq!(container_provenance_severity(true, 5), Severity::Pass);
513 assert_eq!(container_provenance_severity(false, 1), Severity::Error);
515 assert_eq!(container_provenance_severity(false, 10), Severity::Error);
516 }
517}