Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
cb5db1f
draft dependabot backend module
alizard0 Feb 18, 2026
f34f6d4
Merge branch 'main' into RHIDP-12269
alizard0 Feb 25, 2026
f8ca2dc
reviewed graphql api call and thresholds
alizard0 Feb 25, 2026
286074e
Merge branch 'main' into RHIDP-12269
alizard0 Feb 25, 2026
a2cd57e
review work
alizard0 Feb 25, 2026
1b4209c
Merge branch 'main' into RHIDP-12269
alizard0 Feb 27, 2026
7d86f29
added 4 metric dependabot metric providers one for each severity
alizard0 Mar 2, 2026
34b9e39
Merge branch 'main' into RHIDP-12269
alizard0 Mar 2, 2026
c79d957
Merge branch 'main' into RHIDP-12269
alizard0 Mar 2, 2026
f1c31be
Merge branch 'main' into RHIDP-12269
alizard0 Mar 2, 2026
d511c80
review work cicd
alizard0 Mar 2, 2026
1ac52f2
review work cicd
alizard0 Mar 2, 2026
7b81453
review work cicd, removed the regex
alizard0 Mar 2, 2026
ec5ee5e
Merge branch 'main' into RHIDP-12269
alizard0 Mar 2, 2026
9bcb46b
run yarn backstage-cli repo fix --publish
alizard0 Mar 2, 2026
43f6845
Merge branch 'main' into RHIDP-12269
alizard0 Mar 2, 2026
2a65926
rollback run yarn backstage-cli repo fix --publish changes
alizard0 Mar 2, 2026
53ad2ce
review work
alizard0 Mar 3, 2026
f1b0679
Merge branch 'main' into RHIDP-12269
alizard0 Mar 3, 2026
5742feb
added dependabot and missing openssf to changeset
alizard0 Mar 4, 2026
f60cece
review work: use octokit instead, rework some logic
alizard0 Mar 4, 2026
57c4b63
Merge branch 'main' into RHIDP-12269
alizard0 Mar 4, 2026
6c7965b
Merge branch 'main' into RHIDP-12269
alizard0 Mar 5, 2026
e6ed618
create location file all-scorecard.yaml
alizard0 Mar 6, 2026
e481a5d
review work
alizard0 Mar 6, 2026
3b71e4e
Merge branch 'main' into RHIDP-12269
alizard0 Mar 6, 2026
1b43839
review work
alizard0 Mar 6, 2026
0bd4329
Merge branch 'main' into RHIDP-12269
alizard0 Mar 9, 2026
be5cddc
review work
alizard0 Mar 9, 2026
d65008b
review work
alizard0 Mar 9, 2026
b6a41be
Merge branch 'main' into RHIDP-12269
alizard0 Mar 9, 2026
d1a1da1
review work for cicd; fix prettier
alizard0 Mar 9, 2026
6ab7063
Merge branch 'main' into RHIDP-12269
alizard0 Mar 10, 2026
6fbc16e
Merge branch 'main' into RHIDP-12269
alizard0 Mar 12, 2026
62b9dd7
Merge branch 'main' into RHIDP-12269
alizard0 Mar 12, 2026
a7dd2e6
review work
alizard0 Mar 12, 2026
74cbcd3
Merge branch 'main' into RHIDP-12269
alizard0 Mar 12, 2026
252eb80
Merge branch 'main' into RHIDP-12269
alizard0 Mar 13, 2026
8881fad
review work
alizard0 Mar 13, 2026
b2502f1
review work
alizard0 Mar 13, 2026
52dc52e
added changeset
alizard0 Mar 13, 2026
75f99d5
reference dependabot on scorecard-backend
alizard0 Mar 13, 2026
41faf82
Merge branch 'main' into RHIDP-12269
alizard0 Mar 13, 2026
6faa02c
Merge branch 'main' into RHIDP-12269
alizard0 Mar 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions workspaces/scorecard/.changeset/dark-dolls-spend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dependabot': minor
---

added dependabot scorecard
17 changes: 2 additions & 15 deletions workspaces/scorecard/app-config.local.EXAMPLE.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,11 @@ auth:

