215 lines
6.0 KiB
TypeScript
215 lines
6.0 KiB
TypeScript
import * as z from 'zod'
|
|
import {parsePURL} from './purl'
|
|
|
|
export const SEVERITIES = ['critical', 'high', 'moderate', 'low'] as const
|
|
export const SCOPES = ['unknown', 'runtime', 'development'] as const
|
|
|
|
export const SeveritySchema = z.enum(SEVERITIES).default('low')
|
|
|
|
const PackageURL = z
|
|
.string()
|
|
.transform(purlString => {
|
|
return parsePURL(purlString)
|
|
})
|
|
.superRefine((purl, context) => {
|
|
if (purl.error) {
|
|
context.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: `Error parsing package-url: ${purl.error}`
|
|
})
|
|
}
|
|
if (!purl.name) {
|
|
context.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: `Error parsing package-url: name is required`
|
|
})
|
|
}
|
|
})
|
|
|
|
const PackageURLWithNamespace = z
|
|
.string()
|
|
.transform(purlString => {
|
|
return parsePURL(purlString)
|
|
})
|
|
.superRefine((purl, context) => {
|
|
if (purl.error) {
|
|
context.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: `Error parsing purl: ${purl.error}`
|
|
})
|
|
}
|
|
if (purl.namespace === null) {
|
|
context.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: `package-url must have a namespace, and the namespace must be followed by '/'`
|
|
})
|
|
}
|
|
})
|
|
|
|
const PackageURLString = z.string().superRefine((value, context) => {
|
|
const purl = parsePURL(value)
|
|
if (purl.error) {
|
|
context.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: `Error parsing package-url: ${purl.error}`
|
|
})
|
|
}
|
|
if (!purl.name) {
|
|
context.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: `Error parsing package-url: name is required`
|
|
})
|
|
}
|
|
})
|
|
|
|
export const ChangeSchema = z.object({
|
|
change_type: z.enum(['added', 'removed']),
|
|
manifest: z.string(),
|
|
ecosystem: z.string(),
|
|
name: z.string(),
|
|
version: z.string(),
|
|
package_url: z.string(),
|
|
license: z.string().nullable(),
|
|
source_repository_url: z.string().nullable(),
|
|
scope: z.enum(SCOPES).optional(),
|
|
vulnerabilities: z
|
|
.array(
|
|
z.object({
|
|
severity: SeveritySchema,
|
|
advisory_ghsa_id: z.string(),
|
|
advisory_summary: z.string(),
|
|
advisory_url: z.string()
|
|
})
|
|
)
|
|
.optional()
|
|
.default([])
|
|
})
|
|
|
|
export const PullRequestSchema = z.object({
|
|
number: z.number(),
|
|
base: z.object({sha: z.string()}),
|
|
head: z.object({sha: z.string()})
|
|
})
|
|
|
|
export const MergeGroupSchema = z.object({
|
|
base_sha: z.string(),
|
|
head_sha: z.string()
|
|
})
|
|
|
|
export const ConfigurationOptionsSchema = z
|
|
.object({
|
|
fail_on_severity: SeveritySchema,
|
|
fail_on_scopes: z.array(z.enum(SCOPES)).default(['runtime']),
|
|
allow_licenses: z.array(z.string()).optional(),
|
|
deny_licenses: z.array(z.string()).optional(),
|
|
allow_dependencies_licenses: z.array(PackageURLString).optional(),
|
|
allow_ghsas: z.array(z.string()).default([]),
|
|
deny_packages: z.array(PackageURL).default([]),
|
|
deny_groups: z.array(PackageURLWithNamespace).default([]),
|
|
license_check: z.boolean().default(true),
|
|
vulnerability_check: z.boolean().default(true),
|
|
config_file: z.string().optional(),
|
|
base_ref: z.string().optional(),
|
|
head_ref: z.string().optional(),
|
|
retry_on_snapshot_warnings: z.boolean().default(false),
|
|
retry_on_snapshot_warnings_timeout: z.number().default(120),
|
|
show_openssf_scorecard: z.boolean().optional().default(true),
|
|
warn_on_openssf_scorecard_level: z.number().default(3),
|
|
comment_summary_in_pr: z
|
|
.union([
|
|
z.preprocess(
|
|
val => (val === 'true' ? true : val === 'false' ? false : val),
|
|
z.boolean()
|
|
),
|
|
z.enum(['always', 'never', 'on-failure'])
|
|
])
|
|
.default('never'),
|
|
warn_only: z.boolean().default(false)
|
|
})
|
|
.transform(config => {
|
|
if (config.comment_summary_in_pr === true) {
|
|
config.comment_summary_in_pr = 'always'
|
|
} else if (config.comment_summary_in_pr === false) {
|
|
config.comment_summary_in_pr = 'never'
|
|
}
|
|
return config
|
|
})
|
|
.superRefine((config, context) => {
|
|
if (config.allow_licenses && config.deny_licenses) {
|
|
context.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: 'You cannot specify both allow-licenses and deny-licenses'
|
|
})
|
|
}
|
|
if (config.allow_licenses && config.allow_licenses.length < 1) {
|
|
context.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: 'You should provide at least one license in allow-licenses'
|
|
})
|
|
}
|
|
if (
|
|
config.license_check === false &&
|
|
config.vulnerability_check === false
|
|
) {
|
|
context.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: "Can't disable both license-check and vulnerability-check"
|
|
})
|
|
}
|
|
})
|
|
|
|
export const ChangesSchema = z.array(ChangeSchema)
|
|
export const ComparisonResponseSchema = z.object({
|
|
changes: z.array(ChangeSchema),
|
|
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 ScorecardSchema = z.object({
|
|
dependencies: z.array(
|
|
z.object({
|
|
change: ChangeSchema,
|
|
scorecard: ScorecardApiSchema.nullish()
|
|
})
|
|
)
|
|
})
|
|
|
|
export type Change = z.infer<typeof ChangeSchema>
|
|
export type Changes = z.infer<typeof ChangesSchema>
|
|
export type ComparisonResponse = z.infer<typeof ComparisonResponseSchema>
|
|
export type ConfigurationOptions = z.infer<typeof ConfigurationOptionsSchema>
|
|
export type Severity = z.infer<typeof SeveritySchema>
|
|
export type Scope = (typeof SCOPES)[number]
|
|
export type Scorecard = z.infer<typeof ScorecardSchema>
|
|
export type ScorecardApi = z.infer<typeof ScorecardApiSchema>
|