import {Change, Scorecard, ScorecardApi} from './schemas' import * as core from '@actions/core' export async function getScorecardLevels( changes: Change[] ): Promise { 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 { 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 { 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 '' }