Skip to content

Commit 154b096

Browse files
authored
Merge branch 'main' into cursor/fix-path-injection-codeql-05f4
2 parents c891f82 + b93727e commit 154b096

File tree

3 files changed

+62
-19
lines changed

3 files changed

+62
-19
lines changed

.github/workflows/deploy-railway.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
name: Deploy to Railway
22

3+
permissions: {}
4+
35
on:
46
workflow_run:
57
workflows: ["Release Sourcebot (Development)"]

.github/workflows/trivy-vulnerability-triage.yml

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ jobs:
341341
fi
342342
343343
EXTRACTED=$(echo "$BODY" | jq '[.[] | {
344-
id: ("codeql:" + (.rule.id // "") + "#" + ((.number // 0) | tostring)),
344+
id: ("codeql:" + (.rule.id // "")),
345345
number: .number,
346346
rule_id: (.rule.id // ""),
347347
rule_description: (.rule.description // ""),
@@ -394,15 +394,15 @@ jobs:
394394
claude_args: |
395395
--allowedTools Bash,Read,Write,Edit,Glob,Grep,WebSearch,WebFetch
396396
--model claude-sonnet-4-6
397-
--json-schema '{"type":"object","properties":{"cves":{"type":"array","items":{"type":"object","properties":{"cveId":{"type":"string","description":"CVE ID, GHSA ID, or codeql:<rule-id>"},"severity":{"type":"string","enum":["CRITICAL","HIGH","MEDIUM","LOW"]},"source":{"type":"string","enum":["trivy","dependabot","codeql","trivy+dependabot"],"description":"Which scanner(s) reported this finding"},"title":{"type":"string","description":"Short summary for the Linear issue title"},"description":{"type":"string","description":"Markdown analysis: affected packages, direct vs transitive, remediation steps, and references"},"affectedPackage":{"type":"string"},"linearIssueExists":{"type":"boolean"}},"required":["cveId","severity","source","title","description","affectedPackage","linearIssueExists"]}}},"required":["cves"]}'
397+
--json-schema '{"type":"object","properties":{"cves":{"type":"array","items":{"type":"object","properties":{"cveId":{"type":"string","description":"CVE ID, GHSA ID, or codeql:<rule-id>"},"severity":{"type":"string","enum":["CRITICAL","HIGH","MEDIUM","LOW"]},"source":{"type":"string","enum":["trivy","dependabot","codeql","trivy+dependabot"],"description":"Which scanner(s) reported this finding"},"title":{"type":"string","description":"Short summary for the Linear issue title"},"description":{"type":"string","description":"Markdown analysis: affected packages, direct vs transitive, remediation steps, and references"},"affectedPackage":{"type":"string"},"linearIssueExists":{"type":"boolean"},"linearIssueId":{"type":"string","description":"The Linear issue UUID if a matching issue was found, empty string otherwise"},"linearIssueClosed":{"type":"boolean","description":"True if the matching Linear issue is in a completed or canceled state"}},"required":["cveId","severity","source","title","description","affectedPackage","linearIssueExists","linearIssueId","linearIssueClosed"]}}},"required":["cves"]}'
398398
prompt: |
399399
You are a security engineer triaging vulnerabilities and security findings for the Sourcebot Docker image.
400400
You have three data sources to analyze. Each is a JSON array where every entry has a pre-computed
401401
`id` field for deterministic deduplication:
402402
403403
1. **Trivy scan results** in `trivy-alerts.json` — each entry has `id` (CVE ID, e.g., `CVE-2024-1234`)
404404
2. **Dependabot alerts** in `dependabot-alerts.json` — each entry has `id` (CVE ID or GHSA ID)
405-
3. **CodeQL alerts** in `codeql-alerts.json` — each entry has `id` (prefixed, e.g., `codeql:js/sql-injection#33`)
405+
3. **CodeQL alerts** in `codeql-alerts.json` — each entry has `id` (prefixed, e.g., `codeql:js/sql-injection`). Multiple entries may share the same `id` (same rule, different locations).
406406
407407
## Your Task
408408
@@ -419,19 +419,20 @@ jobs:
419419
- Include the affected package, severity, remediation steps, and whether it is direct or transitive.
420420
421421
4. For **CodeQL findings**:
422-
- Each CodeQL alert is a **separate finding** — do NOT group alerts by rule ID. Two alerts with the
423-
same rule but different files/locations must be separate entries.
424-
- Use the `id` field as `cveId` (e.g., `codeql:js/path-injection#18`).
422+
- **Group all alerts with the same `id` (rule ID) into a single entry.** Multiple alerts for
423+
the same rule in different files/locations should produce ONE finding, not separate ones.
424+
- Use the `id` field as `cveId` (e.g., `codeql:js/path-injection`).
425425
- Set `source` to `"codeql"`.
426-
- Set `affectedPackage` to the file path from `location_path`.
426+
- Set `affectedPackage` to a comma-separated list of affected file paths, or the primary one
427+
if there are many.
427428
- Normalize `security_severity_level` to uppercase (CRITICAL/HIGH/MEDIUM/LOW).
428-
- The `description` should include:
429+
- The `description` MUST include details for **every alert instance** in the group:
429430
- The rule ID and what it detects
430-
- The exact file path and line number(s) from the alert
431-
- A link to the alert URL (`html_url`)
432-
- An explanation of the specific code at that location and why it's flagged
431+
- For **each** alert: the exact file path, line number(s), and a link to its alert URL (`html_url`)
432+
- For **each** alert: an explanation of the specific code at that location and why it's flagged
433433
- Concrete remediation steps with code examples where possible
434434
- A link to the CodeQL rule documentation
435+
- A summary count (e.g., "This rule was triggered in 3 locations:")
435436
436437
5. For each finding, determine:
437438
- A short `title` suitable for a Linear issue title.
@@ -443,17 +444,19 @@ jobs:
443444
444445
7. **Check Linear for existing issues** for each finding:
445446
- For each `cveId`, run a GraphQL query against the Linear API to search for issues
446-
whose title contains that ID.
447-
- **Important**: Exclude cancelled issues so that previously cancelled/rejected findings
448-
can be re-created. Use a state type filter to only match active issues.
447+
whose title contains that ID. Search ALL issues regardless of state (open, completed, cancelled).
449448
- Use the following curl command pattern:
450449
```
451450
curl -s -X POST https://api.linear.app/graphql \
452451
-H "Content-Type: application/json" \
453452
-H "Authorization: $LINEAR_API_KEY" \
454-
-d '{"query": "query { issues(filter: { team: { id: { eq: \"'$LINEAR_TEAM_ID'\" } }, title: { contains: \"<ID>\" }, state: { type: { nin: [\"canceled\"] } } }) { nodes { id title } } }"}'
453+
-d '{"query": "query { issues(filter: { team: { id: { eq: \"'$LINEAR_TEAM_ID'\" } }, title: { contains: \"<ID>\" } }) { nodes { id title state { type } } } }"}'
455454
```
456455
- Set `linearIssueExists` to `true` if any matching issue is found, `false` otherwise.
456+
- If multiple issues match, prefer the one with an open state (i.e., state type is NOT `"completed"` or `"canceled"`).
457+
Only use a closed issue if no open issue exists for that finding.
458+
- Set `linearIssueId` to the `id` (UUID) of the selected matching issue, or `""` if none found.
459+
- Set `linearIssueClosed` to `true` if the selected issue's `state.type` is `"completed"` or `"canceled"`, `false` otherwise.
457460
458461
8. Return the structured JSON with all findings in the `cves` array.
459462
@@ -472,7 +475,7 @@ jobs:
472475
echo "| ID | Source | Severity | Package | Linear Status |" >> "$GITHUB_STEP_SUMMARY"
473476
echo "|----|--------|----------|---------|---------------|" >> "$GITHUB_STEP_SUMMARY"
474477
475-
echo "$STRUCTURED_OUTPUT" | jq -r '.cves[] | "| \(.cveId) | \(.source) | \(.severity) | \(.affectedPackage) | \(if .linearIssueExists then "Existing" else "New" end) |"' >> "$GITHUB_STEP_SUMMARY"
478+
echo "$STRUCTURED_OUTPUT" | jq -r '.cves[] | "| \(.cveId) | \(.source) | \(.severity) | \(.affectedPackage) | \(if .linearIssueClosed then "Reopen" elif .linearIssueExists then "Existing" else "New" end) |"' >> "$GITHUB_STEP_SUMMARY"
476479
477480
echo "" >> "$GITHUB_STEP_SUMMARY"
478481
echo "### Details" >> "$GITHUB_STEP_SUMMARY"
@@ -526,6 +529,7 @@ jobs:
526529
527530
CREATED_COUNT=0
528531
SKIPPED_COUNT=0
532+
REOPENED_COUNT=0
529533
FAILED_COUNT=0
530534
531535
echo "## Linear Issue Creation" >> "$GITHUB_STEP_SUMMARY"
@@ -542,13 +546,49 @@ jobs:
542546
TITLE=$(echo "$cve" | jq -r '.title')
543547
DESCRIPTION=$(echo "$cve" | jq -r '.description')
544548
LINEAR_EXISTS=$(echo "$cve" | jq -r '.linearIssueExists')
549+
LINEAR_ISSUE_ID=$(echo "$cve" | jq -r '.linearIssueId')
550+
LINEAR_CLOSED=$(echo "$cve" | jq -r '.linearIssueClosed')
545551
546-
if [ "$LINEAR_EXISTS" = "true" ]; then
547-
echo "Skipping $CVE_ID — Linear issue already exists."
552+
if [ "$LINEAR_EXISTS" = "true" ] && [ "$LINEAR_CLOSED" = "false" ]; then
553+
echo "Skipping $CVE_ID — Linear issue already exists and is open."
548554
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
549555
continue
550556
fi
551557
558+
if [ "$LINEAR_EXISTS" = "true" ] && [ "$LINEAR_CLOSED" = "true" ]; then
559+
# Reopen the closed issue by setting its state back to Triage
560+
if [ -z "$STATE_ID" ]; then
561+
echo "::warning::Cannot reopen $CVE_ID — no Triage state found. Skipping."
562+
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
563+
continue
564+
fi
565+
566+
REOPEN_MUTATION='mutation($issueId: String!, $stateId: String!) { issueUpdate(id: $issueId, input: { stateId: $stateId }) { success issue { id identifier url } } }'
567+
REOPEN_VARIABLES=$(jq -n \
568+
--arg issueId "$LINEAR_ISSUE_ID" \
569+
--arg stateId "$STATE_ID" \
570+
'{issueId: $issueId, stateId: $stateId}')
571+
REOPEN_PAYLOAD=$(jq -n --arg query "$REOPEN_MUTATION" --argjson vars "$REOPEN_VARIABLES" '{query: $query, variables: $vars}')
572+
573+
REOPEN_RESPONSE=$(curl -s -X POST https://api.linear.app/graphql \
574+
-H "Content-Type: application/json" \
575+
-H "Authorization: $LINEAR_API_KEY" \
576+
-d "$REOPEN_PAYLOAD")
577+
578+
REOPEN_URL=$(echo "$REOPEN_RESPONSE" | jq -r '.data.issueUpdate.issue.url // empty')
579+
if [ -n "$REOPEN_URL" ]; then
580+
echo "Reopened Linear issue for $CVE_ID: $REOPEN_URL"
581+
echo "- Reopened [$CVE_ID]($REOPEN_URL) (moved back to Triage)" >> "$GITHUB_STEP_SUMMARY"
582+
REOPENED_COUNT=$((REOPENED_COUNT + 1))
583+
else
584+
echo "::error::Failed to reopen Linear issue for $CVE_ID"
585+
echo "$REOPEN_RESPONSE" | jq .
586+
FAILED_COUNT=$((FAILED_COUNT + 1))
587+
fi
588+
continue
589+
fi
590+
591+
# Create new issue
552592
PRIORITY=$(severity_to_priority "$SEVERITY")
553593
ISSUE_TITLE="[$REPOSITORY] $CVE_ID: $TITLE"
554594
@@ -587,7 +627,7 @@ jobs:
587627
done < /tmp/cves.jsonl
588628
589629
echo "" >> "$GITHUB_STEP_SUMMARY"
590-
echo "**Summary:** Created $CREATED_COUNT issue(s), skipped $SKIPPED_COUNT existing issue(s), failed $FAILED_COUNT issue(s)." >> "$GITHUB_STEP_SUMMARY"
630+
echo "**Summary:** Created $CREATED_COUNT issue(s), reopened $REOPENED_COUNT issue(s), skipped $SKIPPED_COUNT existing issue(s), failed $FAILED_COUNT issue(s)." >> "$GITHUB_STEP_SUMMARY"
591631
592632
if [ "$FAILED_COUNT" -gt 0 ]; then
593633
echo "::error::Failed to create $FAILED_COUNT Linear issue(s)"

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
- Fixed revision selection so the 64-revision cap prefers the newest matching branches and tags instead of pruning by ref-name order. [#1122](https://github.com/sourcebot-dev/sourcebot/pull/1122)
1212
- Fixed infinite pagination loop in Gitea/Forgejo when an API token can only see a subset of org repos (the `x-total-count` header reports org total while token returns fewer items). [#1130](https://github.com/sourcebot-dev/sourcebot/pull/1130)
1313
- Fixed path injection vulnerability (CodeQL js/path-injection) in review agent log writing by validating paths stay within the expected log directory. [#1134](https://github.com/sourcebot-dev/sourcebot/pull/1134)
14+
- Fixed CodeQL missing-workflow-permissions alert by adding explicit empty permissions to `deploy-railway.yml`. [#1132](https://github.com/sourcebot-dev/sourcebot/pull/1132)
1415

1516
## [4.16.11] - 2026-04-17
1617

0 commit comments

Comments
 (0)