|
1 |
| -const debug = require('debug')('checks:validator:adminRepoCreationOnly') |
| 1 | +const debug = require('debug')('checks:validator:staticCodeAnalysis') |
| 2 | +const { |
| 3 | + groupArrayItemsByCriteria, |
| 4 | + getSeverityFromPriorityGroup, |
| 5 | + generatePercentage |
| 6 | +} = require('../../utils') |
| 7 | + |
| 8 | +const groupByProject = groupArrayItemsByCriteria('project_id') |
| 9 | + |
| 10 | +const minumumStaticCodeAnalysis = 7 |
2 | 11 |
|
3 | 12 | // @see: https://github.com/OpenPathfinder/visionBoard/issues/75
|
4 |
| -module.exports = ({ data = [], check, projects = [] }) => { |
| 13 | +module.exports = ({ data: ghOrgs, check, projects = [] }) => { |
5 | 14 | debug('Validating that the repositories have static code analysis...')
|
| 15 | + debug('Grouping repositories by project...') |
| 16 | + const ghOrgsGroupedByProject = groupByProject(ghOrgs) |
6 | 17 |
|
7 | 18 | const alerts = []
|
8 | 19 | const results = []
|
9 | 20 | const tasks = []
|
10 | 21 |
|
| 22 | + debug('Processing repositories...') |
| 23 | + ghOrgsGroupedByProject.forEach((projectOrgs) => { |
| 24 | + debug(`Processing Project (${projectOrgs[0].github_organization_id})`) |
| 25 | + const project = projects.find(p => p.id === projectOrgs[0].project_id) |
| 26 | + const projectRepositories = projectOrgs.map(org => org.repositories).flat() |
| 27 | + |
| 28 | + const baseData = { |
| 29 | + project_id: project.id, |
| 30 | + compliance_check_id: check.id, |
| 31 | + severity: getSeverityFromPriorityGroup(check.default_priority_group) |
| 32 | + } |
| 33 | + |
| 34 | + const allOSSFResultsPass = projectRepositories.every( |
| 35 | + repo => repo.ossf_results?.sast_score >= minumumStaticCodeAnalysis |
| 36 | + ) |
| 37 | + |
| 38 | + if (allOSSFResultsPass) { |
| 39 | + results.push({ |
| 40 | + ...baseData, |
| 41 | + status: 'passed', |
| 42 | + rationale: 'All repositories in all organizations have a static code analysis tool' |
| 43 | + }) |
| 44 | + debug(`Processed project (${project.id}) - All passed`) |
| 45 | + return |
| 46 | + } |
| 47 | + |
| 48 | + const failedRepos = projectRepositories.filter(repo => Number.parseInt(repo.ossf_results?.sast_score) < minumumStaticCodeAnalysis).map(org => org.full_name) |
| 49 | + const unknownRepos = projectRepositories.filter(repo => repo.ossf_results?.sast_score === null).map(org => org.full_name) |
| 50 | + const noGenerateResults = projectRepositories.filter(repo => repo?.ossf_results == null).map(org => org.full_name) |
| 51 | + |
| 52 | + const result = { ...baseData } |
| 53 | + const task = { ...baseData } |
| 54 | + const alert = { ...baseData } |
| 55 | + |
| 56 | + if (noGenerateResults.length === projectRepositories.length) { |
| 57 | + result.status = 'unknown' |
| 58 | + result.rationale = 'No results have been generated from the OSSF Scorecard' |
| 59 | + } else if (failedRepos.length) { |
| 60 | + const percentage = generatePercentage(projectRepositories.length, failedRepos.length) |
| 61 | + |
| 62 | + result.status = 'failed' |
| 63 | + result.rationale = `${failedRepos.length} (${percentage}) repositories do not have a static code analysis tool` |
| 64 | + alert.title = `${failedRepos.length} (${percentage}) repositories do not have a static code analysis tool` |
| 65 | + alert.description = `Check the details on ${check.details_url}` |
| 66 | + task.title = `Add a code analysis tool for ${failedRepos.length} (${percentage}) repositories (${failedRepos.join(', ')}) in GitHub` |
| 67 | + task.description = `Check the details on ${check.details_url}` |
| 68 | + } else if (unknownRepos.length) { |
| 69 | + const percentage = generatePercentage(projectRepositories.length, unknownRepos.length) |
| 70 | + |
| 71 | + result.status = 'unknown' |
| 72 | + result.rationale = `${unknownRepos.length} (${percentage}) repositories could not be determined to have a code analysis tool` |
| 73 | + } else if (noGenerateResults.length) { |
| 74 | + const percentage = generatePercentage(projectRepositories.length, noGenerateResults.length) |
| 75 | + |
| 76 | + result.status = 'unknown' |
| 77 | + result.rationale = `${noGenerateResults.length} (${percentage}) repositories do not generated results from the OSSF Scorecard` |
| 78 | + } |
| 79 | + |
| 80 | + // Include only the task if was populated |
| 81 | + if (Object.keys(task).length > Object.keys(baseData).length) { |
| 82 | + debug(`Adding task for project (${project.id})`) |
| 83 | + tasks.push(task) |
| 84 | + } |
| 85 | + // Include only the alert if was populated |
| 86 | + if (Object.keys(alert).length > Object.keys(baseData).length) { |
| 87 | + debug(`Adding alert for project (${project.id})`) |
| 88 | + alerts.push(alert) |
| 89 | + } |
| 90 | + // Always include the result |
| 91 | + results.push(result) |
| 92 | + debug(`Processed project (${project.id})`) |
| 93 | + |
| 94 | + results.push(result) |
| 95 | + debug(`Processed project (${project.id})`) |
| 96 | + }) |
| 97 | + |
11 | 98 | return {
|
12 | 99 | alerts,
|
13 | 100 | results,
|
|
0 commit comments