@docupace/pipeline 1.0.8-6.xray → 1.0.9

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.
Files changed (64) hide show
  1. package/eslint.config.js +2 -25
  2. package/next/execute.sh +2 -8
  3. package/package.json +7 -23
  4. package/src/changeset/cli.js +195 -151
  5. package/src/changeset/validate.js +1 -45
  6. package/src/jenkins/setParams.groovy +2 -1
  7. package/src/next/cli.js +15 -111
  8. package/src/next/config.js +7 -72
  9. package/src/next/copy.js +1 -32
  10. package/src/next/deploy.js +75 -514
  11. package/src/next/jenkins.js +2 -3
  12. package/src/next/pipline.js +1 -0
  13. package/src/next/publish.js +30 -53
  14. package/README.md +0 -136
  15. package/bin/azuread_update_callbacks_for_app.sh +0 -58
  16. package/bin/xray.sh +0 -273
  17. package/bitbucket-pipelines.yml +0 -142
  18. package/jest.config.js +0 -15
  19. package/src/auth0/alias.js +0 -79
  20. package/src/auth0/alias.test.js +0 -172
  21. package/src/auth0/cli.js +0 -82
  22. package/src/auth0/configure.js +0 -902
  23. package/src/auth0/configure.test.js +0 -167
  24. package/src/auth0/export.js +0 -48
  25. package/src/auth0/export.test.js +0 -103
  26. package/src/auth0/metadata.js +0 -141
  27. package/src/auth0/metadata.test.js +0 -186
  28. package/src/auth0/vault.js +0 -60
  29. package/src/auth0/vault.test.js +0 -134
  30. package/src/changeset/changelog-wiki.js +0 -328
  31. package/src/changeset/changeset-config.js +0 -34
  32. package/src/changeset/create.js +0 -215
  33. package/src/changeset/package-util.js +0 -87
  34. package/src/changeset/util.js +0 -43
  35. package/src/changeset/version.js +0 -102
  36. package/src/jfrog/xray-scan.yaml +0 -29
  37. package/src/lib/merge-driver.js +0 -204
  38. package/src/merge/cli-merge-all.js +0 -521
  39. package/src/merge/cli-merge.js +0 -572
  40. package/src/merge/cli-resolve.js +0 -399
  41. package/src/merge/cli.js +0 -38
  42. package/src/merge/common.js +0 -7
  43. package/src/merge/merge-changelog.js +0 -87
  44. package/src/merge/merge-package.js +0 -106
  45. package/src/merge/merge-types.js +0 -82
  46. package/src/merge/pr.js +0 -231
  47. package/src/micro/cli.js +0 -51
  48. package/src/micro/ms-deploy.js +0 -451
  49. package/src/micro/ms-publish.js +0 -186
  50. package/src/next/alias.js +0 -53
  51. package/src/next/apache.js +0 -81
  52. package/src/next/connect.js +0 -226
  53. package/src/next/git-to-semver.js +0 -79
  54. package/src/next/haproxy.js +0 -76
  55. package/src/next/jira.js +0 -84
  56. package/src/next/logger.js +0 -17
  57. package/src/next/test.js +0 -5
  58. package/src/next/util.js +0 -95
  59. package/src/next/vault.js +0 -45
  60. package/terraform/apply.sh +0 -41
  61. package/terraform/import.sh +0 -111
  62. package/terraform/init.sh +0 -78
  63. package/terraform/plan.sh +0 -95
  64. package/terraform/validate.sh +0 -17
@@ -1,7 +1,7 @@
1
1
  import axios from 'axios';
2
2
 
3
- const CORE_JENKINS_URL = process.env.CORE_JENKINS_URL;
4
- const CORE_JOB_NAME = process.env.CORE_JENKINS_JOB_NAME;
3
+ const CORE_JENKINS_URL = 'http://devops.corp.docupace.com';
4
+ const CORE_JOB_NAME = 'auto-deploy-site';
5
5
  const CORE_USERNAME = process.env.CORE_JENKINS_USERNAME;
6
6
  const CORE_API_TOKEN = process.env.CORE_JENKINS_API_TOKEN;
7
7
 
@@ -26,7 +26,6 @@ export async function deployCore(env, site, liquibase, gitBranch) {
26
26
  });
27
27
  }
28
28
 
