Skip to content

feat: expose security contacts via api [CM-1297]#4304

Merged
mbani01 merged 5 commits into
mainfrom
feat/expose_security_contacts_via_api
Jul 3, 2026
Merged

feat: expose security contacts via api [CM-1297]#4304
mbani01 merged 5 commits into
mainfrom
feat/expose_security_contacts_via_api

Conversation

@mbani01

@mbani01 mbani01 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

This pull request adds support for returning security contact information and related metadata for packages in the public API. It introduces new data structures for security contacts, exposes them in the API response, and updates the data-access layer to retrieve and process this information from the database.

API Schema and Response Enhancements:

  • Added SecurityContact and SecurityContactConfidence types to the OpenAPI schema, and updated the securityContacts field to include detailed information and a new packageConfidence field. Also added a securityPolicies object with security-related URLs and flags. [1] [2]

Backend and Data Layer Updates:

  • Updated the data-access layer (api.ts) to fetch security contacts and related fields from the database, including new fields for security policy URLs and contact refresh times. [1] [2]
  • Added the SecurityContactConfidence type, SecurityContactRow interface, and a securityContactConfidenceBand function to map contact scores to confidence bands. [1] [2]
  • Updated the API handler (getPackage.ts) to process and return security contact details, compute the highest-confidence band, and include the new securityPolicies object in responses. [1] [2] [3]

Note

Medium Risk
Adds a public API contract that exposes contact channels/values (emails, handles, URLs) and changes null vs empty semantics for clients; logic is read-only but disclosure-sensitive.

Overview
Package detail responses now surface security contact data from the linked repo instead of placeholders: up to five scored contacts (channel, value, role, confidence, score), a packageConfidence band from the top score, and securityPolicies URLs plus pvrEnabled. securityContacts is null until the security-contacts pipeline has swept the repo, and [] when swept with no hits; provenance stays internal.

OpenAPI adds SecurityContact / SecurityContactConfidence and documents that behavior. The data layer extends getPackageDetailByPurl to join repo policy fields and aggregate from security_contacts; securityContactConfidenceBand is shared with the packages worker scorer (local duplicate removed).

Reviewed by Cursor Bugbot for commit 0b72429. Bugbot is set up for automated code reviews on this repo. Configure here.

Signed-off-by: Mouad BANI <mouad-mb@outlook.com>
@mbani01 mbani01 self-assigned this Jul 3, 2026
Copilot AI review requested due to automatic review settings July 3, 2026 13:19
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR wires real security-contact data into the public package-detail API (GET /v1/akrites/packages/detail, shared with the deprecated /v1/packages/detail). Previously security.securityContacts and cvd.isPvrEnabled were hard-coded null; now they are sourced from the linked repo's security_contacts pipeline and repos policy columns.

Changes:

  • Data-access layer: adds SecurityContactConfidence/SecurityContactRow types, extends PackageDetailRow and getPackageDetailByPurl with repo policy columns plus a json_agg subquery returning up to 5 active security contacts, and adds a securityContactConfidenceBand helper.
  • API handler: maps contacts (null until swept, empty array when swept with none), derives packageConfidence from the top score, and exposes a securityPolicies block and cvd.isPvrEnabled.
  • OpenAPI (akrites): documents new SecurityContact/SecurityContactConfidence schemas, packageConfidence, and securityPolicies, with null-vs-empty semantics.

Note: the deprecated backend/src/api/public/v1/packages/openapi.yaml still documents the old SecurityContact (name/email) shape and securityContacts: null, so it is now inaccurate for the shared handler — outside this PR's diff, but worth tracking before that spec is removed.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
services/libs/data-access-layer/src/osspckgs/api.ts New security-contact types, SQL columns + json_agg subquery, and confidence-band helper.
backend/src/api/public/v1/packages/getPackage.ts Maps contacts, computes packageConfidence, exposes securityPolicies and cvd.isPvrEnabled.
backend/src/api/public/v1/akrites/openapi.yaml Adds SecurityContact/SecurityContactConfidence schemas and documents new response fields.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread services/libs/data-access-layer/src/osspckgs/api.ts
Signed-off-by: Mouad BANI <mouad-mb@outlook.com>
@mbani01 mbani01 requested a review from ulemons July 3, 2026 13:37
Comment on lines +658 to +663
export function securityContactConfidenceBand(score: number): SecurityContactConfidence {
if (score >= 0.8) return 'PRIMARY'
if (score >= 0.55) return 'SECONDARY'
if (score >= 0.3) return 'FALLBACK'
return 'NONE'
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason why we are rewriting this function ? can we use the existing one ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which existing one are you referring to?
score.ts's confidenceBand is only a wrapper calling securityContactConfidenceBand from the DAL

return { rows, total }
}

export type SecurityContactConfidence = 'PRIMARY' | 'SECONDARY' | 'FALLBACK' | 'NONE'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is also a duplication

ulemons
ulemons previously approved these changes Jul 3, 2026
Signed-off-by: Mouad BANI <mouad-mb@outlook.com>
Copilot AI review requested due to automatic review settings July 3, 2026 15:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

mbani01 and others added 2 commits July 3, 2026 16:41
Copilot AI review requested due to automatic review settings July 3, 2026 15:55
@mbani01 mbani01 merged commit 2576aca into main Jul 3, 2026
11 checks passed
@mbani01 mbani01 deleted the feat/expose_security_contacts_via_api branch July 3, 2026 15:55

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 0b72429. Configure here.

const securityContacts =
pkg.contactsLastRefreshed == null
? null
: (pkg.securityContacts ?? []).map((c) => ({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failed sweep shows empty contacts

Medium Severity

securityContacts is derived only from whether contactsLastRefreshed is set, but the worker also sets that timestamp on failed extractor or repo runs via markRepoAttempted without persisting contacts. Clients then get an empty array, which the OpenAPI text describes as a successful sweep with no contacts, not a failed attempt.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0b72429. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants