feat: add merge-sarif #37

Merged
t.behrendt merged 5 commits from feat-add-merge-sarif into main 2026-02-15 12:07:03 +01:00
5 changed files with 247 additions and 0 deletions
Showing only changes of commit 074556ca44 - Show all commits
+22
View File
@@ -82,3 +82,25 @@ jobs:
echo "" echo ""
echo "All checks passed." echo "All checks passed."
test-merge-sarif-files:
name: Test Merge SARIF Files
runs-on:
- ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Merge SARIF Files
uses: ./merge-sarif-files
with:
files: |
- merge-sarif-files/test_sarif1.json
- merge-sarif-files/test_sarif2.json
output-file: merged.sarif
- name: Check merged SARIF file
run: |
runs=$(jq -r '.runs' merged.sarif)
echo "Runs:"
echo "$runs"
# check that there are two runs in the array
[ "$(echo "$runs" | jq 'length')" -eq 2 ] && echo "OK" || { echo "FAIL (got $(echo "$runs" | jq 'length'), expected 2)"; exit 1; }
echo "All checks passed."
+46
View File
@@ -0,0 +1,46 @@
# Merge SARIF Files Action
A reusable Gitea Action that merges multiple SARIF files into a single SARIF file.
**Note:** This action only merges the files. It doesn't perform any validation, filtering, or deduplication.
## Usage
### Basic Usage
```yaml
- name: Merge SARIF Files
uses: https://gitea.t000-n.de/t.behrendt/trivy-actions/merge-sarif-files@0.0.1
with:
files: |
- test_sarif1.json
- test_sarif2.json
output-file: merged.sarif
```
### Complete Example
```yaml
name: Merge SARIF Files
on: [push, pull_request]
jobs:
merge-sarif-files:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Merge SARIF Files
uses: https://gitea.t000-n.de/t.behrendt/trivy-actions/merge-sarif-files@0.0.1
with:
files: |
- test_sarif1.json
- test_sarif2.json
output-file: merged.sarif
```
## Inputs
| Input | Description | Required | Default |
| ------------- | ----------------------------- | -------- | -------------- |
| `files` | Paths to SARIF files to merge | Yes | |
| `output-file` | Output file path | Yes | `merged.sarif` |
+37
View File
@@ -0,0 +1,37 @@
name: "Merge SARIF Files"
description: "Merge multiple SARIF files into a single SARIF file"
author: "Timo Behrendt <t.behrendt@t00n.de>"
branding:
icon: "database"
color: "blue"
inputs:
files:
description: "Paths to SARIF files to merge"
required: true
output-file:
description: "Output file path"
required: true
default: "merged.sarif"
runs:
using: "composite"
steps:
- id: merge
shell: bash
run: |
set -e
files="${{ inputs.files }}"
output-file="${{ inputs.output-file }}"
# Sarif files are easy to merge. They contain a "runs" array. We just need to concat the runs arrays and write the result to the output file.
# Collect all the runs from all
runs=()
for file in $files; do
runs+=($(jq -r '.runs' $file))
done
# Write the merged runs to the output file.
echo '{"version":"2.1.0","$schema":"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json","runs":[' > $output-file
echo "${runs[@]}" | jq -s '.' >> $output-file
echo ']}' >> $output-file
+70
View File
@@ -0,0 +1,70 @@
{
"version": "2.1.0",
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
"runs": [
{
"tool": {
"driver": {
"fullName": "Trivy Vulnerability Scanner",
"informationUri": "https://github.com/aquasecurity/trivy",
"name": "Trivy",
"rules": [
{
"id": "KSV-0014",
"name": "Misconfiguration",
"shortDescription": {
"text": "Root file system is not read-only"
},
"fullDescription": {
"text": "An immutable root file system prevents applications from writing to their local disk. This can limit intrusions, as attackers will not be able to tamper with the file system or write foreign executables to disk."
},
"defaultConfiguration": {
"level": "error"
},
"helpUri": "https://avd.aquasec.com/misconfig/ksv-0014",
"help": {
"text": "Misconfiguration KSV-0014\nType: Kubernetes Security Check\nSeverity: HIGH\nCheck: Root file system is not read-only\nMessage: Container 'renovate' of CronJob 'renovate' should set 'securityContext.readOnlyRootFilesystem' to true\nLink: [KSV-0014](https://avd.aquasec.com/misconfig/ksv-0014)\nAn immutable root file system prevents applications from writing to their local disk. This can limit intrusions, as attackers will not be able to tamper with the file system or write foreign executables to disk.",
"markdown": "**Misconfiguration KSV-0014**\n| Type | Severity | Check | Message | Link |\n| --- | --- | --- | --- | --- |\n|Kubernetes Security Check|HIGH|Root file system is not read-only|Container 'renovate' of CronJob 'renovate' should set 'securityContext.readOnlyRootFilesystem' to true|[KSV-0014](https://avd.aquasec.com/misconfig/ksv-0014)|\n\nAn immutable root file system prevents applications from writing to their local disk. This can limit intrusions, as attackers will not be able to tamper with the file system or write foreign executables to disk."
},
"properties": {
"precision": "very-high",
"security-severity": "8.0",
"tags": ["misconfiguration", "security", "HIGH"]
}
}
],
"version": "0.69.1"
}
},
"results": [
{
"ruleId": "KSV-0014",
"ruleIndex": 0,
"level": "error",
"message": {
"text": "Artifact: k8s/31_deployment_redis.yaml\nType: kubernetes\nVulnerability KSV-0014\nSeverity: HIGH\nMessage: Container 'redis' of Deployment 'redis' should set 'securityContext.readOnlyRootFilesystem' to true\nLink: [KSV-0014](https://avd.aquasec.com/misconfig/ksv-0014)"
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "k8s/31_deployment_redis.yaml",
"uriBaseId": "ROOTPATH"
},
"region": {
"startLine": 34,
"startColumn": 1,
"endLine": 51,
"endColumn": 1
}
},
"message": {
"text": "k8s/31_deployment_redis.yaml"
}
}
]
}
]
}
]
}
+72
View File
@@ -0,0 +1,72 @@
{
"version": "2.1.0",
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
"runs": [
{
"tool": {
"driver": {
"fullName": "Trivy Vulnerability Scanner",
"informationUri": "https://github.com/aquasecurity/trivy",
"name": "Trivy",
"rules": [
{
"id": "CVE-2026-26019",
"name": "LanguageSpecificPackageVulnerability",
"shortDescription": {
"text": "@langchain/community: @langchain/community SSRF Bypass in RecursiveUrlLoader"
},
"fullDescription": {
"text": "LangChain is a framework for building LLM-powered applications. Prior to 1.1.14, the RecursiveUrlLoader class in @langchain/community is a web crawler that recursively follows links from a starting URL. Its preventOutside option (enabled by default) is intended to restrict crawling to the same site as the base URL. The implementation used String.startsWith() to compare URLs, which does not perform semantic URL validation. An attacker who controls content on a crawled page could include links to domains that share a string prefix with the target, causing the crawler to follow links to attacker-controlled or internal infrastructure. Additionally, the crawler performed no validation against private or reserved IP addresses. A crawled page could include links targeting cloud metadata services, localhost, or RFC 1918 addresses, and the crawler would fetch them without restriction. This vulnerability is fixed in 1.1.14."
},
"defaultConfiguration": {
"level": "warning"
},
"helpUri": "https://avd.aquasec.com/nvd/cve-2026-26019",
"help": {
"text": "Vulnerability CVE-2026-26019\nSeverity: MEDIUM\nPackage: @langchain/community\nFixed Version: 1.1.14\nLink: [CVE-2026-26019](https://avd.aquasec.com/nvd/cve-2026-26019)\nLangChain is a framework for building LLM-powered applications. Prior to 1.1.14, the RecursiveUrlLoader class in @langchain/community is a web crawler that recursively follows links from a starting URL. Its preventOutside option (enabled by default) is intended to restrict crawling to the same site as the base URL. The implementation used String.startsWith() to compare URLs, which does not perform semantic URL validation. An attacker who controls content on a crawled page could include links to domains that share a string prefix with the target, causing the crawler to follow links to attacker-controlled or internal infrastructure. Additionally, the crawler performed no validation against private or reserved IP addresses. A crawled page could include links targeting cloud metadata services, localhost, or RFC 1918 addresses, and the crawler would fetch them without restriction. This vulnerability is fixed in 1.1.14.",
"markdown": "**Vulnerability CVE-2026-26019**\n| Severity | Package | Fixed Version | Link |\n| --- | --- | --- | --- |\n|MEDIUM|@langchain/community|1.1.14|[CVE-2026-26019](https://avd.aquasec.com/nvd/cve-2026-26019)|\n\nLangChain is a framework for building LLM-powered applications. Prior to 1.1.14, the RecursiveUrlLoader class in @langchain/community is a web crawler that recursively follows links from a starting URL. Its preventOutside option (enabled by default) is intended to restrict crawling to the same site as the base URL. The implementation used String.startsWith() to compare URLs, which does not perform semantic URL validation. An attacker who controls content on a crawled page could include links to domains that share a string prefix with the target, causing the crawler to follow links to attacker-controlled or internal infrastructure. Additionally, the crawler performed no validation against private or reserved IP addresses. A crawled page could include links targeting cloud metadata services, localhost, or RFC 1918 addresses, and the crawler would fetch them without restriction. This vulnerability is fixed in 1.1.14."
},
"properties": {
"cvssv3_baseScore": 4.1,
"cvssv3_vector": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:N/A:N",
"precision": "very-high",
"security-severity": "4.1",
"tags": ["vulnerability", "security", "MEDIUM"]
}
}
],
"version": "0.69.1"
}
},
"results": [
{
"ruleId": "CVE-2026-26019",
"ruleIndex": 0,
"level": "warning",
"message": {
"text": "Package: @langchain/community\nInstalled Version: 0.3.36\nVulnerability CVE-2026-26019\nSeverity: MEDIUM\nFixed Version: 1.1.14\nLink: [CVE-2026-26019](https://avd.aquasec.com/nvd/cve-2026-26019)"
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "bun.lock",
"uriBaseId": "ROOTPATH"
},
"region": {
"startLine": 104,
"startColumn": 1,
"endLine": 104,
"endColumn": 1
}
},
"message": {
"text": "bun.lock: @langchain/community@0.3.36"
}
}
]
}
]
}
]
}