diff --git a/__fixtures__/index.js b/__fixtures__/index.js
index 812f53f..f91ae6a 100644
--- a/__fixtures__/index.js
+++ b/__fixtures__/index.js
@@ -10,7 +10,7 @@ const sampleGithubOrg = {
issues_url: 'https://api.github.com/orgs/github/issues',
members_url: 'https://api.github.com/orgs/github/members{/member}',
public_members_url: 'https://api.github.com/orgs/github/public_members{/member}',
- avatar_url: 'https://github.com/images/error/octocat_happy.gif',
+ avatar_url: 'https://avatars.githubusercontent.com/u/9919?v=4',
description: 'A great organization',
name: 'github',
company: 'GitHub',
@@ -76,7 +76,7 @@ const sampleGithubListOrgRepos = [
login: 'octocat',
id: 1,
node_id: 'MDQ6VXNlcjE=',
- avatar_url: 'https://github.com/images/error/octocat_happy.gif',
+ avatar_url: 'https://avatars.githubusercontent.com/u/9919?v=4',
gravatar_id: '',
url: 'https://api.github.com/users/octocat',
html_url: 'https://github.com/octocat',
@@ -197,7 +197,7 @@ const sampleGithubRepository = {
login: 'octocat',
id: 1,
node_id: 'MDQ6VXNlcjE=',
- avatar_url: 'https://github.com/images/error/octocat_happy.gif',
+ avatar_url: 'https://avatars.githubusercontent.com/u/9919?v=4',
gravatar_id: '',
url: 'https://api.github.com/users/octocat',
html_url: 'https://github.com/octocat',
@@ -303,7 +303,7 @@ const sampleGithubRepository = {
login: 'octocat',
id: 1,
node_id: 'MDQ6VXNlcjE=',
- avatar_url: 'https://github.com/images/error/octocat_happy.gif',
+ avatar_url: 'https://avatars.githubusercontent.com/u/9919?v=4',
gravatar_id: '',
url: 'https://api.github.com/users/octocat',
html_url: 'https://github.com/octocat',
@@ -435,7 +435,7 @@ const sampleGithubRepository = {
login: 'octocat',
id: 1,
node_id: 'MDQ6VXNlcjE=',
- avatar_url: 'https://github.com/images/error/octocat_happy.gif',
+ avatar_url: 'https://avatars.githubusercontent.com/u/9919?v=4',
gravatar_id: '',
url: 'https://api.github.com/users/octocat',
html_url: 'https://github.com/octocat',
@@ -460,7 +460,7 @@ const sampleGithubRepository = {
login: 'octocat',
id: 1,
node_id: 'MDQ6VXNlcjE=',
- avatar_url: 'https://github.com/images/error/octocat_happy.gif',
+ avatar_url: 'https://avatars.githubusercontent.com/u/9919?v=4',
gravatar_id: '',
url: 'https://api.github.com/users/octocat',
html_url: 'https://github.com/octocat',
@@ -582,7 +582,7 @@ const sampleGithubRepository = {
login: 'octocat',
id: 1,
node_id: 'MDQ6VXNlcjE=',
- avatar_url: 'https://github.com/images/error/octocat_happy.gif',
+ avatar_url: 'https://avatars.githubusercontent.com/u/9919?v=4',
gravatar_id: '',
url: 'https://api.github.com/users/octocat',
html_url: 'https://github.com/octocat',
diff --git a/__tests__/__snapshots__/providers.test.js.snap b/__tests__/__snapshots__/providers.test.js.snap
index 8921bf5..b994e17 100644
--- a/__tests__/__snapshots__/providers.test.js.snap
+++ b/__tests__/__snapshots__/providers.test.js.snap
@@ -3,7 +3,7 @@
exports[`GitHub Provider mappers Should map organization data correctly 1`] = `
{
"advanced_security_enabled_for_new_repositories": false,
- "avatar_url": "https://github.com/images/error/octocat_happy.gif",
+ "avatar_url": "https://avatars.githubusercontent.com/u/9919?v=4",
"blog": "https://github.com/blog",
"collaborators": 8,
"company": "GitHub",
diff --git a/__tests__/cli/__snapshots__/workflows.test.js.snap b/__tests__/cli/__snapshots__/workflows.test.js.snap
index 0496d20..b2d158c 100644
--- a/__tests__/cli/__snapshots__/workflows.test.js.snap
+++ b/__tests__/cli/__snapshots__/workflows.test.js.snap
@@ -27,5 +27,10 @@ exports[`list - Non-Interactive Mode Should provide a list of available workflow
"name": "show-reports",
"workflow": [Function],
},
+ {
+ "description": "Generate the reports for the stored data.",
+ "name": "generate-reports",
+ "workflow": [Function],
+ },
]
`;
diff --git a/package-lock.json b/package-lock.json
index baa14f8..2dcabd4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
"commander": "12.1.0",
"date-fns": "4.1.0",
"debug": "4.3.7",
+ "ejs": "3.1.10",
"finalhandler": "1.3.1",
"inquirer": "12.1.0",
"knex": "3.1.0",
@@ -2388,6 +2389,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/async": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+ "license": "MIT"
+ },
"node_modules/atomic-sleep": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
@@ -2533,7 +2540,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true,
"license": "MIT"
},
"node_modules/batch": {
@@ -2558,7 +2564,6 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -2728,7 +2733,6 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
@@ -2868,7 +2872,6 @@
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true,
"license": "MIT"
},
"node_modules/convert-source-map": {
@@ -3146,6 +3149,21 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
"license": "MIT"
},
+ "node_modules/ejs": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
+ "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "jake": "^10.8.5"
+ },
+ "bin": {
+ "ejs": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.5.67",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.67.tgz",
@@ -4102,6 +4120,36 @@
"node": "^10.12.0 || >=12.0.0"
}
},
+ "node_modules/filelist": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
+ "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "minimatch": "^5.0.1"
+ }
+ },
+ "node_modules/filelist/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/filelist/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -4477,7 +4525,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -5276,6 +5323,24 @@
"node": ">= 0.4"
}
},
+ "node_modules/jake": {
+ "version": "10.9.2",
+ "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz",
+ "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "async": "^3.2.3",
+ "chalk": "^4.0.2",
+ "filelist": "^1.0.4",
+ "minimatch": "^3.1.2"
+ },
+ "bin": {
+ "jake": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/jest": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
@@ -6423,7 +6488,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -8247,7 +8311,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
diff --git a/package.json b/package.json
index b2d6cd4..180dc93 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,7 @@
"db:seed": "knex seed:run"
},
"keywords": [
- "security",
+ "security",
"CLI"
],
"repository": {
@@ -45,6 +45,7 @@
"commander": "12.1.0",
"date-fns": "4.1.0",
"debug": "4.3.7",
+ "ejs": "3.1.10",
"finalhandler": "1.3.1",
"inquirer": "12.1.0",
"knex": "3.1.0",
diff --git a/src/cli/workflows.js b/src/cli/workflows.js
index 2c079d6..c244d22 100644
--- a/src/cli/workflows.js
+++ b/src/cli/workflows.js
@@ -1,6 +1,7 @@
const inquirer = require('inquirer').default
const debug = require('debug')('cli:workflows')
const { updateGithubOrgs, upsertGithubRepositories, runAllTheComplianceChecks, upsertOSSFScorecardAnalysis } = require('../workflows')
+const { generateReports } = require('../reports')
const { logger } = require('../utils')
const commandList = [{
@@ -23,6 +24,10 @@ const commandList = [{
name: 'show-reports',
description: 'Starts a http server that shows all the files and folders in the output directory.',
workflow: require('../httpServer')
+}, {
+ name: 'generate-reports',
+ description: 'Generate the reports for the stored data.',
+ workflow: generateReports
}]
const validCommandNames = commandList.map(({ name }) => name)
diff --git a/src/reports/assets/favicon.ico b/src/reports/assets/favicon.ico
new file mode 100644
index 0000000..f5af247
Binary files /dev/null and b/src/reports/assets/favicon.ico differ
diff --git a/src/reports/index.js b/src/reports/index.js
new file mode 100644
index 0000000..4eb4e97
--- /dev/null
+++ b/src/reports/index.js
@@ -0,0 +1,108 @@
+const { logger } = require('../utils')
+const ejs = require('ejs')
+const { mkdir, readdir, copyFile, readFile, writeFile } = require('node:fs').promises
+const { join } = require('path')
+const { initializeStore } = require('../store')
+
+const indexTemplatePath = join(process.cwd(), 'src', 'reports', 'templates', 'index.html.ejs')
+const projectTemplatePath = join(process.cwd(), 'src', 'reports', 'templates', 'project.html.ejs')
+const assetsFolder = join(process.cwd(), 'src', 'reports', 'assets')
+const destinationFolder = join(process.cwd(), 'output')
+const copyFolder = async (from, to) => {
+ try {
+ // Ensure the target directory exists
+ await mkdir(to, { recursive: true })
+
+ // Read the contents of the source directory
+ const entries = await readdir(from, { withFileTypes: true })
+
+ // Process each entry
+ await Promise.all(
+ entries.map(async (entry) => {
+ const source = join(from, entry.name)
+ const dest = join(to, entry.name)
+
+ if (entry.isDirectory()) {
+ // Recursively copy subdirectories
+ await copyFolder(source, dest)
+ } else {
+ // Copy files
+ await copyFile(source, dest)
+ }
+ })
+ )
+ } catch (error) {
+ logger.warn(`Error copying folder from "${from}" to "${to}":`)
+ throw error
+ }
+}
+
+const generateReports = async (knex) => {
+ logger.info('Generating reports')
+ const { getAllProjects, getAllChecklists, getAllComplianceChecks, getAllAlerts, getAllResults, getAllTasks, getAllGithubOrganizationsByProjectsId, getAllGithubRepositories, getAllOSSFResults } = initializeStore(knex)
+ // @TODO: Run the queries in parallel
+ const projects = await getAllProjects()
+ const checklists = await getAllChecklists()
+ const checks = await getAllComplianceChecks()
+ const alerts = await getAllAlerts()
+ const results = await getAllResults()
+ const tasks = await getAllTasks()
+ const ossfScorecardResults = await getAllOSSFResults()
+ const githubRepos = await getAllGithubRepositories()
+
+ // @TODO: Read the files in parallel
+ const indexTemplate = await readFile(indexTemplatePath, 'utf8')
+ const projectTemplate = await readFile(projectTemplatePath, 'utf8')
+ await mkdir(join(destinationFolder, 'projects'), { recursive: true })
+
+ // Collecting data from the database
+ const indexData = {
+ projects,
+ checklists,
+ checks
+ }
+
+ const projectsData = {}
+
+ for (const project of projects) {
+ const githubOrgs = await getAllGithubOrganizationsByProjectsId([project.id])
+ const githubOrgsIds = githubOrgs.map(org => org.id)
+ const githubReposInScope = githubRepos.filter(repo => githubOrgsIds.includes(repo.github_organization_id))
+ const githubReposInScopeIds = githubReposInScope.map(repo => repo.id)
+
+ projectsData[project.name] = {
+ project,
+ checks,
+ alerts: alerts.filter(alert => alert.project_id === project.id),
+ results: results.filter(result => result.project_id === project.id),
+ tasks: tasks.filter(task => task.project_id === project.id),
+ githubOrgs,
+ githubRepos: githubReposInScope,
+ ossfScorecardResults: ossfScorecardResults.filter(ossfResult => githubReposInScopeIds.includes(ossfResult.github_repository_id))
+ }
+
+ // Populate the project HTML template
+ const projectHtml = ejs.render(projectTemplate, projectsData[project.name])
+ const projectFilename = join(destinationFolder, 'projects', `${project.name}.html`)
+ await writeFile(projectFilename, projectHtml)
+ }
+
+ // @TODO: Validate against JSON Schemas
+
+ // @TODO: Save the files in parallel
+ await writeFile('output/index_data.json', JSON.stringify(indexData, null, 2))
+ await writeFile('output/projects/projects_data.json', JSON.stringify(projectsData, null, 2))
+
+ // copy assets folder
+ await copyFolder(assetsFolder, join(destinationFolder, 'assets'))
+
+ // Populate the index HTML template
+ const indexHtml = ejs.render(indexTemplate, indexData)
+
+ // Save the index HTML file
+ await writeFile('output/index.html', indexHtml)
+}
+
+module.exports = {
+ generateReports
+}
diff --git a/src/reports/templates/index.html.ejs b/src/reports/templates/index.html.ejs
new file mode 100644
index 0000000..ce1d3aa
--- /dev/null
+++ b/src/reports/templates/index.html.ejs
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+ VisionBoard Reports
+
+
+
+
+
+
+
+
+
VisionBoard Reports
+
+
+
+
+
+ Welcome!
+ In this dashboard, you can find the status of all the projects that you
+ registered. Every project listed includes additional reports with its own dashboard, tasks, and alerts.
+
+
+ Projects
+ Click on any project to get more details:
+
+
+ Checklist
+
+
+
+ Documentation
+ Title
+ Description
+ Author
+
+
+
+ <% checklists.forEach(item=> { %>
+
+
+
+ <%= item.code_name %>
+
+
+
+ <%= item.title %>
+
+
+ <%= item.description %>
+
+
+ <%= item.author %>
+
+
+
+ <% }) %>
+
+
+
+ Compliance Checks
+ Currently
+ <%= checks.filter(i=> i.implementation_status === "completed").length %>/<%= checks.length %>
+ are implemented. Help us to implement more!
+
+
+
+
+ Documentation
+ Name
+ Description
+
+
+
+ <% checks.forEach(item=> { %>
+
+
+
+ <%= item.code_name %>
+
+
+
+ <%= item.title %>
+
+
+ <%= item.description %>
+
+
+ <% }) %>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/reports/templates/project.html.ejs b/src/reports/templates/project.html.ejs
new file mode 100644
index 0000000..8605c29
--- /dev/null
+++ b/src/reports/templates/project.html.ejs
@@ -0,0 +1,250 @@
+
+
+
+
+
+
+ VisionBoard Reports
+
+
+
+
+
+
+
+
+
VisionBoard Reports
+
+
+
+
+
+ <%= project.name %> Report
+
+ In this dashboard, you can find the relevant information for the project
+ <%= project.name %>
+ including results, tasks, and alerts.
+
+
+ In order to elaborate this report we have analyzed
+ <%= githubOrgs.length %> GitHub org(s)
+ and
+ <%= githubRepos.length %> repositories
+ .
+
+
+ Alerts
+
+ <% if (alerts && alerts.length > 0) { %>
+
+ <% } else { %>
+
No alerts available.
+ <% } %>
+
+
+
+ Results
+ <% if (tasks && tasks.length > 0) { %>
+
+
+ <% } else { %>
+ No results available.
+ <% } %>
+
+
+ Tasks
+
+ <% if (tasks && tasks.length > 0) { %>
+ <% tasks.forEach(task => { %>
+
+ <% }) %>
+ <% } else { %>
+
+
🎉 All tasks completed! Great job! 🎉
+
+ <% } %>
+
+
+
+
+ OSSF Scorecard Analysis
+ <% if (ossfScorecardResults && ossfScorecardResults.length > 0) { %>
+
+
+
+
+ Repository
+ Commit
+ Duration
+ Date
+ Score
+
+
+
+ <% ossfScorecardResults.forEach(item => { %>
+ <% currentRepo = githubRepos.filter(i => i.id === item.github_repository_id)[0] %>
+
+
+
+ <%= currentRepo.full_name %>
+
+
+
+
+ <%= item.repo_commit %>
+
+
+
+ <%= item.analysis_execution_time / 1000 %>s
+
+
+ <%= new Date(item.analysis_time).toISOString().slice(0, -5) %>
+
+
+ <%= item.analysis_score %>
+
+
+ <% }) %>
+
+
+ <% } else { %>
+ No OSSF Scorecard Results available.
+ <% } %>
+
+
+
+ GitHub Organizations in scope
+ <% if (githubOrgs && githubOrgs.length > 0) { %>
+
+ <% } else { %>
+ No results available.
+ <% } %>
+
+
+
+ GitHub repositories in scope
+
+ <% if (githubRepos && githubRepos.length > 0) { %>
+
+
+
+
+ Repository
+ Stars
+ Forks
+ Subscribers
+ Open Issues
+
+
+
+ <% githubRepos.forEach(item => { %>
+
+
+
+ <%= item.full_name %>
+
+
+
+ <%= item.stargazers_count %>
+
+
+ <%= item.forks_count %>
+
+
+ <%= item.subscribers_count %>
+
+
+ <%= item.open_issues_count %>
+
+
+ <% }) %>
+
+
+ <% } else { %>
+ No OSSF Scorecard Results available.
+ <% } %>
+
+
+
+
\ No newline at end of file
diff --git a/src/schemas/githubListOrgRepos.json b/src/schemas/githubListOrgRepos.json
index 05ff91c..a3a8246 100644
--- a/src/schemas/githubListOrgRepos.json
+++ b/src/schemas/githubListOrgRepos.json
@@ -70,7 +70,7 @@
"type": "string",
"format": "uri",
"examples": [
- "https://github.com/images/error/octocat_happy.gif"
+ "https://avatars.githubusercontent.com/u/9919?v=4"
]
},
"gravatar_id": {
diff --git a/src/schemas/githubOrganization.json b/src/schemas/githubOrganization.json
index 26c06c2..911f655 100644
--- a/src/schemas/githubOrganization.json
+++ b/src/schemas/githubOrganization.json
@@ -69,7 +69,7 @@
"avatar_url": {
"type": "string",
"examples": [
- "https://github.com/images/error/octocat_happy.gif"
+ "https://avatars.githubusercontent.com/u/9919?v=4"
]
},
"description": {
diff --git a/src/schemas/githubRepository.json b/src/schemas/githubRepository.json
index 5c86a25..c482cf3 100644
--- a/src/schemas/githubRepository.json
+++ b/src/schemas/githubRepository.json
@@ -68,7 +68,7 @@
"type": "string",
"format": "uri",
"examples": [
- "https://github.com/images/error/octocat_happy.gif"
+ "https://avatars.githubusercontent.com/u/9919?v=4"
]
},
"gravatar_id": {
@@ -804,7 +804,7 @@
"type": "string",
"format": "uri",
"examples": [
- "https://github.com/images/error/octocat_happy.gif"
+ "https://avatars.githubusercontent.com/u/9919?v=4"
]
},
"gravatar_id": {
@@ -1713,7 +1713,7 @@
"type": "string",
"format": "uri",
"examples": [
- "https://github.com/images/error/octocat_happy.gif"
+ "https://avatars.githubusercontent.com/u/9919?v=4"
]
},
"gravatar_id": {
@@ -1973,7 +1973,7 @@
"type": "string",
"format": "uri",
"examples": [
- "https://github.com/images/error/octocat_happy.gif"
+ "https://avatars.githubusercontent.com/u/9919?v=4"
]
},
"gravatar_id": {
@@ -2818,7 +2818,7 @@
"type": "string",
"format": "uri",
"examples": [
- "https://github.com/images/error/octocat_happy.gif"
+ "https://avatars.githubusercontent.com/u/9919?v=4"
]
},
"gravatar_id": {
diff --git a/src/store/index.js b/src/store/index.js
index 19b745f..ad1d906 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -101,6 +101,9 @@ const getAllChecksInChecklistById = (knex, checklistId) =>
const getAllGithubOrganizationsByProjectsId = (knex, projectIds) => {
debug(`Fetching all github organizations by projects id (${projectIds})...`)
+ if (!Array.isArray(projectIds)) {
+ throw new Error('projectIds must be an array')
+ }
return knex('github_organizations')
.whereIn('github_organizations.project_id', projectIds)
.select('*')
@@ -144,7 +147,8 @@ const initializeStore = (knex) => {
addGithubRepo: (repo) => addTo('github_repositories', repo),
addOSSFScorecardResult: (ossf) => addTo('ossf_scorecard_results', ossf),
upsertOSSFScorecard: upsertOSSFScorecard(knex),
- upsertComplianceCheckResult: upsertComplianceCheckResult(knex)
+ upsertComplianceCheckResult: upsertComplianceCheckResult(knex),
+ getAllOSSFResults: () => getAll('ossf_scorecard_results')
}
}