Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add check adminRepoCreationOnly #177

Merged
merged 4 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
135 changes: 135 additions & 0 deletions __tests__/checks/adminRepoCreationOnly.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
const knexInit = require('knex')
const { getConfig } = require('../../src/config')
const adminRepoCreationOnly = require('../../src/checks/complianceChecks/adminRepoCreationOnly')
const {
resetDatabase, initializeStore
} = require('../../__utils__')
const { sampleGithubOrg } = require('../../__fixtures__')

const { dbSettings } = getConfig('test')

let knex
let project
let check

let addProject,
addGithubOrg,
getAllResults,
getAllTasks,
getAllAlerts,
addAlert,
addTask,
addResult,
getCheckByCodeName

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

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

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

describe('Integration: adminRepoCreationOnly', () => {
test('Should add results without alerts or tasks', async () => {
// Add a passed check scenario
await addGithubOrg({
login: sampleGithubOrg.login,
html_url: sampleGithubOrg.html_url,
project_id: project.id,
members_can_create_public_repositories: false
})
// Check that the database is empty
let results = await getAllResults()
expect(results.length).toBe(0)
let alerts = await getAllAlerts()
expect(alerts.length).toBe(0)
let tasks = await getAllTasks()
expect(tasks.length).toBe(0)
// Run the check
await expect(adminRepoCreationOnly(knex)).resolves.toBeUndefined()
// Check that the database has the expected results
results = await getAllResults()
expect(results.length).toBe(1)
expect(results[0].status).toBe('passed')
expect(results[0].compliance_check_id).toBe(check.id)
alerts = await getAllAlerts()
expect(alerts.length).toBe(0)
tasks = await getAllTasks()
expect(tasks.length).toBe(0)
})

test('Should delete (previous alerts and tasks) and add results', async () => {
// Prepare the Scenario
await addGithubOrg({
login: sampleGithubOrg.login,
html_url: sampleGithubOrg.html_url,
project_id: project.id,
members_can_create_public_repositories: false
})
await addAlert({ compliance_check_id: check.id, project_id: project.id, title: 'existing', description: 'existing', severity: 'critical' })
await addTask({ compliance_check_id: check.id, project_id: project.id, title: 'existing', description: 'existing', severity: 'critical' })
// Check that the database has the expected results
let results = await getAllResults()
expect(results.length).toBe(0)
let alerts = await getAllAlerts()
expect(alerts.length).toBe(1)
expect(alerts[0].compliance_check_id).toBe(check.id)
let tasks = await getAllTasks()
expect(tasks.length).toBe(1)
expect(tasks[0].compliance_check_id).toBe(check.id)
// Run the check
await adminRepoCreationOnly(knex)
// Check that the database has the expected results
results = await getAllResults()
expect(results.length).toBe(1)
expect(results[0].status).toBe('passed')
alerts = await getAllAlerts()
expect(alerts.length).toBe(0)
tasks = await getAllTasks()
expect(tasks.length).toBe(0)
})
test('Should add (alerts and tasks) and update results', async () => {
// Prepare the Scenario
await addGithubOrg({ login: sampleGithubOrg.login, html_url: sampleGithubOrg.html_url, project_id: project.id, members_can_create_public_repositories: true })
await addResult({ compliance_check_id: check.id, project_id: project.id, status: 'passed', rationale: 'failed previously', severity: 'critical' })
// Check that the database has the expected results
let results = await getAllResults()
expect(results.length).toBe(1)
expect(results[0].compliance_check_id).toBe(check.id)
let alerts = await getAllAlerts()
expect(alerts.length).toBe(0)
let tasks = await getAllTasks()
expect(tasks.length).toBe(0)
// Run the check
await adminRepoCreationOnly(knex)
// Check that the database has the expected results
results = await getAllResults()
expect(results.length).toBe(1)
expect(results[0].status).toBe('failed')
expect(results[0].rationale).not.toBe('failed previously')
alerts = await getAllAlerts()
expect(alerts.length).toBe(1)
expect(alerts[0].compliance_check_id).toBe(check.id)
tasks = await getAllTasks()
expect(tasks.length).toBe(1)
expect(tasks[0].compliance_check_id).toBe(check.id)
})
})
132 changes: 131 additions & 1 deletion __tests__/checks/validators.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { githubOrgMFA, softwareDesignTraining } = require('../../src/checks/validators')
const { githubOrgMFA, softwareDesignTraining, adminRepoCreationOnly } = require('../../src/checks/validators')
// @see: https://github.com/OpenPathfinder/visionBoard/issues/43
describe('githubOrgMFA', () => {
let organizations, check, projects
Expand Down Expand Up @@ -278,3 +278,133 @@ describe('softwareDesignTraining', () => {
})
})
})

