Skip to content
This repository has been archived by the owner on Jul 1, 2024. It is now read-only.

Commit

Permalink
feat: Filter alerts by severity (kunalnagarco#151)
Browse files Browse the repository at this point in the history
  • Loading branch information
kunalnagar authored Feb 2, 2024
1 parent 0df7e7e commit 73e22d9
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 135 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jobs:
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
# microsoft_teams_webhook: ${{ secrets.MICROSOFT_TEAMS_WEBHOOK }}
# slack_webhook: ${{ secrets.SLACK_WEBHOOK }}
# severity: low,medium
# count: 20
# pager_duty_integration_key: ${{ secrets.PAGER_DUTY_INTEGRATION_KEY }}
# zenduty_api_key: ${{ secrets.ZENDUTY_API_KEY }}
Expand Down
7 changes: 1 addition & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@

## @kunalnagarco/action-cve

A [GitHub action](https://github.com/features/actions) that sends Dependabot Vulnerability Alerts to multiple sources:

- Microsoft Teams
- Slack
- PagerDuty
- Zenduty
A [GitHub action](https://github.com/features/actions) that sends Dependabot Vulnerability Alerts to multiple sources.

**For more info and getting started, check out the [Wiki](https://github.com/kunalnagarco/action-cve/wiki).**

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
"dependencies": {
"@actions/core": "1.10.1",
"@actions/github": "5.1.1",
"@octokit/rest": "^20.0.2",
"@octokit/types": "^12.4.0",
"@pagerduty/pdjs": "2.2.4",
"@slack/webhook": "6.1.0",
"adaptivecards": "2.11.3",
Expand All @@ -54,7 +56,6 @@
},
"devDependencies": {
"@kunalnagarco/eslint-config": "^0.2.7",
"@octokit/graphql-schema": "10.74.2",
"@semantic-release/changelog": "6.0.3",
"@semantic-release/commit-analyzer": "9.0.2",
"@semantic-release/git": "10.0.1",
Expand Down
21 changes: 12 additions & 9 deletions src/entities/advisory.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { SecurityAdvisory } from '@octokit/graphql-schema'
import { DependabotAlert } from './alert'

type SecurityAdvisory = DependabotAlert['security_advisory']

export interface Advisory {
/**
Expand Down Expand Up @@ -35,15 +37,16 @@ export interface Advisory {
withdrawnAt?: string
}

type AdvisorySeverity = 'LOW' | 'MODERATE' | 'HIGH' | 'CRITICAL'
type AdvisorySeverity = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'

export const toAdvisory = (securityAdvisory: SecurityAdvisory): Advisory => ({
cvssScore: securityAdvisory.cvss.score,
severity: securityAdvisory.severity,
cvssScore: securityAdvisory.cvss?.score || 0,
severity:
(securityAdvisory.severity?.toUpperCase() as AdvisorySeverity) || 'LOW',
summary: securityAdvisory.summary,
description: securityAdvisory.description,
url: securityAdvisory.permalink,
publishedAt: securityAdvisory.publishedAt,
updatedAt: securityAdvisory.updatedAt,
withdrawnAt: securityAdvisory.withdrawnAt,
description: securityAdvisory.description || '',
url: securityAdvisory.references[0].url,
publishedAt: securityAdvisory.published_at || '',
updatedAt: securityAdvisory.updated_at || '',
withdrawnAt: securityAdvisory.withdrawn_at || '',
})
39 changes: 21 additions & 18 deletions src/entities/alert.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,43 @@
import { RepositoryVulnerabilityAlert } from '@octokit/graphql-schema'
import { Endpoints } from '@octokit/types'

import { Advisory, toAdvisory } from './advisory'
import { Repository, toRepository } from './repository'
import { Repository } from './repository'
import { Vulnerability, toVulnerability } from './vulnerability'

export type DependabotAlert =
Endpoints['GET /repos/{owner}/{repo}/dependabot/alerts']['response']['data'][0]

export interface Alert {
repository: Repository
packageName: string
advisory?: Advisory
vulnerability?: Vulnerability
manifest: string
createdAt: string
}

export const toAlert = (
repositoryVulnerabilityAlert: RepositoryVulnerabilityAlert,
dependabotAlert: DependabotAlert,
repositoryName: string,
repositoryOwner: string,
): Alert => ({
repository: toRepository(repositoryVulnerabilityAlert.repository),
packageName:
repositoryVulnerabilityAlert.securityVulnerability?.package.name || '',
advisory: repositoryVulnerabilityAlert.securityAdvisory
? toAdvisory(repositoryVulnerabilityAlert.securityAdvisory)
repository: {
name: repositoryName,
owner: repositoryOwner,
},
packageName: dependabotAlert.security_vulnerability.package.name || '',
advisory: dependabotAlert.security_advisory
? toAdvisory(dependabotAlert.security_advisory)
: undefined,
vulnerability: repositoryVulnerabilityAlert.securityVulnerability
? toVulnerability(repositoryVulnerabilityAlert.securityVulnerability)
vulnerability: dependabotAlert.security_vulnerability
? toVulnerability(dependabotAlert.security_vulnerability)
: undefined,
manifest: repositoryVulnerabilityAlert.vulnerableManifestFilename,
createdAt: repositoryVulnerabilityAlert.createdAt,
createdAt: dependabotAlert.created_at,
})

export const isActiveAlert = (
repositoryVulnerabilityAlert: RepositoryVulnerabilityAlert,
): boolean => {
export const isActiveAlert = (dependabotAlert: DependabotAlert): boolean => {
if (
repositoryVulnerabilityAlert.dismissedAt === null &&
repositoryVulnerabilityAlert.fixedAt === null
dependabotAlert.dismissed_at === null &&
dependabotAlert.fixed_at === null
) {
return true
}
Expand Down
7 changes: 0 additions & 7 deletions src/entities/repository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Repository as GitHubRepository } from '@octokit/graphql-schema'

import { Alert } from '.'

export interface Repository {
Expand All @@ -13,10 +11,5 @@ export interface Repository {
owner: string
}

export const toRepository = (repository: GitHubRepository): Repository => ({
name: repository.name,
owner: repository.owner.login,
})

export const getFullRepositoryNameFromAlert = (alert: Alert): string =>
`${alert.repository.owner}/${alert.repository.name}`
13 changes: 5 additions & 8 deletions src/entities/vulnerability.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { SecurityVulnerability } from '@octokit/graphql-schema'
import { DependabotAlert } from './alert'

type SecurityVulnerability = DependabotAlert['security_vulnerability']

export interface Vulnerability {
/**
Expand All @@ -15,16 +17,11 @@ export interface Vulnerability {
* + `>= 0.0.1` denotes a version range with a known minimum, but no known maximum
*/
vulnerableVersionRange: string
/**
* When the vulnerability was last updated
*/
updatedAt: string
}

export const toVulnerability = (
securityVulnerability: SecurityVulnerability,
): Vulnerability => ({
firstPatchedVersion: securityVulnerability.firstPatchedVersion?.identifier,
vulnerableVersionRange: securityVulnerability.vulnerableVersionRange,
updatedAt: securityVulnerability.updatedAt,
firstPatchedVersion: securityVulnerability.first_patched_version?.identifier,
vulnerableVersionRange: securityVulnerability.vulnerable_version_range,
})
89 changes: 23 additions & 66 deletions src/fetch-alerts.ts
Original file line number Diff line number Diff line change
@@ -1,74 +1,31 @@
import { Alert, toAlert, isActiveAlert } from './entities'
import { Repository } from '@octokit/graphql-schema'
import { getOctokit } from '@actions/github'
import fetch from 'node-fetch'
import { Octokit } from '@octokit/rest'

import { Alert, isActiveAlert, toAlert } from './entities'

export const fetchAlerts = async (
gitHubPersonalAccessToken: string,
repositoryName: string,
repositoryOwner: string,
severity: string,
count: number,
): Promise<Alert[] | []> => {
const octokit = getOctokit(gitHubPersonalAccessToken)
const { repository } = await octokit.graphql<{
repository: Repository
}>(`
query {
repository(owner:"${repositoryOwner}" name:"${repositoryName}") {
vulnerabilityAlerts(last: ${count}) {
edges {
node {
id
dismissedAt
fixedAt
repository {
name
owner {
login
}
}
securityAdvisory {
id
description
cvss {
score
vectorString
}
permalink
severity
summary
}
securityVulnerability {
firstPatchedVersion {
identifier
}
package {
ecosystem
name
}
vulnerableVersionRange
advisory {
cvss {
score
vectorString
}
summary
}
}
}
}
}
}
}
`)
const gitHubAlerts = repository.vulnerabilityAlerts?.edges
if (gitHubAlerts) {
const alerts: Alert[] = []
for (const gitHubAlert of gitHubAlerts) {
if (gitHubAlert && gitHubAlert.node && isActiveAlert(gitHubAlert.node)) {
alerts.push(toAlert(gitHubAlert.node))
}
}
return alerts
}
return []
const octokit = new Octokit({
auth: gitHubPersonalAccessToken,
request: {
fetch,
},
})
const response = await octokit.dependabot.listAlertsForRepo({
owner: repositoryOwner,
repo: repositoryName,
severity,
per_page: count,
})
const alerts: Alert[] = response.data
.filter((dependabotAlert) => isActiveAlert(dependabotAlert))
.map((dependabotAlert) =>
toAlert(dependabotAlert, repositoryName, repositoryOwner),
)
return alerts
}
6 changes: 4 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { getInput, setFailed } from '@actions/core'
import { context } from '@actions/github'

import {
sendAlertsToMicrosoftTeams,
sendAlertsToPagerDuty,
Expand All @@ -7,7 +9,6 @@ import {
sendAlertsToEmailSmtp,
validateSlackWebhookUrl,
} from './destinations'
import { context } from '@actions/github'
import { fetchAlerts } from './fetch-alerts'

async function run(): Promise<void> {
Expand All @@ -29,9 +30,10 @@ async function run(): Promise<void> {
const emailTransportSmtpUser = getInput('email_transport_smtp_user')
const emailTransportSmtpPassword = getInput('email_transport_smtp_password')
const count = parseInt(getInput('count'))
const severity = getInput('severity')
const owner = context.repo.owner
const repo = context.repo.repo
const alerts = await fetchAlerts(token, repo, owner, count)
const alerts = await fetchAlerts(token, repo, owner, severity, count)
if (alerts.length > 0) {
if (microsoftTeamsWebhookUrl) {
await sendAlertsToMicrosoftTeams(microsoftTeamsWebhookUrl, alerts)
Expand Down
Loading

0 comments on commit 73e22d9

Please sign in to comment.