2024-03-11 22:17:28 +00:00
|
|
|
import {Change, Scorecard, ScorecardApi} from './schemas'
|
2024-03-03 00:31:13 +00:00
|
|
|
import * as core from '@actions/core'
|
2024-03-02 22:37:50 +00:00
|
|
|
|
2024-03-03 05:24:07 +00:00
|
|
|
export async function getScorecardLevels(
|
|
|
|
|
changes: Change[]
|
|
|
|
|
): Promise<Scorecard> {
|
2024-03-03 06:50:11 +00:00
|
|
|
const data: Scorecard = {dependencies: []} as Scorecard
|
2024-03-03 00:25:40 +00:00
|
|
|
for (const change of changes) {
|
2024-03-04 18:51:52 +00:00
|
|
|
const ecosystem = change.ecosystem
|
|
|
|
|
const packageName = change.name
|
|
|
|
|
const version = change.version
|
2024-03-06 14:43:49 +00:00
|
|
|
|
|
|
|
|
//Get the project repository
|
|
|
|
|
let repositoryUrl = change.source_repository_url
|
2024-03-06 20:06:26 +00:00
|
|
|
//If the repository_url includes the protocol, remove it
|
|
|
|
|
if (repositoryUrl?.startsWith('https://')) {
|
|
|
|
|
repositoryUrl = repositoryUrl.replace('https://', '')
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-22 21:00:38 +00:00
|
|
|
// Handle the special case for GitHub Actions, where the repository URL is null
|
|
|
|
|
if (ecosystem === 'actions') {
|
|
|
|
|
// The package name for GitHub Actions in the API is in the format `owner/repo/`, so we can use that to get the repository URL
|
|
|
|
|
// If the package name has more than 2 slashes, it's referencing a sub-action, and we need to strip the last part out
|
|
|
|
|
const parts = packageName.split('/')
|
|
|
|
|
repositoryUrl = `github.com/${parts[0]}/${parts[1]}` // e.g. github.com/actions/checkout
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-06 14:43:49 +00:00
|
|
|
// If GitHub API doesn't have the repository URL, query deps.dev for it.
|
2024-03-22 21:00:38 +00:00
|
|
|
if (!repositoryUrl) {
|
2024-03-06 14:43:49 +00:00
|
|
|
// Call the deps.dev API to get the repository URL from there
|
|
|
|
|
repositoryUrl = await getProjectUrl(ecosystem, packageName, version)
|
2024-03-03 01:34:03 +00:00
|
|
|
}
|
2024-03-06 14:43:49 +00:00
|
|
|
|
|
|
|
|
// Get the scorecard API response from the scorecards API
|
|
|
|
|
let scorecardApi: ScorecardApi | null = null
|
2024-03-12 21:49:01 +00:00
|
|
|
if (repositoryUrl) {
|
2024-03-06 14:43:49 +00:00
|
|
|
try {
|
|
|
|
|
scorecardApi = await getScorecard(repositoryUrl)
|
2024-03-11 22:17:28 +00:00
|
|
|
} catch (error: unknown) {
|
|
|
|
|
core.debug(`Error querying for scorecard: ${(error as Error).message}`)
|
2024-03-06 14:43:49 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
data.dependencies.push({
|
2024-03-08 02:31:11 +00:00
|
|
|
change,
|
2024-03-06 14:43:49 +00:00
|
|
|
scorecard: scorecardApi
|
|
|
|
|
})
|
2024-03-03 00:25:40 +00:00
|
|
|
}
|
2024-03-03 01:34:03 +00:00
|
|
|
return data
|
2024-03-02 22:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
2024-03-06 14:43:49 +00:00
|
|
|
async function getScorecard(repositoryUrl: string): Promise<ScorecardApi> {
|
2024-03-22 21:20:15 +00:00
|
|
|
const apiRoot = 'https://api.securityscorecards.dev'
|
2024-03-06 14:43:49 +00:00
|
|
|
let scorecardResponse: ScorecardApi = {} as ScorecardApi
|
2024-03-02 22:37:50 +00:00
|
|
|
|
2024-03-06 19:44:54 +00:00
|
|
|
const url = `${apiRoot}/projects/${repositoryUrl}`
|
2024-03-06 14:43:49 +00:00
|
|
|
const response = await fetch(url)
|
|
|
|
|
if (response.ok) {
|
|
|
|
|
scorecardResponse = await response.json()
|
2024-03-06 19:44:54 +00:00
|
|
|
} else {
|
|
|
|
|
core.debug(`Couldn't get scorecard data for ${repositoryUrl}`)
|
2024-03-03 00:25:40 +00:00
|
|
|
}
|
2024-03-06 14:43:49 +00:00
|
|
|
return scorecardResponse
|
2024-03-02 22:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
2024-03-12 17:55:10 +00:00
|
|
|
export async function getProjectUrl(
|
2024-03-06 14:43:49 +00:00
|
|
|
ecosystem: string,
|
|
|
|
|
packageName: string,
|
|
|
|
|
version: string
|
|
|
|
|
): Promise<string> {
|
|
|
|
|
core.debug(`Getting deps.dev data for ${packageName} ${version}`)
|
|
|
|
|
const depsDevAPIRoot = 'https://api.deps.dev'
|
2024-04-09 16:11:32 +10:00
|
|
|
const url = `${depsDevAPIRoot}/v3/systems/${ecosystem}/packages/${packageName}/versions/${version}`
|
2024-03-06 14:43:49 +00:00
|
|
|
const response = await fetch(url)
|
|
|
|
|
if (response.ok) {
|
|
|
|
|
const data = await response.json()
|
|
|
|
|
if (data.relatedProjects.length > 0) {
|
|
|
|
|
return data.relatedProjects[0].projectKey.id
|
2024-03-03 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
2024-03-06 14:43:49 +00:00
|
|
|
return ''
|
2024-03-22 21:59:08 +00:00
|
|
|
}
|