29
- // eslint-disable-next-line no-unused-vars
30
29
  export async function deployConnect(env, site, liquibase, branch) {
31
30
  const parameters = {
32
31
  BUILD_ENVIRONMENT: env,
@@ -99,6 +99,7 @@ export async function runPipeline(
99
99
  return;
100
100
  }
101
101
 
102
+
102
103
  let status = '';
103
104
  do {
104
105
  console.log('Checking pipeline status...');
@@ -1,71 +1,48 @@
1
- import { $ } from './logger.js';
1
+ import { $ } from 'zx';
2
2
 
3
- const {
4
- JF_REGISTRY_URL,
5
- JF_REGISTRY_REPO_NAME,
6
- JF_REGISTRY_PASSWORD_DEV,
7
- JF_REGISTRY_USER_DEV,
8
- BITBUCKET_REPO_SLUG,
9
- BITBUCKET_BUILD_NUMBER,
10
- APP_NAME,
11
- } = process.env;
3
+ export async function publish(GIT_SHA) {
4
+ const BITBUCKET_REPO_SLUG = process.env.BITBUCKET_REPO_SLUG;
5
+ const BUILD_IMAGE_NAME = `${BITBUCKET_REPO_SLUG}:build-${process.env.BITBUCKET_BUILD_NUMBER}`;
6
+ const IMAGE_NAME = `${BITBUCKET_REPO_SLUG}:sha-${GIT_SHA}`;
7
+ const JF_REGISTRY_FULL_URL = `${process.env.JF_REGISTRY_URL}/${process.env.JF_REGISTRY_REPO_NAME}`;
12
8
 
13
- const JF_REGISTRY_FULL_URL = `${JF_REGISTRY_URL}/${JF_REGISTRY_REPO_NAME}`;
9
+ console.log(`Publishing Docker image: ${IMAGE_NAME}`);
14
10
 
15
- async function loginRegistry() {
16
- await $`echo ${JF_REGISTRY_PASSWORD_DEV} | docker login --username ${JF_REGISTRY_USER_DEV} --password-stdin ${JF_REGISTRY_URL}`;
17
- }
18
-
19
- async function logoutRegistry() {
20
- await $`docker logout ${JF_REGISTRY_URL}`;
21
- }
22
-
23
- export async function publish(gitSha) {
24
- process.env.DOCKER_HOST = '';
25
-
26
- console.log(JSON.stringify(process.env));
27
-
28
- const IMAGE_PREFIX = APP_NAME ?? BITBUCKET_REPO_SLUG;
29
- const BUILD_IMAGE_NAME = `${IMAGE_PREFIX}:build-${BITBUCKET_BUILD_NUMBER}`;
30
- const IMAGE_NAME = `${IMAGE_PREFIX}:sha-${gitSha}`;
31
-
32
- console.log(`Publishing Docker image ${IMAGE_NAME}...`);
11
+ // Docker login
12
+ await $`echo ${process.env.JF_REGISTRY_PASSWORD_DEV} | docker login --username ${process.env.JF_REGISTRY_USER_DEV} --password-stdin ${process.env.JF_REGISTRY_URL}`;
33
13
 
34
- await loginRegistry();
35
-
36
- let manifestExists = false;
14
+ // Check if the image already exists
37
15
  try {
38
- $.verbose = false; // Silence output temporarily
39
16
  await $`docker manifest inspect ${JF_REGISTRY_FULL_URL}/${IMAGE_NAME}`;
40
- manifestExists = true;
41
- } catch {
42
- manifestExists = false;
43
- } finally {
44
- $.verbose = true; // Restore normal output
45
- }
46
-
47
- if (manifestExists) {
48
17
  console.log(
49
- `Tag sha-${gitSha} already exists in the remote repository. Skipping push.`,
18
+ `Tag sha-${GIT_SHA} already exists in the remote repository. Skipping push.`,
50
19
  );
51
- } else {
20
+ } catch {
52
21
  await $`docker tag ${IMAGE_NAME} ${JF_REGISTRY_FULL_URL}/${IMAGE_NAME}`;
53
22
  await $`docker push ${JF_REGISTRY_FULL_URL}/${IMAGE_NAME}`;
54
23
  }
55
24
 
25
+ // Tag and push build image
56
26
  await $`docker tag ${IMAGE_NAME} ${JF_REGISTRY_FULL_URL}/${BUILD_IMAGE_NAME}`;
57
27
  await $`docker push ${JF_REGISTRY_FULL_URL}/${BUILD_IMAGE_NAME}`;
58
28
 
59
- const gitTags = (await $`git tag --points-at HEAD`).stdout
60
- .trim()
61
- .split('\n')
62
- .filter(Boolean);
63
- for (const gitTag of gitTags) {
64
- const version = gitTag.includes('@') ? 'v' + gitTag.split('@')[1] : gitTag;
65
- const tagName = `${IMAGE_PREFIX}:${version}`;
66
- await $`docker tag ${IMAGE_NAME} ${JF_REGISTRY_FULL_URL}/${tagName}`;
67
- await $`docker push ${JF_REGISTRY_FULL_URL}/${tagName}`;
29
+ // Fetch Git tags pointing to the current HEAD
30
+ const gitTagsOutput = (await $`git tag --points-at HEAD`).stdout.trim();
31
+ const gitTags = gitTagsOutput.split('\n').filter((tag) => tag);
32
+
33
+ // Tag and push each Git tag as a Docker tag
34
+ if (gitTags.length > 0) {
35
+ console.log(`Found Git tags pointing to HEAD: ${gitTags.join(', ')}`);
36
+ for (const gitTag of gitTags) {
37
+ const dockerTag = `${JF_REGISTRY_FULL_URL}/${BITBUCKET_REPO_SLUG}:${gitTag}`;
38
+ console.log(`Tagging and pushing Docker image for Git tag: ${gitTag}`);
39
+ await $`docker tag ${IMAGE_NAME} ${dockerTag}`;
40
+ await $`docker push ${dockerTag}`;
41
+ }
42
+ } else {
43
+ console.log('No Git tags found pointing to the current HEAD.');
68
44
  }
69
45
 
70
- await logoutRegistry();
46
+ // Docker logout
47
+ await $`docker logout ${process.env.JF_REGISTRY_URL}`;
71
48
  }
package/README.md DELETED
@@ -1,136 +0,0 @@
1
- # Pipeline Shared Scripts
2
-
3
- A collection of CLI tools for Docupace's CI/CD pipelines and deployment workflows.
4
-
5
- ## Overview
6
-
7
- This package provides a set of command-line interfaces (CLIs) to facilitate various DevOps operations in the Docupace ecosystem:
8
-
9
- - `dp-next-cli`: Deployment and pipeline management for Next applications
10
- - `dp-changeset-cli`: Versioning and changeset management
11
- - `dp-auth0-cli`: Auth0 tenant configuration and management
12
-
13
- ## Installation
14
-
15
- ```bash
16
- npm install @docupace/pipeline
17
- ```
18
-
19
- Or with pnpm:
20
-
21
- ```bash
22
- pnpm add @docupace/pipeline
23
- ```
24
-
25
- ## Command Line Interfaces
26
-
27
- ### dp-next-cli
28
-
29
- Manages deployment, Docker image handling, and infrastructure configuration.
30
-
31
- ```bash
32
- dp-next-cli [command] [options]
33
- ```
34
-
35
- **Commands:**
36
-
37
- - `pull <imageName>`: Pull a Docker image from the registry
38
- - `sonar`: Run Sonar analysis
39
- - `addApacheSite`: Add site to apache
40
- - `connectClone`: Clone connect site
41
- - `haproxySync`: Sync haproxy config
42
- - `vaultAddSiteData`: Add m2m auth0 data to vault
43
- - `-s, --site-name <siteName>`: Site name
44
- - `-p, --site-config-remote-path <path>`: Site config remote path
45
- - `publish`: Publish a Docker image
46
- - `deploy-from-site`: Deploy an application for a specific site
47
- - `-f, --from-env <fromEnv>`: Source environment
48
- - `-t, --to-env <toEnv>`: Target environment
49
- - `-F, --from-site <fromSite>`: Source site
50
- - `-T, --to-site <toSite>`: Target site
51
- - `-c, --deploy-core <deployCore>`: Deploy Core (default: "false")
52
- - `-C, --deploy-connect <deployConnect>`: Deploy Connect (default: "false")
53
- - `deploy-template`: Deploy an application for a specific site
54
- - `deploy-app <application>`: Deploy an application for a specific site
55
- - `deploy-core <env> <site>`: Deploy Core
56
- - `-l, --liquibase <liquibase>`: Application name (default: "true")
57
- - `-b, --branch <branch>`: Branch (default: "master")
58
- - `deploy-connect <env> <site>`: Deploy Connect
59
- - `-l, --liquibase <liquibase>`: Application name (default: "true")
60
- - `-b, --branch <branch>`: Branch (default: "master")
61
- - `deploy-core-pipeline <env> <site>`: Deploy Core via pipeline
62
- - `-l, --liquibase <liquibase>`: Application name (default: "true")
63
- - `-b, --branch <branch>`: Branch (default: "master")
64
- - `copy`: Copy a Docker image between registries
65
- - `-a, --application <application>`: Application name
66
- - `-f, --from-env <fromEnv>`: Source environment
67
- - `-t, --to-env <toEnv>`: Target environment
68
- - `-g, --tag <tag>`: Image tag
69
- - `run-pipeline`: Trigger a pipeline by name
70
- - `-r, --repository <repository>`: Repository name
71
- - `-p, --pipeline-name <pipelineName>`: Pipeline name
72
- - `-b, --branch <branch>`: Branch name
73
- - `-v, --variables <key=value>`: Pipeline variable as key=value pair
74
- - `-w, --wait`: Wait for the pipeline to complete (default: false)
75
-
76
- ### dp-changeset-cli
77
-
78
- Manages versioning and changesets for mono-repos and single-package repos.
79
-
80
- ```bash
81
- dp-changeset-cli [command] [options]
82
- ```
83
-
84
- **Commands:**
85
-
86
- - `validate`: Validate changesets for the provided PR
87
- - `version`: Run Changeset versioning
88
- - `commit-tag`: Commit and tag the new version
89
- - `version-commit-tag`: Run versioning and commit-and-tag in sequence
90
- - `close-version`: Close a version and create a release branch
91
- - `create-changeset`: Create a changeset based on the current branch and Jira ticket information
92
-
93
- ### dp-auth0-cli
94
-
95
- Manages Auth0 tenant configuration across environments.
96
-
97
- ```bash
98
- dp-auth0-cli [command] [options]
99
- ```
100
-
101
- **Commands:**
102
-
103
- - `configureFromSite <fromSite> <toSite> <fromEnv> <toEnv> <deployUI> <deployGraphQLServer> <useNewDomain> <useS3>`: Configure Auth0 tenants
104
- - `getVaultSecrets <vaultPath>`: Get secrets from Vault
105
- - `configureAlias <site> <env> <username> <password> <realm>`: Configure Core Alias for the given site
106
- - `exportConf <site> <env>`: Export Auth0 configuration for the given site
107
- - `getAuth0Metadata <site> <env>`: Get Auth0 metadata for the given site
108
-
109
- ## Environment Configuration
110
-
111
- The CLI tools look for environment configuration in the following locations:
112
- - `.env.pipeline.local`
113
- - `config/.env.pipeline.local`
114
-
115
- ## Examples
116
-
117
- ```bash
118
- # Deploy from one site to another
119
- dp-next-cli deploy-from-site --from-env dev --to-env dev --from-site financialdev --to-site template --deploy-core true
120
-
121
- # Run a pipeline
122
- dp-next-cli run-pipeline -r docupace-next-e2e -b master -p run-tests-qa
123
-
124
- # Validate changesets
125
- dp-changeset-cli validate
126
-
127
- # Create a new changeset
128
- dp-changeset-cli create-changeset
129
-
130
- # Configure Auth0 for a site
131
- dp-auth0-cli configureFromSite sourceSite targetSite dev prod true true true false
132
- ```
133
-
134
- ## License
135
-
136
- ISC
@@ -1,58 +0,0 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- ENV=$1
5
-
6
- if [ -z "$ENV" ]; then
7
- echo "Usage: $0 <environment>"
8
- exit 1
9
- fi
10
-
11
- TENANT_ID="docupace.onmicrosoft.com"
12
- CLIENT_ID=$ARM_CLIENT_ID
13
- CLIENT_SECRET=$ARM_CLIENT_SECRET
14
- NEW_REDIRECT="https://docupace-$ENV-$SITE_NAME.us.auth0.com/login/callback"
15
- APP_ID="auth0-$ENV-docupace"
16
- APP_SCOPE="https://graph.microsoft.com/.default"
17
- GRAPH_API="https://graph.microsoft.com/v1.0"
18
-
19
- ACCESS_TOKEN=$(curl -s -X POST \
20
- -H "Content-Type: application/x-www-form-urlencoded" \
21
- -d "grant_type=client_credentials&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&scope=$APP_SCOPE" \
22
- https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/token | jq -r '.access_token')
23
-
24
- APP_DETAILS=$(curl -s -G "https://graph.microsoft.com/v1.0/applications" \
25
- -H "Authorization: Bearer $ACCESS_TOKEN" \
26
- -H "Content-Type: application/json" \
27
- --data-urlencode "\$filter=appId eq '$CLIENT_ID'")
28
-
29
- APP_ID=$(echo "$APP_DETAILS" | jq -r '.value[0].id')
30
- echo "Application ID: $APP_ID"
31
-
32
- CURRENT_REDIRECTS=$(echo "$APP_DETAILS" | jq -r '.value[0].web.redirectUris // []')
33
- echo "Current redirect URIs: $CURRENT_REDIRECTS"
34
-
35
- if echo "$CURRENT_REDIRECTS" | jq -e --arg uri "$NEW_REDIRECT" 'index($uri)' > /dev/null; then
36
- echo "Redirect URI '$NEW_REDIRECT' already exists. No update needed."
37
- else
38
- UPDATED_REDIRECTS=$(echo "$CURRENT_REDIRECTS" | jq --arg uri "$NEW_REDIRECT" '. + [$uri]')
39
- echo "Updated redirect URIs: $UPDATED_REDIRECTS"
40
-
41
- UPDATE_REDIRECTS=$(curl -fs -X PATCH \
42
- -H "Authorization: Bearer $ACCESS_TOKEN" \
43
- -H "Content-Type: application/json" \
44
- -d "{
45
- \"web\": {
46
- \"redirectUris\": $UPDATED_REDIRECTS
47
- }
48
- }" \
49
- "https://graph.microsoft.com/v1.0/applications/$APP_ID")
50
-
51
- if [ $? -eq 0 ]; then
52
- echo "Successfully updated redirect URIs"
53
- echo $UPDATE_REDIRECTS
54
- else
55
- echo "Failed to update redirect URIs"
56
- echo $UPDATE_REDIRECTS
57
- fi
58
- fi
package/bin/xray.sh DELETED
@@ -1,273 +0,0 @@
1
- #!/usr/bin/env bash
2
- GIT_PATH=$(git rev-parse --show-toplevel)
3
- BASENAME=$(basename $GIT_PATH)
4
- BASENAME="${BITBUCKET_REPO_SLUG}"
5
- SLACK_API="https://slack.com/api/chat.postMessage"
6
- INPUT_TABLE="xray.txt"
7
- INPUT_JSON="xray.json"
8
-
9
- # ------------------------------------------------
10
- # 1️⃣ Parse table to JSON (handle multi-line wrapping)
11
- # ------------------------------------------------
12
-
13
- awk '
14
- BEGIN {
15
- print "["
16
- first = 1
17
- in_vuln = 0
18
- }
19
-
20
- # Skip separator and header lines
21
- /^[┌├└]/ { next }
22
- /CVE.*SEVERITY.*DIRECT.*DEPENDENCY/ { next }
23
-
24
- # Process data rows
25
- /^│/ {
26
- gsub(/^│ /, "")
27
- gsub(/ *│ *$/, "")
28
-
29
- n = split($0, fields, / *│ */)
30
-
31
- # New vulnerability (has CVE in first column)
32
- if (n >= 8 && fields[1] ~ /^CVE-/) {
33
- # Output previous entry if exists
34
- if (in_vuln) {
35
- # Parse fixed versions
36
- fixed_versions = "[]"
37
- if (saved_fixed_raw != "") {
38
- gsub(/\] *\[/, "][", saved_fixed_raw)
39
- gsub(/\[/, "\"", saved_fixed_raw)
40
- gsub(/\]/, "\"", saved_fixed_raw)
41
- gsub(/" *"/, "\", \"", saved_fixed_raw)
42
- gsub(/""/, "\", \"", saved_fixed_raw)
43
- fixed_versions = "[" saved_fixed_raw "]"
44
- }
45
-
46
- component_key = saved_type "://" saved_affected
47
- direct_component = saved_type "://" saved_direct
48
-
49
- print " {"
50
- print " \"vulnerabilities\": [{"
51
- print " \"severity\": \"" saved_severity "\","
52
- print " \"cves\": [{\"cve\": \"" saved_cve "\"}],"
53
- print " \"components\": {"
54
- print " \"" component_key "\": {"
55
- print " \"impact_paths\": [[null, {\"component_id\": \"" direct_component "\"}]],"
56
- print " \"affected_version\": \"" saved_affected_ver "\","
57
- print " \"fixed_versions\": " fixed_versions
58
- print " }"
59
- print " }"
60
- print " }]"
61
- print " },"
62
- }
63
-
64
- first = 0
65
- in_vuln = 1
66
-
67
- # Store new vulnerability
68
- saved_cve = fields[1]
69
- saved_severity = fields[2]
70
- saved_direct = fields[3]
71
- saved_direct_ver = fields[4]
72
- saved_affected = fields[5]
73
- saved_affected_ver = fields[6]
74
- saved_fixed_raw = fields[7]
75
- saved_type = tolower(fields[8])
76
- }
77
- # Continuation line - append to previous field
78
- else if (in_vuln && fields[1] == "" && fields[2] == "") {
79
- if (fields[3] != "") {
80
- saved_direct = saved_direct fields[3]
81
- }
82
- if (fields[5] != "") {
83
- saved_affected = saved_affected fields[5]
84
- }
85
- if (fields[7] != "") {
86
- saved_fixed_raw = saved_fixed_raw " " fields[7]
87
- }
88
- }
89
- }
90
-
91
- END {
92
- if (in_vuln) {
93
- # Output the last entry
94
- fixed_versions = "[]"
95
- if (saved_fixed_raw != "") {
96
- gsub(/\] *\[/, "][", saved_fixed_raw)
97
- gsub(/\[/, "\"", saved_fixed_raw)
98
- gsub(/\]/, "\"", saved_fixed_raw)
99
- gsub(/" *"/, "\", \"", saved_fixed_raw)
100
- gsub(/""/, "\", \"", saved_fixed_raw)
101
- fixed_versions = "[" saved_fixed_raw "]"
102
- }
103
-
104
- component_key = saved_type "://" saved_affected
105
- direct_component = saved_type "://" saved_direct
106
-
107
- print " {"
108
- print " \"vulnerabilities\": [{"
109
- print " \"severity\": \"" saved_severity "\","
110
- print " \"cves\": [{\"cve\": \"" saved_cve "\"}],"
111
- print " \"components\": {"
112
- print " \"" component_key "\": {"
113
- print " \"impact_paths\": [[null, {\"component_id\": \"" direct_component "\"}]],"
114
- print " \"affected_version\": \"" saved_affected_ver "\","
115
- print " \"fixed_versions\": " fixed_versions
116
- print " }"
117
- print " }"
118
- print " }]"
119
- print " }"
120
- }
121
- print "]"
122
- }
123
- ' "$INPUT_TABLE" > "$INPUT_JSON"
124
-
125
- # Validate JSON
126
- if ! jq empty "$INPUT_JSON" 2>/dev/null; then
127
- echo "❌ Failed to create valid JSON"
128
- cat "$INPUT_JSON"
129
- exit 1
130
- fi
131
-
132
- echo "✅ JSON created: $INPUT_JSON"
133
-
134
- # ------------------------------------------------
135
- # 2️⃣ Severity counts
136
- # ------------------------------------------------
137
- read CRITICAL HIGH MEDIUM LOW <<< $(
138
- jq -r '
139
- .[]
140
- | select(.vulnerabilities != null)
141
- | .vulnerabilities[]
142
- | .severity
143
- ' "$INPUT_JSON" | awk '
144
- { c[$1]++ }
145
- END {
146
- print c["Critical"]+0, c["High"]+0, c["Medium"]+0, c["Low"]+0
147
- }'
148
- )
149
-
150
- echo "📊 Counts: Critical=$CRITICAL, High=$HIGH, Medium=$MEDIUM, Low=$LOW"
151
-
152
- # ------------------------------------------------
153
- # 3️⃣ Parent Slack message
154
- # ------------------------------------------------
155
- read -r -d '' PARENT_PAYLOAD <<JSON
156
- {
157
- "channel": "$XRAY_SLACK_CHANNEL",
158
- "blocks": [
159
- {
160
- "type": "header",
161
- "text": { "type": "plain_text", "text": "🚨 Dependency Vulnerability Report" }
162
- },
163
- {
164
- "type": "section",
165
- "text": { "type": "mrkdwn", "text": "*Project:* $BASENAME" }
166
- },
167
- {
168
- "type": "section",
169
- "text": {
170
- "type": "mrkdwn",
171
- "text": "🔴 *Critical:* $CRITICAL 🔥 *High:* $HIGH 🎃 *Medium:* $MEDIUM "
172
- }
173
- },
174
- {
175
- "type": "context",
176
- "elements": [
177
- { "type": "mrkdwn", "text": "Detailed findings are posted in the thread below 👇" }
178
- ]
179
- },
180
- { "type": "divider" }
181
- ]
182
- }
183
- JSON
184
-
185
- PARENT_RESPONSE=$(curl -s -X POST "$SLACK_API" \
186
- -H "Authorization: Bearer $XRAY_SLACK_TOKEN" \
187
- -H "Content-Type: application/json" \
188
- --data "$PARENT_PAYLOAD")
189
-
190
- THREAD_TS=$(echo "$PARENT_RESPONSE" | jq -r '.ts')
191
-
192
- if [[ -z "$THREAD_TS" || "$THREAD_TS" == "null" ]]; then
193
- echo "❌ Failed to create parent message"
194
- echo "$PARENT_RESPONSE"
195
- exit 1
196
- fi
197
-
198
- echo "✅ Parent message created. thread_ts=$THREAD_TS"
199
-
200
- # ------------------------------------------------
201
- # 4️⃣ Thread entries (sorted, CVE links)
202
- # ------------------------------------------------
203
- jq -r '
204
- def rank:
205
- if . == "Critical" then 0
206
- elif . == "High" then 1
207
- elif . == "Medium" then 2
208
- elif . == "Low" then 3
209
- else 9 end;
210
-
211
- [
212
- .[]
213
- | select(.vulnerabilities != null)
214
- | .vulnerabilities[]
215
- | . as $v
216
- | ($v.components | to_entries[]) as $comp
217
- | ($v.cves // [{cve:"N/A"}])[]
218
- | {
219
- sev: $v.severity,
220
- r: ($v.severity | rank),
221
- text: "*<https://nvd.nist.gov/vuln/detail/\(.cve)|\(.cve)>*\n*Impacted:* `\(
222
- $comp.key | sub("^[a-z]+://"; "")
223
- )` v\(
224
- $comp.value.affected_version // "N/A"
225
- )\n*Fixed in:* \(
226
- ($comp.value.fixed_versions // [])
227
- | join(", ")
228
- | if . == "" then "N/A" else . end
229
- )\n*Direct dependencies:*\n• \(
230
- $comp.value.impact_paths[0][1].component_id
231
- | sub("^[a-z]+://"; "")
232
- )"
233
- }
234
- ]
235
- | sort_by(.r)
236
- | .[]
237
- | [.sev, .text]
238
- | @tsv
239
- ' "$INPUT_JSON" |
240
- while IFS=$'\t' read -r SEV TEXT; do
241
-
242
- EMOJI="👻"
243
- [[ "$SEV" == "Critical" ]] && EMOJI="🔴"
244
- [[ "$SEV" == "High" ]] && EMOJI="🔥"
245
- [[ "$SEV" == "Medium" ]] && EMOJI="🎃"
246
-
247
- read -r -d '' THREAD_PAYLOAD <<JSON
248
- {
249
- "channel": "$XRAY_SLACK_CHANNEL",
250
- "thread_ts": "$THREAD_TS",
251
- "blocks": [
252
- {
253
- "type": "section",
254
- "text": {
255
- "type": "mrkdwn",
256
- "text": "$EMOJI *$SEV*\n$TEXT"
257
- }
258
- }
259
- ]
260
- }
261
- JSON
262
-
263
- curl -s -X POST "$SLACK_API" \
264
- -H "Authorization: Bearer $XRAY_SLACK_TOKEN" \
265
- -H "Content-Type: application/json" \
266
- --data "$THREAD_PAYLOAD" > /dev/null
267
-
268
- # Small delay to avoid rate limiting
269
- sleep 0.1
270
-
271
- done
272
-
273
- echo "✅ All vulnerabilities posted to thread"