describe('adminRepoCreationOnly', () => {
let organizations, check, projects
beforeEach(() => {
organizations = [
{
project_id: 1,
login: 'org1',
members_can_create_public_repositories: false
},
{
project_id: 1,
login: 'org2',
members_can_create_public_repositories: false
},
{
project_id: 2,
login: 'org3',
members_can_create_public_repositories: false
}
]

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

projects = [
{
id: 1
},
{
id: 2
}
]
})
it('Should generate a passed result if only admins can create public repos in all the organizations', () => {
const analysis = adminRepoCreationOnly({ organizations, check, projects })
expect(analysis).toEqual({
alerts: [],
results: [
{
project_id: 1,
compliance_check_id: 1,
severity: 'critical',
status: 'passed',
rationale: 'Only Admins can create public repositories in the organization(s)'
},
{
compliance_check_id: 1,
project_id: 2,
rationale: 'Only Admins can create public repositories in the organization(s)',
severity: 'critical',
status: 'passed'
}
],
tasks: []
})
})

it('should generate a failed result if some organizations have mixed permissions', () => {
organizations[0].members_can_create_public_repositories = true
// IMPORTANT: If one organization fails, the whole project fails no matter how other organizations are in the project
organizations[1].members_can_create_public_repositories = null

const analysis = adminRepoCreationOnly({ organizations, check, projects })
expect(analysis).toEqual({
alerts: [
{
project_id: 1,
compliance_check_id: 1,
severity: 'critical',
title: 'Not Only Admins can create public repositories in the following (org1) organization(s)',
description: 'Check the details on https://example.com'
}
],
results: [
{
project_id: 1,
compliance_check_id: 1,
severity: 'critical',
status: 'failed',
rationale: 'Not Only Admins can create public repositories in the following (org1) organization(s)'
},
{
project_id: 2,
compliance_check_id: 1,
severity: 'critical',
status: 'passed',
rationale: 'Only Admins can create public repositories in the organization(s)'
}
],
tasks: [
{
project_id: 1,
compliance_check_id: 1,
severity: 'critical',
title: 'Limit public repo creation to admins for the following (org1) organization(s)',
description: 'Check the details on https://example.com'
}
]
})
})

it('should generate an unknown result if some organizations have unknown permissions', () => {
organizations[1].members_can_create_public_repositories = null
const analysis = adminRepoCreationOnly({ organizations, check, projects })
expect(analysis).toEqual({
alerts: [],
results: [
{
project_id: 1,
compliance_check_id: 1,
severity: 'critical',
status: 'unknown',
rationale: 'It was not possible to confirm if only admins can create public repositories in the following (org2) organization(s)'
},
{
project_id: 2,
compliance_check_id: 1,
severity: 'critical',
status: 'passed',
rationale: 'Only Admins can create public repositories in the organization(s)'
}
],
tasks: []
})
})
})
31 changes: 31 additions & 0 deletions src/checks/complianceChecks/adminRepoCreationOnly.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:adminRepoCreationOnly')

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

debug('Extracting the validation results...')
const analysis = validators.adminRepoCreationOnly({ organizations, 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)))
}
68 changes: 68 additions & 0 deletions src/checks/validators/adminRepoCreationOnly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const debug = require('debug')('checks:validator:adminRepoCreationOnly')
const { getSeverityFromPriorityGroup, groupArrayItemsByCriteria } = require('../../utils')

const groupByProject = groupArrayItemsByCriteria('project_id')

// @see: https://github.com/OpenPathfinder/visionBoard/issues/75
module.exports = ({ organizations = [], check, projects = [] }) => {
debug('Validating that only admins can create public repositories...')
debug('Grouping organizations by project...')
const organizationsGroupedByProject = groupByProject(organizations)

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

debug('Processing organizations...')
organizationsGroupedByProject.forEach((projectOrgs) => {
debug(`Processing project (${projectOrgs[0].project_id})`)
const project = projects.find(p => p.id === projectOrgs[0].project_id)

const baseData = {
project_id: projectOrgs[0].project_id,
compliance_check_id: check.id,
severity: getSeverityFromPriorityGroup(check.default_priority_group)
}

const result = { ...baseData }
const task = { ...baseData }
const alert = { ...baseData }

const failedOrgs = projectOrgs.filter(org => org.members_can_create_public_repositories === true).map(org => org.login)
const unknownOrgs = projectOrgs.filter(org => org.members_can_create_public_repositories === null).map(org => org.login)

if (projectOrgs.every(org => org.members_can_create_public_repositories === false)) {
result.status = 'passed'
result.rationale = 'Only Admins can create public repositories in the organization(s)'
} else if (failedOrgs.length) {
result.status = 'failed'
result.rationale = `Not Only Admins can create public repositories in the following (${failedOrgs.join(',')}) organization(s)`
alert.title = `Not Only Admins can create public repositories in the following (${failedOrgs.join(',')}) organization(s)`
alert.description = `Check the details on ${check.details_url}`
task.title = `Limit public repo creation to admins for the following (${failedOrgs.join(',')}) organization(s)`
task.description = `Check the details on ${check.details_url}`
} else if (unknownOrgs.length) {
result.status = 'unknown'
result.rationale = `It was not possible to confirm if only admins can create public repositories in the following (${unknownOrgs.join(',')}) organization(s)`
}
// Include only the task if was populated
if (Object.keys(task).length > Object.keys(baseData).length) {
debug(`Adding task for project (${project.id})`)
tasks.push(task)
}
// Include only the alert if was populated
if (Object.keys(alert).length > Object.keys(baseData).length) {
debug(`Adding alert for project (${project.id})`)
alerts.push(alert)
}
// Always include the result
results.push(result)
debug(`Processed project (${project.id})`)
})

return {
alerts,
results,
tasks
}
}
4 changes: 3 additions & 1 deletion src/checks/validators/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
const githubOrgMFA = require('./githubOrgMFA')
const softwareDesignTraining = require('./softwareDesignTraining')
const adminRepoCreationOnly = require('./adminRepoCreationOnly')

const validators = {
githubOrgMFA,
softwareDesignTraining
softwareDesignTraining,
adminRepoCreationOnly
}

module.exports = validators
Loading
Loading