catalog:
locations:
- type: file
target: ../../examples/entities.yaml
- type: file
target: ../../examples/github-scorecard-only.yaml
rules:
- allow: [Component]
- type: file
target: ../../examples/jira-scorecard-only.yaml
rules:
- allow: [Component]
- type: file
target: ../../examples/all-scorecards.yaml
rules:
- allow: [Component]
- type: file
target: ../../examples/no-scorecards.yaml
rules:
- allow: [Component]
- allow:
[Component, System, API, Resource, Location, Template, User, Group]
# TODO: Additional catalog entities for your user

proxy:
Expand Down
44 changes: 1 addition & 43 deletions workspaces/scorecard/app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,56 +93,14 @@ catalog:
rules:
- allow: [Component, System, Group, Resource, Location, Template, API]
locations:
# Local example data, file locations are relative to the backend process, typically `packages/backend`
- type: file
target: ../../examples/entities.yaml

# Local example scorecards
- type: file
target: ../../examples/github-scorecard-only.yaml
rules:
- allow: [Component]

- type: file
target: ../../examples/jira-scorecard-only.yaml
rules:
- allow: [Component]

- type: file
target: ../../examples/all-scorecards.yaml
rules:
- allow: [Component]

- type: file
target: ../../examples/no-scorecards.yaml
target: ../../examples/all-scorecards-location.yaml
rules:
- allow: [Component]

# Local example template
- type: file
target: ../../examples/template/template.yaml
rules:
- allow: [Template]

# Local example organizational data
- type: file
target: ../../examples/org.yaml
rules:
- allow: [User, Group]

- type: url
target: https://github.com/redhat-developer/rhdh/blob/main/catalog-entities/components/showcase.yaml

## Uncomment these lines to add more example data
# - type: url
# target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/all.yaml

## Uncomment these lines to add an example org
# - type: url
# target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme-corp.yaml
# rules:
# - allow: [User, Group]

kubernetes:
# see https://backstage.io/docs/features/kubernetes/configuration for kubernetes configuration options

Expand Down
14 changes: 14 additions & 0 deletions workspaces/scorecard/examples/all-scorecards-location.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: backstage.io/v1alpha1
kind: Location
metadata:
name: all-scorecards-location

description: A collection of all the scorecards
spec:
targets:
- ./components/dependabot-scorecard-only.yaml
- ./components/github-scorecard-only.yaml
- ./components/jira-scorecard-only.yaml
- ./components/openssf-scorecard-only.yaml
- ./components/all-scorecards.yaml
- ./components/no-scorecards.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
# Component with OpenSSF Scorecard
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: dependabot-scorecard-only
Comment thread
alizard0 marked this conversation as resolved.
annotations:
github.com/project-slug: redhat-developer/rhdh-plugins
backstage.io/source-location: url:https://github.com/redhat-developer/rhdh-plugins
spec:
type: service
owner: group:development/guests
lifecycle: experimental
1 change: 1 addition & 0 deletions workspaces/scorecard/packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"@backstage/plugin-search-backend-node": "^1.3.17",
"@backstage/plugin-techdocs-backend": "^2.1.2",
"@red-hat-developer-hub/backstage-plugin-scorecard-backend": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dependabot": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-github": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-jira": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-openssf": "workspace:^",
Expand Down
5 changes: 5 additions & 0 deletions workspaces/scorecard/packages/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,9 @@ backend.add(
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-openssf'
),
);
backend.add(
import(
'@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dependabot'
),
);
backend.start();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Scorecard Backend Module: Dependabot

Adds Dependabot alerts as a scorecard metric (`dependabot.alerts`, 0–9 from severity).

**Install:** `yarn workspace backend add @red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dependabot` then `backend.add(import('@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dependabot'))`.

**Setup:** Entities need `github.com/project-slug: owner/repo`. GitHub token must have `security_events` (or Dependabot read) so the backend can call the Dependabot API.

