Skip to content

Commit 756209e

Browse files
authored
fix, test, chore: runtime bug fixes, Vitest migration, and ESLint v10 upgrade (#219)
## Bug Fixes - **Missing `await` on email send** (`src/main.ts`) — `sendAlertsToEmailSmtp()` was fire-and-forget, silently dropping email failures - **Unsafe `alerts[0]` access** (`slack.ts`, `microsoft-teams.ts`, `zenduty.ts`) — added early return guard in each destination so they are safe to call independently - **Unsafe `references[0]` access** (`src/entities/advisory.ts`) — replaced with optional chaining (`references?.[0]?.url ?? ''`) to handle advisories with no references - **No HTTP error handling** (`src/utils/request/index.ts`) — fetch wrapper now throws on non-OK responses, surfacing 4xx/5xx failures instead of silently succeeding - **`parseInt` missing radix** (`src/main.ts`) — added `, 10` to both calls to prevent potential octal interpretation - **Floating promise** (`src/main.ts`) — added `void` to the top-level `run()` call to satisfy `no-floating-promises` ## Test Coverage - Migrated from Jest + ts-jest to **Vitest** (`jest.config.js` removed, `vitest.config.ts` added, `test` script updated) - Added tests for all previously untested modules: - `src/entities/` — `toAdvisory`, `toVulnerability`, `toRepositoryAlert`, `toOrgAlert`, `toEnterpriseAlert`, `getFullRepositoryNameFromAlert` - `src/fetch-alerts.ts` — repo, org, and enterprise alert fetching, ecosystem filtering, count passthrough - `src/destinations/` — Slack (including `validateSlackWebhookUrl`), PagerDuty, Zenduty, Email - Mock data in entity and fetch-alert tests typed with `DependabotAlert`, `DependabotOrgAlert`, `DependabotEnterpriseAlert` from `@octokit/types` — no `as any` - Test files moved to a top-level `tests/` directory mirroring `src/` structure to keep source files uncluttered ## ESLint Upgrade - Upgraded `@kunalnagarco/eslint-config` from v2.2.0 to v3.0.5 - Upgraded ESLint from v8 to v10 with flat config format (`eslint.config.mjs`) - Removed: `@typescript-eslint/eslint-plugin`, `@typescript-eslint/parser`, `eslint-config-airbnb`, `eslint-config-airbnb-typescript`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y`, `eslint-plugin-react`, `.eslintrc`, `.eslintignore` - Added: `@eslint/js`, `typescript-eslint`, `eslint-plugin-import-x`, `eslint-import-resolver-typescript` ## Test plan - [x] `yarn test` — all 48 tests pass - [x] `yarn build` — TypeScript compiles cleanly - [x] `yarn lint` — no lint errors - [ ] Trigger the action with an SMTP destination and verify email failures surface as action failures - [ ] Trigger against a repo with no open alerts and confirm no crash on `alerts[0]`
1 parent e8db247 commit 756209e

23 files changed

Lines changed: 2434 additions & 4750 deletions

.eslintignore

Lines changed: 0 additions & 4 deletions
This file was deleted.

.eslintrc

Lines changed: 0 additions & 17 deletions
This file was deleted.

eslint.config.mjs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import configPkg from '@kunalnagarco/eslint-config'
2+
import tseslint from 'typescript-eslint'
3+
import { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript'
4+
5+
const config = configPkg.default ?? configPkg
6+
7+
export default tseslint.config(
8+
{ ignores: ['dist/**', 'lib/**', 'node_modules/**'] },
9+
...config,
10+
{
11+
languageOptions: {
12+
parserOptions: {
13+
project: true,
14+
},
15+
},
16+
settings: {
17+
jest: { version: 29 },
18+
'import-x': {
19+
resolver: createTypeScriptImportResolver(),
20+
},
21+
},
22+
rules: {
23+
'import-x/prefer-default-export': 'off',
24+
'import-x/no-cycle': 'off',
25+
'import-x/no-extraneous-dependencies': [
26+
'error',
27+
{ devDependencies: ['tests/**/*.test.ts', 'vitest.config.ts'] },
28+
],
29+
},
30+
},
31+
{
32+
files: ['tests/**/*.test.ts'],
33+
rules: {
34+
'@typescript-eslint/no-explicit-any': 'off',
35+
'@typescript-eslint/no-unsafe-argument': 'off',
36+
'@typescript-eslint/no-unsafe-assignment': 'off',
37+
'@typescript-eslint/no-unsafe-member-access': 'off',
38+
'@typescript-eslint/no-unsafe-return': 'off',
39+
'@typescript-eslint/no-unsafe-call': 'off',
40+
},
41+
},
42+
)

jest.config.js

Lines changed: 0 additions & 11 deletions
This file was deleted.

package.json

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"lint": "eslint src/**/*.ts",
3131
"lint:fix": "eslint --fix src/**/*.ts",
3232
"package": "ncc build --source-map --license licenses.txt",
33-
"test": "jest",
33+
"test": "vitest run",
3434
"all": "yarn build && yarn format && yarn lint && yarn package && yarn test",
3535
"release": "semantic-release"
3636
},
@@ -56,36 +56,31 @@
5656
"nodemailer": "8.0.4"
5757
},
5858
"devDependencies": {
59-
"@kunalnagarco/eslint-config": "2.2.0",
59+
"@eslint/js": "^10.0.1",
60+
"@kunalnagarco/eslint-config": "3.0.5",
6061
"@semantic-release/changelog": "6.0.3",
6162
"@semantic-release/commit-analyzer": "13.0.1",
6263
"@semantic-release/git": "10.0.1",
6364
"@semantic-release/github": "10.3.5",
6465
"@semantic-release/release-notes-generator": "14.0.3",
65-
"@types/jest": "29.5.14",
6666
"@types/node": "20.19.39",
6767
"@types/nodemailer": "6.4.23",
68-
"@typescript-eslint/eslint-plugin": "^7.18.0",
69-
"@typescript-eslint/parser": "^7.18.0",
7068
"@vercel/ncc": "0.38.4",
7169
"conventional-changelog-conventionalcommits": "7.0.2",
72-
"eslint": "^8.57.0",
73-
"eslint-config-airbnb": "^19.0.4",
74-
"eslint-config-airbnb-typescript": "^18.0.0",
70+
"eslint": "^10.2.0",
7571
"eslint-config-prettier": "^9.1.0",
76-
"eslint-plugin-import": "^2.29.1",
77-
"eslint-plugin-jest": "^28.8.0",
78-
"eslint-plugin-jsx-a11y": "^6.9.0",
79-
"eslint-plugin-react": "^7.35.0",
72+
"eslint-import-resolver-typescript": "^4.4.4",
73+
"eslint-plugin-import-x": "^4.16.2",
74+
"eslint-plugin-jest": "^29.15.2",
8075
"husky": "9.1.7",
81-
"jest": "29.7.0",
8276
"lint-staged": "15.5.2",
8377
"prettier": "3.7.3",
8478
"semantic-release": "23.1.1",
8579
"sort-package-json": "2.10.0",
8680
"swiper": "^12.0.0",
87-
"ts-jest": "29.2.4",
88-
"typescript": "5.5.4"
81+
"typescript": "5.5.4",
82+
"typescript-eslint": "^8.58.1",
83+
"vitest": "^4.1.4"
8984
},
9085
"packageManager": "yarn@4.1.1"
9186
}

