@docupace/pipeline 1.0.119 → 1.0.120

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.
@@ -0,0 +1,5 @@
1
+ ---
2
+ '@docupace/pipeline': patch
3
+ ---
4
+
5
+ Fix to repo name for compliance edge
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @docupace/pipeline
2
2
 
3
+ ## 1.0.120
4
+
5
+ ### Patch Changes
6
+
7
+ - 4729a56: Add JFrog Xray dependency security scan pipeline
8
+
3
9
  ## 1.0.112
4
10
 
5
11
  ### Patch Changes
package/bin/xray.sh ADDED
@@ -0,0 +1,253 @@
1
+ #!/usr/bin/env bash
2
+ BASENAME="${BITBUCKET_REPO_SLUG}"
3
+ SLACK_API="https://slack.com/api/chat.postMessage"
4
+ INPUT_TABLE="xray.txt"
5
+ INPUT_JSON="xray.json"
6
+
7
+ # ------------------------------------------------
8
+ # 1️⃣ Parse table to JSON (handle multi-line wrapping)
9
+ # ------------------------------------------------
10
+
11
+ awk '
12
+ BEGIN {
13
+ print "["
14
+ in_vuln = 0
15
+ }
16
+
17
+ # Skip separator and header lines
18
+ /^[┌├└]/ { next }
19
+ /CVE.*SEVERITY.*DIRECT.*DEPENDENCY/ { next }
20
+
21
+ # Process data rows
22
+ /^│/ {
23
+ gsub(/^│ /, "")
24
+ gsub(/ *│ *$/, "")
25
+
26
+ n = split($0, fields, / *│ */)
27
+
28
+ # New vulnerability (has CVE in first column)
29
+ if (n >= 8 && fields[1] ~ /^CVE-/) {
30
+ # Output previous entry if exists
31
+ if (in_vuln) {
32
+ # Parse fixed versions
33
+ fixed_versions = "[]"
34
+ if (saved_fixed_raw != "") {
35
+ gsub(/\] *\[/, "][", saved_fixed_raw)
36
+ gsub(/\[/, "\"", saved_fixed_raw)
37
+ gsub(/\]/, "\"", saved_fixed_raw)
38
+ gsub(/" *"/, "\", \"", saved_fixed_raw)
39
+ gsub(/""/, "\", \"", saved_fixed_raw)
40
+ fixed_versions = "[" saved_fixed_raw "]"
41
+ }
42
+
43
+ component_key = saved_type "://" saved_affected
44
+ direct_component = saved_type "://" saved_direct
45
+
46
+ print " {"
47
+ print " \"vulnerabilities\": [{"
48
+ print " \"severity\": \"" saved_severity "\","
49
+ print " \"cves\": [{\"cve\": \"" saved_cve "\"}],"
50
+ print " \"components\": {"
51
+ print " \"" component_key "\": {"
52
+ print " \"impact_paths\": [[null, {\"component_id\": \"" direct_component "\"}]],"
53
+ print " \"affected_version\": \"" saved_affected_ver "\","
54
+ print " \"fixed_versions\": " fixed_versions
55
+ print " }"
56
+ print " }"
57
+ print " }]"
58
+ print " },"
59
+ }
60
+
61
+ in_vuln = 1
62
+
63
+ # Store new vulnerability
64
+ saved_cve = fields[1]
65
+ saved_severity = fields[2]
66
+ saved_direct = fields[3]
67
+
68
+ saved_affected = fields[5]
69
+ saved_affected_ver = fields[6]
70
+ saved_fixed_raw = fields[7]
71
+ saved_type = tolower(fields[8])
72
+ }
73
+ # Continuation line - append to previous field
74
+ else if (in_vuln && fields[1] == "" && fields[2] == "") {
75
+ if (fields[3] != "") {
76
+ saved_direct = saved_direct fields[3]
77
+ }
78
+ if (fields[5] != "") {
79
+ saved_affected = saved_affected fields[5]
80
+ }
81
+ if (fields[7] != "") {
82
+ saved_fixed_raw = saved_fixed_raw " " fields[7]
83
+ }
84
+ }
85
+ }
86
+
87
+ END {
88
+ if (in_vuln) {
89
+ # Output the last entry
90
+ fixed_versions = "[]"
91
+ if (saved_fixed_raw != "") {
92
+ gsub(/\] *\[/, "][", saved_fixed_raw)
93
+ gsub(/\[/, "\"", saved_fixed_raw)
94
+ gsub(/\]/, "\"", saved_fixed_raw)
95
+ gsub(/" *"/, "\", \"", saved_fixed_raw)
96
+ gsub(/""/, "\", \"", saved_fixed_raw)
97
+ fixed_versions = "[" saved_fixed_raw "]"
98
+ }
99
+
100
+ component_key = saved_type "://" saved_affected
101
+ direct_component = saved_type "://" saved_direct
102
+
103
+ print " {"
104
+ print " \"vulnerabilities\": [{"
105
+ print " \"severity\": \"" saved_severity "\","
106
+ print " \"cves\": [{\"cve\": \"" saved_cve "\"}],"
107
+ print " \"components\": {"
108
+ print " \"" component_key "\": {"
109
+ print " \"impact_paths\": [[null, {\"component_id\": \"" direct_component "\"}]],"
110
+ print " \"affected_version\": \"" saved_affected_ver "\","
111
+ print " \"fixed_versions\": " fixed_versions
112
+ print " }"
113
+ print " }"
114
+ print " }]"
115
+ print " }"
116
+ }
117
+ print "]"
118
+ }
119
+ ' "$INPUT_TABLE" > "$INPUT_JSON"
120
+
121
+ # Validate JSON
122
+ if ! jq empty "$INPUT_JSON" 2>/dev/null; then
123
+ echo "❌ Failed to create valid JSON"
124
+ cat "$INPUT_JSON"
125
+ exit 1
126
+ fi
127
+
128
+ echo "✅ JSON created: $INPUT_JSON"
129
+
130
+ # ------------------------------------------------
131
+ # 2️⃣ Severity counts
132
+ # ------------------------------------------------
133
+ read CRITICAL HIGH MEDIUM LOW <<< $(
134
+ jq -r '
135
+ .[]
136
+ | select(.vulnerabilities != null)
137
+ | .vulnerabilities[]
138
+ | .severity
139
+ ' "$INPUT_JSON" | awk '
140
+ { c[$1]++ }
141
+ END {
142
+ print c["Critical"]+0, c["High"]+0, c["Medium"]+0, c["Low"]+0
143
+ }'
144
+ )
145
+
146
+ echo "📊 Counts: Critical=$CRITICAL, High=$HIGH, Medium=$MEDIUM, Low=$LOW"
147
+
148
+ TOTAL=$((CRITICAL + HIGH + MEDIUM + LOW))
149
+ if [[ "$TOTAL" -eq 0 ]]; then
150
+ echo "✅ No vulnerabilities found, skipping Slack notification"
151
+ exit 0
152
+ fi
153
+
154
+ # ------------------------------------------------
155
+ # 3️⃣ Parent Slack message
156
+ # ------------------------------------------------
157
+ PARENT_PAYLOAD=$(jq -cn \
158
+ --arg channel "$XRAY_SLACK_CHANNEL" \
159
+ --arg project "$BASENAME" \
160
+ --argjson critical "$CRITICAL" \
161
+ --argjson high "$HIGH" \
162
+ --argjson medium "$MEDIUM" \
163
+ '{
164
+ channel: $channel,
165
+ blocks: [
166
+ { type: "header", text: { type: "plain_text", text: "🚨 Dependency Vulnerability Report" } },
167
+ { type: "section", text: { type: "mrkdwn", text: ("*Project:* " + $project) } },
168
+ { type: "section", text: { type: "mrkdwn", text: ("🔴 *Critical:* \($critical) 🔥 *High:* \($high) 🎃 *Medium:* \($medium)") } },
169
+ { type: "context", elements: [{ type: "mrkdwn", text: "Detailed findings are posted in the thread below 👇" }] },
170
+ { type: "divider" }
171
+ ]
172
+ }')
173
+
174
+ PARENT_RESPONSE=$(printf '%s' "$PARENT_PAYLOAD" | curl -s -X POST "$SLACK_API" \
175
+ -H "Authorization: Bearer $XRAY_SLACK_TOKEN" \
176
+ -H "Content-Type: application/json" \
177
+ --data @-)
178
+
179
+ THREAD_TS=$(echo "$PARENT_RESPONSE" | jq -r '.ts')
180
+
181
+ if [[ -z "$THREAD_TS" || "$THREAD_TS" == "null" ]]; then
182
+ echo "❌ Failed to create parent message"
183
+ echo "$PARENT_RESPONSE"
184
+ exit 1
185
+ fi
186
+
187
+ echo "✅ Parent message created. thread_ts=$THREAD_TS"
188
+
189
+ # ------------------------------------------------
190
+ # 4️⃣ Thread entries (sorted, CVE links)
191
+ # ------------------------------------------------
192
+ jq -r '
193
+ def rank:
194
+ if . == "Critical" then 0
195
+ elif . == "High" then 1
196
+ elif . == "Medium" then 2
197
+ elif . == "Low" then 3
198
+ else 9 end;
199
+
200
+ [
201
+ .[]
202
+ | select(.vulnerabilities != null)
203
+ | .vulnerabilities[]
204
+ | . as $v
205
+ | ($v.components | to_entries[]) as $comp
206
+ | ($v.cves // [{cve:"N/A"}])[]
207
+ | {
208
+ sev: $v.severity,
209
+ r: ($v.severity | rank),
210
+ text: "*<https://nvd.nist.gov/vuln/detail/\(.cve)|\(.cve)>*\n*Impacted:* `\(
211
+ $comp.key | sub("^[a-z]+://"; "")
212
+ )` v\(
213
+ $comp.value.affected_version // "N/A"
214
+ )\n*Fixed in:* \(
215
+ ($comp.value.fixed_versions // [])
216
+ | join(", ")
217
+ | if . == "" then "N/A" else . end
218
+ )\n*Direct dependencies:*\n• \(
219
+ $comp.value.impact_paths[0][1].component_id
220
+ | sub("^[a-z]+://"; "")
221
+ )"
222
+ }
223
+ ]
224
+ | sort_by(.r)
225
+ | .[]
226
+ | [.sev, .text]
227
+ | @tsv
228
+ ' "$INPUT_JSON" |
229
+ while IFS=$'\t' read -r SEV TEXT; do
230
+
231
+ EMOJI="👻"
232
+ [[ "$SEV" == "Critical" ]] && EMOJI="🔴"
233
+ [[ "$SEV" == "High" ]] && EMOJI="🔥"
234
+ [[ "$SEV" == "Medium" ]] && EMOJI="🎃"
235
+
236
+ jq -cn \
237
+ --arg channel "$XRAY_SLACK_CHANNEL" \
238
+ --arg ts "$THREAD_TS" \
239
+ --arg body "$EMOJI *$SEV*\n$TEXT" \
240
+ '{
241
+ channel: $channel,
242
+ thread_ts: $ts,
243
+ blocks: [{ type: "section", text: { type: "mrkdwn", text: $body } }]
244
+ }' | curl -s -X POST "$SLACK_API" \
245
+ -H "Authorization: Bearer $XRAY_SLACK_TOKEN" \
246
+ -H "Content-Type: application/json" \
247
+ --data @- > /dev/null
248
+
249
+ sleep 0.1
250
+
251
+ done
252
+
253
+ echo "✅ All vulnerabilities posted to thread"
@@ -1,4 +1,6 @@
1
1
  # bitbucket-pipelines.yml
2
+ export: true
3
+
2
4
  clone:
3
5
  depth: 2
4
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docupace/pipeline",
3
- "version": "1.0.119",
3
+ "version": "1.0.120",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -0,0 +1,29 @@
1
+ definitions:
2
+ steps:
3
+ - step: &xray
4
+ name: JFrog Xray Dependency Scan (TABLE report only)
5
+ runs-on:
6
+ - self.hosted
7
+ - linux.shell
8
+ - onprem
9
+ script:
10
+ - curl -fL https://install-cli.jfrog.io | sh
11
+ - jf --version
12
+ - jf config add scan1 --url=$JFROG_XRAY_URL --user=$JFROG_XRAY_USER --access-token=$JFROG_XRAY_PASSWORD
13
+ - jf c show
14
+ - mkdir -p xray-report
15
+ - jf audit . --format=table > xray-report/xray-audit.txt
16
+ - jf config remove scan1
17
+ artifacts:
18
+ - xray-report/xray-audit.txt
19
+ - step: &version-step
20
+ runs-on:
21
+ - self.hosted
22
+ - linux.shell
23
+ - onprem
24
+ name: Version, Tag
25
+ caches:
26
+ - gradle
27
+ script:
28
+ - npm config set //registry.npmjs.org/:_authToken $DOCUPACE_NPM_TOKEN
29
+ - eval $PIPELINE_CMD_VERSION_CHANGESET
@@ -53,7 +53,7 @@ export const appInfo = {
53
53
  deployAttributes: ['image.tag'],
54
54
  },
55
55
  'compliance-edge-graphql-server': {
56
- repositoryName: 'compliance-edge-graphql-server',
56
+ repositoryName: 'docupace-graphql-server',
57
57
  imageName: 'compliance-edge-graphql-server',
58
58
  deployAttributes: [
59
59
  'image.tag',