**How it works:** **DependabotClient** fetches open alerts from the GitHub API (by severity, with pagination). **DependabotMetricProvider** (one per severity) uses the client to score entities. The **factory** (`createDependabotMetricProvider` / `createDependabotMetricProviders`) builds single or all-four providers; the module registers the four (critical, high, medium, low) with the scorecard backend.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
Comment thread
alizard0 marked this conversation as resolved.
"name": "@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dependabot",
"version": "0.1.0",
"license": "Apache-2.0",
"description": "The dependabot backend module for the scorecard plugin.",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"repository": {
"type": "git",
"url": "https://github.com/redhat-developer/rhdh-plugins",
"directory": "workspaces/scorecard/plugins/scorecard-backend-module-dependabot"
},
"backstage": {
"role": "backend-plugin-module",
"pluginId": "scorecard",
"pluginPackage": "@red-hat-developer-hub/backstage-plugin-scorecard-backend"
},
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"clean": "backstage-cli package clean",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack"
},
"dependencies": {
"@backstage/backend-plugin-api": "^1.5.0",
"@backstage/catalog-client": "^1.12.1",
"@backstage/catalog-model": "^1.7.6",
"@backstage/config": "^1.3.6",
"@backstage/integration": "^1.18.2",
"@octokit/rest": "^19.0.3",
"@red-hat-developer-hub/backstage-plugin-scorecard-common": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-scorecard-node": "workspace:^"
},
"devDependencies": {
"@backstage/backend-test-utils": "^1.10.0",
"@backstage/cli": "^0.34.5"
},
"files": [
"dist"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## API Report File for "@red-hat-developer-hub/backstage-plugin-scorecard-backend-module-dependabot"

> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).

```ts
import { BackendFeature } from '@backstage/backend-plugin-api';

// @public (undocumented)
const scorecardModuleDependabot: BackendFeature;
export default scorecardModuleDependabot;
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { ConfigReader } from '@backstage/config';
import { DefaultGithubCredentialsProvider } from '@backstage/integration';
import { DependabotClient } from './DependabotClient';

const mockPaginate = jest.fn();

jest
.spyOn(DefaultGithubCredentialsProvider.prototype, 'getCredentials')
.mockResolvedValue({
type: 'token',
token: 'dummy-token',
});

jest.mock('@octokit/rest', () => ({
Octokit: jest.fn().mockImplementation(() => ({ paginate: mockPaginate })),
}));

describe('DependabotClient', () => {
const config = new ConfigReader({
integrations: {
github: [
{
host: 'github.com',
token: 'dummy-token',
apiBaseUrl: 'https://api.github.com',
},
],
},
});
const logger = {
child: jest.fn().mockReturnThis(),
info: jest.fn(),
warn: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
} as any;
const repo = { owner: 'owner', repo: 'repo' };
const url = 'https://github.com/owner/repo';

let client: DependabotClient;

beforeEach(() => {
jest.clearAllMocks();
client = new DependabotClient(config, logger);
mockPaginate.mockResolvedValue([]);
});

it('delegates to Octokit paginate with correct params', async () => {
const alerts = [
{
number: 1,
state: 'open',
createdAt: '2024-01-01',
securityAdvisory: { severity: 'critical' },
},
];
mockPaginate.mockResolvedValueOnce(alerts);

const result = await client.getAlerts(url, repo, 'critical');

expect(result).toEqual(alerts);
const { Octokit } = jest.requireMock('@octokit/rest');
expect(Octokit).toHaveBeenCalledWith({
auth: 'dummy-token',
baseUrl: 'https://api.github.com',
});
expect(mockPaginate).toHaveBeenCalledWith(
'GET /repos/{owner}/{repo}/dependabot/alerts',
expect.objectContaining({
owner: 'owner',
repo: 'repo',
state: 'open',
severity: 'critical',
per_page: 100,
}),
);
});

it('throws when GitHub integration is missing', async () => {
await expect(
client.getAlerts('https://unknown/owner/repo', repo, 'critical'),
).rejects.toThrow(
"Missing GitHub integration for 'https://unknown/owner/repo'",
);
expect(mockPaginate).not.toHaveBeenCalled();
});

it('throws when token is missing', async () => {
(
DefaultGithubCredentialsProvider.prototype.getCredentials as jest.Mock
).mockResolvedValueOnce({ type: 'token' });

await expect(client.getAlerts(url, repo, 'critical')).rejects.toThrow(
`Missing GitHub token for '${url}'`,
);
expect(mockPaginate).not.toHaveBeenCalled();
});

it('throws when Octokit paginate fails', async () => {
mockPaginate.mockRejectedValueOnce(new Error('GitHub API error: 403'));

await expect(client.getAlerts(url, repo, 'critical')).rejects.toThrow(
/GitHub API error/,
);
});
});
Loading
Loading