82 lines
2.8 KiB
TypeScript
82 lines
2.8 KiB
TypeScript
import {Change, Scorecard, ScorecardApi} from './schemas'
|
|
import * as core from '@actions/core'
|
|
|
|
export async function getScorecardLevels(
|
|
changes: Change[]
|
|
): Promise<Scorecard> {
|
|
const data: Scorecard = {dependencies: []} as Scorecard
|
|
for (const change of changes) {
|
|
const ecosystem = change.ecosystem
|
|
const packageName = change.name
|
|
const version = change.version
|
|
|
|
//Get the project repository
|
|
let repositoryUrl = change.source_repository_url
|
|
//If the repository_url includes the protocol, remove it
|
|
if (repositoryUrl?.startsWith('https://')) {
|
|
repositoryUrl = repositoryUrl.replace('https://', '')
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// If GitHub API doesn't have the repository URL, query deps.dev for it.
|
|
if (!repositoryUrl) {
|
|
// Call the deps.dev API to get the repository URL from there
|
|
repositoryUrl = await getProjectUrl(ecosystem, packageName, version)
|
|
}
|
|
|
|
// Get the scorecard API response from the scorecards API
|
|
let scorecardApi: ScorecardApi | null = null
|
|
if (repositoryUrl) {
|
|
try {
|
|
scorecardApi = await getScorecard(repositoryUrl)
|
|
} catch (error: unknown) {
|
|
core.debug(`Error querying for scorecard: ${(error as Error).message}`)
|
|
}
|
|
}
|
|
data.dependencies.push({
|
|
change,
|
|
scorecard: scorecardApi
|
|
})
|
|
}
|
|
return data
|
|
}
|
|
|
|
async function getScorecard(repositoryUrl: string): Promise<ScorecardApi> {
|
|
const apiRoot = 'https://api.securityscorecards.dev'
|
|
let scorecardResponse: ScorecardApi = {} as ScorecardApi
|
|
|
|
const url = `${apiRoot}/projects/${repositoryUrl}`
|
|
const response = await fetch(url)
|
|
if (response.ok) {
|
|
scorecardResponse = await response.json()
|
|
} else {
|
|
core.debug(`Couldn't get scorecard data for ${repositoryUrl}`)
|
|
}
|
|
return scorecardResponse
|
|
}
|
|
|
|
export async function getProjectUrl(
|
|
ecosystem: string,
|
|
packageName: string,
|
|
version: string
|
|
): Promise<string> {
|
|
core.debug(`Getting deps.dev data for ${packageName} ${version}`)
|
|
const depsDevAPIRoot = 'https://api.deps.dev'
|
|
const url = `${depsDevAPIRoot}/v3/systems/${ecosystem}/packages/${packageName}/versions/${version}`
|
|
const response = await fetch(url)
|
|
if (response.ok) {
|
|
const data = await response.json()
|
|
if (data.relatedProjects.length > 0) {
|
|
return data.relatedProjects[0].projectKey.id
|
|
}
|
|
}
|
|
return ''
|
|
}
|