diff --git a/__tests__/checks/genericProjectPolicyComplianceCheck.test.js b/__tests__/checks/genericProjectPolicyComplianceCheck.test.js new file mode 100644 index 0000000..90bab2c --- /dev/null +++ b/__tests__/checks/genericProjectPolicyComplianceCheck.test.js @@ -0,0 +1,146 @@ +const knexInit = require('knex') +const { getConfig } = require('../../src/config') + +const complianceChecks = require('../../src/checks') +const { + resetDatabase, initializeStore +} = require('../../__utils__') + +const { sampleGithubOrg } = require('../../__fixtures__') + +const { dbSettings } = getConfig('test') + +let knex +let check + +let addProject, + getAllResults, + getAllTasks, + getAllAlerts, + addAlert, + addTask, + addResult, + getCheckByCodeName + +beforeAll(async () => { + knex = knexInit(dbSettings); + ({ + addProject, + getAllResults, + getAllTasks, + getAllAlerts, + addAlert, + addTask, + addResult, + getCheckByCodeName + } = initializeStore(knex)) + check = await getCheckByCodeName('defineFunctionalRoles') +}) + +beforeEach(async () => { + await resetDatabase(knex) +}) + +afterAll(async () => { + await knex.destroy() +}) + +describe('Integration: Generic Project Policy Compliance Checks', () => { + // @TODO: ensure that the genericProjectPolicyComplianceCheck is used in the complianceChecks + it('Should include all the generic Project policy compliance checks', () => { + expect(complianceChecks).toHaveProperty('defineFunctionalRoles') + expect(complianceChecks).toHaveProperty('orgToolingMFA') + expect(complianceChecks).toHaveProperty('softwareArchitectureDocs') + expect(complianceChecks).toHaveProperty('MFAImpersonationDefense') + expect(complianceChecks).toHaveProperty('includeCVEInReleaseNotes') + expect(complianceChecks).toHaveProperty('assignCVEForKnownVulns') + expect(complianceChecks).toHaveProperty('incidentResponsePlan') + expect(complianceChecks).toHaveProperty('regressionTestsForVulns') + expect(complianceChecks).toHaveProperty('vulnResponse14Days') + expect(complianceChecks).toHaveProperty('useCVDToolForVulns') + expect(complianceChecks).toHaveProperty('securityMdMeetsOpenJSCVD') + expect(complianceChecks).toHaveProperty('consistentBuildProcessDocs') + expect(complianceChecks).toHaveProperty('machineReadableDependencies') + expect(complianceChecks).toHaveProperty('identifyModifiedDependencies') + expect(complianceChecks).toHaveProperty('ciAndCdPipelineAsCode') + expect(complianceChecks).toHaveProperty('npmOrgMFA') + expect(complianceChecks).toHaveProperty('npmPublicationMFA') + expect(complianceChecks).toHaveProperty('upgradePathDocs') + }) + + test('Should add results without alerts or tasks', async () => { + // Add a passed check scenario + await addProject({ name: sampleGithubOrg.login, has_defineFunctionalRoles_policy: true }) + // 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(complianceChecks.defineFunctionalRoles(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 + const project = await addProject({ name: sampleGithubOrg.login, has_defineFunctionalRoles_policy: true }) + 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 complianceChecks.defineFunctionalRoles(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 + const project = await addProject({ name: sampleGithubOrg.login, has_defineFunctionalRoles_policy: false }) + 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 complianceChecks.defineFunctionalRoles(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) + }) +}) diff --git a/__tests__/checks/validators/genericProjectPolicyValidator.test.js b/__tests__/checks/validators/genericProjectPolicyValidator.test.js new file mode 100644 index 0000000..aa46e4a --- /dev/null +++ b/__tests__/checks/validators/genericProjectPolicyValidator.test.js @@ -0,0 +1,134 @@ +const validators = require('../../../src/checks/validators') + +describe('Generic Project Policy Validators', () => { + let check, projects + + beforeEach(() => { + projects = [ + { + id: 1, + has_defineFunctionalRoles_policy: true + }, { + id: 2, + has_defineFunctionalRoles_policy: true + }] + + check = { + id: 1, + default_priority_group: 'P2', + details_url: 'https://example.com' + } + }) + + // @TODO: ensure that the genericProjectPolicyValidator is used in the validators + it('Should include all the generic validators', () => { + expect(validators).toHaveProperty('defineFunctionalRoles') + expect(validators).toHaveProperty('orgToolingMFA') + expect(validators).toHaveProperty('softwareArchitectureDocs') + expect(validators).toHaveProperty('MFAImpersonationDefense') + expect(validators).toHaveProperty('includeCVEInReleaseNotes') + expect(validators).toHaveProperty('assignCVEForKnownVulns') + expect(validators).toHaveProperty('incidentResponsePlan') + expect(validators).toHaveProperty('regressionTestsForVulns') + expect(validators).toHaveProperty('vulnResponse14Days') + expect(validators).toHaveProperty('useCVDToolForVulns') + expect(validators).toHaveProperty('securityMdMeetsOpenJSCVD') + expect(validators).toHaveProperty('consistentBuildProcessDocs') + expect(validators).toHaveProperty('machineReadableDependencies') + expect(validators).toHaveProperty('identifyModifiedDependencies') + expect(validators).toHaveProperty('ciAndCdPipelineAsCode') + expect(validators).toHaveProperty('npmOrgMFA') + expect(validators).toHaveProperty('npmPublicationMFA') + expect(validators).toHaveProperty('upgradePathDocs') + }) + + it('Should generate a passed result if all the projects subscribes the policy', () => { + const analysis = validators.defineFunctionalRoles({ check, projects }) + expect(analysis).toEqual({ + alerts: [], + results: [ + { + project_id: 1, + compliance_check_id: 1, + severity: 'critical', + status: 'passed', + rationale: 'The project subscribes to the defineFunctionalRoles policy' + }, + { + compliance_check_id: 1, + project_id: 2, + rationale: 'The project subscribes to the defineFunctionalRoles policy', + severity: 'critical', + status: 'passed' + } + ], + tasks: [] + }) + }) + + it('Should generate a failed result if any project does not subscribes the policy', () => { + projects[0].has_defineFunctionalRoles_policy = false + const analysis = validators.defineFunctionalRoles({ check, projects }) + expect(analysis).toEqual({ + alerts: [ + { + project_id: 1, + compliance_check_id: 1, + severity: 'critical', + title: 'The project does not subscribe to the defineFunctionalRoles policy', + description: 'Check the details on https://example.com' + } + ], + results: [ + { + project_id: 1, + compliance_check_id: 1, + severity: 'critical', + status: 'failed', + rationale: 'The project does not subscribe to the defineFunctionalRoles policy' + }, + { + compliance_check_id: 1, + project_id: 2, + rationale: 'The project subscribes to the defineFunctionalRoles policy', + severity: 'critical', + status: 'passed' + } + ], + tasks: [ + { + project_id: 1, + compliance_check_id: 1, + severity: 'critical', + title: 'Subscribe to the defineFunctionalRoles policy', + description: 'Check the details on https://example.com' + } + ] + }) + }) + + it('Should generate an unknown result if any project has an unknown policy status', () => { + projects[0].has_defineFunctionalRoles_policy = null + const analysis = validators.defineFunctionalRoles({ check, projects }) + expect(analysis).toEqual({ + alerts: [], + results: [ + { + project_id: 1, + compliance_check_id: 1, + severity: 'critical', + status: 'unknown', + rationale: 'The project has the policy defineFunctionalRoles with an unknown status' + }, + { + compliance_check_id: 1, + project_id: 2, + rationale: 'The project subscribes to the defineFunctionalRoles policy', + severity: 'critical', + status: 'passed' + } + ], + tasks: [] + }) + }) +}) diff --git a/src/checks/complianceChecks/genericProjectPolicyComplianceCheck.js b/src/checks/complianceChecks/genericProjectPolicyComplianceCheck.js new file mode 100644 index 0000000..263728d --- /dev/null +++ b/src/checks/complianceChecks/genericProjectPolicyComplianceCheck.js @@ -0,0 +1,31 @@ +const validators = require('../validators') +const debugInstance = require('debug') +const { initializeStore } = require('../../store') + +module.exports = (checkName) => async (knex, { projects } = {}) => { + const debug = debugInstance(`checks:${checkName}`) + const { + getCheckByCodeName, + getAllProjects, addAlert, addTask, upsertComplianceCheckResult, + deleteAlertsByComplianceCheckId, deleteTasksByComplianceCheckId + } = initializeStore(knex) + debug('Collecting relevant data...') + const check = await getCheckByCodeName(checkName) + if (!projects || (Array.isArray(projects) && projects.length === 0)) { + projects = await getAllProjects() + } + + debug('Extracting the validation results...') + const analysis = validators[checkName]({ projects, check }) + + 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))) +} diff --git a/src/checks/index.js b/src/checks/index.js index 7567285..ce6534b 100644 --- a/src/checks/index.js +++ b/src/checks/index.js @@ -1,12 +1,13 @@ const { readdirSync } = require('fs') const { join } = require('path') const debug = require('debug')('checks:index') +const genericProjectPolicyComplianceCheck = require('./complianceChecks/genericProjectPolicyComplianceCheck') // This will load all the files in the complianceChecks directory and export them as an object. It works similar to require-all debug('Loading compliance check files...') const checksPath = join(__dirname, 'complianceChecks') const files = readdirSync(checksPath) -const jsFiles = files.filter(file => file.endsWith('.js')) +const jsFiles = files.filter(file => file.endsWith('.js') && file !== 'genericProjectPolicyComplianceCheck.js') const checks = {} for (const file of jsFiles) { debug(`Loading ${file}...`) @@ -17,4 +18,26 @@ for (const file of jsFiles) { debug('Checks files loaded') +// Generic Policies +checks.defineFunctionalRoles = genericProjectPolicyComplianceCheck('defineFunctionalRoles') +checks.orgToolingMFA = genericProjectPolicyComplianceCheck('orgToolingMFA') +checks.softwareArchitectureDocs = genericProjectPolicyComplianceCheck('softwareArchitectureDocs') +checks.MFAImpersonationDefense = genericProjectPolicyComplianceCheck('MFAImpersonationDefense') +checks.includeCVEInReleaseNotes = genericProjectPolicyComplianceCheck('includeCVEInReleaseNotes') +checks.assignCVEForKnownVulns = genericProjectPolicyComplianceCheck('assignCVEForKnownVulns') +checks.incidentResponsePlan = genericProjectPolicyComplianceCheck('incidentResponsePlan') +checks.regressionTestsForVulns = genericProjectPolicyComplianceCheck('regressionTestsForVulns') +checks.vulnResponse14Days = genericProjectPolicyComplianceCheck('vulnResponse14Days') +checks.useCVDToolForVulns = genericProjectPolicyComplianceCheck('useCVDToolForVulns') +checks.securityMdMeetsOpenJSCVD = genericProjectPolicyComplianceCheck('securityMdMeetsOpenJSCVD') +checks.consistentBuildProcessDocs = genericProjectPolicyComplianceCheck('consistentBuildProcessDocs') +checks.machineReadableDependencies = genericProjectPolicyComplianceCheck('machineReadableDependencies') +checks.identifyModifiedDependencies = genericProjectPolicyComplianceCheck('identifyModifiedDependencies') +checks.ciAndCdPipelineAsCode = genericProjectPolicyComplianceCheck('ciAndCdPipelineAsCode') +checks.npmOrgMFA = genericProjectPolicyComplianceCheck('npmOrgMFA') +checks.npmPublicationMFA = genericProjectPolicyComplianceCheck('npmPublicationMFA') +checks.upgradePathDocs = genericProjectPolicyComplianceCheck('upgradePathDocs') + +debug('Generic Policies loaded') + module.exports = checks diff --git a/src/checks/validators/genericProjectPolicyValidator.js b/src/checks/validators/genericProjectPolicyValidator.js new file mode 100644 index 0000000..f5bccaf --- /dev/null +++ b/src/checks/validators/genericProjectPolicyValidator.js @@ -0,0 +1,64 @@ +const debugInstance = require('debug') +const { getSeverityFromPriorityGroup } = require('../../utils') + +module.exports = (checkName) => ({ check, projects = [] }) => { + const debug = debugInstance(`checks:validator:${checkName}`) + debug('Starting validation process...') + const alerts = [] + const results = [] + const tasks = [] + + debug('Processing projects...') + projects.forEach((project) => { + debug(`Processing project (${project.id})`) + + const baseData = { + project_id: project.id, + compliance_check_id: check.id, + severity: getSeverityFromPriorityGroup(check.default_priority_group) + } + + const result = { ...baseData } + const task = { ...baseData } + const alert = { ...baseData } + + const columnInScope = `has_${checkName}_policy` + + result.status = 'passed' + result.rationale = `The project subscribes to the ${checkName} policy` + + if (project[columnInScope] === false) { + result.status = 'failed' + result.rationale = `The project does not subscribe to the ${checkName} policy` + alert.title = `The project does not subscribe to the ${checkName} policy` + alert.description = `Check the details on ${check.details_url}` + task.title = `Subscribe to the ${checkName} policy` + task.description = `Check the details on ${check.details_url}` + } + + if (typeof project[columnInScope] !== 'boolean') { + result.status = 'unknown' + result.rationale = `The project has the policy ${checkName} with an unknown status` + } + + // 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 + } +} diff --git a/src/checks/validators/index.js b/src/checks/validators/index.js index 40d472c..13acfd7 100644 --- a/src/checks/validators/index.js +++ b/src/checks/validators/index.js @@ -3,13 +3,33 @@ const softwareDesignTraining = require('./softwareDesignTraining') const owaspTop10Training = require('./owaspTop10Training') const adminRepoCreationOnly = require('./adminRepoCreationOnly') const noSensitiveInfoInRepositories = require('./noSensitiveInfoInRepositories') +const genericProjectPolicyValidator = require('./genericProjectPolicyValidator') const validators = { githubOrgMFA, softwareDesignTraining, owaspTop10Training, adminRepoCreationOnly, - noSensitiveInfoInRepositories + noSensitiveInfoInRepositories, + // Generic Policies + defineFunctionalRoles: genericProjectPolicyValidator('defineFunctionalRoles'), + orgToolingMFA: genericProjectPolicyValidator('orgToolingMFA'), + softwareArchitectureDocs: genericProjectPolicyValidator('softwareArchitectureDocs'), + MFAImpersonationDefense: genericProjectPolicyValidator('MFAImpersonationDefense'), + includeCVEInReleaseNotes: genericProjectPolicyValidator('includeCVEInReleaseNotes'), + assignCVEForKnownVulns: genericProjectPolicyValidator('assignCVEForKnownVulns'), + incidentResponsePlan: genericProjectPolicyValidator('incidentResponsePlan'), + regressionTestsForVulns: genericProjectPolicyValidator('regressionTestsForVulns'), + vulnResponse14Days: genericProjectPolicyValidator('vulnResponse14Days'), + useCVDToolForVulns: genericProjectPolicyValidator('useCVDToolForVulns'), + securityMdMeetsOpenJSCVD: genericProjectPolicyValidator('securityMdMeetsOpenJSCVD'), + consistentBuildProcessDocs: genericProjectPolicyValidator('consistentBuildProcessDocs'), + machineReadableDependencies: genericProjectPolicyValidator('machineReadableDependencies'), + identifyModifiedDependencies: genericProjectPolicyValidator('identifyModifiedDependencies'), + ciAndCdPipelineAsCode: genericProjectPolicyValidator('ciAndCdPipelineAsCode'), + npmOrgMFA: genericProjectPolicyValidator('npmOrgMFA'), + npmPublicationMFA: genericProjectPolicyValidator('npmPublicationMFA'), + upgradePathDocs: genericProjectPolicyValidator('upgradePathDocs') } module.exports = validators diff --git a/src/database/migrations/1739183546535_alter_projects.js b/src/database/migrations/1739183546535_alter_projects.js new file mode 100644 index 0000000..ff46b71 --- /dev/null +++ b/src/database/migrations/1739183546535_alter_projects.js @@ -0,0 +1,45 @@ +exports.up = async (knex) => { + await knex.schema.alterTable('projects', (table) => { + table.boolean('has_defineFunctionalRoles_policy').nullable() + table.boolean('has_orgToolingMFA_policy').nullable() + table.boolean('has_softwareArchitectureDocs_policy').nullable() + table.boolean('has_MFAImpersonationDefense_policy').nullable() + table.boolean('has_includeCVEInReleaseNotes_policy').nullable() + table.boolean('has_assignCVEForKnownVulns_policy').nullable() + table.boolean('has_incidentResponsePlan_policy').nullable() + table.boolean('has_regressionTestsForVulns_policy').nullable() + table.boolean('has_vulnResponse14Days_policy').nullable() + table.boolean('has_useCVDToolForVulns_policy').nullable() + table.boolean('has_securityMdMeetsOpenJSCVD_policy').nullable() + table.boolean('has_consistentBuildProcessDocs_policy').nullable() + table.boolean('has_machineReadableDependencies_policy').nullable() + table.boolean('has_identifyModifiedDependencies_policy').nullable() + table.boolean('has_ciAndCdPipelineAsCode_policy').nullable() + table.boolean('has_npmOrgMFA_policy').nullable() + table.boolean('has_npmPublicationMFA_policy').nullable() + table.boolean('has_upgradePathDocs_policy').nullable() + }) +} + +exports.down = async (knex) => { + await knex.schema.alterTable('projects', (table) => { + table.dropColumn('has_defineFunctionalRoles_policy') + table.dropColumn('has_orgToolingMFA_policy') + table.dropColumn('has_softwareArchitectureDocs_policy') + table.dropColumn('has_MFAImpersonationDefense_policy') + table.dropColumn('has_includeCVEInReleaseNotes_policy') + table.dropColumn('has_assignCVEForKnownVulns_policy') + table.dropColumn('has_incidentResponsePlan_policy') + table.dropColumn('has_regressionTestsForVulns_policy') + table.dropColumn('has_vulnResponse14Days_policy') + table.dropColumn('has_useCVDToolForVulns_policy') + table.dropColumn('has_securityMdMeetsOpenJSCVD_policy') + table.dropColumn('has_consistentBuildProcessDocs_policy') + table.dropColumn('has_machineReadableDependencies_policy') + table.dropColumn('has_identifyModifiedDependencies_policy') + table.dropColumn('has_ciAndCdPipelineAsCode_policy') + table.dropColumn('has_npmOrgMFA_policy') + table.dropColumn('has_npmPublicationMFA_policy') + table.dropColumn('has_upgradePathDocs_policy') + }) +} diff --git a/src/database/migrations/1739185914475_alter_compliance_checks.js b/src/database/migrations/1739185914475_alter_compliance_checks.js new file mode 100644 index 0000000..9e3b9d6 --- /dev/null +++ b/src/database/migrations/1739185914475_alter_compliance_checks.js @@ -0,0 +1,79 @@ +const checks = [ + { + code_name: 'defineFunctionalRoles', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/77' + }, { + code_name: 'orgToolingMFA', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/65' + }, { + code_name: 'softwareArchitectureDocs', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/107' + }, { + code_name: 'MFAImpersonationDefense', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/66' + }, { + code_name: 'includeCVEInReleaseNotes', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/92' + }, { + code_name: 'assignCVEForKnownVulns', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/91' + }, { + code_name: 'incidentResponsePlan', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/90' + }, { + code_name: 'regressionTestsForVulns', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/93' + }, { + code_name: 'vulnResponse14Days', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/89' + }, { + code_name: 'useCVDToolForVulns', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/88' + }, { + code_name: 'securityMdMeetsOpenJSCVD', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/87' + }, { + code_name: 'consistentBuildProcessDocs', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/105' + }, { + code_name: 'machineReadableDependencies', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/110' + }, { + code_name: 'identifyModifiedDependencies', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/111' + }, { + code_name: 'ciAndCdPipelineAsCode', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/108' + }, { + code_name: 'npmOrgMFA', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/64' + }, { + code_name: 'npmPublicationMFA', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/72' + }, { + code_name: 'upgradePathDocs', + implementation_details_reference: 'https://github.com/OpenPathfinder/visionBoard/issues/106' + } +] + +exports.up = async (knex) => { + await Promise.all(checks.map(async check => knex('compliance_checks') + .where({ code_name: check.code_name }) + .update({ + implementation_status: 'completed', + implementation_type: 'manual', + implementation_details_reference: check.implementation_details_reference + }) + )) +} + +exports.down = async (knex) => { + await Promise.all(checks.map(async check => knex('compliance_checks') + .where({ code_name: check.code_name }) + .update({ + implementation_status: 'pending', + implementation_type: null, + implementation_details_reference: null + }) + )) +} diff --git a/src/database/schema/schema.sql b/src/database/schema/schema.sql index 5674321..67ac3f0 100644 --- a/src/database/schema/schema.sql +++ b/src/database/schema/schema.sql @@ -713,7 +713,22 @@ CREATE TABLE public.projects ( id integer NOT NULL, name character varying(255) NOT NULL, created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, - updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL + updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + "has_defineFunctionalRoles_policy" boolean, + "has_orgToolingMFA_policy" boolean, + "has_softwareArchitectureDocs_policy" boolean, + "has_MFAImpersonationDefense_policy" boolean, + "has_includeCVEInReleaseNotes_policy" boolean, + "has_assignCVEForKnownVulns_policy" boolean, + "has_incidentResponsePlan_policy" boolean, + "has_regressionTestsForVulns_policy" boolean, + "has_vulnResponse14Days_policy" boolean, + "has_useCVDToolForVulns_policy" boolean, + "has_securityMdMeetsOpenJSCVD_policy" boolean, + "has_consistentBuildProcessDocs_policy" boolean, + "has_machineReadableDependencies_policy" boolean, + "has_identifyModifiedDependencies_policy" boolean, + "has_ciAndCdPipelineAsCode_policy" boolean ); diff --git a/src/database/seeds/index.js b/src/database/seeds/index.js index 0709feb..865fadf 100644 --- a/src/database/seeds/index.js +++ b/src/database/seeds/index.js @@ -21,7 +21,8 @@ exports.seed = async (knex) => { // Add a project const project = await addProject({ - name: 'github' + name: 'github', + has_defineFunctionalRoles_policy: false }) // Add a GitHub organization diff --git a/src/store/index.js b/src/store/index.js index 0750a71..0e84fed 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -46,9 +46,7 @@ const addProject = knex => async (project) => { throw new Error(`Project with name (${name}) already exists`) } debug(`Inserting project (${name})...`) - return knex('projects').insert({ - name - }).returning('*').then(results => results[0]) + return knex('projects').insert(project).returning('*').then(results => results[0]) } const getCheckByCodeName = knex => (codeName) => {