@codyswann/lisa 1.46.4 → 1.47.0
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.
- package/all/copy-overwrite/.claude/rules/lisa.md +2 -1
- package/package.json +1 -1
- package/typescript/copy-contents/.husky/pre-push +113 -102
- package/typescript/copy-overwrite/.github/workflows/auto-update-pr-branches.yml +15 -1
- package/typescript/copy-overwrite/.github/workflows/claude-ci-auto-fix.yml +33 -1
- package/typescript/copy-overwrite/.github/workflows/claude-code-review-response.yml +1 -1
- package/typescript/copy-overwrite/.github/workflows/claude-deploy-auto-fix.yml +142 -0
- package/typescript/copy-overwrite/.github/workflows/claude-nightly-code-complexity.yml +1 -1
- package/typescript/copy-overwrite/.github/workflows/claude-nightly-test-coverage.yml +1 -1
- package/typescript/copy-overwrite/.github/workflows/claude-nightly-test-improvement.yml +2 -2
- package/typescript/copy-overwrite/.github/workflows/claude.yml +1 -1
- package/typescript/copy-overwrite/.github/workflows/create-github-issue-on-failure.yml +115 -0
- package/typescript/copy-overwrite/.github/workflows/create-issue-on-failure.yml +176 -0
- package/typescript/copy-overwrite/.github/workflows/create-jira-issue-on-failure.yml +197 -0
- package/typescript/copy-overwrite/.github/workflows/create-sentry-issue-on-failure.yml +269 -0
- package/typescript/copy-overwrite/.github/workflows/quality.yml +85 -97
- package/typescript/copy-overwrite/audit.ignore.config.json +87 -0
- package/typescript/copy-overwrite/eslint.ignore.config.json +4 -1
- package/typescript/create-only/audit.ignore.local.json +3 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# This file is managed by Lisa.
|
|
2
|
+
# Do not edit directly — changes will be overwritten on the next `lisa` run.
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Sentry Issue Creation Workflow
|
|
5
|
+
# -----------------------------------------------------------------------------
|
|
6
|
+
# ⚠️ WARNING: THIS FILE IS AUTO-GENERATED. DO NOT EDIT MANUALLY! ⚠️
|
|
7
|
+
# Any changes may be overwritten by the generation process.
|
|
8
|
+
# This workflow creates a Sentry issue when another workflow fails.
|
|
9
|
+
# It captures details about the failure and creates a standardized issue
|
|
10
|
+
# to help track and resolve CI/CD problems in Sentry.
|
|
11
|
+
#
|
|
12
|
+
# Example usage in another workflow:
|
|
13
|
+
# ```yaml
|
|
14
|
+
# create_sentry_issue_on_failure:
|
|
15
|
+
# if: failure()
|
|
16
|
+
# uses: ./.github/workflows/create-sentry-issue-on-failure.yml
|
|
17
|
+
# with:
|
|
18
|
+
# workflow_name: 'My Workflow'
|
|
19
|
+
# failed_job: 'build_and_test'
|
|
20
|
+
# SENTRY_ORG: ${{ vars.SENTRY_ORG }}
|
|
21
|
+
# SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT }}
|
|
22
|
+
# secrets:
|
|
23
|
+
# SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
|
24
|
+
# ```
|
|
25
|
+
|
|
26
|
+
name: 🔴 Sentry Issue on Workflow Failure
|
|
27
|
+
|
|
28
|
+
on:
|
|
29
|
+
workflow_call:
|
|
30
|
+
inputs:
|
|
31
|
+
workflow_name:
|
|
32
|
+
required: true
|
|
33
|
+
type: string
|
|
34
|
+
description: 'Name of the workflow that failed'
|
|
35
|
+
failed_job:
|
|
36
|
+
required: false
|
|
37
|
+
type: string
|
|
38
|
+
description: 'Name of the job that failed (optional)'
|
|
39
|
+
SENTRY_ORG:
|
|
40
|
+
required: true
|
|
41
|
+
type: string
|
|
42
|
+
description: 'Sentry organization slug (e.g., your-company)'
|
|
43
|
+
SENTRY_PROJECT:
|
|
44
|
+
required: true
|
|
45
|
+
type: string
|
|
46
|
+
description: 'Sentry project slug (e.g., serverless-knowledge-platform)'
|
|
47
|
+
environment:
|
|
48
|
+
required: false
|
|
49
|
+
type: string
|
|
50
|
+
default: 'production'
|
|
51
|
+
description: 'Environment where the failure occurred'
|
|
52
|
+
level:
|
|
53
|
+
required: false
|
|
54
|
+
type: string
|
|
55
|
+
default: 'error'
|
|
56
|
+
description: 'Sentry issue level (debug, info, warning, error, fatal)'
|
|
57
|
+
node_version:
|
|
58
|
+
description: 'Node.js version to use'
|
|
59
|
+
required: false
|
|
60
|
+
default: '22.21.1'
|
|
61
|
+
type: string
|
|
62
|
+
package_manager:
|
|
63
|
+
description: 'Package manager to use (npm, yarn, or bun)'
|
|
64
|
+
required: false
|
|
65
|
+
default: 'npm'
|
|
66
|
+
type: string
|
|
67
|
+
working_directory:
|
|
68
|
+
description: 'Directory to run commands in (if not root)'
|
|
69
|
+
required: false
|
|
70
|
+
default: ''
|
|
71
|
+
type: string
|
|
72
|
+
secrets:
|
|
73
|
+
SENTRY_AUTH_TOKEN:
|
|
74
|
+
required: true
|
|
75
|
+
description: 'Sentry Auth Token with project:write scope'
|
|
76
|
+
|
|
77
|
+
# Concurrency is managed by the parent workflow that calls this one
|
|
78
|
+
# This avoids deadlocks between parent and child workflows
|
|
79
|
+
|
|
80
|
+
jobs:
|
|
81
|
+
create_sentry_issue:
|
|
82
|
+
name: 📝 Create Sentry Issue
|
|
83
|
+
runs-on: ubuntu-latest
|
|
84
|
+
timeout-minutes: 5
|
|
85
|
+
steps:
|
|
86
|
+
- name: 📥 Checkout repository
|
|
87
|
+
uses: actions/checkout@v4
|
|
88
|
+
|
|
89
|
+
- name: 🔧 Setup Node.js
|
|
90
|
+
uses: actions/setup-node@v4
|
|
91
|
+
with:
|
|
92
|
+
node-version: ${{ inputs.node_version }}
|
|
93
|
+
cache: ${{ inputs.package_manager != 'bun' && inputs.package_manager || '' }}
|
|
94
|
+
|
|
95
|
+
- name: 🔴 Create Sentry Issue
|
|
96
|
+
id: create_sentry_issue
|
|
97
|
+
run: |
|
|
98
|
+
cd "${{ inputs.working_directory || '.' }}"
|
|
99
|
+
|
|
100
|
+
# Set variables
|
|
101
|
+
WORKFLOW_NAME="${{ inputs.workflow_name }}"
|
|
102
|
+
FAILED_JOB="${{ inputs.failed_job || 'Unknown' }}"
|
|
103
|
+
ENVIRONMENT="${{ inputs.environment }}"
|
|
104
|
+
LEVEL="${{ inputs.level }}"
|
|
105
|
+
RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
|
106
|
+
|
|
107
|
+
# Get commit message, handling special characters properly
|
|
108
|
+
COMMIT_MESSAGE="${{ github.event.head_commit.message || 'N/A' }}"
|
|
109
|
+
|
|
110
|
+
# Create error message
|
|
111
|
+
if [ "$FAILED_JOB" != "Unknown" ]; then
|
|
112
|
+
ERROR_MESSAGE="CI/CD Workflow Failure: ${WORKFLOW_NAME} - ${FAILED_JOB}"
|
|
113
|
+
else
|
|
114
|
+
ERROR_MESSAGE="CI/CD Workflow Failure: ${WORKFLOW_NAME}"
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
# Get current timestamp in ISO format
|
|
118
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
|
|
119
|
+
|
|
120
|
+
# Create JSON payload for Sentry API using jq for proper escaping
|
|
121
|
+
PAYLOAD=$(jq -n \
|
|
122
|
+
--arg message "${ERROR_MESSAGE}" \
|
|
123
|
+
--arg level "${LEVEL}" \
|
|
124
|
+
--arg timestamp "${TIMESTAMP}" \
|
|
125
|
+
--arg workflow_name "${WORKFLOW_NAME}" \
|
|
126
|
+
--arg failed_job "${FAILED_JOB}" \
|
|
127
|
+
--arg run_url "${RUN_URL}" \
|
|
128
|
+
--arg repository "${{ github.repository }}" \
|
|
129
|
+
--arg commit "${{ github.sha }}" \
|
|
130
|
+
--arg commit_message "${COMMIT_MESSAGE}" \
|
|
131
|
+
--arg triggered_by "${{ github.actor }}" \
|
|
132
|
+
--arg environment "${ENVIRONMENT}" \
|
|
133
|
+
--arg ref "${{ github.ref }}" \
|
|
134
|
+
--arg run_id "${{ github.run_id }}" \
|
|
135
|
+
'{
|
|
136
|
+
"message": $message,
|
|
137
|
+
"level": $level,
|
|
138
|
+
"timestamp": $timestamp,
|
|
139
|
+
"platform": "other",
|
|
140
|
+
"sdk": {
|
|
141
|
+
"name": "github-actions",
|
|
142
|
+
"version": "1.0.0"
|
|
143
|
+
},
|
|
144
|
+
"logger": "github-actions.ci",
|
|
145
|
+
"environment": $environment,
|
|
146
|
+
"tags": {
|
|
147
|
+
"workflow": $workflow_name,
|
|
148
|
+
"job": $failed_job,
|
|
149
|
+
"repository": $repository,
|
|
150
|
+
"triggered_by": $triggered_by,
|
|
151
|
+
"ref": $ref,
|
|
152
|
+
"source": "github-actions"
|
|
153
|
+
},
|
|
154
|
+
"extra": {
|
|
155
|
+
"workflow_run_url": $run_url,
|
|
156
|
+
"commit_sha": $commit,
|
|
157
|
+
"commit_message": $commit_message,
|
|
158
|
+
"run_id": $run_id,
|
|
159
|
+
"failure_type": "ci_cd_workflow"
|
|
160
|
+
},
|
|
161
|
+
"contexts": {
|
|
162
|
+
"runtime": {
|
|
163
|
+
"name": "github-actions",
|
|
164
|
+
"version": "latest"
|
|
165
|
+
},
|
|
166
|
+
"os": {
|
|
167
|
+
"name": "ubuntu-latest"
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"fingerprint": ["github-actions", $workflow_name, $failed_job]
|
|
171
|
+
}')
|
|
172
|
+
|
|
173
|
+
# Debug: Print the payload to see what'\''s being sent (without sensitive data)
|
|
174
|
+
echo "Debug: Generated payload:"
|
|
175
|
+
echo "$PAYLOAD" | jq 'del(.extra.commit_message)' | head -20
|
|
176
|
+
|
|
177
|
+
# Debug: Print Sentry configuration
|
|
178
|
+
echo "Debug: SENTRY_ORG=${{ inputs.SENTRY_ORG }}"
|
|
179
|
+
echo "Debug: SENTRY_PROJECT=${{ inputs.SENTRY_PROJECT }}"
|
|
180
|
+
echo "Debug: API URL=https://sentry.io/api/0/projects/${{ inputs.SENTRY_ORG }}/${{ inputs.SENTRY_PROJECT }}/store/"
|
|
181
|
+
|
|
182
|
+
# First, let's get the DSN for this project
|
|
183
|
+
DSN_RESPONSE=$(curl -s -w "\n%{http_code}" \
|
|
184
|
+
-H "Authorization: Bearer ${{ secrets.SENTRY_AUTH_TOKEN }}" \
|
|
185
|
+
"https://sentry.io/api/0/projects/${{ inputs.SENTRY_ORG }}/${{ inputs.SENTRY_PROJECT }}/keys/")
|
|
186
|
+
|
|
187
|
+
DSN_STATUS=$(echo "$DSN_RESPONSE" | tail -n1)
|
|
188
|
+
DSN_BODY=$(echo "$DSN_RESPONSE" | head -n -1)
|
|
189
|
+
|
|
190
|
+
if [ "$DSN_STATUS" = "200" ]; then
|
|
191
|
+
# Extract the DSN from the first key
|
|
192
|
+
DSN=$(echo "$DSN_BODY" | jq -r '.[0].dsn.public // empty')
|
|
193
|
+
echo "Debug: Found DSN: ${DSN:0:50}..." # Show first 50 chars for security
|
|
194
|
+
|
|
195
|
+
# Parse DSN to get the project ID and key
|
|
196
|
+
if [[ $DSN =~ https://([^@]+)@([^/]+)/([0-9]+) ]]; then
|
|
197
|
+
SENTRY_KEY="${BASH_REMATCH[1]}"
|
|
198
|
+
SENTRY_HOST="${BASH_REMATCH[2]}"
|
|
199
|
+
PROJECT_ID="${BASH_REMATCH[3]}"
|
|
200
|
+
|
|
201
|
+
# Call Sentry API to create issue using the store endpoint with proper auth
|
|
202
|
+
RESPONSE=$(curl -s -w "\n%{http_code}" \
|
|
203
|
+
-H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=$SENTRY_KEY" \
|
|
204
|
+
-H "Content-Type: application/json" \
|
|
205
|
+
-X POST \
|
|
206
|
+
--data "${PAYLOAD}" \
|
|
207
|
+
"https://${SENTRY_HOST}/api/${PROJECT_ID}/store/")
|
|
208
|
+
else
|
|
209
|
+
echo "Error: Could not parse DSN"
|
|
210
|
+
exit 1
|
|
211
|
+
fi
|
|
212
|
+
else
|
|
213
|
+
echo "Error: Could not retrieve project DSN. Status: $DSN_STATUS"
|
|
214
|
+
echo "Response: $DSN_BODY"
|
|
215
|
+
exit 1
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
# Extract HTTP status code from response
|
|
219
|
+
HTTP_STATUS=$(echo "$RESPONSE" | tail -n1)
|
|
220
|
+
RESPONSE_BODY=$(echo "$RESPONSE" | head -n -1)
|
|
221
|
+
|
|
222
|
+
echo "HTTP Status: $HTTP_STATUS"
|
|
223
|
+
|
|
224
|
+
if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "201" ]; then
|
|
225
|
+
# Extract issue ID from response
|
|
226
|
+
ISSUE_ID=$(echo "$RESPONSE_BODY" | jq -r '.id // empty')
|
|
227
|
+
|
|
228
|
+
if [ -n "$ISSUE_ID" ] && [ "$ISSUE_ID" != "null" ]; then
|
|
229
|
+
echo "Successfully created Sentry issue: $ISSUE_ID"
|
|
230
|
+
echo "issue_id=$ISSUE_ID" >> $GITHUB_OUTPUT
|
|
231
|
+
echo "issue_url=https://sentry.io/organizations/${{ inputs.SENTRY_ORG }}/issues/?project=${{ inputs.SENTRY_PROJECT }}&query=$ISSUE_ID" >> $GITHUB_OUTPUT
|
|
232
|
+
else
|
|
233
|
+
echo "Issue created but no ID returned. Response:"
|
|
234
|
+
echo "$RESPONSE_BODY" | jq . || echo "$RESPONSE_BODY"
|
|
235
|
+
fi
|
|
236
|
+
else
|
|
237
|
+
echo "Failed to create Sentry issue. API response:"
|
|
238
|
+
echo "Status: $HTTP_STATUS"
|
|
239
|
+
echo "Body: $RESPONSE_BODY"
|
|
240
|
+
|
|
241
|
+
# Provide helpful error messages
|
|
242
|
+
if [ "$HTTP_STATUS" = "400" ]; then
|
|
243
|
+
echo "Error: Bad request. Please check the payload format."
|
|
244
|
+
elif [ "$HTTP_STATUS" = "401" ]; then
|
|
245
|
+
echo "Error: Authentication failed. Please check SENTRY_AUTH_TOKEN."
|
|
246
|
+
elif [ "$HTTP_STATUS" = "403" ]; then
|
|
247
|
+
echo "Error: Permission denied. Please check token permissions (needs project:write)."
|
|
248
|
+
elif [ "$HTTP_STATUS" = "404" ]; then
|
|
249
|
+
echo "Error: Project not found. Please check SENTRY_ORG and SENTRY_PROJECT."
|
|
250
|
+
elif [ "$HTTP_STATUS" = "429" ]; then
|
|
251
|
+
echo "Error: Rate limit exceeded. Please try again later."
|
|
252
|
+
fi
|
|
253
|
+
|
|
254
|
+
exit 1
|
|
255
|
+
fi
|
|
256
|
+
|
|
257
|
+
- name: 📢 Report Issue Creation
|
|
258
|
+
if: steps.create_sentry_issue.outputs.issue_id
|
|
259
|
+
run: |
|
|
260
|
+
cd "${{ inputs.working_directory || '.' }}"
|
|
261
|
+
echo "Created Sentry issue: ${{ steps.create_sentry_issue.outputs.issue_id }}"
|
|
262
|
+
echo "Issue URL: ${{ steps.create_sentry_issue.outputs.issue_url }}"
|
|
263
|
+
|
|
264
|
+
- name: 📢 Report Creation Attempt
|
|
265
|
+
if: steps.create_sentry_issue.conclusion == 'success' && !steps.create_sentry_issue.outputs.issue_id
|
|
266
|
+
run: |
|
|
267
|
+
cd "${{ inputs.working_directory || '.' }}"
|
|
268
|
+
echo "Sentry event was sent successfully, but issue ID was not returned."
|
|
269
|
+
echo "Check your Sentry dashboard: https://sentry.io/organizations/${{ inputs.SENTRY_ORG }}/issues/?project=${{ inputs.SENTRY_PROJECT }}"
|
|
@@ -964,30 +964,53 @@ jobs:
|
|
|
964
964
|
fi
|
|
965
965
|
working-directory: ${{ inputs.working_directory || '.' }}
|
|
966
966
|
|
|
967
|
-
- name:
|
|
967
|
+
- name: 📋 Load audit exclusions
|
|
968
|
+
id: audit_exclusions
|
|
968
969
|
run: |
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
970
|
+
GHSA_IDS=""
|
|
971
|
+
CVE_IDS=""
|
|
972
|
+
for config_file in audit.ignore.config.json audit.ignore.local.json; do
|
|
973
|
+
if [ -f "$config_file" ]; then
|
|
974
|
+
FILE_IDS=$(jq -r '.exclusions[].id' "$config_file" 2>/dev/null)
|
|
975
|
+
if [ -n "$FILE_IDS" ]; then
|
|
976
|
+
GHSA_IDS="$GHSA_IDS $FILE_IDS"
|
|
977
|
+
fi
|
|
978
|
+
FILE_CVES=$(jq -r '.exclusions[] | select(.cve != null) | .cve' "$config_file" 2>/dev/null)
|
|
979
|
+
if [ -n "$FILE_CVES" ]; then
|
|
980
|
+
CVE_IDS="$CVE_IDS $FILE_CVES"
|
|
981
|
+
fi
|
|
982
|
+
fi
|
|
983
|
+
done
|
|
984
|
+
GHSA_IDS=$(echo "$GHSA_IDS" | tr ' ' '\n' | sort -u | grep -v '^$' | tr '\n' ' ')
|
|
985
|
+
CVE_IDS=$(echo "$CVE_IDS" | tr ' ' '\n' | sort -u | grep -v '^$' | tr '\n' ' ')
|
|
986
|
+
echo "ghsa_ids=$GHSA_IDS" >> $GITHUB_OUTPUT
|
|
987
|
+
echo "cve_ids=$CVE_IDS" >> $GITHUB_OUTPUT
|
|
988
|
+
echo "Loaded GHSA exclusions: $GHSA_IDS"
|
|
989
|
+
echo "Loaded CVE exclusions: $CVE_IDS"
|
|
990
|
+
working-directory: ${{ inputs.working_directory || '.' }}
|
|
980
991
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
992
|
+
- name: 🔒 Run security audit
|
|
993
|
+
run: |
|
|
994
|
+
GHSA_IDS="${{ steps.audit_exclusions.outputs.ghsa_ids }}"
|
|
995
|
+
CVE_IDS="${{ steps.audit_exclusions.outputs.cve_ids }}"
|
|
984
996
|
|
|
985
|
-
|
|
986
|
-
#
|
|
987
|
-
|
|
997
|
+
if [ "${{ inputs.package_manager }}" = "npm" ]; then
|
|
998
|
+
# Build jq exclusion filter for npm audit GHSA IDs
|
|
999
|
+
NPM_EXCLUDE_FILTER=""
|
|
1000
|
+
for _id in $GHSA_IDS; do
|
|
1001
|
+
if [ -n "$NPM_EXCLUDE_FILTER" ]; then
|
|
1002
|
+
NPM_EXCLUDE_FILTER="$NPM_EXCLUDE_FILTER or . == \"$_id\""
|
|
1003
|
+
else
|
|
1004
|
+
NPM_EXCLUDE_FILTER=". == \"$_id\""
|
|
1005
|
+
fi
|
|
1006
|
+
done
|
|
988
1007
|
|
|
989
1008
|
AUDIT_JSON=$(npm audit --production --json 2>/dev/null || true)
|
|
990
|
-
|
|
1009
|
+
if [ -n "$NPM_EXCLUDE_FILTER" ]; then
|
|
1010
|
+
UNFIXED_HIGH=$(echo "$AUDIT_JSON" | jq "[.vulnerabilities | to_entries[] | select(.value.severity == \"high\" or .value.severity == \"critical\") | .value.via[] | select(type == \"object\") | .url | ltrimstr(\"https://github.com/advisories/\")] | unique | map(select($NPM_EXCLUDE_FILTER | not)) | length")
|
|
1011
|
+
else
|
|
1012
|
+
UNFIXED_HIGH=$(echo "$AUDIT_JSON" | jq '[.vulnerabilities | to_entries[] | select(.value.severity == "high" or .value.severity == "critical") | .value.via[] | select(type == "object") | .url | ltrimstr("https://github.com/advisories/")] | unique | length')
|
|
1013
|
+
fi
|
|
991
1014
|
if [ "$UNFIXED_HIGH" -gt 0 ]; then
|
|
992
1015
|
echo "::warning::Found high or critical vulnerabilities (after excluding known false positives)"
|
|
993
1016
|
npm audit --production --audit-level=high || true
|
|
@@ -995,26 +1018,42 @@ jobs:
|
|
|
995
1018
|
fi
|
|
996
1019
|
echo "::notice::No high or critical vulnerabilities found (excluding known false positives)"
|
|
997
1020
|
elif [ "${{ inputs.package_manager }}" = "yarn" ]; then
|
|
998
|
-
#
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
#
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1021
|
+
# Build jq filter for GHSA IDs
|
|
1022
|
+
GHSA_FILTER=""
|
|
1023
|
+
for _id in $GHSA_IDS; do
|
|
1024
|
+
if [ -n "$GHSA_FILTER" ]; then
|
|
1025
|
+
GHSA_FILTER="$GHSA_FILTER or .data.advisory.github_advisory_id == \"$_id\""
|
|
1026
|
+
else
|
|
1027
|
+
GHSA_FILTER=".data.advisory.github_advisory_id == \"$_id\""
|
|
1028
|
+
fi
|
|
1029
|
+
done
|
|
1030
|
+
|
|
1031
|
+
# Build jq filter for CVE IDs
|
|
1032
|
+
CVE_FILTER=""
|
|
1033
|
+
for _cve in $CVE_IDS; do
|
|
1034
|
+
if [ -n "$CVE_FILTER" ]; then
|
|
1035
|
+
CVE_FILTER="$CVE_FILTER or . == \"$_cve\""
|
|
1036
|
+
else
|
|
1037
|
+
CVE_FILTER=". == \"$_cve\""
|
|
1038
|
+
fi
|
|
1039
|
+
done
|
|
1040
|
+
|
|
1041
|
+
# Combine GHSA and CVE filters
|
|
1042
|
+
COMBINED_FILTER=""
|
|
1043
|
+
if [ -n "$GHSA_FILTER" ] && [ -n "$CVE_FILTER" ]; then
|
|
1044
|
+
COMBINED_FILTER="($GHSA_FILTER or (.data.advisory.cves | any($CVE_FILTER)))"
|
|
1045
|
+
elif [ -n "$GHSA_FILTER" ]; then
|
|
1046
|
+
COMBINED_FILTER="($GHSA_FILTER)"
|
|
1047
|
+
elif [ -n "$CVE_FILTER" ]; then
|
|
1048
|
+
COMBINED_FILTER="((.data.advisory.cves | any($CVE_FILTER)))"
|
|
1049
|
+
fi
|
|
1050
|
+
|
|
1051
|
+
if [ -n "$COMBINED_FILTER" ]; then
|
|
1052
|
+
yarn audit --groups dependencies --json | jq -r "select(.type == \"auditAdvisory\") | select(.data.advisory.severity == \"high\" or .data.advisory.severity == \"critical\") | select(($COMBINED_FILTER) | not) | .data.advisory" > high_vulns.json
|
|
1053
|
+
else
|
|
1054
|
+
yarn audit --groups dependencies --json | jq -r 'select(.type == "auditAdvisory") | select(.data.advisory.severity == "high" or .data.advisory.severity == "critical") | .data.advisory' > high_vulns.json
|
|
1055
|
+
fi
|
|
1056
|
+
|
|
1018
1057
|
if [ -s high_vulns.json ]; then
|
|
1019
1058
|
echo "::error::Found high or critical vulnerabilities:"
|
|
1020
1059
|
cat high_vulns.json
|
|
@@ -1023,64 +1062,13 @@ jobs:
|
|
|
1023
1062
|
echo "::notice::No high or critical vulnerabilities found (excluding known false positives)"
|
|
1024
1063
|
fi
|
|
1025
1064
|
elif [ "${{ inputs.package_manager }}" = "bun" ]; then
|
|
1026
|
-
#
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
# Excluding GHSA-37qj-frw5-hhjh: fast-xml-parser RangeError DoS with numeric entities
|
|
1035
|
-
# Transitive dependency via @react-native-community/cli (Android/iOS build tooling)
|
|
1036
|
-
# Parent packages pin ^4.4.1; fix requires major version 5.x (incompatible)
|
|
1037
|
-
# Risk: None - CLI build tool, not a production runtime dependency
|
|
1038
|
-
|
|
1039
|
-
# Excluding GHSA-3ppc-4f35-3m26: minimatch ReDoS via repeated wildcards
|
|
1040
|
-
# Transitive dependency in devDependencies (eslint, jest, nodemon, ts-morph, etc.)
|
|
1041
|
-
# Fix requires minimatch v10 which changes export shape (object vs function),
|
|
1042
|
-
# breaking test-exclude (used by Jest coverage). No production code path is affected.
|
|
1043
|
-
# Risk: None - only devDependency tooling, never processes untrusted user input
|
|
1044
|
-
|
|
1045
|
-
# Excluding GHSA-jmr7-xgp7-cmfj: fast-xml-parser DoS through entity expansion in DOCTYPE
|
|
1046
|
-
# Transitive dependency via AWS SDK (@aws-sdk/xml-builder) and snowflake-sdk
|
|
1047
|
-
# Resolution to >=5.3.6 set in package.json but bun audit still flags intermediate ranges
|
|
1048
|
-
# Risk: Low - XML parsing of untrusted DOCTYPE content not in our code paths
|
|
1049
|
-
|
|
1050
|
-
# Excluding GHSA-m7jm-9gc2-mpf2: fast-xml-parser entity encoding bypass via regex injection
|
|
1051
|
-
# Same transitive path as GHSA-jmr7-xgp7-cmfj (AWS SDK, snowflake-sdk)
|
|
1052
|
-
# Resolution to >=5.3.6 set in package.json but bun audit still flags intermediate ranges
|
|
1053
|
-
# Risk: Low - no untrusted XML with DOCTYPE entity names processed
|
|
1054
|
-
|
|
1055
|
-
# Excluding GHSA-r6q2-hw4h-h46w: node-tar race condition via Unicode Ligature Collisions on macOS APFS
|
|
1056
|
-
# Transitive via @nestjs/apollo > @apollo/gateway > make-fetch-happen > cacache > tar
|
|
1057
|
-
# Resolution to ^7.5.8 set in package.json but bun audit still flags intermediate ranges
|
|
1058
|
-
# Risk: None - tar extraction not used in production runtime
|
|
1059
|
-
|
|
1060
|
-
# Excluding GHSA-34x7-hfp2-rc4v: node-tar arbitrary file creation via hardlink path traversal
|
|
1061
|
-
# Same transitive path as GHSA-r6q2-hw4h-h46w
|
|
1062
|
-
# Risk: None - tar extraction not used in production runtime
|
|
1063
|
-
|
|
1064
|
-
# Excluding GHSA-83g3-92jg-28cx: node-tar arbitrary file read/write via hardlink target escape
|
|
1065
|
-
# Same transitive path as GHSA-r6q2-hw4h-h46w
|
|
1066
|
-
# Risk: None - tar extraction not used in production runtime
|
|
1067
|
-
|
|
1068
|
-
# Excluding GHSA-3h5v-q93c-6h6q: ws DoS when handling request with many HTTP headers
|
|
1069
|
-
# Transitive via @nestjs/graphql, graphql-ws, openai, serverless-offline, serverless-esbuild
|
|
1070
|
-
# Resolution to ^8.17.1 set in package.json but bun audit still flags intermediate ranges
|
|
1071
|
-
# Risk: Low - WebSocket servers behind API Gateway which limits headers
|
|
1072
|
-
|
|
1073
|
-
# Excluding GHSA-7r86-cg39-jmmj: minimatch ReDoS via multiple non-adjacent GLOBSTAR segments
|
|
1074
|
-
# Same transitive dependency chain as GHSA-3ppc-4f35-3m26 (eslint, jest, ts-morph, etc.)
|
|
1075
|
-
# Fix requires minimatch >=3.1.3 but bun cannot override transitive dependency version ranges
|
|
1076
|
-
# Risk: None - only devDependency tooling, never processes untrusted user input
|
|
1077
|
-
|
|
1078
|
-
# Excluding GHSA-23c5-xmqv-rm74: minimatch ReDoS via nested *() extglobs
|
|
1079
|
-
# Same transitive dependency chain as GHSA-3ppc-4f35-3m26 (eslint, jest, ts-morph, etc.)
|
|
1080
|
-
# Fix requires minimatch >=3.1.3 but bun cannot override transitive dependency version ranges
|
|
1081
|
-
# Risk: None - only devDependency tooling, never processes untrusted user input
|
|
1082
|
-
|
|
1083
|
-
if ! bun audit --audit-level=high --ignore GHSA-5j98-mcp5-4vw2 --ignore GHSA-8qq5-rm4j-mr97 --ignore GHSA-37qj-frw5-hhjh --ignore GHSA-3ppc-4f35-3m26 --ignore GHSA-jmr7-xgp7-cmfj --ignore GHSA-m7jm-9gc2-mpf2 --ignore GHSA-r6q2-hw4h-h46w --ignore GHSA-34x7-hfp2-rc4v --ignore GHSA-83g3-92jg-28cx --ignore GHSA-3h5v-q93c-6h6q --ignore GHSA-7r86-cg39-jmmj --ignore GHSA-23c5-xmqv-rm74; then
|
|
1065
|
+
# Build --ignore flags dynamically from exclusion list
|
|
1066
|
+
BUN_IGNORE_FLAGS=""
|
|
1067
|
+
for _id in $GHSA_IDS; do
|
|
1068
|
+
BUN_IGNORE_FLAGS="$BUN_IGNORE_FLAGS --ignore $_id"
|
|
1069
|
+
done
|
|
1070
|
+
|
|
1071
|
+
if ! bun audit --audit-level=high $BUN_IGNORE_FLAGS; then
|
|
1084
1072
|
echo "::warning::Found high or critical vulnerabilities"
|
|
1085
1073
|
exit 1
|
|
1086
1074
|
fi
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"exclusions": [
|
|
3
|
+
{
|
|
4
|
+
"id": "GHSA-5j98-mcp5-4vw2",
|
|
5
|
+
"cve": "CVE-2025-64756",
|
|
6
|
+
"package": "glob",
|
|
7
|
+
"reason": "CLI command injection — only affects glob CLI --cmd flag, not library usage"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"id": "GHSA-8qq5-rm4j-mr97",
|
|
11
|
+
"package": "node-tar",
|
|
12
|
+
"reason": "Path sanitization vulnerability — nested in @expo/cli, tar extraction not in our code path"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "GHSA-37qj-frw5-hhjh",
|
|
16
|
+
"package": "fast-xml-parser",
|
|
17
|
+
"reason": "RangeError DoS with numeric entities — transitive via React Native CLI, build tool only"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "GHSA-3ppc-4f35-3m26",
|
|
21
|
+
"package": "minimatch",
|
|
22
|
+
"reason": "ReDoS via repeated wildcards — devDeps only, fix requires breaking minimatch v10"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "GHSA-7r86-cg39-jmmj",
|
|
26
|
+
"package": "minimatch",
|
|
27
|
+
"reason": "ReDoS via multiple non-adjacent GLOBSTAR segments — devDeps only, fix requires minimatch >=3.1.3"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "GHSA-23c5-xmqv-rm74",
|
|
31
|
+
"package": "minimatch",
|
|
32
|
+
"reason": "ReDoS via nested *() extglobs — devDeps only, fix requires minimatch >=3.1.3"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": "GHSA-2g4f-4pwh-qvx6",
|
|
36
|
+
"package": "ajv",
|
|
37
|
+
"reason": "ReDoS with $data option — $data option not used, nested in aws-cdk-lib/eslint"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": "GHSA-jmr7-xgp7-cmfj",
|
|
41
|
+
"package": "fast-xml-parser",
|
|
42
|
+
"reason": "DoS through entity expansion in DOCTYPE — transitive via AWS SDK, no untrusted XML parsing"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "GHSA-m7jm-9gc2-mpf2",
|
|
46
|
+
"package": "fast-xml-parser",
|
|
47
|
+
"reason": "Entity encoding bypass via regex injection — same path as GHSA-jmr7-xgp7-cmfj"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "GHSA-r6q2-hw4h-h46w",
|
|
51
|
+
"package": "node-tar",
|
|
52
|
+
"reason": "Race condition via Unicode Ligature Collisions on macOS APFS — transitive via NestJS/Apollo, tar not used in production"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"id": "GHSA-34x7-hfp2-rc4v",
|
|
56
|
+
"package": "node-tar",
|
|
57
|
+
"reason": "Arbitrary file creation via hardlink path traversal — same path as GHSA-r6q2-hw4h-h46w"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "GHSA-83g3-92jg-28cx",
|
|
61
|
+
"package": "node-tar",
|
|
62
|
+
"reason": "Arbitrary file read/write via hardlink target escape — same path as GHSA-r6q2-hw4h-h46w"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"id": "GHSA-3h5v-q93c-6h6q",
|
|
66
|
+
"package": "ws",
|
|
67
|
+
"reason": "DoS via many HTTP headers — WebSocket servers behind API Gateway which limits headers"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "GHSA-w532-jxjh-hjhj",
|
|
71
|
+
"cve": "CVE-2025-29907",
|
|
72
|
+
"package": "jsPDF",
|
|
73
|
+
"reason": "ReDoS in addImage — controlled usage only, no user-controlled input to addImage"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "GHSA-8mvj-3j78-4qmw",
|
|
77
|
+
"cve": "CVE-2025-57810",
|
|
78
|
+
"package": "jsPDF",
|
|
79
|
+
"reason": "DoS in addImage — controlled usage only, no user-controlled input to addImage"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "GHSA-36jr-mh4h-2g58",
|
|
83
|
+
"package": "d3-color",
|
|
84
|
+
"reason": "ReDoS — transitive via react-native-svg-charts, color parsing not user-controlled"
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|