Skip to content

Comments

feat(scorecard): Implement baseUrl for fetching openssf data#2301

Open
alizard0 wants to merge 18 commits intomainfrom
RHIDP-12106
Open

feat(scorecard): Implement baseUrl for fetching openssf data#2301
alizard0 wants to merge 18 commits intomainfrom
RHIDP-12106

Conversation

@alizard0
Copy link
Member

Hey, I just made a Pull Request!

  1. Remove abstract metric providers
  2. Left only OpenSSF metric provider
  3. Simplied the usage of the openssf client by fetching scorecards only using a baseUrl

✔️ Checklist

  • A changeset describing the change and affected packages. (more info)
  • Added or Updated documentation
  • Tests for new functionality and regression tests for bug fixes
  • Screenshots attached (for UI changes)

…nd simplied the usage of the openssf client by fetching scorecards only using a baseUrl
@rhdh-gh-app
Copy link

rhdh-gh-app bot commented Feb 10, 2026

Missing Changesets

The following package(s) are changed by this PR but do not have a changeset:

  • @red-hat-developer-hub/backstage-plugin-scorecard-backend-module-openssf

See CONTRIBUTING.md for more information about how to add changesets.

Changed Packages

Package Name Package Path Changeset Bump Current Version
@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-openssf workspaces/scorecard/plugins/scorecard-backend-module-openssf none v0.1.5

@alizard0
Copy link
Member Author

Testing image, it loads all openssf metrics using baseUrl component annotation.
Screenshot 2026-02-11 at 15 23 08

async getScorecard(owner: string, repo: string): Promise<OpenSSFResponse> {
const apiUrl = `${this.baseUrl}/${this.gitServiceHost}/${owner}/${repo}`;
async getScorecard(entity: Entity): Promise<OpenSSFResponse> {
const baseUrl = entity.metadata.annotations?.['openssf/baseUrl'] ?? '';
Copy link
Member

Choose a reason for hiding this comment

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

I would rather take baseUrl from app-config of openssf. @christoph-jerolimov WDYT?

Copy link
Member Author

Choose a reason for hiding this comment

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

As we spoke earlier (in our wg), the idea of having it inside the component is to be able to have a different URL (per project) to fetch the openssf-scorecard json file.

Copy link
Member Author

Choose a reason for hiding this comment

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

In the lastest commit I have renamed the baseUrl to scorecardUrl.

Copy link
Member Author

Choose a reason for hiding this comment

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

Also, an important argument to keep the openssf/scorecardUrl in the component: the scorecardUrl is unique per component, therefore moving this to app-config.yaml doesn't make sense.

Copy link
Member

Choose a reason for hiding this comment

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

The argument about keeping url in the component due to being unique for the component can be resolved by using other annotations to specify parts of url, for example like github does with github.com/project-slug (but it would make code and setup more complex).
Not sure if exposing whole url is alright, but it is true there are some well known annotations that do that, like source location. The other thing that comes to mind is that if company moves to other domain where it publishes scorecard data, all component annotations will need to be updated.

In case auth is needed, we can in future utilize integrations no matter if we use the whole url in annotations or just part, so that is fine.

Choose a reason for hiding this comment

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

As shared in another comment, maybe align this with https://backstage.io/docs/features/software-catalog/well-known-annotations/ and call it [security-]scorecard-location ? Wdyt?

I think its a fair point to specific a base URL somewhere. But we can start simple and support first just "sources" and a base URL in the app-config later?

name: openssf-scorecard
annotations:
openssf/baseUrl: https://api.securityscorecards.dev/projects/github.com/alizard0/rhdh-plugins
openssf/scorecardUrl: https://api.securityscorecards.dev/projects/github.com/alizard0/rhdh-plugins
Copy link
Member Author

Choose a reason for hiding this comment

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

@dzemanov I think scorecardUrl is a better name for it.

Choose a reason for hiding this comment

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

Maybe you can align it with others annotations, see https://backstage.io/docs/features/software-catalog/well-known-annotations/ and call it openssf.dev/scorecard-location? Wdyt?

@alizard0 alizard0 requested a review from dzemanov February 17, 2026 10:51
kind: Component
metadata:
name: openssf-scorecard-only
name: openssf-scorecard

Choose a reason for hiding this comment

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

Is the name change needed for something? The idea was that it is obvous that this entity has just openssf-scorecard scorecard features enabled.

- The repository is private (OpenSSF only analyzes public repositories)
- The repository path in the annotation is incorrect
- The metric score is lower than -1 or higher than 10.
18 metrics from [OpenSSF checks](https://github.com/ossf/scorecard/blob/main/docs/checks.md): `openssf.binary_artifacts`, `openssf.branch_protection`, `openssf.cii_best_practices`, `openssf.ci_tests`, `openssf.code_review`, `openssf.contributors`, `openssf.dangerous_workflow`, `openssf.dependency_update_tool`, `openssf.fuzzing`, `openssf.license`, `openssf.maintained`, `openssf.packaging`, `openssf.pinned_dependencies`, `openssf.sast`, `openssf.security_policy`, `openssf.signed_releases`, `openssf.token_permissions`, `openssf.vulnerabilities`.

Choose a reason for hiding this comment

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

Why did you replaced the table with this metrics? I personally find a list or table more readable then this comma separated list?

type: service
lifecycle: production
owner: my-team
openssf/baseUrl: https://api.securityscorecards.dev/projects/github.com/owner/repo

Choose a reason for hiding this comment

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

I think you have changed this annotation

For the OpenSSF metrics to work, your catalog entities must have the required annotation:
| Annotation | Required | Description |
| ----------------- | -------- | --------------------------------------------------------------------------- |
| `openssf/baseUrl` | Yes | Full scorecard API URL for this component (e.g. public API or self-hosted). |

Choose a reason for hiding this comment

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

You changed that annotation

const apiUrl = `${this.baseUrl}/${this.gitServiceHost}/${owner}/${repo}`;
async getScorecard(entity: Entity): Promise<OpenSSFResponse> {
const scorecardUrl =
entity.metadata.annotations?.['openssf/scorecardUrl'] ?? '';
Copy link
Member

@christoph-jerolimov christoph-jerolimov Feb 19, 2026

Choose a reason for hiding this comment

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

Can you please create a src/annotations.ts with an export for the annotations?

/**
 * @public
 */
export enum OpenSSFAnnotation {
  URL = 'openssf/scorecardUrl',
}

And I've added above. Mayby this should be called "openssf.dev/scorecard-location"? /cc @dzemanov

Copy link
Member Author

Choose a reason for hiding this comment

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

why .dev?

@rhdh-qodo-merge
Copy link

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: check all required jobs

Failed stage: Run exit 1 [❌]

Failed test name: ""

Failure summary:

The action failed because the workflow explicitly ran exit 1, which forces the step to terminate
with a non-zero exit code.
The failure occurs in the step Run exit 1 (lines 41-45), causing the job
to stop with Process completed with exit code 1.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

30:  Packages: write
31:  Pages: write
32:  PullRequests: write
33:  RepositoryProjects: write
34:  SecurityEvents: write
35:  Statuses: write
36:  ##[endgroup]
37:  Secret source: Actions
38:  Prepare workflow directory
39:  Prepare all required actions
40:  Complete job name: check all required jobs
41:  ##[group]Run exit 1
42:  �[36;1mexit 1�[0m
43:  shell: /usr/bin/bash -e {0}
44:  ##[endgroup]
45:  ##[error]Process completed with exit code 1.
46:  Cleaning up orphan processes

@sonarqubecloud
Copy link

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.

3 participants