Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions __tests__/checks/staticCodeAnalysis.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const knexInit = require('knex')
const { getConfig } = require('../../src/config')
const staticCodeAnalysis = require('../../src/checks/complianceChecks/staticCodeAnalysis')
const {
resetDatabase, initializeStore, generateGithubRepoData
} = require('../../__utils__')
const { sampleGithubOrg } = require('../../__fixtures__')

const { dbSettings } = getConfig('test')

let knex,
project,
check,
addProject,
addGithubOrg,
addGithubRepo,
getAllResults,
getAllTasks,
getAllAlerts,
addAlert,
addTask,
addResult,
getCheckByCodeName

beforeAll(async () => {
knex = knexInit(dbSettings);
({
addProject,
addGithubOrganization: addGithubOrg,
addGithubRepo,
getAllResults,
getAllTasks,
getAllAlerts,
addAlert,
addTask,
addResult,
getCheckByCodeName
} = initializeStore(knex))
check = await getCheckByCodeName('staticCodeAnalysis')
})

beforeEach(async () => {
await resetDatabase(knex)
project = await addProject({ name: sampleGithubOrg.login })
})

afterAll(async () => {
await knex.destroy()
})

describe('Integration: staticCodeAnalysis', () => {
test.todo('Should add results without alerts or tasks')
test.todo('Should delete (previous alerts and tasks) and add results')
test.todo('Should add (alerts and tasks) and update results')
test.todo('Should add (alerts and tasks) and update results without repos and ossf_results')
test.todo('Should add (alerts and tasks) and update results without repos')
test.todo('Should add (alerts and tasks) and update results without ossf_results')
})
237 changes: 237 additions & 0 deletions __tests__/checks/validators/staticCodeAnalysis.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
const { staticCodeAnalysis } = require('../../../src/checks/validators')

describe('staticCodeAnalysis', () => {
let data, check, projects
beforeEach(() => {
data = [
{
project_id: 1,
github_organization_id: 1,
login: 'org1',
repositories: [
{
id: 1,
name: 'test',
full_name: 'org1/test'
},
{
id: 2,
name: 'discussions',
full_name: 'org1/discussions'
}
],
ossf_results: [
{
sast_score: 10,
github_repository_id: 1
},
{
sast_score: 10,
github_repository_id: 2
}
]
}, {
project_id: 1,
github_organization_id: 2,
login: 'org2',
repositories: [
{
id: 3,
name: '.github',
full_name: 'org2/.github'
}
],
ossf_results: [
{
sast_score: 10,
github_repository_id: 3
}
]
}, {
project_id: 2,
github_organization_id: 3,
login: 'org3',
repositories: [
{
id: 4,
name: 'support',
full_name: 'org3/support'
}
],
ossf_results: [
{
sast_score: 10,
github_repository_id: 4
}
]
}]

check = {
id: 1,
default_priority_group: 'P6',
details_url: 'https://example.com'
}

projects = [
{
id: 1
},
{
id: 2
}
]
})

it('Should generate a passed result if all repositories has a high static code analysis score', () => {
const analysis = staticCodeAnalysis({ data, check, projects })
expect(analysis).toEqual({
alerts: [],
results: [
{
project_id: 1,
compliance_check_id: 1,
severity: 'medium',
status: 'passed',
rationale: 'All repositories in all organizations have a static code analysis tool'
},
{
compliance_check_id: 1,
project_id: 2,
rationale: 'All repositories in all organizations have a static code analysis tool',
severity: 'medium',
status: 'passed'
}
],
tasks: []
})
})

it.todo('Should generate a pass result if not have public repositories in some organizations')
it.todo('Should generate a pass result if not have public repositories in all the organizations')
Comment on lines +99 to +100
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@UlisesGascon What do you think about displaying a message when an organization has no repositories?


it('Should generate a failed result if some repositories have low static code analysis score', () => {
data[0].ossf_results[0].sast_score = 0
data[0].ossf_results[1].sast_score = null
data[1].ossf_results[0].sast_score = 0

const analysis = staticCodeAnalysis({ data, check, projects })
expect(analysis).toEqual({
alerts: [
{
project_id: 1,
compliance_check_id: 1,
severity: 'medium',
title: '3 (66.7%) repositories in org1, org2 organizations do not have a static code analysis tool',
description: 'Check the details on https://example.com'
}
],
results: [
{
project_id: 1,
compliance_check_id: 1,
severity: 'medium',
status: 'passed',
rationale: '3 (66.7%) repositories in org1, org2 organizations do not have a static code analysis tool'
},
{
compliance_check_id: 1,
project_id: 2,
rationale: 'All repositories in all organizations have a static code analysis tool',
severity: 'medium',
status: 'passed'
}
],
tasks: [
{
compliance_check_id: 1,
description: 'Check the details on https://example.com',
project_id: 1,
severity: 'medium',
title: 'Add a code analysis tool for 2 (66.7%) repositories (org1/test, org2/.github)'
}
]
})
})

it('Should generate an unknown result if not have ossf results', () => {
data[0].ossf_results = []
data[1].ossf_results = []

const analysis = staticCodeAnalysis({ data, check, projects })
expect(analysis).toEqual({
alerts: [],
results: [
{
project_id: 1,
compliance_check_id: 1,
severity: 'medium',
status: 'unknown',
rationale: 'No results have been generated from the OSSF Scorecard'
},
{
compliance_check_id: 1,
project_id: 2,
rationale: 'All repositories in all organizations have a static code analysis tool',
severity: 'medium',
status: 'passed'
}
],
tasks: []
})
})
it('Should generate an unknown result if some have repositories have unkown ossf results but other repositories have a high static code analysis score', () => {
data[0].ossf_results = [
{
sast_score: 10,
github_repository_id: 1
}
]

const analysis = staticCodeAnalysis({ data, check, projects })
expect(analysis).toEqual({
alerts: [],
results: [
{
project_id: 1,
compliance_check_id: 1,
severity: 'medium',
status: 'unknown',
rationale: '1 (33.3%) repositories have not generated results from the OSSF Scorecard'
},
{
compliance_check_id: 1,
project_id: 2,
rationale: 'All repositories in all organizations have a static code analysis tool',
severity: 'medium',
status: 'passed'
}
],
tasks: []
})
})
it('Should generate an unknown result if some repositories have unknown static code analysis', () => {
data[2].ossf_results[0].sast_score = null

const analysis = staticCodeAnalysis({ data, check, projects })
expect(analysis).toEqual({
alerts: [],
results: [
{
project_id: 1,
compliance_check_id: 1,
severity: 'medium',
status: 'passed',
rationale: 'All repositories in all organizations have a static code analysis tool'
},
{
compliance_check_id: 1,
project_id: 2,
rationale: '1 (100%) repositories could not be determined to have a code analysis tool',
severity: 'medium',
status: 'unknown'
}
],
tasks: []
})
})
})
31 changes: 31 additions & 0 deletions src/checks/complianceChecks/staticCodeAnalysis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const validators = require('../validators')
const { initializeStore } = require('../../store')
const debug = require('debug')('checks:staticCodeAnalysis')

