Skip to content

Commit 3079df4

Browse files
committed
fix: lint and consistency
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
1 parent 6b4b120 commit 3079df4

6 files changed

Lines changed: 87 additions & 32 deletions

File tree

backend/src/api/public/v1/ossprey/openapi.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,11 @@ components:
263263
description: ROUND(scorecard_score × 10). X-axis position (0–100). 0 if no repo.
264264
example: 52
265265
healthBand:
266-
$ref: '#/components/schemas/HealthBand'
266+
type: string
267+
enum: [healthy, fair, concerning, critical]
268+
description: >
269+
Falls back to scorecard thresholds — never 'excellent' (scatter uses
270+
scorecard score only, not Tinybird health_label).
267271
stewardshipStatus:
268272
oneOf:
269273
- $ref: '#/components/schemas/StewardshipStatus'

backend/src/api/public/v1/ossprey/packageList.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { ok } from '@/utils/api'
1313
import { validateOrThrow } from '@/utils/validation'
1414

1515
import { purlFilterSchema } from '../packages/purl'
16-
import { LIFECYCLE_VALUES } from '../packages/types'
16+
import { HEALTH_BAND_SET, HEALTH_BAND_VALUES, LIFECYCLE_VALUES } from '../packages/types'
1717

1818
const MAX_PAGE_SIZE = 250
1919
const LIFECYCLE_SET = new Set<string>(LIFECYCLE_VALUES)
@@ -39,7 +39,7 @@ const querySchema = z.object({
3939
'inactive',
4040
])
4141
.optional(),
42-
healthBand: z.enum(['excellent', 'healthy', 'fair', 'concerning', 'critical']).optional(),
42+
healthBand: z.enum(HEALTH_BAND_VALUES).optional(),
4343
vulnSeverity: z.enum(['any', 'high', 'critical', 'none']).optional(),
4444
staleOnly: boolParam,
4545
unstewardedOnly: boolParam,
@@ -85,7 +85,10 @@ export async function packageListHandler(req: Request, res: Response): Promise<v
8585
health: {
8686
score:
8787
r.healthScore ?? (r.scorecardScore != null ? Math.round(r.scorecardScore * 10) : null),
88-
label: r.healthLabel ?? computeHealthBand(r.scorecardScore),
88+
label:
89+
r.healthLabel != null && HEALTH_BAND_SET.has(r.healthLabel)
90+
? r.healthLabel
91+
: computeHealthBand(r.scorecardScore),
8992
},
9093
lifecycle:
9194
r.lifecycleLabel != null && LIFECYCLE_SET.has(r.lifecycleLabel) ? r.lifecycleLabel : null,

backend/src/api/public/v1/packages/getPackage.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import { ok } from '@/utils/api'
1313
import { validateOrThrow } from '@/utils/validation'
1414

1515
import { purlQuerySchema } from './purl'
16-
import type { StewardshipStatus } from './types'
16+
import { HEALTH_BAND_SET, LIFECYCLE_VALUES, type StewardshipStatus } from './types'
17+
18+
const LIFECYCLE_SET = new Set<string>(LIFECYCLE_VALUES)
1719

