@docupace/pipeline 1.0.123-xray.3 → 1.0.123

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,278 +0,0 @@
1
- import { describe, expect, test } from '@jest/globals';
2
- import {
3
- rankOf,
4
- extractFindings,
5
- countBySeverity,
6
- buildBuildLink,
7
- buildParentPayload,
8
- buildFindingText,
9
- buildThreadPayload,
10
- parseReportArgs,
11
- sortBySeverity,
12
- } from './report.js';
13
-
14
- describe('rankOf', () => {
15
- test('ranks known severities Critical -> Low', () => {
16
- expect(rankOf('Critical')).toBe(0);
17
- expect(rankOf('High')).toBe(1);
18
- expect(rankOf('Medium')).toBe(2);
19
- expect(rankOf('Low')).toBe(3);
20
- });
21
-
22
- test('unranked/unknown severities sort last', () => {
23
- expect(rankOf('Unknown')).toBe(9);
24
- expect(rankOf(undefined)).toBe(9);
25
- });
26
- });
27
-
28
- describe('extractFindings', () => {
29
- test('flattens SCA rows with CVE ids, package and direct components', () => {
30
- const data = {
31
- vulnerabilities: [
32
- {
33
- severity: 'Critical',
34
- cves: [{ cve: 'CVE-2024-0001' }, { cve: 'CVE-2024-0002' }],
35
- impactedPackageName: 'lodash',
36
- impactedPackageVersion: '4.17.15',
37
- fixedVersions: ['4.17.21'],
38
- components: [{ name: 'my-app' }, { name: 'my-app' }],
39
- },
40
- ],
41
- };
42
-
43
- const [finding] = extractFindings(data, 'my-repo deps');
44
-
45
- expect(finding).toMatchObject({
46
- scan: 'my-repo deps',
47
- kind: 'Vulnerability',
48
- severity: 'Critical',
49
- rank: 0,
50
- cve: 'CVE-2024-0001',
51
- cvesAll: ['CVE-2024-0001', 'CVE-2024-0002'],
52
- pkg: 'lodash 4.17.15',
53
- fixed: '4.17.21',
54
- directs: 'my-app',
55
- path: '',
56
- line: 0,
57
- });
58
- });
59
-
60
- test('falls back to issueId when a vulnerability has no CVEs', () => {
61
- const data = {
62
- securityViolations: [{ severity: 'High', issueId: 'XRAY-123' }],
63
- };
64
- const [finding] = extractFindings(data, 'scan');
65
- expect(finding.cve).toBe('XRAY-123');
66
- expect(finding.cvesAll).toEqual([]);
67
- expect(finding.kind).toBe('Security violation');
68
- });
69
-
70
- test('flattens code rows (secrets/SAST/IaC) with file + line', () => {
71
- const data = {
72
- secrets: [
73
- {
74
- severity: 'Medium',
75
- finding: 'AWS key',
76
- file: 'src/config.js',
77
- startLine: 12,
78
- },
79
- ],
80
- sast: [
81
- {
82
- severity: 'Low',
83
- ruleId: 'js/hardcoded-secret',
84
- scannerShortDescription: 'x',
85
- },
86
- ],
87
- };
88
-
89
- const findings = extractFindings(data, 'scan');
90
-
91
- expect(findings[0]).toMatchObject({
92
- kind: 'Secret',
93
- severity: 'Medium',
94
- pkg: 'AWS key',
95
- path: 'src/config.js',
96
- line: 12,
97
- });
98
- expect(findings[1]).toMatchObject({
99
- kind: 'SAST',
100
- cve: 'js/hardcoded-secret',
101
- pkg: 'x',
102
- });
103
- });
104
-
105
- test('missing sections produce no findings', () => {
106
- expect(extractFindings({}, 'scan')).toEqual([]);
107
- });
108
- });
109
-
110
- describe('countBySeverity', () => {
111
- test('counts only the four named severities and totals them', () => {
112
- const findings = [
113
- { severity: 'Critical' },
114
- { severity: 'High' },
115
- { severity: 'High' },
116
- { severity: 'Unknown' },
117
- ];
118
- expect(countBySeverity(findings)).toEqual({
119
- Critical: 1,
120
- High: 2,
121
- Medium: 0,
122
- Low: 0,
123
- total: 3,
124
- });
125
- });
126
- });
127
-
128
- describe('buildBuildLink', () => {
129
- test('builds a pipeline results URL when all pieces are present', () => {
130
- expect(
131
- buildBuildLink({
132
- workspace: 'dp-cloud',
133
- repoSlug: 'my-repo',
134
- buildNumber: '42',
135
- }),
136
- ).toBe('https://bitbucket.org/dp-cloud/my-repo/pipelines/results/42');
137
- });
138
-
139
- test('returns empty string when any piece is missing', () => {
140
- expect(
141
- buildBuildLink({
142
- workspace: 'dp-cloud',
143
- repoSlug: '',
144
- buildNumber: '42',
145
- }),
146
- ).toBe('');
147
- expect(buildBuildLink({})).toBe('');
148
- });
149
- });
150
-
151
- describe('buildParentPayload', () => {
152
- test('includes branch and pipeline link when present', () => {
153
- const payload = buildParentPayload({
154
- channel: '#security-alerts',
155
- project: 'my-repo',
156
- branch: 'main',
157
- buildLink: 'https://bitbucket.org/x/y/pipelines/results/1',
158
- counts: { Critical: 1, High: 2, Medium: 0, Low: 0, total: 3 },
159
- });
160
-
161
- expect(payload.channel).toBe('#security-alerts');
162
- const projectSection = payload.blocks[1].text.text;
163
- expect(projectSection).toContain('*Project:* my-repo');
164
- expect(projectSection).toContain('*Branch:* main');
165
- expect(payload.blocks[3].elements[0].text).toContain('Pipeline run');
166
- });
167
-
168
- test('omits branch and link when not provided', () => {
169
- const payload = buildParentPayload({
170
- channel: '#c',
171
- project: 'my-repo',
172
- branch: '',
173
- buildLink: '',
174
- counts: { Critical: 0, High: 0, Medium: 0, Low: 0, total: 0 },
175
- });
176
-
177
- expect(payload.blocks[1].text.text).toBe('*Project:* my-repo');
178
- expect(payload.blocks[3].elements[0].text).toBe(
179
- 'Detailed findings are in the thread below 👇',
180
- );
181
- });
182
- });
183
-
184
- describe('buildFindingText / buildThreadPayload', () => {
185
- test('links CVE ids to NVD', () => {
186
- const finding = {
187
- severity: 'Critical',
188
- scan: 'my-repo deps',
189
- kind: 'Vulnerability',
190
- cve: 'CVE-2024-0001',
191
- cvesAll: ['CVE-2024-0001'],
192
- pkg: 'lodash 4.17.15',
193
- fixed: '4.17.21',
194
- directs: 'my-app',
195
- path: '',
196
- line: 0,
197
- };
198
-
199
- const text = buildFindingText(finding);
200
- expect(text).toContain('🔴 *Critical*');
201
- expect(text).toContain(
202
- '<https://nvd.nist.gov/vuln/detail/CVE-2024-0001|CVE-2024-0001>',
203
- );
204
- expect(text).toContain('*Fixed in:* 4.17.21');
205
- expect(text).toContain('*Via:* my-app');
206
- expect(text).not.toContain('*File:*');
207
- });
208
-
209
- test('non-CVE rule ids are left as plain text', () => {
210
- const finding = {
211
- severity: 'Low',
212
- scan: 'scan',
213
- kind: 'SAST',
214
- cve: 'js/hardcoded-secret',
215
- cvesAll: [],
216
- pkg: 'x',
217
- fixed: '',
218
- directs: '',
219
- path: 'src/config.js',
220
- line: 12,
221
- };
222
-
223
- const text = buildFindingText(finding);
224
- expect(text).toContain('👻 *Low*');
225
- expect(text).toContain('*ID:* js/hardcoded-secret');
226
- expect(text).toContain('*File:* `src/config.js:12`');
227
- });
228
-
229
- test('buildThreadPayload wraps the text in a Slack section block', () => {
230
- const finding = {
231
- severity: 'Medium',
232
- scan: 'scan',
233
- kind: 'IaC',
234
- cve: 'N/A',
235
- cvesAll: [],
236
- pkg: 'x',
237
- fixed: '',
238
- directs: '',
239
- path: '',
240
- line: 0,
241
- };
242
- const payload = buildThreadPayload({
243
- channel: '#c',
244
- threadTs: '123.456',
245
- finding,
246
- });
247
- expect(payload).toMatchObject({ channel: '#c', thread_ts: '123.456' });
248
- expect(payload.blocks[0].text.text).toContain('🎃 *Medium*');
249
- });
250
- });
251
-
252
- describe('parseReportArgs', () => {
253
- test('splits "label:file" lines and ignores blanks', () => {
254
- expect(
255
- parseReportArgs(
256
- 'my-repo deps:xray-report/my-repo-audit.json\n\napp image:xray-report/app-docker.json\n',
257
- ),
258
- ).toEqual([
259
- { label: 'my-repo deps', file: 'xray-report/my-repo-audit.json' },
260
- { label: 'app image', file: 'xray-report/app-docker.json' },
261
- ]);
262
- });
263
-
264
- test('returns empty file when a line has no colon', () => {
265
- expect(parseReportArgs('just-a-label')).toEqual([
266
- { label: 'just-a-label', file: '' },
267
- ]);
268
- });
269
- });
270
-
271
- describe('sortBySeverity', () => {
272
- test('orders Critical -> High -> Medium -> Low without mutating input', () => {
273
- const findings = [{ rank: 3 }, { rank: 0 }, { rank: 1 }];
274
- const sorted = sortBySeverity(findings);
275
- expect(sorted.map((f) => f.rank)).toEqual([0, 1, 3]);
276
- expect(findings.map((f) => f.rank)).toEqual([3, 0, 1]);
277
- });
278
- });
package/src/xray/slack.js DELETED
@@ -1,14 +0,0 @@
1
- import axios from 'axios';
2
-
3
- const SLACK_API = 'https://slack.com/api/chat.postMessage';
4
-
5
- // Thin wrapper so callers can mock the network boundary in tests.
6
- export async function postMessage(payload, token) {
7
- const { data } = await axios.post(SLACK_API, payload, {
8
- headers: {
9
- Authorization: `Bearer ${token}`,
10
- 'Content-Type': 'application/json',
11
- },
12
- });
13
- return data;
14
- }