diff --git a/__tests__/cli/__snapshots__/workflows.test.js.snap b/__tests__/cli/__snapshots__/workflows.test.js.snap index ee5c4cb..0ae1739 100644 --- a/__tests__/cli/__snapshots__/workflows.test.js.snap +++ b/__tests__/cli/__snapshots__/workflows.test.js.snap @@ -26,12 +26,48 @@ exports[`list - Non-Interactive Mode Should provide a list of available workflow "operations": null, "workflow": [Function], }, + { + "description": "Run a specific compliance check for the stored data.", + "isEnabled": true, + "isRequiredAdditionalData": true, + "name": "run-one-check", + "operations": null, + "schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "check_name": { + "description": "The name of the check to run", + "type": "string", + }, + }, + "required": [ + "check_name", + ], + "type": "object", + }, + "workflow": [Function], + }, { "description": "Upsert the OSSF Scorecard scoring by running and checking every repository in the database.", "isEnabled": false, "isRequiredAdditionalData": false, "name": "upsert-ossf-scorecard", "operations": null, + "schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "project_id": { + "description": "The id of the project to run the check on", + "type": "integer", + }, + }, + "required": [ + "check_name", + ], + "type": "object", + }, "workflow": [Function], }, { diff --git a/src/cli/workflows.js b/src/cli/workflows.js index abd2d04..4de758f 100644 --- a/src/cli/workflows.js +++ b/src/cli/workflows.js @@ -1,11 +1,11 @@ const inquirer = require('inquirer').default const _ = require('lodash') const debug = require('debug')('cli:workflows') -const { updateGithubOrgs, upsertGithubRepositories, runAllTheComplianceChecks, upsertOSSFScorecardAnalysis } = require('../workflows') +const { updateGithubOrgs, upsertGithubRepositories, runAllTheComplianceChecks, runOneComplianceCheck, upsertOSSFScorecardAnalysis } = require('../workflows') const { generateStaticReports } = require('../reports') const { bulkImport } = require('../importers') const { logger } = require('../utils') -const bulkImportSchema = require('../schemas/bulkImport.json') +const { executeOneCheckSchema, executeOptionalProjectSchema, bulkImportSchema } = require('../schemas') const commandList = [{ name: 'update-github-orgs', @@ -28,9 +28,18 @@ const commandList = [{ description: 'Run all the compliance checks for the stored data.', operations: null, workflow: runAllTheComplianceChecks +}, { + name: 'run-one-check', + isRequiredAdditionalData: true, + isEnabled: true, + description: 'Run a specific compliance check for the stored data.', + operations: null, + schema: executeOneCheckSchema, + workflow: runOneComplianceCheck }, { name: 'upsert-ossf-scorecard', isRequiredAdditionalData: false, + schema: executeOptionalProjectSchema, isEnabled: false, description: 'Upsert the OSSF Scorecard scoring by running and checking every repository in the database.', operations: null, @@ -64,13 +73,14 @@ const getWorkflowsDetails = () => { commandList.forEach((workflow) => { const workflowName = _.kebabCase(workflow.name) - workflowsList.push({ id: workflowName, description: workflow.description, isEnabled: workflow.isEnabled, isRequiredAdditionalData: workflow.isRequiredAdditionalData, operations: workflow.operations }) + workflowsList.push({ id: workflowName, description: workflow.description, isEnabled: workflow.isEnabled, isRequiredAdditionalData: workflow.isRequiredAdditionalData, operations: workflow.operations, schema: JSON.stringify(workflow.schema) }) workflows[workflowName] = { description: workflow.description, workflow: workflow.workflow, isEnabled: workflow.isEnabled, isRequiredAdditionalData: workflow.isRequiredAdditionalData, - operations: workflow.operations + operations: workflow.operations, + schema: JSON.stringify(workflow.schema) } }) diff --git a/src/schemas/execute-one-check.json b/src/schemas/execute-one-check.json new file mode 100644 index 0000000..d350ae4 --- /dev/null +++ b/src/schemas/execute-one-check.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": false, + "properties": { + "check_name": { + "type": "string", + "description": "The name of the check to run" + } + }, + "required": ["check_name"] +} \ No newline at end of file diff --git a/src/schemas/execute-optional-project.json b/src/schemas/execute-optional-project.json new file mode 100644 index 0000000..133f164 --- /dev/null +++ b/src/schemas/execute-optional-project.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": false, + "properties": { + "project_id": { + "type": "integer", + "description": "The id of the project to run the check on" + } + }, + "required": ["check_name"] +} \ No newline at end of file diff --git a/src/schemas/index.js b/src/schemas/index.js index 252fc46..1ac6aa8 100644 --- a/src/schemas/index.js +++ b/src/schemas/index.js @@ -7,6 +7,8 @@ const ossfScorecardResultSchema = require('./ossfScorecardResult.json') const bulkImportSchema = require('./bulkImport.json') const projectDataSchema = require('./projectData.json') const indexDataSchema = require('./indexData.json') +const executeOneCheckSchema = require('./execute-one-check.json') +const executeOptionalProjectSchema = require('./execute-optional-project.json') const ajv = new Ajv({ allowUnionTypes: true // Allow union types for fields like Date/string @@ -25,6 +27,16 @@ const validateGithubOrg = (data) => { return null } +const validateExecuteOneCheck = (data) => { + const validate = ajv.compile(executeOneCheckSchema) + const valid = validate(data) + if (!valid) { + const readableErrors = getReadableErrors(validate) + throw new Error(`Error when validating the execute one check request: ${readableErrors}`) + } + return null +} + const validateGithubListOrgRepos = (data) => { const validate = ajv.compile(githubListOrgReposSchema) const valid = validate(data) @@ -92,5 +104,9 @@ module.exports = { validateOSSFResult, validateBulkImport, validateProjectData, - validateIndexData + validateIndexData, + validateExecuteOneCheck, + executeOneCheckSchema, + executeOptionalProjectSchema, + bulkImportSchema } diff --git a/src/workflows/index.js b/src/workflows/index.js index 7c7553a..abe56ee 100644 --- a/src/workflows/index.js +++ b/src/workflows/index.js @@ -2,7 +2,7 @@ const debug = require('debug')('workflows') const { github, ossf } = require('../providers') const { initializeStore } = require('../store') const { logger } = require('../utils') -const { validateGithubOrg, validateGithubListOrgRepos, validateGithubRepository, validateOSSFResult } = require('../schemas') +const { validateGithubOrg, validateGithubListOrgRepos, validateGithubRepository, validateOSSFResult, validateExecuteOneCheck } = require('../schemas') const checks = require('../checks') const { chunkArray } = require('@ulisesgascon/array-to-chunks') const { ossfScorecardSettings } = require('../config').getConfig() @@ -109,9 +109,21 @@ const upsertOSSFScorecardAnalysis = async (knex) => { logger.info('The OSSF Scorecard ran successfully') } +const runOneComplianceCheck = async (knex, data) => { + validateExecuteOneCheck(data) + const checkName = data.check_name + const check = checks[checkName] + if (!check) { + throw new Error('Check not found') + } + await check(knex) + logger.info(`${checkName} check completed successfully`) +} + module.exports = { updateGithubOrgs, upsertGithubRepositories, runAllTheComplianceChecks, - upsertOSSFScorecardAnalysis + upsertOSSFScorecardAnalysis, + runOneComplianceCheck }