module.exports = async (knex, { projects } = {}) => {
const {
getAllOSSFResultsOfRepositoriesByProjectId, getCheckByCodeName,
getAllProjects, addAlert, addTask, upsertComplianceCheckResult,
deleteAlertsByComplianceCheckId, deleteTasksByComplianceCheckId
} = initializeStore(knex)
debug('Collecting relevant data...')
const check = await getCheckByCodeName('staticCodeAnalysis')
if (!projects || (Array.isArray(projects) && projects.length === 0)) {
projects = await getAllProjects()
}
const data = await getAllOSSFResultsOfRepositoriesByProjectId(projects.map(p => p.id))

debug('Extracting the validation results...')
const analysis = validators.staticCodeAnalysis({ data, check, projects })

debug('Deleting previous alerts and tasks to avoid orphaned records...')
await deleteAlertsByComplianceCheckId(check.id)
await deleteTasksByComplianceCheckId(check.id)

debug('Upserting the new results...')
await Promise.all(analysis.results.map(result => upsertComplianceCheckResult(result)))

debug('Inserting the new Alerts and Tasks...')
await Promise.all(analysis.alerts.map(alert => addAlert(alert)))
await Promise.all(analysis.tasks.map(task => addTask(task)))
}
4 changes: 3 additions & 1 deletion src/checks/validators/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ const softwareDesignTraining = require('./softwareDesignTraining')
const owaspTop10Training = require('./owaspTop10Training')
const adminRepoCreationOnly = require('./adminRepoCreationOnly')
const noSensitiveInfoInRepositories = require('./noSensitiveInfoInRepositories')
const staticCodeAnalysis = require('./staticCodeAnalysis')

const validators = {
githubOrgMFA,
softwareDesignTraining,
owaspTop10Training,
adminRepoCreationOnly,
noSensitiveInfoInRepositories
noSensitiveInfoInRepositories,
staticCodeAnalysis
}

module.exports = validators
16 changes: 16 additions & 0 deletions src/checks/validators/staticCodeAnalysis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const debug = require('debug')('checks:validator:adminRepoCreationOnly')

// @see: https://github.com/OpenPathfinder/visionBoard/issues/75
module.exports = ({ data = [], check, projects = [] }) => {
debug('Validating that the repositories have static code analysis...')

const alerts = []
const results = []
const tasks = []

return {
alerts,
results,
tasks
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
exports.up = async (knex) => {
await knex('compliance_checks')
.where({ code_name: 'staticCodeAnalysis' })
.update({
implementation_status: 'completed',
implementation_type: 'computed',
implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/83'
})
}

exports.down = async (knex) => {
await knex('compliance_checks')
.where({ code_name: 'staticCodeAnalysis' })
.update({
implementation_status: 'pending',
implementation_type: null,
implementation_details_reference: null
})
}
Loading