Refactor scorecard API implementation
This commit is contained in:
+113
-67
@@ -750,10 +750,10 @@ function printNullLicenses(changes) {
|
|||||||
}
|
}
|
||||||
function printScorecardBlock(scorecard, config) {
|
function printScorecardBlock(scorecard, config) {
|
||||||
core.group('Scorecard', () => __awaiter(this, void 0, void 0, function* () {
|
core.group('Scorecard', () => __awaiter(this, void 0, void 0, function* () {
|
||||||
var _a, _b;
|
var _a;
|
||||||
if (scorecard) {
|
if (scorecard) {
|
||||||
for (const dependency of scorecard.dependencies) {
|
for (const dependency of scorecard.dependencies) {
|
||||||
core.info(`${dependency.ecosystem}/${dependency.packageName}: OpenSSF Scorecard Score: ${(_b = (_a = dependency === null || dependency === void 0 ? void 0 : dependency.depsDevData) === null || _a === void 0 ? void 0 : _a.scorecard) === null || _b === void 0 ? void 0 : _b.overallScore}`);
|
core.info(`${dependency.ecosystem}/${dependency.packageName}: OpenSSF Scorecard Score: ${(_a = dependency === null || dependency === void 0 ? void 0 : dependency.scorecard) === null || _a === void 0 ? void 0 : _a.score}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -839,7 +839,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.ScorecardSchema = exports.DepsDevProjectSchema = exports.ComparisonResponseSchema = exports.ChangesSchema = exports.ConfigurationOptionsSchema = exports.PullRequestSchema = exports.ChangeSchema = exports.SeveritySchema = exports.SCOPES = exports.SEVERITIES = void 0;
|
exports.ScorecardSchema = exports.DepsDevProjectSchema = exports.ScorecardApiSchema = exports.ComparisonResponseSchema = exports.ChangesSchema = exports.ConfigurationOptionsSchema = exports.PullRequestSchema = exports.ChangeSchema = exports.SeveritySchema = exports.SCOPES = exports.SEVERITIES = void 0;
|
||||||
const z = __importStar(__nccwpck_require__(3301));
|
const z = __importStar(__nccwpck_require__(3301));
|
||||||
exports.SEVERITIES = ['critical', 'high', 'moderate', 'low'];
|
exports.SEVERITIES = ['critical', 'high', 'moderate', 'low'];
|
||||||
exports.SCOPES = ['unknown', 'runtime', 'development'];
|
exports.SCOPES = ['unknown', 'runtime', 'development'];
|
||||||
@@ -931,6 +931,34 @@ exports.ComparisonResponseSchema = z.object({
|
|||||||
changes: z.array(exports.ChangeSchema),
|
changes: z.array(exports.ChangeSchema),
|
||||||
snapshot_warnings: z.string()
|
snapshot_warnings: z.string()
|
||||||
});
|
});
|
||||||
|
exports.ScorecardApiSchema = z.object({
|
||||||
|
date: z.string(),
|
||||||
|
repo: z
|
||||||
|
.object({
|
||||||
|
name: z.string(),
|
||||||
|
commit: z.string()
|
||||||
|
})
|
||||||
|
.nullish(),
|
||||||
|
scorecard: z
|
||||||
|
.object({
|
||||||
|
version: z.string(),
|
||||||
|
commit: z.string()
|
||||||
|
})
|
||||||
|
.nullish(),
|
||||||
|
checks: z
|
||||||
|
.array(z.object({
|
||||||
|
name: z.string(),
|
||||||
|
documentation: z.object({
|
||||||
|
shortDescription: z.string(),
|
||||||
|
url: z.string()
|
||||||
|
}),
|
||||||
|
score: z.string(),
|
||||||
|
reason: z.string(),
|
||||||
|
details: z.array(z.string())
|
||||||
|
}))
|
||||||
|
.nullish(),
|
||||||
|
score: z.number().nullish()
|
||||||
|
});
|
||||||
exports.DepsDevProjectSchema = z
|
exports.DepsDevProjectSchema = z
|
||||||
.object({
|
.object({
|
||||||
projectKey: z.object({
|
projectKey: z.object({
|
||||||
@@ -985,7 +1013,7 @@ exports.ScorecardSchema = z.object({
|
|||||||
ecosystem: z.string(),
|
ecosystem: z.string(),
|
||||||
packageName: z.string(),
|
packageName: z.string(),
|
||||||
version: z.string().nullish(),
|
version: z.string().nullish(),
|
||||||
depsDevData: exports.DepsDevProjectSchema
|
scorecard: exports.ScorecardApiSchema.nullish()
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1031,7 +1059,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.getScorecardLevels = void 0;
|
exports.getScorecardLevels = void 0;
|
||||||
const schemas_1 = __nccwpck_require__(8774);
|
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
function getScorecardLevels(changes) {
|
function getScorecardLevels(changes) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@@ -1040,72 +1067,63 @@ function getScorecardLevels(changes) {
|
|||||||
const ecosystem = change.ecosystem;
|
const ecosystem = change.ecosystem;
|
||||||
const packageName = change.name;
|
const packageName = change.name;
|
||||||
const version = change.version;
|
const version = change.version;
|
||||||
try {
|
//Get the project repository
|
||||||
const depsDevResponse = yield getDepsDevData(ecosystem, packageName, version);
|
let repositoryUrl = change.source_repository_url;
|
||||||
data.dependencies.push({
|
// If GitHub API doesn't have the repository URL, query deps.dev for it.
|
||||||
ecosystem,
|
if (repositoryUrl === null ||
|
||||||
packageName,
|
repositoryUrl === undefined ||
|
||||||
version,
|
repositoryUrl === '') {
|
||||||
depsDevData: depsDevResponse
|
// Call the deps.dev API to get the repository URL from there
|
||||||
});
|
repositoryUrl = yield getProjectUrl(ecosystem, packageName, version);
|
||||||
}
|
}
|
||||||
catch (error) {
|
// Get the scorecard API response from the scorecards API
|
||||||
core.debug(`Error querying for depsDevData: ${error.message}`);
|
let scorecardApi = null;
|
||||||
data.dependencies.push({
|
if (repositoryUrl !== null &&
|
||||||
ecosystem,
|
repositoryUrl !== undefined &&
|
||||||
packageName,
|
repositoryUrl !== '') {
|
||||||
version,
|
try {
|
||||||
depsDevData: null
|
scorecardApi = yield getScorecard(repositoryUrl);
|
||||||
});
|
}
|
||||||
|
catch (error) {
|
||||||
|
core.debug(`Error querying for scorecard: ${error.message}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
data.dependencies.push({
|
||||||
|
ecosystem,
|
||||||
|
packageName,
|
||||||
|
version,
|
||||||
|
scorecard: scorecardApi
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.getScorecardLevels = getScorecardLevels;
|
exports.getScorecardLevels = getScorecardLevels;
|
||||||
const depsDevAPIRoot = 'https://api.deps.dev';
|
function getScorecard(repositoryUrl) {
|
||||||
function getDepsDevData(ecosystem, packageName, version) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
const apiRoot = 'https://api.securityscorecards.dev/';
|
||||||
core.debug(`Getting deps.dev data for ${packageName} ${version}`);
|
let scorecardResponse = {};
|
||||||
const url = `${depsDevAPIRoot}/v3alpha/systems/${ecosystem}/packages/${packageName}/versions/${version}`;
|
const url = `${apiRoot}/${repositoryUrl}`;
|
||||||
const response = yield fetch(url);
|
const response = yield fetch(url);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = yield response.json();
|
scorecardResponse = yield response.json();
|
||||||
const projects = data.relatedProjects;
|
|
||||||
for (const project of projects) {
|
|
||||||
return yield getDepsDevProjectData(project.projectKey.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error(`Failed to fetch data with status code: ${response.status}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
return scorecardResponse;
|
||||||
core.debug(`Error fetching data: ${error.message}`);
|
|
||||||
}
|
|
||||||
return schemas_1.DepsDevProjectSchema.parse({});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function getDepsDevProjectData(projectKeyId) {
|
function getProjectUrl(ecosystem, packageName, version) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
core.debug(`Getting deps.dev data for ${packageName} ${version}`);
|
||||||
core.debug(`Getting deps.dev project data for ${projectKeyId}`);
|
const depsDevAPIRoot = 'https://api.deps.dev';
|
||||||
const url = `${depsDevAPIRoot}/v3alpha/projects/${encodeURIComponent(projectKeyId)}`;
|
const url = `${depsDevAPIRoot}/v3alpha/systems/${ecosystem}/packages/${packageName}/versions/${version}`;
|
||||||
const response = yield fetch(url);
|
const response = yield fetch(url);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = yield response.json();
|
const data = yield response.json();
|
||||||
//core.debug(`Got deps.dev project data: ${JSON.stringify(data)}`)
|
if (data.relatedProjects.length > 0) {
|
||||||
return schemas_1.DepsDevProjectSchema.parse(data);
|
return data.relatedProjects[0].projectKey.id;
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error(`Failed to fetch project data with status code: ${response.status}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
return '';
|
||||||
core.debug(`Error fetching project data: ${error.message}`);
|
|
||||||
}
|
|
||||||
return schemas_1.DepsDevProjectSchema.parse({});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1328,23 +1346,23 @@ function addScorecardToSummary(scorecard, config) {
|
|||||||
core.summary.addRaw(`<table><tr><th>Package</th><th>Version</th><th>Score</th><th>Details</th></tr>`, true);
|
core.summary.addRaw(`<table><tr><th>Package</th><th>Version</th><th>Score</th><th>Details</th></tr>`, true);
|
||||||
for (const dependency of scorecard.dependencies) {
|
for (const dependency of scorecard.dependencies) {
|
||||||
core.debug('Adding scorecard to summary');
|
core.debug('Adding scorecard to summary');
|
||||||
core.debug(`Overall score ${(_a = dependency.depsDevData) === null || _a === void 0 ? void 0 : _a.scorecard.overallScore}`);
|
core.debug(`Overall score ${(_a = dependency.scorecard) === null || _a === void 0 ? void 0 : _a.score}`);
|
||||||
// Set the icon based on the overall score value
|
// Set the icon based on the overall score value
|
||||||
let overallIcon = '';
|
let overallIcon = '';
|
||||||
if (((_b = dependency.depsDevData) === null || _b === void 0 ? void 0 : _b.scorecard.overallScore) !== undefined &&
|
if (((_b = dependency.scorecard) === null || _b === void 0 ? void 0 : _b.score) !== undefined &&
|
||||||
((_c = dependency.depsDevData) === null || _c === void 0 ? void 0 : _c.scorecard.overallScore) !== null) {
|
((_c = dependency.scorecard) === null || _c === void 0 ? void 0 : _c.score) !== null) {
|
||||||
overallIcon =
|
overallIcon =
|
||||||
((_d = dependency.depsDevData) === null || _d === void 0 ? void 0 : _d.scorecard.overallScore) <
|
((_d = dependency.scorecard) === null || _d === void 0 ? void 0 : _d.score) < config.warn_on_openssf_scorecard_level
|
||||||
config.warn_on_openssf_scorecard_level
|
|
||||||
? ':warning:'
|
? ':warning:'
|
||||||
: ':green_circle:';
|
: ':green_circle:';
|
||||||
}
|
}
|
||||||
//Add a row for the dependency
|
//Add a row for the dependency
|
||||||
core.summary.addRaw(`<tr><td>${dependency.ecosystem}/${dependency.packageName}</td><td>${dependency.version}</td>
|
core.summary.addRaw(`<tr><td>${dependency.ecosystem}/${dependency.packageName}</td><td>${dependency.version}</td>
|
||||||
<td>${overallIcon} ${((_e = dependency.depsDevData) === null || _e === void 0 ? void 0 : _e.scorecard.overallScore) === undefined || ((_f = dependency.depsDevData) === null || _f === void 0 ? void 0 : _f.scorecard.overallScore) === null ? 'Unknown' : (_g = dependency.depsDevData) === null || _g === void 0 ? void 0 : _g.scorecard.overallScore}</td>`, false);
|
<td>${overallIcon} ${((_e = dependency.scorecard) === null || _e === void 0 ? void 0 : _e.score) === undefined || ((_f = dependency.scorecard) === null || _f === void 0 ? void 0 : _f.score) === null ? 'Unknown' : (_g = dependency.scorecard) === null || _g === void 0 ? void 0 : _g.score}</td>`, false);
|
||||||
if (((_h = dependency.depsDevData) === null || _h === void 0 ? void 0 : _h.scorecard.checks) !== undefined) {
|
//Add details table in the last column
|
||||||
|
if (((_h = dependency.scorecard) === null || _h === void 0 ? void 0 : _h.checks) !== undefined) {
|
||||||
let detailsTable = '<table><tr><th>Check</th><th>Score</th><th>Reason</th></tr>';
|
let detailsTable = '<table><tr><th>Check</th><th>Score</th><th>Reason</th></tr>';
|
||||||
for (const check of ((_j = dependency.depsDevData) === null || _j === void 0 ? void 0 : _j.scorecard.checks) || []) {
|
for (const check of ((_j = dependency.scorecard) === null || _j === void 0 ? void 0 : _j.checks) || []) {
|
||||||
const icon = parseFloat(check.score) < config.warn_on_openssf_scorecard_level
|
const icon = parseFloat(check.score) < config.warn_on_openssf_scorecard_level
|
||||||
? ':warning:'
|
? ':warning:'
|
||||||
: ':green_circle:';
|
: ':green_circle:';
|
||||||
@@ -49997,7 +50015,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.ScorecardSchema = exports.DepsDevProjectSchema = exports.ComparisonResponseSchema = exports.ChangesSchema = exports.ConfigurationOptionsSchema = exports.PullRequestSchema = exports.ChangeSchema = exports.SeveritySchema = exports.SCOPES = exports.SEVERITIES = void 0;
|
exports.ScorecardSchema = exports.DepsDevProjectSchema = exports.ScorecardApiSchema = exports.ComparisonResponseSchema = exports.ChangesSchema = exports.ConfigurationOptionsSchema = exports.PullRequestSchema = exports.ChangeSchema = exports.SeveritySchema = exports.SCOPES = exports.SEVERITIES = void 0;
|
||||||
const z = __importStar(__nccwpck_require__(3301));
|
const z = __importStar(__nccwpck_require__(3301));
|
||||||
exports.SEVERITIES = ['critical', 'high', 'moderate', 'low'];
|
exports.SEVERITIES = ['critical', 'high', 'moderate', 'low'];
|
||||||
exports.SCOPES = ['unknown', 'runtime', 'development'];
|
exports.SCOPES = ['unknown', 'runtime', 'development'];
|
||||||
@@ -50089,6 +50107,34 @@ exports.ComparisonResponseSchema = z.object({
|
|||||||
changes: z.array(exports.ChangeSchema),
|
changes: z.array(exports.ChangeSchema),
|
||||||
snapshot_warnings: z.string()
|
snapshot_warnings: z.string()
|
||||||
});
|
});
|
||||||
|
exports.ScorecardApiSchema = z.object({
|
||||||
|
date: z.string(),
|
||||||
|
repo: z
|
||||||
|
.object({
|
||||||
|
name: z.string(),
|
||||||
|
commit: z.string()
|
||||||
|
})
|
||||||
|
.nullish(),
|
||||||
|
scorecard: z
|
||||||
|
.object({
|
||||||
|
version: z.string(),
|
||||||
|
commit: z.string()
|
||||||
|
})
|
||||||
|
.nullish(),
|
||||||
|
checks: z
|
||||||
|
.array(z.object({
|
||||||
|
name: z.string(),
|
||||||
|
documentation: z.object({
|
||||||
|
shortDescription: z.string(),
|
||||||
|
url: z.string()
|
||||||
|
}),
|
||||||
|
score: z.string(),
|
||||||
|
reason: z.string(),
|
||||||
|
details: z.array(z.string())
|
||||||
|
}))
|
||||||
|
.nullish(),
|
||||||
|
score: z.number().nullish()
|
||||||
|
});
|
||||||
exports.DepsDevProjectSchema = z
|
exports.DepsDevProjectSchema = z
|
||||||
.object({
|
.object({
|
||||||
projectKey: z.object({
|
projectKey: z.object({
|
||||||
@@ -50143,7 +50189,7 @@ exports.ScorecardSchema = z.object({
|
|||||||
ecosystem: z.string(),
|
ecosystem: z.string(),
|
||||||
packageName: z.string(),
|
packageName: z.string(),
|
||||||
version: z.string().nullish(),
|
version: z.string().nullish(),
|
||||||
depsDevData: exports.DepsDevProjectSchema
|
scorecard: exports.ScorecardApiSchema.nullish()
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -279,7 +279,7 @@ function printScorecardBlock(
|
|||||||
if (scorecard) {
|
if (scorecard) {
|
||||||
for (const dependency of scorecard.dependencies) {
|
for (const dependency of scorecard.dependencies) {
|
||||||
core.info(
|
core.info(
|
||||||
`${dependency.ecosystem}/${dependency.packageName}: OpenSSF Scorecard Score: ${dependency?.depsDevData?.scorecard?.overallScore}`
|
`${dependency.ecosystem}/${dependency.packageName}: OpenSSF Scorecard Score: ${dependency?.scorecard?.score}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-1
@@ -102,6 +102,37 @@ export const ComparisonResponseSchema = z.object({
|
|||||||
snapshot_warnings: z.string()
|
snapshot_warnings: z.string()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const ScorecardApiSchema = z.object({
|
||||||
|
date: z.string(),
|
||||||
|
repo: z
|
||||||
|
.object({
|
||||||
|
name: z.string(),
|
||||||
|
commit: z.string()
|
||||||
|
})
|
||||||
|
.nullish(),
|
||||||
|
scorecard: z
|
||||||
|
.object({
|
||||||
|
version: z.string(),
|
||||||
|
commit: z.string()
|
||||||
|
})
|
||||||
|
.nullish(),
|
||||||
|
checks: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
name: z.string(),
|
||||||
|
documentation: z.object({
|
||||||
|
shortDescription: z.string(),
|
||||||
|
url: z.string()
|
||||||
|
}),
|
||||||
|
score: z.string(),
|
||||||
|
reason: z.string(),
|
||||||
|
details: z.array(z.string())
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.nullish(),
|
||||||
|
score: z.number().nullish()
|
||||||
|
})
|
||||||
|
|
||||||
export const DepsDevProjectSchema = z
|
export const DepsDevProjectSchema = z
|
||||||
.object({
|
.object({
|
||||||
projectKey: z.object({
|
projectKey: z.object({
|
||||||
@@ -160,7 +191,7 @@ export const ScorecardSchema = z.object({
|
|||||||
ecosystem: z.string(),
|
ecosystem: z.string(),
|
||||||
packageName: z.string(),
|
packageName: z.string(),
|
||||||
version: z.string().nullish(),
|
version: z.string().nullish(),
|
||||||
depsDevData: DepsDevProjectSchema
|
scorecard: ScorecardApiSchema.nullish()
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -173,3 +204,4 @@ export type Severity = z.infer<typeof SeveritySchema>
|
|||||||
export type Scope = (typeof SCOPES)[number]
|
export type Scope = (typeof SCOPES)[number]
|
||||||
export type DepsDevProject = z.infer<typeof DepsDevProjectSchema>
|
export type DepsDevProject = z.infer<typeof DepsDevProjectSchema>
|
||||||
export type Scorecard = z.infer<typeof ScorecardSchema>
|
export type Scorecard = z.infer<typeof ScorecardSchema>
|
||||||
|
export type ScorecardApi = z.infer<typeof ScorecardApiSchema>
|
||||||
|
|||||||
+55
-63
@@ -2,7 +2,8 @@ import {
|
|||||||
Change,
|
Change,
|
||||||
DepsDevProject,
|
DepsDevProject,
|
||||||
DepsDevProjectSchema,
|
DepsDevProjectSchema,
|
||||||
Scorecard
|
Scorecard,
|
||||||
|
ScorecardApi
|
||||||
} from './schemas'
|
} from './schemas'
|
||||||
import {isSPDXValid, octokitClient} from './utils'
|
import {isSPDXValid, octokitClient} from './utils'
|
||||||
import {PackageURL} from 'packageurl-js'
|
import {PackageURL} from 'packageurl-js'
|
||||||
@@ -16,77 +17,68 @@ export async function getScorecardLevels(
|
|||||||
const ecosystem = change.ecosystem
|
const ecosystem = change.ecosystem
|
||||||
const packageName = change.name
|
const packageName = change.name
|
||||||
const version = change.version
|
const version = change.version
|
||||||
try {
|
|
||||||
const depsDevResponse: DepsDevProject = await getDepsDevData(
|
//Get the project repository
|
||||||
ecosystem,
|
let repositoryUrl = change.source_repository_url
|
||||||
packageName,
|
// If GitHub API doesn't have the repository URL, query deps.dev for it.
|
||||||
version
|
if (
|
||||||
)
|
repositoryUrl === null ||
|
||||||
data.dependencies.push({
|
repositoryUrl === undefined ||
|
||||||
ecosystem,
|
repositoryUrl === ''
|
||||||
packageName,
|
) {
|
||||||
version,
|
// Call the deps.dev API to get the repository URL from there
|
||||||
depsDevData: depsDevResponse
|
repositoryUrl = await getProjectUrl(ecosystem, packageName, version)
|
||||||
})
|
|
||||||
} catch (error: any) {
|
|
||||||
core.debug(`Error querying for depsDevData: ${error.message}`)
|
|
||||||
data.dependencies.push({
|
|
||||||
ecosystem,
|
|
||||||
packageName,
|
|
||||||
version,
|
|
||||||
depsDevData: null
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the scorecard API response from the scorecards API
|
||||||
|
let scorecardApi: ScorecardApi | null = null
|
||||||
|
if (
|
||||||
|
repositoryUrl !== null &&
|
||||||
|
repositoryUrl !== undefined &&
|
||||||
|
repositoryUrl !== ''
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
scorecardApi = await getScorecard(repositoryUrl)
|
||||||
|
} catch (error: any) {
|
||||||
|
core.debug(`Error querying for scorecard: ${error.message}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.dependencies.push({
|
||||||
|
ecosystem,
|
||||||
|
packageName,
|
||||||
|
version,
|
||||||
|
scorecard: scorecardApi
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
const depsDevAPIRoot = 'https://api.deps.dev'
|
async function getScorecard(repositoryUrl: string): Promise<ScorecardApi> {
|
||||||
|
const apiRoot = 'https://api.securityscorecards.dev/'
|
||||||
|
let scorecardResponse: ScorecardApi = {} as ScorecardApi
|
||||||
|
|
||||||
async function getDepsDevData(
|
const url = `${apiRoot}/${repositoryUrl}`
|
||||||
ecosystem: String,
|
const response = await fetch(url)
|
||||||
packageName: String,
|
if (response.ok) {
|
||||||
version: any
|
scorecardResponse = await response.json()
|
||||||
): Promise<DepsDevProject> {
|
|
||||||
try {
|
|
||||||
core.debug(`Getting deps.dev data for ${packageName} ${version}`)
|
|
||||||
const url = `${depsDevAPIRoot}/v3alpha/systems/${ecosystem}/packages/${packageName}/versions/${version}`
|
|
||||||
const response = await fetch(url)
|
|
||||||
if (response.ok) {
|
|
||||||
const data = await response.json()
|
|
||||||
const projects = data.relatedProjects
|
|
||||||
for (const project of projects) {
|
|
||||||
return await getDepsDevProjectData(project.projectKey.id)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error(
|
|
||||||
`Failed to fetch data with status code: ${response.status}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
core.debug(`Error fetching data: ${error.message}`)
|
|
||||||
}
|
}
|
||||||
return DepsDevProjectSchema.parse({})
|
return scorecardResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getDepsDevProjectData(
|
async function getProjectUrl(
|
||||||
projectKeyId: string
|
ecosystem: string,
|
||||||
): Promise<DepsDevProject> {
|
packageName: string,
|
||||||
try {
|
version: string
|
||||||
core.debug(`Getting deps.dev project data for ${projectKeyId}`)
|
): Promise<string> {
|
||||||
const url = `${depsDevAPIRoot}/v3alpha/projects/${encodeURIComponent(projectKeyId)}`
|
core.debug(`Getting deps.dev data for ${packageName} ${version}`)
|
||||||
const response = await fetch(url)
|
const depsDevAPIRoot = 'https://api.deps.dev'
|
||||||
if (response.ok) {
|
const url = `${depsDevAPIRoot}/v3alpha/systems/${ecosystem}/packages/${packageName}/versions/${version}`
|
||||||
const data = await response.json()
|
const response = await fetch(url)
|
||||||
//core.debug(`Got deps.dev project data: ${JSON.stringify(data)}`)
|
if (response.ok) {
|
||||||
return DepsDevProjectSchema.parse(data)
|
const data = await response.json()
|
||||||
} else {
|
if (data.relatedProjects.length > 0) {
|
||||||
throw new Error(
|
return data.relatedProjects[0].projectKey.id
|
||||||
`Failed to fetch project data with status code: ${response.status}`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
|
||||||
core.debug(`Error fetching project data: ${error.message}`)
|
|
||||||
}
|
}
|
||||||
return DepsDevProjectSchema.parse({})
|
return ''
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-10
@@ -260,19 +260,16 @@ export function addScorecardToSummary(
|
|||||||
)
|
)
|
||||||
for (const dependency of scorecard.dependencies) {
|
for (const dependency of scorecard.dependencies) {
|
||||||
core.debug('Adding scorecard to summary')
|
core.debug('Adding scorecard to summary')
|
||||||
core.debug(
|
core.debug(`Overall score ${dependency.scorecard?.score}`)
|
||||||
`Overall score ${dependency.depsDevData?.scorecard.overallScore}`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set the icon based on the overall score value
|
// Set the icon based on the overall score value
|
||||||
let overallIcon = ''
|
let overallIcon = ''
|
||||||
if (
|
if (
|
||||||
dependency.depsDevData?.scorecard.overallScore !== undefined &&
|
dependency.scorecard?.score !== undefined &&
|
||||||
dependency.depsDevData?.scorecard.overallScore !== null
|
dependency.scorecard?.score !== null
|
||||||
) {
|
) {
|
||||||
overallIcon =
|
overallIcon =
|
||||||
dependency.depsDevData?.scorecard.overallScore <
|
dependency.scorecard?.score < config.warn_on_openssf_scorecard_level
|
||||||
config.warn_on_openssf_scorecard_level
|
|
||||||
? ':warning:'
|
? ':warning:'
|
||||||
: ':green_circle:'
|
: ':green_circle:'
|
||||||
}
|
}
|
||||||
@@ -280,13 +277,15 @@ export function addScorecardToSummary(
|
|||||||
//Add a row for the dependency
|
//Add a row for the dependency
|
||||||
core.summary.addRaw(
|
core.summary.addRaw(
|
||||||
`<tr><td>${dependency.ecosystem}/${dependency.packageName}</td><td>${dependency.version}</td>
|
`<tr><td>${dependency.ecosystem}/${dependency.packageName}</td><td>${dependency.version}</td>
|
||||||
<td>${overallIcon} ${dependency.depsDevData?.scorecard.overallScore === undefined || dependency.depsDevData?.scorecard.overallScore === null ? 'Unknown' : dependency.depsDevData?.scorecard.overallScore}</td>`,
|
<td>${overallIcon} ${dependency.scorecard?.score === undefined || dependency.scorecard?.score === null ? 'Unknown' : dependency.scorecard?.score}</td>`,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
if (dependency.depsDevData?.scorecard.checks !== undefined) {
|
|
||||||
|
//Add details table in the last column
|
||||||
|
if (dependency.scorecard?.checks !== undefined) {
|
||||||
let detailsTable =
|
let detailsTable =
|
||||||
'<table><tr><th>Check</th><th>Score</th><th>Reason</th></tr>'
|
'<table><tr><th>Check</th><th>Score</th><th>Reason</th></tr>'
|
||||||
for (const check of dependency.depsDevData?.scorecard.checks || []) {
|
for (const check of dependency.scorecard?.checks || []) {
|
||||||
const icon =
|
const icon =
|
||||||
parseFloat(check.score) < config.warn_on_openssf_scorecard_level
|
parseFloat(check.score) < config.warn_on_openssf_scorecard_level
|
||||||
? ':warning:'
|
? ':warning:'
|
||||||
|
|||||||
Reference in New Issue
Block a user