Skip to content

Commit 6ff75b8

Browse files
committed
feat: initial logic of staticCodeAnalysis validator
1 parent 63b0e02 commit 6ff75b8

File tree

3 files changed

+95
-9
lines changed

3 files changed

+95
-9
lines changed

__tests__/checks/validators/staticCodeAnalysis.test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ describe('staticCodeAnalysis', () => {
111111
project_id: 1,
112112
compliance_check_id: 1,
113113
severity: 'medium',
114-
title: '3 (66.7%) repositories in org1, org2 organizations do not have a static code analysis tool',
114+
title: '2 (66.7%) repositories do not have a static code analysis tool',
115115
description: 'Check the details on https://example.com'
116116
}
117117
],
@@ -120,8 +120,8 @@ describe('staticCodeAnalysis', () => {
120120
project_id: 1,
121121
compliance_check_id: 1,
122122
severity: 'medium',
123-
status: 'passed',
124-
rationale: '3 (66.7%) repositories in org1, org2 organizations do not have a static code analysis tool'
123+
status: 'failed',
124+
rationale: '2 (66.7%) repositories do not have a static code analysis tool'
125125
},
126126
{
127127
compliance_check_id: 1,
@@ -137,7 +137,7 @@ describe('staticCodeAnalysis', () => {
137137
description: 'Check the details on https://example.com',
138138
project_id: 1,
139139
severity: 'medium',
140-
title: 'Add a code analysis tool for 2 (66.7%) repositories (org1/test, org2/.github)'
140+
title: 'Add a code analysis tool for 2 (66.7%) repositories (org1/test, org2/.github) in GitHub'
141141
}
142142
]
143143
})
@@ -147,7 +147,6 @@ describe('staticCodeAnalysis', () => {
147147
data[0].repositories[0].ossf_results = null
148148
data[0].repositories[1].ossf_results = null
149149
data[1].repositories[0].ossf_results = null
150-
data[2].repositories[0].ossf_results = null
151150

152151
const analysis = staticCodeAnalysis({ data, check, projects })
153152
expect(analysis).toEqual({
@@ -184,7 +183,7 @@ describe('staticCodeAnalysis', () => {
184183
compliance_check_id: 1,
185184
severity: 'medium',
186185
status: 'unknown',
187-
rationale: '1 (33.3%) repositories have not generated results from the OSSF Scorecard'
186+
rationale: '1 (33.3%) repositories do not generated results from the OSSF Scorecard'
188187
},
189188
{
190189
compliance_check_id: 1,
@@ -197,6 +196,7 @@ describe('staticCodeAnalysis', () => {
197196
tasks: []
198197
})
199198
})
199+
200200
it('Should generate an unknown result if some repositories have unknown static code analysis', () => {
201201
data[2].repositories[0].ossf_results.sast_score = null
202202

src/checks/validators/staticCodeAnalysis.js

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,100 @@
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
211

312
// @see: https://github.com/OpenPathfinder/visionBoard/issues/75
4-
module.exports = ({ data = [], check, projects = [] }) => {
13+
module.exports = ({ data: ghOrgs, check, projects = [] }) => {
514
debug('Validating that the repositories have static code analysis...')
15+
debug('Grouping repositories by project...')
16+
const ghOrgsGroupedByProject = groupByProject(ghOrgs)
617

718
const alerts = []
819
const results = []
920
const tasks = []
1021

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+
1198
return {
1299
alerts,
13100
results,

src/store/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ const getAllOSSFResultsOfRepositoriesByProjectId = async (knex, projectIds) => {
224224
exclude: ['repo_id', 'ossf_id']
225225
})
226226
orgData.repositories = []
227-
orgData.ossf_results = []
228227
organizationsMap.set(orgId, orgData)
229228
}
230229

0 commit comments

Comments
 (0)