src/destinations/microsoft-teams.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const sendAlertsToMicrosoftTeams = async (
3737
webhookUrl: string,
3838
alerts: Alert[],
3939
): Promise<void> => {
40+
if (alerts.length === 0) return
4041
const alertCount = alerts.length
4142
const repositoryOwner = alerts[0].repository.owner
4243
const repositoryName = alerts[0].repository.name

src/destinations/slack.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export const sendAlertsToSlack = async (
6363
webhookUrl: string,
6464
alerts: Alert[],
6565
): Promise<void> => {
66+
if (alerts.length === 0) return
6667
const webhook = new IncomingWebhook(webhookUrl)
6768
const alertBlocks: KnownBlock[] = []
6869
alerts.forEach((alert) => {

src/destinations/zenduty.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const sendAlertsToZenduty = async (
88
escalationPolicyId: string,
99
alerts: Alert[],
1010
): Promise<void> => {
11+
if (alerts.length === 0) return
1112
let summary = `
1213
You have ${alerts.length} vulnerabilities in ${alerts[0].repository.owner}/${alerts[0].repository.name}
1314

src/entities/advisory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const toAdvisory = (securityAdvisory: SecurityAdvisory): Advisory => ({
4545
(securityAdvisory.severity?.toUpperCase() as AdvisorySeverity) || 'LOW',
4646
summary: securityAdvisory.summary,
4747
description: securityAdvisory.description || '',
48-
url: securityAdvisory.references[0].url,
48+
url: securityAdvisory.references?.[0]?.url ?? '',
4949
publishedAt: securityAdvisory.published_at || '',
5050
updatedAt: securityAdvisory.updated_at || '',
5151
withdrawnAt: securityAdvisory.withdrawn_at || '',

src/main.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@ async function run(): Promise<void> {
3333
const emailTransportSmtpHost = getInput('email_transport_smtp_host')
3434
const emailTransportSmtpPort = parseInt(
3535
getInput('email_transport_smtp_port'),
36+
10,
3637
)
3738
const emailTransportSmtpUser = getInput('email_transport_smtp_user')
3839
const emailTransportSmtpPassword = getInput('email_transport_smtp_password')
39-
const count = parseInt(getInput('count'))
40+
const count = parseInt(getInput('count'), 10)
4041
const severity = getInput('severity')
4142
const ecosystem = getInput('ecosystem')
4243

@@ -103,7 +104,7 @@ async function run(): Promise<void> {
103104
pass: emailTransportSmtpPassword,
104105
},
105106
}
106-
sendAlertsToEmailSmtp(
107+
await sendAlertsToEmailSmtp(
107108
emailTransportSmtpConfig,
108109
alerts,
109110
emailList,
@@ -126,4 +127,4 @@ async function run(): Promise<void> {
126127
}
127128
}
128129

129-
run()
130+
void run()

0 commit comments

Comments
 (0)