openapi: 3.0.3 info: title: CDP → Akrites External Advisories Packages API version: 0.1.0 description: 'Read-only external API exposing CDP package security data to the Akrites service. Authenticated via Auth0 M2M client-credentials — CDP only verifies the resulting access token; the assertion exchange happens entirely between Akrites and Auth0. Packages, Advisories and Contacts endpoints are implemented. Blast Radius is specced separately and not yet built. TODO: scopes below (read:packages, read:stewardships) are the existing internal CDP UI scopes, reused here for now. Swap for a dedicated cdp:packages:read scope once Akrites gets its own Auth0 M2M scopes per the akrites-external draft contract. ' servers: - url: https://cm.lfx.dev/api/v1 description: Production security: - M2MBearer: - read:packages - read:stewardships tags: - name: Packages description: Package detail — requires read:packages and read:stewardships (see TODO above). paths: /akrites-external/packages/detail: get: operationId: getPackageDetail summary: Get package detail by PURL tags: - Packages security: - M2MBearer: - read:packages - read:stewardships parameters: - name: purl in: query required: true schema: type: string example: pkg:npm/%40angular/core responses: '200': description: Package detail. content: application/json: schema: $ref: '#/components/schemas/PackageDetail' '400': description: Malformed purl. content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Token missing read:packages or read:stewardships scope. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Package not found. content: application/json: schema: $ref: '#/components/schemas/Error' /akrites-external/packages/detail:batch: post: operationId: getPackageDetailBatch summary: Bulk package detail lookup tags: - Packages security: - M2MBearer: - read:packages - read:stewardships requestBody: required: true content: application/json: schema: type: object required: - purls properties: purls: type: array minItems: 1 maxItems: 100 items: type: string page: type: integer minimum: 1 default: 1 pageSize: type: integer minimum: 1 maximum: 100 default: 20 responses: '200': description: One page of results, in request order. content: application/json: schema: type: object required: - page - pageSize - total - results properties: page: type: integer pageSize: type: integer total: type: integer description: Total number of requested purls, across all pages. results: type: array items: $ref: '#/components/schemas/PackageDetailBulkEntry' '400': description: Validation error (empty array, >100 items, malformed purl). content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Token missing read:packages or read:stewardships scope. content: application/json: schema: $ref: '#/components/schemas/Error' /akrites/packages: get: operationId: listAkritesPackages summary: List packages with stewardship data description: 'Paginated list of critical packages enriched with stewardship status, vulnerability counts, health band, and the latest stewardship activity. Supports rich filtering and sorting. ' tags: - Packages parameters: - name: page in: query schema: type: integer minimum: 1 default: 1 - name: pageSize in: query schema: type: integer minimum: 1 maximum: 250 default: 25 - name: ecosystem in: query schema: type: string - name: lifecycle in: query schema: type: string enum: - active - stable - declining - abandoned - name: name in: query description: Substring match on package name. schema: type: string - name: status in: query schema: $ref: '#/components/schemas/StewardshipStatus' - name: healthBand in: query schema: $ref: '#/components/schemas/HealthBand_2' - name: vulnSeverity in: query description: 'Filter by highest open vulnerability severity present on the package. `none` returns packages with zero vulnerabilities; `any` disables the filter. ' schema: type: string enum: - any - high - critical - none - name: staleOnly in: query schema: type: boolean default: false - name: unstewardedOnly in: query schema: type: boolean default: false - name: busFactor1Only in: query description: Return only packages whose maintainer count is 1. schema: type: boolean default: false - name: sortBy in: query schema: type: string enum: - name - risk - impact - openVulns - health default: risk - name: sortDir in: query schema: type: string enum: - asc - desc default: desc responses: '200': description: Paginated package list. content: application/json: schema: allOf: - $ref: '#/components/schemas/PaginationMeta' - type: object required: - rows - statusCounts properties: rows: type: array items: $ref: '#/components/schemas/PackageListRow' statusCounts: $ref: '#/components/schemas/StatusCounts' '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/Error_2' '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error_2' /akrites/packages/scatter: get: operationId: getAkritesPackagesScatter summary: Get risk matrix scatter data description: 'Returns all critical packages as scatter-plot points with impact score (x-axis) and health score (y-axis). No pagination — the full dataset is returned. ' tags: - Packages responses: '200': description: Scatter plot dataset. content: application/json: schema: type: object required: - points - total properties: points: type: array items: $ref: '#/components/schemas/ScatterPoint' total: type: integer '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error_2' /akrites/packages/metrics: get: operationId: getAkritesPackagesMetrics summary: Get package count metrics description: 'Returns total and critical package counts. Lighter alternative to `/akrites/metrics` when only package-level counts are needed. ' tags: - Packages responses: '200': description: Package count metrics. content: application/json: schema: $ref: '#/components/schemas/PackageMetrics' '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error_2' /akrites/packages/detail: get: operationId: getAkritesPackageDetail summary: Get package detail description: 'Returns the full detail view for a single package identified by its PURL, including risk signals, security advisories, repository provenance, and current stewardship state. ' tags: - Packages parameters: - name: purl in: query required: true description: 'Package URL (PURL) — must start with `pkg:`. Version qualifiers are normalised server-side. ' schema: type: string example: pkg:npm/%40angular/core@17.0.0 responses: '200': description: Package detail. content: application/json: schema: $ref: '#/components/schemas/PackageDetail_2' '400': description: Validation error (malformed purl). content: application/json: schema: $ref: '#/components/schemas/Error_2' '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error_2' '404': description: Package not found. content: application/json: schema: $ref: '#/components/schemas/Error_2' /akrites/packages/advisories: get: operationId: getAkritesPackageAdvisories summary: Get advisories for a package description: 'Returns a paginated list of security advisories for a single package identified by PURL. Intended for lazy-loading the Security tab in the package detail drawer. ' tags: - Packages parameters: - name: purl in: query required: true description: Package URL (PURL) — must start with `pkg:`. schema: type: string example: pkg:npm/%40angular/core@17.0.0 - name: page in: query required: false description: Page number (1-based). schema: type: integer minimum: 1 default: 1 - name: pageSize in: query required: false description: Number of advisories per page (max 100). schema: type: integer minimum: 1 maximum: 100 default: 20 - name: severity in: query required: false description: Filter by severity. Accepts comma-separated values or multiple params. schema: type: array items: type: string enum: - critical - high - moderate - low - name: resolution in: query required: false description: Filter by resolution status. Accepts comma-separated values or multiple params. schema: type: array items: type: string enum: - open - patched - name: critical in: query required: false description: Filter by criticality flag (CVSS >= 7.0). schema: type: boolean responses: '200': description: Paginated advisory list. content: application/json: schema: type: object required: - page - pageSize - total - advisories properties: page: type: integer pageSize: type: integer total: type: integer advisories: type: array items: $ref: '#/components/schemas/Advisory' '400': description: Validation error (malformed purl). content: application/json: schema: $ref: '#/components/schemas/Error_2' '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error_2' '404': description: Package not found. content: application/json: schema: $ref: '#/components/schemas/Error_2' /akrites/packages/history: get: operationId: getAkritesPackageHistory summary: Get stewardship history for a package description: 'Returns the full activity log for the stewardship associated with the given PURL, ordered newest-first. Returns an empty list if no stewardship exists. Intended for lazy-loading the History tab in the package detail drawer. ' tags: - Packages parameters: - name: purl in: query required: true description: Package URL (PURL) — must start with `pkg:`. schema: type: string example: pkg:npm/%40angular/core@17.0.0 responses: '200': description: Stewardship activity history. content: application/json: schema: type: object required: - events - total properties: events: type: array items: $ref: '#/components/schemas/PackageHistoryEvent' total: type: integer '400': description: Validation error (malformed purl). content: application/json: schema: $ref: '#/components/schemas/Error_2' '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error_2' '404': description: Package not found. content: application/json: schema: $ref: '#/components/schemas/Error_2' /akrites/packages:batch-stewardship: post: operationId: batchGetStewardship summary: Batch stewardship lookup by PURL description: 'Given up to 100 PURLs, returns a map of `purl → stewardship summary` for each. Missing packages are returned as `null`. Useful for enriching external package listings with CDP stewardship state. ' tags: - Packages requestBody: required: true content: application/json: schema: type: object required: - purls properties: purls: type: array minItems: 1 maxItems: 100 items: type: string description: Must start with `pkg:`. example: pkg:npm/%40angular/core@17.0.0 responses: '200': description: Per-purl stewardship map. content: application/json: schema: type: object required: - packages properties: packages: type: object description: 'Keys are the original PURLs from the request. Values are null when the package is not found in CDP. ' additionalProperties: oneOf: - $ref: '#/components/schemas/PackageStewardshipSummary' - type: 'null' '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/Error_2' '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error_2' /ossprey/packages: get: operationId: listOsspreyPackages summary: Filtered paginated package list description: "Returns a paginated, filtered, sorted list of critical packages with their stewardship state and risk signals.\n\nUsed by three tabs:\n- **Queue tab** — full table with all filters\n- **Triage Board** — one request per status column, fired in parallel\n (`?status=X&pageSize=50`)\n\n- **Summary panel** — click-through navigates to Queue with pre-filled filter\n\nThe response always includes `statusCounts` — per-status counts computed without the active `status` filter, used to drive the tab bar badge numbers.\n" tags: - Packages security: - BearerAuth: [] parameters: - name: page in: query schema: type: integer minimum: 1 default: 1 - name: pageSize in: query schema: type: integer minimum: 1 maximum: 250 default: 25 - name: name in: query description: Case-insensitive substring search on package name. schema: type: string - name: ecosystem in: query description: Filter by package ecosystem. Not validated server-side — any ecosystem stored in the DB is accepted. schema: type: string - name: lifecycle in: query schema: type: string enum: - active - stable - declining - abandoned - archived - name: status in: query description: 'Filter by stewardship status. `unassigned` includes packages with no stewardship row (s.id IS NULL). ' schema: $ref: '#/components/schemas/StewardshipStatus' - name: healthBand in: query schema: $ref: '#/components/schemas/HealthBand_3' - name: vulnSeverity in: query description: '`any` = at least one open advisory · `high` = worst rank ≥ HIGH · `critical` = worst rank = CRITICAL · `none` = zero advisories. ' schema: type: string enum: - any - high - critical - none - name: staleOnly in: query description: Return only packages with no release in ≥ 18 months. schema: type: boolean default: false - name: unstewardedOnly in: query description: Return only packages with status = unassigned or no stewardship row. schema: type: boolean default: false - name: busFactor1Only in: query description: Return only packages with exactly one maintainer. schema: type: boolean default: false - name: sortBy in: query schema: type: string enum: - risk - name - impact - openVulns - health default: risk - name: sortDir in: query schema: type: string enum: - asc - desc default: desc responses: '200': description: Paginated package list. content: application/json: schema: type: object required: - rows - total - page - pageSize - statusCounts properties: rows: type: array items: $ref: '#/components/schemas/PackageRow' total: type: integer example: 1842 page: type: integer example: 1 pageSize: type: integer example: 25 statusCounts: $ref: '#/components/schemas/StatusCounts_2' example: rows: - purl: pkg:maven/org.slf4j/slf4j-api name: slf4j-api ecosystem: maven criticalityScore: 0.998 impact: 100 stewardshipId: '101' stewardshipStatus: active openVulns: 0 maxVulnSeverity: null maintainerCount: 2 scorecardScore: 7.5 health: score: 75 label: healthy lifecycle: active latestReleaseAt: '2026-04-10T00:00:00Z' lastActivity: type: state_changed content: Assessment complete, moving to active at: '2026-06-01T10:00:00Z' stewards: - userId: auth0|mock-user-alice role: lead assignedAt: '2026-01-15T09:00:00Z' total: 9 page: 1 pageSize: 25 statusCounts: all: 9 unassigned: 1 open: 1 assessing: 1 active: 2 needs_attention: 1 escalated: 1 blocked: 1 inactive: 1 '400': description: Validation error. content: application/json: schema: $ref: '#/components/schemas/Error_3' '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error_3' /ossprey/packages/scatter: get: operationId: getOsspreyPackagesScatter summary: Scatter plot data for the Risk Matrix tab description: 'Returns all packages where `is_critical = true AND has_critical_vulnerability = true` as lightweight data points for the health-vs-impact scatter plot. No pagination — this filter set is expected to stay around 2 000 packages. Ordered by `impact DESC`. Dot color is determined by `stewardshipStatus`. Legend checkboxes toggle visibility client-side — no additional API calls needed. ' tags: - Packages security: - BearerAuth: [] responses: '200': description: Scatter plot data points. content: application/json: schema: type: object required: - points - total properties: points: type: array items: $ref: '#/components/schemas/ScatterPoint_2' total: type: integer description: 'Count of packages matching the filter (is_critical = true AND has_critical_vulnerability = true). Equals points.length — no separate count query. ' example: 2000 example: points: - purl: pkg:maven/org.slf4j/slf4j-api name: slf4j-api criticalityScore: 100 healthScore: 75 healthBand: healthy stewardshipStatus: active stewardshipId: '101' openVulns: 0 advisoryCount: 0 - purl: pkg:maven/com.fasterxml.jackson.core/jackson-databind name: jackson-databind criticalityScore: 99 healthScore: 0 healthBand: critical stewardshipStatus: needs_attention stewardshipId: '102' openVulns: 2 advisoryCount: 2 total: 2000 '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error_3' /packages: get: operationId: listPackages summary: List packages tags: - Packages security: - M2MBearer: - read:packages - read:stewardships parameters: - name: page in: query schema: type: integer minimum: 1 default: 1 - name: pageSize in: query schema: type: integer minimum: 1 maximum: 100 default: 20 - name: ecosystem in: query schema: type: string - name: lifecycle in: query schema: type: string enum: - active - stable - declining - abandoned - archived - name: busFactor1Only in: query schema: type: boolean default: false description: Return only packages with bus factor = 1. - name: staleOnly in: query schema: type: boolean default: false description: Return only packages with no release in >= 18 months. - name: unstewardedOnly in: query schema: type: boolean default: false description: Return only packages with stewardship = unassigned. - name: sortBy in: query schema: type: string enum: - name - health - impact - openVulns default: name - name: sortDir in: query schema: type: string enum: - asc - desc default: asc responses: '200': description: Paginated list of packages. content: application/json: schema: type: object required: - page - pageSize - total - filters - sort - packages properties: page: type: integer pageSize: type: integer total: type: integer filters: type: object properties: ecosystem: type: - string - 'null' lifecycle: type: - string - 'null' busFactor1Only: type: boolean staleOnly: type: boolean unstewardedOnly: type: boolean sort: type: object properties: by: type: string dir: type: string packages: type: array items: $ref: '#/components/schemas/PackageListItem' '400': description: Validation error (e.g. invalid query parameters). content: application/json: schema: $ref: '#/components/schemas/Error_4' '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error_4' '403': description: Insufficient scopes. content: application/json: schema: $ref: '#/components/schemas/Error_4' /packages/metrics: get: operationId: getPackagesMetrics summary: Overview metrics for the list page header tags: - Packages security: - M2MBearer: - read:packages - read:stewardships responses: '200': description: Aggregate package metrics. content: application/json: schema: $ref: '#/components/schemas/PackagesMetrics' '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error_4' '403': description: Insufficient scopes. content: application/json: schema: $ref: '#/components/schemas/Error_4' /packages/detail: get: operationId: getPackage summary: Get full package detail description: 'Returns data for the drawer''s Overview, Security, and Provenance tabs. Pass the canonical purl as a query parameter — no URL-encoding needed. Example: `?purl=pkg:npm/lodash@4.17.21`. ' tags: - Packages security: - M2MBearer: - read:packages - read:stewardships parameters: - name: purl in: query required: true schema: type: string example: pkg:npm/lodash@4.17.21 responses: '200': description: Package found. content: application/json: schema: $ref: '#/components/schemas/PackageDetail_3' example: purl: pkg:npm/lodash name: lodash ecosystem: npm general: healthScore: 18 healthScoreDetails: total: 18 label: critical maintainerHealth: 4 securitySupplyChain: 8 developmentActivity: 6 healthBand: critical impact: impactScore: 71 downloadsLastMonth: 52142891 dependentPackages: 142312 dependentRepos: 39104 transitiveReach: Top 0.4% riskSignals: lifecycle: declining maintainerBusFactor: 1 lastRelease: '2021-02-20T00:00:00Z' hasSecurityFile: null openSSFScorecard: 5.2 assessment: {} security: securityContacts: null advisories: - osvId: CVE-2021-44906 severity: high resolution: null cvd: isPvrEnabled: null hasSecurityPolicyEnabled: null tier0Steward: null criticalVulnerabilityFlag: true provenance: repositoryMapping: declaredRepo: https://github.com/lodash/lodash mappingConfidence: 0.98 lastCommitAt: '2024-09-14T00:00:00Z' supplyChainIntegrity: buildProvenance: null signedReleases: null stewardship: status: unassigned stewards: null lastActivityAt: null history: {} '404': description: Package not found. content: application/json: schema: $ref: '#/components/schemas/Error_4' '401': description: Missing or invalid bearer token. content: application/json: schema: $ref: '#/components/schemas/Error_4' '403': description: Insufficient scopes. content: application/json: schema: $ref: '#/components/schemas/Error_4' components: schemas: OpenVulns: type: object description: Open vulnerability counts by severity from advisory_packages + advisories. required: - low - medium - high - critical properties: low: type: integer example: 0 medium: type: integer example: 0 high: type: integer example: 1 critical: type: integer example: 0 PackageDetail_2: type: object required: - purl - name - ecosystem - general - assessment - security - provenance - stewardship - history properties: purl: type: string name: type: string ecosystem: type: string latestVersion: type: string nullable: true general: type: object properties: healthScore: type: integer nullable: true description: OpenSSF Scorecard score scaled to 0–100 (scorecardScore × 10, rounded). healthBand: $ref: '#/components/schemas/HealthBand_2' impact: type: object properties: impactScore: type: integer nullable: true description: Criticality score scaled to 0–100. downloadsLastMonth: type: string nullable: true description: Raw download count string from the registry. dependentPackages: type: integer nullable: true dependentRepos: type: integer nullable: true transitiveReach: type: integer nullable: true riskSignals: type: object properties: lifecycle: type: string nullable: true maintainerBusFactor: type: integer nullable: true lastRelease: type: string format: date-time nullable: true hasSecurityFile: type: boolean nullable: true hasSecurityPolicy: type: boolean nullable: true description: repos.security_policy_enabled branchProtectionEnabled: type: boolean nullable: true description: repos.branch_protection_enabled openSSFScorecard: type: number format: float nullable: true assessment: nullable: true description: Reserved for future stewardship assessment fields (G1). security: type: object properties: securityContacts: type: array nullable: true description: null when the linked repo has not yet been swept by the security-contacts pipeline; empty array when swept with no contacts found. Provenance and internal scoring metadata are never included. items: $ref: '#/components/schemas/SecurityContact' packageConfidence: allOf: - $ref: '#/components/schemas/SecurityContactConfidence' nullable: true description: Confidence band of the highest-scoring contact in securityContacts. securityPolicies: type: object properties: securityPolicyUrl: type: string nullable: true vulnerabilityReportingUrl: type: string nullable: true bugBountyUrl: type: string nullable: true pvrEnabled: type: boolean nullable: true advisories: type: array items: $ref: '#/components/schemas/Advisory' cvd: type: object properties: isPvrEnabled: type: boolean nullable: true tier0Steward: type: string nullable: true criticalVulnerabilityFlag: type: boolean nullable: true provenance: type: object properties: repositoryMapping: type: object properties: declaredRepo: type: string nullable: true mappingConfidence: type: number format: float nullable: true mappingLabel: type: string enum: - High - Medium - Low nullable: true lastCommitAt: type: string format: date-time nullable: true supplyChainIntegrity: type: object properties: buildProvenance: type: string nullable: true description: Not yet ingested. signedReleases: type: string nullable: true description: Not yet ingested. stewardship: type: object properties: id: type: string nullable: true status: $ref: '#/components/schemas/StewardshipStatus' origin: type: string nullable: true version: type: integer nullable: true openedAt: type: string format: date-time nullable: true lastStatusAt: type: string format: date-time nullable: true resolutionPath: $ref: '#/components/schemas/EscalationResolutionPath' nullable: true statusNote: type: string nullable: true stewards: type: array nullable: true items: $ref: '#/components/schemas/StewardEntry' lastActivityAt: type: string format: date-time nullable: true history: nullable: true description: Always null in /detail — full history available at GET /packages/history. PackagesMetrics: type: object required: - totalPackages - criticalPackages properties: totalPackages: type: integer example: 0 criticalPackages: type: integer example: 0 ScatterPoint: type: object required: - purl - name - criticalityScore - healthScore - healthBand - openVulns - advisoryCount properties: purl: type: string name: type: string criticalityScore: type: integer description: Impact score scaled to 0–100. healthScore: type: integer description: OpenSSF Scorecard score scaled to 0–100. healthBand: $ref: '#/components/schemas/HealthBand_2' stewardshipStatus: $ref: '#/components/schemas/StewardshipStatus' nullable: true stewardshipId: type: string nullable: true openVulns: type: integer advisoryCount: type: integer PackageListItem: type: object required: - purl - name - ecosystem properties: purl: type: string description: Used to call GET /packages/detail?purl= when a row is clicked. example: pkg:npm/lodash name: type: string example: lodash ecosystem: type: string example: npm health: type: object required: - score - label properties: score: type: - integer - 'null' description: Health score (0–100). Tinybird composite score when enriched, OpenSSF Scorecard × 10 otherwise. Null if neither is available. example: 18 label: type: string enum: - excellent - healthy - fair - concerning - critical description: Tinybird band when enriched (excellent ≥85, healthy 70–84, fair 50–69, concerning 30–49, critical <30), scorecard band otherwise. example: critical impact: type: - integer - 'null' example: 71 lifecycle: type: - string - 'null' enum: - active - stable - declining - abandoned - archived - null maintainerBusFactor: type: - integer - 'null' example: 1 openVulns: oneOf: - $ref: '#/components/schemas/OpenVulns' - type: 'null' stewardshipId: type: - string - 'null' description: Stewardship ID. Required to call mutation endpoints (assign/escalate/status). Null if no stewardship row exists. example: '42' stewardship: $ref: '#/components/schemas/StewardshipStatus' stewards: description: Assigned stewards. Empty array if none. type: array items: $ref: '#/components/schemas/Steward_2' SecurityContact_2: type: object required: - name properties: name: type: - string - 'null' email: type: - string - 'null' format: email PackageDetail_3: type: object required: - purl - name - ecosystem - general - assessment - security - provenance - history properties: purl: type: string example: pkg:npm/lodash name: type: string example: lodash ecosystem: type: string example: npm general: type: object properties: healthScore: type: - integer - 'null' description: Composite health score (0–100). Tinybird-enriched when available, null otherwise. example: 18 healthScoreDetails: type: - object - 'null' description: Breakdown of the composite health score. Null until Tinybird enrichment runs. properties: total: type: - integer - 'null' example: 18 label: type: - string - 'null' example: Good maintainerHealth: type: - integer - 'null' example: 4 securitySupplyChain: type: - integer - 'null' example: 8 developmentActivity: type: - integer - 'null' example: 6 healthBand: type: - string - 'null' enum: - excellent - healthy - fair - concerning - critical - null description: Derived from Tinybird health score when available, OpenSSF Scorecard otherwise. example: concerning impact: type: - object - 'null' properties: impactScore: type: - integer - 'null' example: 71 downloadsLastMonth: type: - integer - 'null' description: Null for Maven (Sonatype data not yet ingested). example: 52142891 dependentPackages: type: - integer - 'null' example: 142312 dependentRepos: type: - integer - 'null' example: 39104 transitiveReach: type: - string - 'null' example: Top 0.4% riskSignals: type: - object - 'null' properties: lifecycle: type: - string - 'null' enum: - active - stable - declining - abandoned - archived - null maintainerBusFactor: type: - integer - 'null' example: 1 lastRelease: type: - string - 'null' format: date-time hasSecurityFile: type: - boolean - 'null' openSSFScorecard: type: - number - 'null' format: float example: 5.2 assessment: type: object description: Stewardship assessment data. Empty in v1 — assessment flow deferred to v2. security: type: object properties: securityContacts: type: - array - 'null' items: $ref: '#/components/schemas/SecurityContact_2' advisories: type: array items: $ref: '#/components/schemas/Advisory_2' cvd: type: object description: Coordinated Vulnerability Disclosure readiness signals. properties: isPvrEnabled: type: - boolean - 'null' description: Private Vulnerability Reporting enabled. Null in v1. hasSecurityPolicyEnabled: type: - boolean - 'null' description: SECURITY.md present in repo. Null until enricher captures this. tier0Steward: type: - string - 'null' description: Name of the Tier 0 steward if assigned. Null in v1. criticalVulnerabilityFlag: type: - boolean - 'null' description: True if any open advisory has cvss >= 7.0. provenance: type: object properties: repositoryMapping: type: - object - 'null' properties: declaredRepo: type: - string - 'null' format: uri example: https://github.com/lodash/lodash mappingConfidence: type: - number - 'null' format: float example: 0.98 lastCommitAt: type: - string - 'null' format: date-time supplyChainIntegrity: type: object description: All fields null in v1 — separate ingestion workstream required. properties: buildProvenance: type: - string - 'null' signedReleases: type: - string - 'null' stewardship: type: object description: Stewardship state. properties: id: type: - string - 'null' description: Stewardship ID. Required to call mutation endpoints (assign/escalate/status). example: '42' status: $ref: '#/components/schemas/StewardshipStatus' stewards: description: Assigned stewards or null. oneOf: - type: array items: $ref: '#/components/schemas/Steward_2' - type: 'null' lastActivityAt: type: - string - 'null' format: date-time resolutionPath: type: - string - 'null' description: Set on `escalated` status. Null for all other statuses. statusNote: type: - string - 'null' description: Free-text note for the current status. history: type: object description: Package history data. Empty in v1. signalCoverageHealth: type: - object - 'null' description: Signal coverage health data enriched by Tinybird. Null until enriched. additionalProperties: true EscalationResolutionPath: type: string enum: - right_of_first_refusal - replace_the_dependency - find_vendor_for_lts - consortium_adopts_maintainership - compensating_controls_monitor - namespace_takeover StatusCounts: type: object description: Count of packages per stewardship status (used to drive filter pill badges). required: - all - unassigned - open - assessing - active - needs_attention - escalated - blocked - inactive properties: all: type: integer description: Total count across all statuses (matches total from the package list without status filter). unassigned: type: integer open: type: integer assessing: type: integer active: type: integer needs_attention: type: integer escalated: type: integer blocked: type: integer inactive: type: integer example: all: 95 unassigned: 42 open: 5 assessing: 12 active: 30 needs_attention: 3 escalated: 1 blocked: 0 inactive: 2 PackageStewardshipSummary: type: object description: Slim stewardship summary returned per-purl by the batch endpoint. nullable: true required: - name - ecosystem properties: name: type: string ecosystem: type: string lifecycle: type: string enum: - active - stable - declining - abandoned nullable: true health: type: number format: float nullable: true impact: type: integer nullable: true description: Criticality score scaled to 0–100. openVulns: type: object nullable: true properties: low: type: integer medium: type: integer high: type: integer critical: type: integer stewardship: $ref: '#/components/schemas/StewardshipStatus' nullable: true stewards: type: array nullable: true items: $ref: '#/components/schemas/Steward' lastActivityAt: type: string format: date-time nullable: true lastActivityDescription: type: string nullable: true PackageDetail: type: object required: - purl - name - ecosystem - latestVersion - versionCount - health - impact - riskSignals - security - provenance - supplyChainIntegrity properties: purl: type: string name: type: string ecosystem: $ref: '#/components/schemas/Ecosystem' latestVersion: type: string nullable: true versionCount: type: integer nullable: true health: type: object required: - score - band - subScores - signalCoverageHealth properties: score: type: integer nullable: true minimum: 0 maximum: 100 band: $ref: '#/components/schemas/HealthBand' subScores: type: object required: - maintainerHealth - securitySupplyChain - developmentActivity properties: maintainerHealth: type: number nullable: true securitySupplyChain: type: number nullable: true developmentActivity: type: number nullable: true signalCoverageHealth: type: object nullable: true additionalProperties: true impact: type: object required: - score - downloadsLast30Days - dependentPackagesCount - dependentReposCount - transitiveReach properties: score: type: integer nullable: true minimum: 0 maximum: 100 downloadsLast30Days: type: string nullable: true description: Raw registry count string, not normalized. dependentPackagesCount: type: integer nullable: true dependentReposCount: type: integer nullable: true transitiveReach: type: integer nullable: true description: Always null for now — reserved for future computation. riskSignals: type: object required: - lifecycle - maintainerBusFactor - lastReleaseAt - hasSecurityFile - hasSecurityPolicy - branchProtectionEnabled - openssfScorecardScore properties: lifecycle: type: string enum: - active - stable - declining - abandoned - archived - null nullable: true description: 'Lifecycle stage on the internal scale, returned verbatim — no external crosswalk. Null when unknown or unrecognized. ' maintainerBusFactor: type: integer nullable: true lastReleaseAt: type: string format: date-time nullable: true hasSecurityFile: type: boolean nullable: true hasSecurityPolicy: type: boolean nullable: true branchProtectionEnabled: type: boolean nullable: true openssfScorecardScore: type: number format: float minimum: 0 maximum: 10 nullable: true security: type: object required: - securityPolicyUrl - vulnerabilityReportingUrl - bugBountyUrl - pvrEnabled - criticalVulnerabilityFlag properties: securityPolicyUrl: type: string nullable: true vulnerabilityReportingUrl: type: string nullable: true bugBountyUrl: type: string nullable: true pvrEnabled: type: boolean nullable: true criticalVulnerabilityFlag: type: boolean nullable: true provenance: type: object required: - resolvedRepositoryUrl - declaredRepositoryUrl - mappingConfidenceScore - mappingConfidenceLabel - lastCommitAt properties: resolvedRepositoryUrl: type: string nullable: true description: 'Best available repository URL. Preferred source is the confidence-ranked package_repos → repos join — the repo CDP has actually resolved and enriched (scorecard, branch protection, etc.). When the package has no package_repos link yet, this falls back to the canonical repository_url on the package row, which is NOT confidence-resolved or enriched. Use mappingConfidenceScore / mappingConfidenceLabel to tell the two apart: both are null when the fallback URL is returned. ' declaredRepositoryUrl: type: string nullable: true description: Raw repository URL as declared in the package's own metadata. mappingConfidenceScore: type: number format: float minimum: 0 maximum: 1 nullable: true mappingConfidenceLabel: type: string enum: - High - Medium - Low - null nullable: true lastCommitAt: type: string format: date-time nullable: true supplyChainIntegrity: type: object required: - buildProvenance - signedReleases properties: buildProvenance: type: string nullable: true description: Always null for now — reserved. signedReleases: type: string nullable: true description: Always null for now — reserved. StewardEntry: type: object required: - id - stewardshipId - userId - role - assignedAt properties: id: type: string stewardshipId: type: string userId: type: string name: type: string nullable: true role: type: string enum: - lead - co_steward assignedAt: type: string format: date-time assignedBy: type: string nullable: true Steward_2: type: object required: - userId - role - assignedAt properties: userId: type: string description: Auth0 sub of the assigned steward. example: abc123 username: type: - string - 'null' description: Username of the steward. Null if not available. example: jrodriguez displayName: type: - string - 'null' description: Display name of the steward. Null if not available. example: Jonathan R. role: type: string enum: - lead - co_steward assignedAt: type: string format: date-time Ecosystem: type: string example: npm ScatterPoint_2: type: object required: - purl - name - criticalityScore - healthScore - healthBand - openVulns - advisoryCount properties: purl: type: string example: pkg:npm/lodash@4.17.21 name: type: string example: lodash criticalityScore: type: integer description: ROUND(p.impact × 100). Y-axis position (0–100). example: 94 healthScore: type: integer description: ROUND(scorecard_score × 10). X-axis position (0–100). 0 if no repo. example: 52 healthBand: type: string enum: - healthy - fair - concerning - critical description: 'Falls back to scorecard thresholds — never ''excellent'' (scatter uses scorecard score only, not Tinybird health_label). ' stewardshipStatus: oneOf: - $ref: '#/components/schemas/StewardshipStatus' - type: 'null' stewardshipId: type: - string - 'null' example: '4501' openVulns: type: integer example: 3 advisoryCount: type: integer description: Alias of openVulns — explicit field for tooltip display. example: 3 Error_2: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string example: VALIDATION_ERROR message: type: string example: Invalid query parameter. StatusCounts_2: type: object description: Per-status package counts for the tab bar. Computed without the active status filter. required: - all - unassigned - open - assessing - active - needs_attention - escalated - blocked - inactive properties: all: type: integer unassigned: type: integer open: type: integer assessing: type: integer active: type: integer needs_attention: type: integer escalated: type: integer blocked: type: integer inactive: type: integer Error_3: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string example: VALIDATION_ERROR message: type: string example: Invalid query parameter. Error_4: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string example: NOT_FOUND message: type: string example: Package not found. Advisory: type: object required: - osvId - severity - resolution - isCritical properties: osvId: type: string example: GHSA-xxxx-xxxx-xxxx severity: type: string enum: - critical - high - moderate - low nullable: true resolution: type: string enum: - open - patched nullable: true isCritical: type: boolean description: True when CVSS score >= 7.0. PackageDetailBulkEntry: type: object required: - requestedPurl - found - package properties: requestedPurl: type: string found: type: boolean package: type: object nullable: true allOf: - $ref: '#/components/schemas/PackageDetail' Error: type: object required: - error properties: error: type: object required: - code - message properties: code: type: string example: BAD_REQUEST message: type: string PackageHistoryEvent: type: object required: - id - actorType - activityType - createdAt properties: id: type: string actorUserId: type: string nullable: true actorType: type: string example: user activityType: type: string example: state_changed content: type: string nullable: true metadata: type: object nullable: true additionalProperties: true createdAt: type: string format: date-time Steward: type: object required: - userId - role - assignedAt properties: userId: type: string description: Auth0 sub of the assigned steward. example: auth0|abc123 role: type: string enum: - lead - co_steward assignedAt: type: string format: date-time StewardshipStatus: type: string enum: - unassigned - open - assessing - active - needs_attention - escalated - blocked - inactive PaginationMeta: type: object required: - total - page - pageSize properties: total: type: integer page: type: integer pageSize: type: integer PackageMetrics: type: object required: - criticalPackages properties: criticalPackages: type: integer description: Total packages marked as critical (is_critical = true). HealthBand: type: string enum: - excellent - healthy - fair - concerning - critical description: 'Health band on the internal scale (best→worst), returned verbatim — no external crosswalk. ' SecurityContact: type: object required: - channel - value - role - confidence - score properties: channel: type: string enum: - email - github-pvr - url - github-handle - web-form value: type: string example: security@expressjs.com role: type: string enum: - security-team - maintainer - admin - committer - org-owner confidence: $ref: '#/components/schemas/SecurityContactConfidence' score: type: number format: float minimum: 0 maximum: 1 HealthBand_2: type: string enum: - healthy - fair - concerning - critical description: 'Derived from `scorecardScore`: `null or < 3.0` → critical · `< 5.0` → concerning · `< 7.0` → fair · `≥ 7.0` → healthy ' HealthBand_3: type: string enum: - excellent - healthy - fair - concerning - critical description: 'Tinybird band when enriched (excellent ≥85, healthy 70–84, fair 50–69, concerning 30–49, critical <30). Falls back to scorecard thresholds: `null or < 3.0` → critical · `< 5.0` → concerning · `< 7.0` → fair · `≥ 7.0` → healthy. ' Advisory_2: type: object required: - osvId - severity properties: osvId: type: string description: GHSA or CVE identifier. example: CVE-2021-44906 severity: type: string enum: - critical - high - medium - low resolution: type: - string - 'null' description: Resolution status. TBD. PackageRow: type: object required: - purl - name - ecosystem - openVulns - maintainerCount - health - stewards properties: purl: type: string example: pkg:npm/lodash@4.17.21 name: type: string example: lodash ecosystem: type: string example: npm stewardshipId: type: - string - 'null' example: '4501' stewardshipStatus: oneOf: - $ref: '#/components/schemas/StewardshipStatus' - type: 'null' openVulns: type: integer description: Count of advisory_packages rows for this package. example: 3 maxVulnSeverity: type: - string - 'null' enum: - critical - high - medium - low description: Worst advisory severity. Null if no advisories. maintainerCount: type: integer description: Count of package_maintainers rows. Bus factor proxy. example: 2 criticalityScore: type: - number - 'null' description: Raw criticality score (0–1 float). Use `impact` for display. example: 0.94 impact: type: - integer - 'null' description: Display score (0–100). criticalityScore × 100, rounded. Null if no score. example: 94 scorecardScore: type: - number - 'null' description: OpenSSF Scorecard score (0–10). Null if no repo mapped. example: 5.2 health: type: object required: - score - label properties: score: type: - integer - 'null' description: 'Health score (0–100). Tinybird composite score when enriched, OpenSSF Scorecard × 10 otherwise. Null if neither is available. ' example: 52 label: type: - string - 'null' enum: - excellent - healthy - fair - concerning - critical - null description: 'Tinybird band when enriched (excellent ≥85, healthy 70–84, fair 50–69, concerning 30–49, critical <30), scorecard band otherwise. ' example: fair lifecycle: type: - string - 'null' enum: - active - stable - declining - abandoned - archived - null description: Tinybird-enriched lifecycle label. Null if not yet enriched. example: active latestReleaseAt: type: - string - 'null' format: date-time description: Used by the frontend to derive the stale flag (≥ 18 months). lastActivity: description: Most recent stewardship activity for this package. Null if none. oneOf: - type: object required: - type - at properties: type: type: - string - 'null' example: state_changed content: type: - string - 'null' example: Moved to active stewardship at: type: string format: date-time - type: 'null' stewards: type: array description: Active stewards (deleted_at IS NULL). Empty array if none. items: $ref: '#/components/schemas/Steward' PackageListRow: type: object required: - purl - name - ecosystem - openVulns - maintainerCount - healthBand - stewards properties: purl: type: string example: pkg:npm/%40angular/core@17.0.0 name: type: string ecosystem: type: string criticalityScore: type: number format: float nullable: true stewardshipId: type: string nullable: true stewardshipStatus: $ref: '#/components/schemas/StewardshipStatus' nullable: true openVulns: type: integer maxVulnSeverity: type: string enum: - critical - high - medium - low nullable: true maintainerCount: type: integer scorecardScore: type: number format: float nullable: true healthBand: $ref: '#/components/schemas/HealthBand_2' latestReleaseAt: type: string format: date-time nullable: true lastActivity: type: object nullable: true required: - type - content - at properties: type: type: string content: type: string nullable: true at: type: string format: date-time stewards: type: array items: $ref: '#/components/schemas/StewardEntry' SecurityContactConfidence: type: string enum: - PRIMARY - SECONDARY - FALLBACK - NONE securitySchemes: M2MBearer: type: oauth2 description: 'Auth0 machine-to-machine client-credentials flow. Akrites exchanges its client ID/secret with Auth0 for a JWT and sends it as `Authorization: Bearer `; CDP only verifies the resulting token. ' flows: clientCredentials: tokenUrl: https://linuxfoundation.auth0.com/oauth/token scopes: read:packages: Read package detail read:stewardships: Read package stewardship data read:maintainer-roles: Read security contacts (interim scope for Contacts; see the Contacts tag)