1820
function snakeToCamelKeys(obj: Record<string, unknown> | null): Record<string, unknown> | null {
1921
if (obj === null) return null
@@ -47,7 +49,6 @@ export async function getPackage(req: Request, res: Response): Promise<void> {
4749
const scorecardScore = pkg.scorecardScore != null ? Number(pkg.scorecardScore) : null
4850
const mappingConfidence =
4951
pkg.repoMappingConfidence != null ? Number(pkg.repoMappingConfidence) : null
50-
const healthBandScore = pkg.healthScore !== null ? pkg.healthScore / 10 : scorecardScore
5152

5253
ok(res, {
5354
purl: pkg.purl,
@@ -58,22 +59,28 @@ export async function getPackage(req: Request, res: Response): Promise<void> {
5859
healthScore: pkg.healthScore,
5960
healthScoreDetails: {
6061
total: pkg.healthScore,
61-
label: pkg.healthLabel,
62+
label:
63+
pkg.healthLabel != null && HEALTH_BAND_SET.has(pkg.healthLabel) ? pkg.healthLabel : null,
6264
maintainerHealth: pkg.maintainerHealthScore,
6365
securitySupplyChain: pkg.securitySupplyChainScore,
6466
developmentActivity: pkg.developmentActivityScore,
6567
},
66-
healthBand: computeHealthBand(healthBandScore),
68+
healthBand:
69+
pkg.healthLabel != null && HEALTH_BAND_SET.has(pkg.healthLabel)
70+
? pkg.healthLabel
71+
: computeHealthBand(scorecardScore),
6772
impact: {
68-
impactScore:
69-
pkg.criticalityScore != null ? Math.round(Number(pkg.criticalityScore) * 100) : null,
73+
impactScore: pkg.criticalityScore != null ? Math.round(pkg.criticalityScore * 100) : null,
7074
downloadsLastMonth: pkg.downloadsLast30d ?? null,
7175
dependentPackages: pkg.dependentPackagesCount ?? null,
7276
dependentRepos: pkg.dependentReposCount ?? null,
7377
transitiveReach: pkg.transitiveReach,
7478
},
7579
riskSignals: {
76-
lifecycle: pkg.lifecycleLabel,
80+
lifecycle:
81+
pkg.lifecycleLabel != null && LIFECYCLE_SET.has(pkg.lifecycleLabel)
82+
? pkg.lifecycleLabel
83+
: null,
7784
maintainerBusFactor: pkg.maintainerCount,
7885
lastRelease: pkg.latestReleaseAt ? pkg.latestReleaseAt.toISOString() : null,
7986
hasSecurityFile: pkg.hasSecurityFile,

backend/src/api/public/v1/packages/listPackages.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,20 @@ import { ok } from '@/utils/api'
1212
import { validateOrThrow } from '@/utils/validation'
1313

1414
import { purlFilterSchema } from './purl'
15-
import { LIFECYCLE_VALUES, STEWARDSHIP_STATUS_VALUES, type StewardshipStatus } from './types'
15+
import {
16+
HEALTH_BAND_SET,
17+
HEALTH_BAND_VALUES,
18+
LIFECYCLE_VALUES,
19+
STEWARDSHIP_STATUS_VALUES,
20+
type StewardshipStatus,
21+
} from './types'
1622

1723
const DEFAULT_PAGE_SIZE = 20
1824
const MAX_PAGE_SIZE = 100
1925

2026
const booleanQueryParam = z.preprocess((v) => v === 'true', z.boolean()).default(false)
2127

2228
const LIFECYCLE_SET = new Set<string>(LIFECYCLE_VALUES)
23-
const healthBandValues = ['excellent', 'healthy', 'fair', 'concerning', 'critical'] as const
2429
const vulnSeverityValues = ['any', 'high', 'critical', 'none'] as const
2530

2631
const querySchema = z.object({
@@ -31,7 +36,7 @@ const querySchema = z.object({
3136
name: z.string().trim().optional(),
3237
purl: purlFilterSchema,
3338
status: z.enum(STEWARDSHIP_STATUS_VALUES).optional(),
34-
healthBand: z.enum(healthBandValues).optional(),
39+
healthBand: z.enum(HEALTH_BAND_VALUES).optional(),
3540
vulnSeverity: z.enum(vulnSeverityValues).optional(),
3641
busFactor1Only: booleanQueryParam,
3742
staleOnly: booleanQueryParam,
@@ -90,7 +95,10 @@ export async function listPackages(req: Request, res: Response): Promise<void> {
9095
ecosystem: r.ecosystem,
9196
health: {
9297
score: r.healthScore ?? (r.scorecardScore != null ? Math.round(r.scorecardScore * 10) : null),
93-
label: r.healthLabel ?? computeHealthBand(r.scorecardScore),
98+
label:
99+
r.healthLabel != null && HEALTH_BAND_SET.has(r.healthLabel)
100+
? r.healthLabel
101+
: computeHealthBand(r.scorecardScore),
94102
},
95103
impact: r.criticalityScore != null ? Math.round(r.criticalityScore * 100) : null,
96104
lifecycle:

backend/src/api/public/v1/packages/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ export const LIFECYCLE_VALUES = ['active', 'stable', 'declining', 'abandoned', '
1515

1616
export type Lifecycle = (typeof LIFECYCLE_VALUES)[number]
1717

18+
export const HEALTH_BAND_VALUES = [
19+
'excellent',
20+
'healthy',
21+
'fair',
22+
'concerning',
23+
'critical',
24+
] as const
25+
26+
export type HealthBand = (typeof HEALTH_BAND_VALUES)[number]
27+
28+
export const HEALTH_BAND_SET = new Set<string>(HEALTH_BAND_VALUES)
29+
1830
export type SeverityLevel = 'critical' | 'high' | 'medium' | 'low'
1931

2032
export interface OpenVulns {

services/libs/data-access-layer/src/osspckgs/api.ts

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export interface PackageMetrics {
1111
criticalPackages: number
1212
}
1313

14-
export async function getPackageMetrics(qx: QueryExecutor): Promise {
14+
export async function getPackageMetrics(qx: QueryExecutor): Promise<PackageMetrics> {
1515
const row: { total: string; critical: string } = await qx.selectOne(`
1616
SELECT
1717
COUNT(*) AS total,
@@ -34,7 +34,10 @@ export interface PackageStewardshipRow {
3434
stewardshipStatus: string | null
3535
}
3636

37-
export async function getPackagesByStewardshipPurls(qx: QueryExecutor, purls: string[]): Promise {
37+
export async function getPackagesByStewardshipPurls(
38+
qx: QueryExecutor,
39+
purls: string[],
40+
): Promise<PackageStewardshipRow[]> {
3841
if (purls.length === 0) return []
3942
return qx.select(
4043
`
@@ -65,7 +68,7 @@ export interface OsspreyMetrics {
6568
}
6669

6770
// TODO[deprecate]: rename to getAkritesMetrics once /v1/ossprey is removed
68-
export async function getOsspreyMetrics(qx: QueryExecutor): Promise {
71+
export async function getOsspreyMetrics(qx: QueryExecutor): Promise<OsspreyMetrics> {
6972
const [counts, stewardRow]: [
7073
{
7174
totalPackages: string
@@ -138,7 +141,7 @@ export interface PackageListRow {
138141
lifecycleLabel: string | null
139142
lastActivityType?: string | null
140143
lastActivityContent?: string | null
141-
lastActivityMetadata?: Record | null
144+
lastActivityMetadata?: Record<string, unknown> | null
142145
lastActivityAt?: Date | null
143146
stewards?: StewardEntry[]
144147
total: string
@@ -196,7 +199,10 @@ export interface PackageStatusCounts {
196199
inactive: number
197200
}
198201

199-
export type StatusCountsOptions = Omit
202+
export type StatusCountsOptions = Omit<
203+
ListPackagesOptions,
204+
'status' | 'page' | 'pageSize' | 'sortBy' | 'sortDir'
205+
>
200206

201207
const ALL_STEWARDSHIP_STATUSES = [
202208
'unassigned',
@@ -216,9 +222,9 @@ const ALL_STEWARDSHIP_STATUSES = [
216222
export async function getPackageStatusCounts(
217223
qx: QueryExecutor,
218224
opts: StatusCountsOptions,
219-
): Promise {
225+
): Promise<PackageStatusCounts> {
220226
const conditions: string[] = ['p.is_critical = true']
221-
const params: Record = {}
227+
const params: Record<string, unknown> = {}
222228

223229
if (opts.ecosystem) {
224230
conditions.push('p.ecosystem = $(ecosystem)')
@@ -315,7 +321,7 @@ export async function getPackageStatusCounts(
315321
params,
316322
)
317323

318-
const countsMap: Record = {}
324+
const countsMap: Record<string, number> = {}
319325
let all = 0
320326
for (const row of rows) {
321327
countsMap[row.status] = row.count
@@ -339,9 +345,12 @@ export async function getPackageStatusCounts(
339345
return result
340346
}
341347

342-
export async function listPackagesForApi(qx: QueryExecutor, opts: ListPackagesOptions): Promise {
348+
export async function listPackagesForApi(
349+
qx: QueryExecutor,
350+
opts: ListPackagesOptions,
351+
): Promise<{ rows: PackageListRow[]; total: number }> {
343352
const conditions: string[] = ['p.is_critical = true']
344-
const params: Record = {}
353+
const params: Record<string, unknown> = {}
345354

346355
if (opts.ecosystem) {
347356
conditions.push('p.ecosystem = $(ecosystem)')
@@ -444,7 +453,7 @@ export async function listPackagesForApi(qx: QueryExecutor, opts: ListPackagesOp
444453
const sortDir = opts.sortDir === 'desc' ? 'DESC' : 'ASC'
445454

446455
// Separate paginated params from filter-only params used by the fallback COUNT query
447-
const queryParams: Record = {
456+
const queryParams: Record<string, unknown> = {
448457
...params,
449458
limit: opts.pageSize,
450459
offset: (opts.page - 1) * opts.pageSize,
@@ -551,8 +560,8 @@ export async function listPackagesForApi(qx: QueryExecutor, opts: ListPackagesOp
551560
r_sc.scorecard_score AS "scorecardScore",
552561
p.health_score AS "healthScore",
553562
p.health_label AS "healthLabel",
554-
p.latest_release_at AS "latestReleaseAt",
555563
p.lifecycle_label AS "lifecycleLabel",
564+
p.latest_release_at AS "latestReleaseAt",
556565
${opts.includeLastActivity === true ? `last_act.activity_type AS "lastActivityType", last_act.content AS "lastActivityContent", last_act.metadata AS "lastActivityMetadata", last_act.created_at AS "lastActivityAt",` : ''}
557566
${opts.includeStewards === true ? 'ss_agg.stewards AS stewards,' : ''}
558567
COUNT(*) OVER() AS total
@@ -626,7 +635,7 @@ export interface PackageDetailRow {
626635
securitySupplyChainScore: number | null
627636
developmentActivityScore: number | null
628637
lifecycleLabel: string | null
629-
signalCoverageHealth: Record | null
638+
signalCoverageHealth: Record<string, unknown> | null
630639
}
631640

632641
export interface AdvisoryRow {
@@ -636,7 +645,10 @@ export interface AdvisoryRow {
636645
isCritical: boolean
637646
}
638647

639-
export async function getPackageDetailByPurl(qx: QueryExecutor, purl: string): Promise {
648+
export async function getPackageDetailByPurl(
649+
qx: QueryExecutor,
650+
purl: string,
651+
): Promise<PackageDetailRow | null> {
640652
return qx.selectOneOrNone(
641653
`
642654
SELECT
@@ -727,7 +739,7 @@ export interface ScatterPoint {
727739
export async function listPackagesForScatter(
728740
qx: QueryExecutor,
729741
options: { status?: string[]; ecosystem?: string } = {},
730-
): Promise {
742+
): Promise<ScatterPoint[]> {
731743
const { status, ecosystem } = options
732744

733745
// 'unassigned' covers packages with no stewardship row (s.id IS NULL) in addition
@@ -739,7 +751,16 @@ export async function listPackagesForScatter(
739751
: ''
740752
const ecosystemFilter = ecosystem ? `AND p.ecosystem = $(ecosystem)` : ''
741753

742-
const rows: Array = await qx.select(
754+
const rows: Array<{
755+
purl: string
756+
name: string
757+
criticalityScore: number
758+
healthScore: number
759+
scorecardScoreRaw: number | null
760+
stewardshipId: string | null
761+
stewardshipStatus: string | null
762+
openVulns: number
763+
}> = await qx.select(
743764
`
744765
SELECT
745766
p.purl,
@@ -795,7 +816,7 @@ export async function getAdvisoriesByPackageId(
795816
resolutions?: ('open' | 'patched')[]
796817
critical?: boolean
797818
},
798-
): Promise {
819+
): Promise<{ rows: AdvisoryRow[]; total: number }> {
799820
const cte = `
800821
WITH advisory_data AS (
801822
SELECT

0 commit comments

Comments
 (0)