From cc490bf549d9142cb3a6007f78864dab3bf8c788 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Thu, 27 Nov 2025 11:39:17 +0100 Subject: [PATCH 01/27] Test of AquaSec API --- .github/workflows/trivy_repository_scan.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/trivy_repository_scan.yml b/.github/workflows/trivy_repository_scan.yml index dfe3a26..a030b1b 100644 --- a/.github/workflows/trivy_repository_scan.yml +++ b/.github/workflows/trivy_repository_scan.yml @@ -30,7 +30,11 @@ jobs: trivy fs . \ --format sarif \ --scanners vuln,secret,misconfig,license \ + --sast \ --output trivy_repository_report.sarif + env: + AQUA_KEY: ${{ secrets.AQUA_KEY }} + AQUA_SECRET: ${{ secrets.AQUA_SECRET }} - name: Upload SARIF to GitHub Security Hub uses: github/codeql-action/upload-sarif@v4 From 345b1afcb18962a4d409e17d3c69be70a61f9267 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Thu, 27 Nov 2025 14:45:40 +0100 Subject: [PATCH 02/27] Test of AquaSec API --- .github/workflows/aquasec_repository_scan.yml | 79 ++++++++++ .github/workflows/trivy_repository_scan.yml | 147 ------------------ 2 files changed, 79 insertions(+), 147 deletions(-) create mode 100644 .github/workflows/aquasec_repository_scan.yml delete mode 100644 .github/workflows/trivy_repository_scan.yml diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml new file mode 100644 index 0000000..078a94f --- /dev/null +++ b/.github/workflows/aquasec_repository_scan.yml @@ -0,0 +1,79 @@ +name: AquaSec Full Repository Scan + +on: + workflow_dispatch: + pull_request: + types: [ opened, synchronize ] + +permissions: + contents: read + issues: write + pull-requests: write + security-events: write + +jobs: + aquasec: + name: AquaSec Full Repository Scan + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v5 + with: + persist-credentials: false + fetch-depth: 0 + + - name: Retrieve AquaSec Scan Results + env: + AQUA_KEY: ${{ secrets.AQUA_KEY }} + AQUA_SECRET: ${{ secrets.AQUA_SECRET }} + run: | + echo "=== Authenticating with AquaSec ===" + + TIMESTAMP=$(date +%s) + AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/v2/tokens" + METHOD="POST" + POST_BODY='{"validity":240,"allowed_endpoints":["GET"]}' + STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" + SIGNATURE=$(echo -n "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "$AQUA_SECRET" -hex | sed 's/.*= //g') + + AUTH_RESPONSE=$(curl -s -X POST "$AUTH_ENDPOINT" \ + -H "Content-Type: application/json" \ + -H "X-API-Key: $AQUA_KEY" \ + -H "X-Timestamp: $TIMESTAMP" \ + -H "X-Signature: $SIGNATURE" \ + -d "$POST_BODY") + + RESPONSE_STATUS=$(echo AUTH_RESPONSE | jq -r '.status') + + if [ $RESPONSE_STATUS -eq 200 ]; then + echo "Login successful." + BEARER_TOKEN=$(echo $AUTH_RESPONSE | jq -r '.data') + else + echo "Login failed. Status: $AUTH_RESPONSE" + exit 1 + fi + + echo "=== Getting Repository ID from GitHub ===" + + REPO_ID=$(curl -s "https://api.github.com/repos/${{ github.repository }}" | jq -r '.id') + + if [ -z "$REPO_ID" ] || [ "$REPO_ID" == "null" ]; then + echo "Failed to get repository ID from GitHub" + exit 1 + fi + + echo "=== Receiving AquaSec Scan Results ===" + + SCAN_RESULTS_ENDPOINT="https://eu-central-1.edge.cloud.aquasec.com/codesec/api/v1/scans/results" + SCAN_RESULTS=$(curl -s -X GET \ + "$SCAN_RESULTS_ENDPOINT?repositoryIds=$REPO_ID" \ + -H "Authorization: Bearer $BEARER_TOKEN" \ + -H "Accept: application/json") + + if [ -z "$SCAN_RESULTS" ]; then + echo "Failed to retrieve scan results" + exit 1 + fi + + echo "=== Scan Results ===" + echo "$SCAN_RESULTS" | jq '.' diff --git a/.github/workflows/trivy_repository_scan.yml b/.github/workflows/trivy_repository_scan.yml deleted file mode 100644 index a030b1b..0000000 --- a/.github/workflows/trivy_repository_scan.yml +++ /dev/null @@ -1,147 +0,0 @@ -name: Trivy Full Repository Scan - -on: - workflow_dispatch: - pull_request: - types: [ opened, synchronize ] - -permissions: - contents: read - issues: write - pull-requests: write - security-events: write - -jobs: - trivy: - name: Trivy Full Repository Scan - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v5 - with: - persist-credentials: false - fetch-depth: 0 - - - name: Setup Trivy - uses: aquasecurity/setup-trivy@v0.2.4 - - - name: Run Trivy filesystem scan - run: | - trivy fs . \ - --format sarif \ - --scanners vuln,secret,misconfig,license \ - --sast \ - --output trivy_repository_report.sarif - env: - AQUA_KEY: ${{ secrets.AQUA_KEY }} - AQUA_SECRET: ${{ secrets.AQUA_SECRET }} - - - name: Upload SARIF to GitHub Security Hub - uses: github/codeql-action/upload-sarif@v4 - with: - sarif_file: trivy_repository_report.sarif - - - name: Create scan summary table - id: scan_summary_table - run: | - python <<'PY' - import os - import json - import sys - from collections import defaultdict, Counter - - SARIF_PATH = "trivy_repository_report.sarif" - SEVERITIES = ["CRITICAL", "HIGH", "MEDIUM", "LOW"] - CATEGORIES = ["vulnerability", "secret", "misconfiguration", "license"] - - try: - # Parse results from SARIF - with open(SARIF_PATH, "r", encoding="utf-8") as f: - sarif = json.load(f) - - # Validate SARIF structure - if "runs" not in sarif or not sarif["runs"]: - raise ValueError("SARIF file contains no runs") - - run = sarif["runs"][0] - if "tool" not in run or "driver" not in run["tool"]: - raise ValueError("SARIF structure missing expected tool/driver keys") - - rules = run["tool"]["driver"].get("rules", []) - results = run.get("results", []) - category_severity_counts = defaultdict(Counter) - - except (IOError, json.JSONDecodeError, KeyError, ValueError) as e: - print(f"Error processing SARIF file: {e}", file=sys.stderr) - sys.exit(1) - - # Count results by category and severity - for result in results: - try: - rule_idx = result.get("ruleIndex") - if rule_idx is None or rule_idx >= len(rules): - continue - rule = rules[rule_idx] - tags = rule.get("properties", {}).get("tags", []) - # Find category and severity - category = next((c for c in CATEGORIES if c in tags), None) - severity = next((s for s in SEVERITIES if s in tags), None) - if category and severity: - category_severity_counts[category][severity] += 1 - except (KeyError, IndexError, TypeError) as e: - print(f"Warning: Error processing result: {e}", file=sys.stderr) - continue - - # Build Markdown summary table - headers = ["TRIVY"] + SEVERITIES + ["TOTAL"] - summary_table = "| " + " | ".join(headers) + " |\n" - summary_table += "|---|---|---|---|---|---|\n" - - # Rows with counts for each category - total_severity = Counter() - total_all = 0 - for category in CATEGORIES: - row = [category] - category_total = 0 - for severity in SEVERITIES: - count = category_severity_counts[category][severity] - row.append(str(count)) - total_severity[severity] += count - category_total += count - row.append(f"**{category_total}**") - total_all += category_total - summary_table += "| " + " | ".join(row) + " |\n" - - total_row = ["**➡️ Total**"] + [f"**{total_severity[sev]}**" for sev in SEVERITIES] + [f"**{total_all}**"] - summary_table += "| " + " | ".join(total_row) + " |" - - # Set summary table output - try: - if "GITHUB_OUTPUT" in os.environ: - with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f: - f.write("table< Date: Thu, 27 Nov 2025 14:57:43 +0100 Subject: [PATCH 03/27] Test of AquaSec API --- .github/workflows/aquasec_repository_scan.yml | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml index 078a94f..41783ad 100644 --- a/.github/workflows/aquasec_repository_scan.yml +++ b/.github/workflows/aquasec_repository_scan.yml @@ -28,7 +28,7 @@ jobs: AQUA_SECRET: ${{ secrets.AQUA_SECRET }} run: | echo "=== Authenticating with AquaSec ===" - + TIMESTAMP=$(date +%s) AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/v2/tokens" METHOD="POST" @@ -42,22 +42,23 @@ jobs: -H "X-Timestamp: $TIMESTAMP" \ -H "X-Signature: $SIGNATURE" \ -d "$POST_BODY") - - RESPONSE_STATUS=$(echo AUTH_RESPONSE | jq -r '.status') - if [ $RESPONSE_STATUS -eq 200 ]; then - echo "Login successful." - BEARER_TOKEN=$(echo $AUTH_RESPONSE | jq -r '.data') + RESPONSE_STATUS=$(echo "$AUTH_RESPONSE" | jq -r '.status') + + if [ "$RESPONSE_STATUS" = "200" ]; then + echo "Login successful." + BEARER_TOKEN=$(echo "$AUTH_RESPONSE" | jq -r '.data') + echo "::add-mask::$BEARER_TOKEN" else - echo "Login failed. Status: $AUTH_RESPONSE" - exit 1 + echo "Login failed" + exit 1 fi echo "=== Getting Repository ID from GitHub ===" REPO_ID=$(curl -s "https://api.github.com/repos/${{ github.repository }}" | jq -r '.id') - if [ -z "$REPO_ID" ] || [ "$REPO_ID" == "null" ]; then + if [ -z "$REPO_ID" ] || [ "$REPO_ID" = "null" ]; then echo "Failed to get repository ID from GitHub" exit 1 fi @@ -76,4 +77,4 @@ jobs: fi echo "=== Scan Results ===" - echo "$SCAN_RESULTS" | jq '.' + echo "$SCAN_RESULTS" | jq '.' \ No newline at end of file From 66f5c8959d611a5e083cbf7a47cea82ddbd6d27d Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Thu, 27 Nov 2025 15:01:55 +0100 Subject: [PATCH 04/27] AquaSec workflow fix --- .github/workflows/aquasec_repository_scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml index 41783ad..d213ac3 100644 --- a/.github/workflows/aquasec_repository_scan.yml +++ b/.github/workflows/aquasec_repository_scan.yml @@ -30,7 +30,7 @@ jobs: echo "=== Authenticating with AquaSec ===" TIMESTAMP=$(date +%s) - AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/v2/tokens" + AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/" METHOD="POST" POST_BODY='{"validity":240,"allowed_endpoints":["GET"]}' STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" From 77f0e240b2ff7b5835957d4ce9be2ffcfcb65a07 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Thu, 27 Nov 2025 15:15:52 +0100 Subject: [PATCH 05/27] AquaSec workflow fix --- .github/workflows/aquasec_repository_scan.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml index d213ac3..4494099 100644 --- a/.github/workflows/aquasec_repository_scan.yml +++ b/.github/workflows/aquasec_repository_scan.yml @@ -29,14 +29,14 @@ jobs: run: | echo "=== Authenticating with AquaSec ===" - TIMESTAMP=$(date +%s) + TIMESTAMP=$(date -u +%s) AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/" METHOD="POST" - POST_BODY='{"validity":240,"allowed_endpoints":["GET"]}' + POST_BODY='{"validity":240,"allowed_endpoints":["GET","POST"]}' STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" SIGNATURE=$(echo -n "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "$AQUA_SECRET" -hex | sed 's/.*= //g') - AUTH_RESPONSE=$(curl -s -X POST "$AUTH_ENDPOINT" \ + AUTH_RESPONSE=$(curl -s -X "$METHOD" "$AUTH_ENDPOINT" \ -H "Content-Type: application/json" \ -H "X-API-Key: $AQUA_KEY" \ -H "X-Timestamp: $TIMESTAMP" \ From 2713be6af852c44273f4a21f5cbcee2b2baa162c Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Thu, 27 Nov 2025 15:24:46 +0100 Subject: [PATCH 06/27] AquaSec workflow fix --- .github/workflows/aquasec_repository_scan.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml index 4494099..f3d166d 100644 --- a/.github/workflows/aquasec_repository_scan.yml +++ b/.github/workflows/aquasec_repository_scan.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false fetch-depth: 0 @@ -28,9 +28,9 @@ jobs: AQUA_SECRET: ${{ secrets.AQUA_SECRET }} run: | echo "=== Authenticating with AquaSec ===" - + TIMESTAMP=$(date -u +%s) - AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/" + AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/v2/tokens" METHOD="POST" POST_BODY='{"validity":240,"allowed_endpoints":["GET","POST"]}' STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" From 83308262330f55c1659a5b220575c4bf5736d4f4 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Thu, 27 Nov 2025 15:26:45 +0100 Subject: [PATCH 07/27] AquaSec workflow fix --- .github/workflows/aquasec_repository_scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml index f3d166d..d615f6b 100644 --- a/.github/workflows/aquasec_repository_scan.yml +++ b/.github/workflows/aquasec_repository_scan.yml @@ -30,7 +30,7 @@ jobs: echo "=== Authenticating with AquaSec ===" TIMESTAMP=$(date -u +%s) - AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/v2/tokens" + AUTH_ENDPOINT="https://api.cloudsploit.com/v2/tokens" METHOD="POST" POST_BODY='{"validity":240,"allowed_endpoints":["GET","POST"]}' STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" From 8d1b523cf01898522500309c5c052ce1adc66419 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Thu, 27 Nov 2025 15:28:56 +0100 Subject: [PATCH 08/27] AquaSec workflow fix --- .github/workflows/aquasec_repository_scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml index d615f6b..b17def9 100644 --- a/.github/workflows/aquasec_repository_scan.yml +++ b/.github/workflows/aquasec_repository_scan.yml @@ -30,7 +30,7 @@ jobs: echo "=== Authenticating with AquaSec ===" TIMESTAMP=$(date -u +%s) - AUTH_ENDPOINT="https://api.cloudsploit.com/v2/tokens" + AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com" METHOD="POST" POST_BODY='{"validity":240,"allowed_endpoints":["GET","POST"]}' STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" From 371f052d60f0cafb6001f53795da57d45d6bc7a6 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Wed, 10 Dec 2025 11:03:34 +0100 Subject: [PATCH 09/27] AquaSec Scan update --- .github/workflows/aquasec_repository_scan.yml | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml index b17def9..1bd2ed3 100644 --- a/.github/workflows/aquasec_repository_scan.yml +++ b/.github/workflows/aquasec_repository_scan.yml @@ -27,20 +27,29 @@ jobs: AQUA_KEY: ${{ secrets.AQUA_KEY }} AQUA_SECRET: ${{ secrets.AQUA_SECRET }} run: | + set -euo pipefail + echo "=== Authenticating with AquaSec ===" - TIMESTAMP=$(date -u +%s) - AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com" METHOD="POST" - POST_BODY='{"validity":240,"allowed_endpoints":["GET","POST"]}' + AUTH_ENDPOINT="https://api.cloudsploit.com/v2/tokens" + TIMESTAMP=$(date -u +%s) + POST_BODY='{ + # 1155 for CAO + "group_id": 1228, + "allowed_endpoints": ["GET", "POST"], + "validity": 240, + "csp_roles": ["developer", "devops"] + }' STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" SIGNATURE=$(echo -n "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "$AQUA_SECRET" -hex | sed 's/.*= //g') + AUTH_RESPONSE=$(curl -s -X "$METHOD" "$AUTH_ENDPOINT" \ -H "Content-Type: application/json" \ -H "X-API-Key: $AQUA_KEY" \ - -H "X-Timestamp: $TIMESTAMP" \ -H "X-Signature: $SIGNATURE" \ + -H "X-Timestamp: $TIMESTAMP" \ -d "$POST_BODY") RESPONSE_STATUS=$(echo "$AUTH_RESPONSE" | jq -r '.status') @@ -54,20 +63,11 @@ jobs: exit 1 fi - echo "=== Getting Repository ID from GitHub ===" - - REPO_ID=$(curl -s "https://api.github.com/repos/${{ github.repository }}" | jq -r '.id') - - if [ -z "$REPO_ID" ] || [ "$REPO_ID" = "null" ]; then - echo "Failed to get repository ID from GitHub" - exit 1 - fi - echo "=== Receiving AquaSec Scan Results ===" SCAN_RESULTS_ENDPOINT="https://eu-central-1.edge.cloud.aquasec.com/codesec/api/v1/scans/results" SCAN_RESULTS=$(curl -s -X GET \ - "$SCAN_RESULTS_ENDPOINT?repositoryIds=$REPO_ID" \ + "$SCAN_RESULTS_ENDPOINT?repositoryIds=${{ github.repository_id }} \ -H "Authorization: Bearer $BEARER_TOKEN" \ -H "Accept: application/json") From 057d3f88b4e0d39f8c8e42b9db804926cb58abd2 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Wed, 10 Dec 2025 11:08:11 +0100 Subject: [PATCH 10/27] AquaSec Scan update --- .github/workflows/aquasec_repository_scan.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml index 1bd2ed3..951f84f 100644 --- a/.github/workflows/aquasec_repository_scan.yml +++ b/.github/workflows/aquasec_repository_scan.yml @@ -35,8 +35,7 @@ jobs: AUTH_ENDPOINT="https://api.cloudsploit.com/v2/tokens" TIMESTAMP=$(date -u +%s) POST_BODY='{ - # 1155 for CAO - "group_id": 1228, + "group_id": 1155, "allowed_endpoints": ["GET", "POST"], "validity": 240, "csp_roles": ["developer", "devops"] From 0d3ff0e6a9c7813d7efb7361b7adad99b3d2cff1 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Wed, 10 Dec 2025 11:14:03 +0100 Subject: [PATCH 11/27] AquaSec Scan update --- .github/workflows/aquasec_repository_scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml index 951f84f..d1684aa 100644 --- a/.github/workflows/aquasec_repository_scan.yml +++ b/.github/workflows/aquasec_repository_scan.yml @@ -32,7 +32,7 @@ jobs: echo "=== Authenticating with AquaSec ===" METHOD="POST" - AUTH_ENDPOINT="https://api.cloudsploit.com/v2/tokens" + AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/v2/tokens" TIMESTAMP=$(date -u +%s) POST_BODY='{ "group_id": 1155, From c099d52979bb6941b801713d610f0a5d7aa3fa90 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Wed, 10 Dec 2025 12:01:28 +0100 Subject: [PATCH 12/27] AquaSec Scan update --- .github/workflows/aquasec_repository_scan.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml index d1684aa..08f3820 100644 --- a/.github/workflows/aquasec_repository_scan.yml +++ b/.github/workflows/aquasec_repository_scan.yml @@ -35,15 +35,13 @@ jobs: AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/v2/tokens" TIMESTAMP=$(date -u +%s) POST_BODY='{ - "group_id": 1155, - "allowed_endpoints": ["GET", "POST"], - "validity": 240, - "csp_roles": ["developer", "devops"] + "group_id": 1228, + "allowed_endpoints": ["GET"], + "validity": 240 }' STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" SIGNATURE=$(echo -n "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "$AQUA_SECRET" -hex | sed 's/.*= //g') - AUTH_RESPONSE=$(curl -s -X "$METHOD" "$AUTH_ENDPOINT" \ -H "Content-Type: application/json" \ -H "X-API-Key: $AQUA_KEY" \ From 445a2d4507da261cea5d9b84dc52b5abfb112457 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Wed, 10 Dec 2025 12:27:48 +0100 Subject: [PATCH 13/27] AquaSec Scan update --- .github/workflows/aquasec_repository_scan.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml index 08f3820..2a98271 100644 --- a/.github/workflows/aquasec_repository_scan.yml +++ b/.github/workflows/aquasec_repository_scan.yml @@ -30,15 +30,12 @@ jobs: set -euo pipefail echo "=== Authenticating with AquaSec ===" + echo "${{ github.repository_id }}" METHOD="POST" AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/v2/tokens" TIMESTAMP=$(date -u +%s) - POST_BODY='{ - "group_id": 1228, - "allowed_endpoints": ["GET"], - "validity": 240 - }' + POST_BODY='{"group_id":1228,"allowed_endpoints":["GET"],"validity":240}' STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" SIGNATURE=$(echo -n "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "$AQUA_SECRET" -hex | sed 's/.*= //g') @@ -54,9 +51,8 @@ jobs: if [ "$RESPONSE_STATUS" = "200" ]; then echo "Login successful." BEARER_TOKEN=$(echo "$AUTH_RESPONSE" | jq -r '.data') - echo "::add-mask::$BEARER_TOKEN" else - echo "Login failed" + echo "Login failed with error message: $(echo "$AUTH_RESPONSE" | jq -r '.errors')" exit 1 fi From a661cb0982e7efaeab551d7af7cc7aa7d070bb0b Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Wed, 10 Dec 2025 14:21:36 +0100 Subject: [PATCH 14/27] AquaSec Scan update --- .github/workflows/aquasec_repository_scan.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml index 2a98271..5d65080 100644 --- a/.github/workflows/aquasec_repository_scan.yml +++ b/.github/workflows/aquasec_repository_scan.yml @@ -26,24 +26,23 @@ jobs: env: AQUA_KEY: ${{ secrets.AQUA_KEY }} AQUA_SECRET: ${{ secrets.AQUA_SECRET }} + REPOSITORY_ID: ${{ secrets.AQUA_REPOSITORY_ID }} run: | set -euo pipefail echo "=== Authenticating with AquaSec ===" - echo "${{ github.repository_id }}" - METHOD="POST" AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/v2/tokens" TIMESTAMP=$(date -u +%s) POST_BODY='{"group_id":1228,"allowed_endpoints":["GET"],"validity":240}' STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" - SIGNATURE=$(echo -n "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "$AQUA_SECRET" -hex | sed 's/.*= //g') + SIGNATURE=$(echo -n "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "${AQUA_SECRET}" -hex | sed 's/.*= //g') - AUTH_RESPONSE=$(curl -s -X "$METHOD" "$AUTH_ENDPOINT" \ + AUTH_RESPONSE=$(curl -s -X $METHOD "$AUTH_ENDPOINT" \ -H "Content-Type: application/json" \ -H "X-API-Key: $AQUA_KEY" \ - -H "X-Signature: $SIGNATURE" \ -H "X-Timestamp: $TIMESTAMP" \ + -H "X-Signature: $SIGNATURE" \ -d "$POST_BODY") RESPONSE_STATUS=$(echo "$AUTH_RESPONSE" | jq -r '.status') @@ -58,9 +57,8 @@ jobs: echo "=== Receiving AquaSec Scan Results ===" - SCAN_RESULTS_ENDPOINT="https://eu-central-1.edge.cloud.aquasec.com/codesec/api/v1/scans/results" - SCAN_RESULTS=$(curl -s -X GET \ - "$SCAN_RESULTS_ENDPOINT?repositoryIds=${{ github.repository_id }} \ + SCAN_RESULTS_ENDPOINT="https://eu-1.codesec.aquasec.com/api/v1/scans/results" + SCAN_RESULTS=$(curl -s -X GET "$SCAN_RESULTS_ENDPOINT?repositoryIds=${REPOSITORY_ID}" \ -H "Authorization: Bearer $BEARER_TOKEN" \ -H "Accept: application/json") @@ -70,4 +68,4 @@ jobs: fi echo "=== Scan Results ===" - echo "$SCAN_RESULTS" | jq '.' \ No newline at end of file + echo "$SCAN_RESULTS" \ No newline at end of file From f92d2d629d7d6fd16bc6fcd5d5ab3d6922323b7c Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Tue, 30 Dec 2025 11:56:10 +0100 Subject: [PATCH 15/27] Fetching aquasec scan data logic + converting logic from json to sarif 2.1.0 format --- .github/workflows/aquasec_repo_scan.yml | 235 ++++++++++++++++++ .github/workflows/aquasec_repository_scan.yml | 71 ------ .gitignore | 3 + 3 files changed, 238 insertions(+), 71 deletions(-) create mode 100644 .github/workflows/aquasec_repo_scan.yml delete mode 100644 .github/workflows/aquasec_repository_scan.yml diff --git a/.github/workflows/aquasec_repo_scan.yml b/.github/workflows/aquasec_repo_scan.yml new file mode 100644 index 0000000..c74c4bb --- /dev/null +++ b/.github/workflows/aquasec_repo_scan.yml @@ -0,0 +1,235 @@ +name: AquaSec Full Repository Scan + +on: + workflow_dispatch: + pull_request: + types: [ opened, synchronize ] + +permissions: + contents: read + issues: write + pull-requests: write + security-events: write + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +jobs: + aquasec: + name: AquaSec Full Repository Scan + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + persist-credentials: false + fetch-depth: 0 + + - name: Retrieve AquaSec Scan Results + env: + AQUA_KEY: ${{ secrets.AQUA_KEY }} + AQUA_SECRET: ${{ secrets.AQUA_SECRET }} + REPOSITORY_ID: ${{ secrets.AQUA_REPOSITORY_ID }} + run: | + set -euo pipefail + + echo "=== Authenticating with AquaSec ===" + METHOD="POST" + AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/v2/tokens" + TIMESTAMP=$(date -u +%s) + POST_BODY='{"group_id":1228,"allowed_endpoints":["GET"],"validity":240}' + STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" + SIGNATURE=$(echo -n "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "${AQUA_SECRET}" -hex | sed 's/.*= //g') + + AUTH_RESPONSE=$(curl -s -X $METHOD "$AUTH_ENDPOINT" \ + -H "Content-Type: application/json" \ + -H "X-API-Key: $AQUA_KEY" \ + -H "X-Timestamp: $TIMESTAMP" \ + -H "X-Signature: $SIGNATURE" \ + -d "$POST_BODY") + + RESPONSE_STATUS=$(echo "$AUTH_RESPONSE" | jq -r '.status') + + if [ "$RESPONSE_STATUS" = "200" ]; then + echo "Login successful." + BEARER_TOKEN=$(echo "$AUTH_RESPONSE" | jq -r '.data') + else + echo "Login failed with error message: $(echo "$AUTH_RESPONSE" | jq -r '.errors')" + exit 1 + fi + + echo "=== Receiving AquaSec Scan Results ===" + + SCAN_RESULTS_ENDPOINT="https://eu-1.codesec.aquasec.com/api/v1/scans/results" + ALL_DATA="[]" + PAGE_NUM=1 + PAGE_SIZE=100 + TOTAL_EXPECTED=0 + + while true; do + echo "Fetching page $PAGE_NUM..." + + REQUEST_URL="${SCAN_RESULTS_ENDPOINT}?repositoryIds=${REPOSITORY_ID}&size=${PAGE_SIZE}&page=${PAGE_NUM}" + + PAGE_RESPONSE=$(curl -s -X GET "$REQUEST_URL" \ + -H "Authorization: Bearer $BEARER_TOKEN" \ + -H "Accept: application/json") + + if [ -z "$PAGE_RESPONSE" ]; then + echo "Failed to retrieve scan results on page $PAGE_NUM" + exit 1 + fi + + if [ $PAGE_NUM -eq 1 ]; then + TOTAL_EXPECTED=$(echo "$PAGE_RESPONSE" | jq -r '.total // 0') + echo "Total findings expected: $TOTAL_EXPECTED" + fi + + PAGE_DATA=$(echo "$PAGE_RESPONSE" | jq -c '.data // []') + PAGE_COUNT=$(echo "$PAGE_DATA" | jq 'length') + echo "Retrieved $PAGE_COUNT findings on page $PAGE_NUM" + + ALL_DATA=$(echo "$ALL_DATA" "$PAGE_DATA" | jq -s 'add') + + TOTAL_RETRIEVED=$(echo "$ALL_DATA" | jq 'length') + + if [ "$TOTAL_RETRIEVED" -ge "$TOTAL_EXPECTED" ] || [ "$PAGE_COUNT" -eq 0 ]; then + break + fi + + PAGE_NUM=$((PAGE_NUM + 1)) + sleep 2 + done + + TOTAL_RETRIEVED=$(echo "$ALL_DATA" | jq 'length') + echo "Total findings retrieved: $TOTAL_RETRIEVED" + + jq -n --argjson total "$TOTAL_RETRIEVED" --argjson data "$ALL_DATA" \ + '{"total": $total, "size": $total, "page": 1, "data": $data}' > aquasec_scan_results.json + + echo "Full repository scan retrieved successfully" + + - name: Convert to SARIF 2.1.0 + shell: python + run: | + import json + + print("=== Converting Scan Result to SARIF Format ===") + + # Severity mapping: SARIF level, security-severity, severity tag + SEVERITY_MAP = { + 1: ("note", "2.0", "LOW"), + 2: ("warning", "5.5", "MEDIUM"), + 3: ("error", "8.0", "HIGH"), + 4: ("error", "9.5", "CRITICAL"), + } + + # Truncate text to follow with GitHub SARIF field limits + def truncate(text, max_len=1024): + if not text: + return "Security issue detected" + return text[:max_len] if len(text) > max_len else text + + with open("aquasec_scan_results.json", "r") as f: + data = json.load(f) + + aquasec_findings = data.get("data", []) + rule_index_lookup = {} + sarif_unique_rules = [] + sarif_findings = [] + + for finding in aquasec_findings: + target_file = finding.get("target_file", "") + avd_id = finding.get("avd_id", "") + severity = finding.get("severity", 1) + level, sec_severity, sev_tag = SEVERITY_MAP.get(severity, SEVERITY_MAP[1]) + title = finding.get("title", "") + message = finding.get("message", "") + extra = finding.get("extraData", {}) + category = finding.get("category", "") + + if avd_id not in rule_index_lookup: + tags = [category, "security", sev_tag] + + refs = extra.get("references", []) + remediation = extra.get("remediation", "") + + rule = { + "id": avd_id, + "name": category, + "shortDescription": {"text": truncate(title)}, + "fullDescription": {"text": truncate(message)}, + "defaultConfiguration": {"level": level}, + "help": { + "text": truncate(remediation), + "markdown": f"**{category} {avd_id}**\n| Severity | Check | Message |\n| --- | --- | --- |\n|{sev_tag}|{truncate(title, 100)}|{truncate(message, 200)}|" + }, + "properties": { + "precision": "very-high", + "security-severity": sec_severity, + "tags": tags + } + } + + if refs: + rule["helpUri"] = refs[0] + + rule_index_lookup[avd_id] = len(sarif_unique_rules) + sarif_unique_rules.append(rule) + + # Sanitize security finding line numbers to please SARIF schema + start_line = finding.get("target_start_line") + if not start_line or start_line < 1: + start_line = 1 + end_line = finding.get("target_end_line") + if not end_line or end_line < start_line: + end_line = start_line + + sarif_finding = { + "ruleId": avd_id, + "ruleIndex": rule_index_lookup[avd_id], + "level": level, + "message": {"text": truncate(message)}, + "locations": [{ + "physicalLocation": { + "artifactLocation": {"uri": target_file}, + "region": {"startLine": start_line, "endLine": end_line} + } + }] + } + + # Add finding unique hash for cross-scan deduplication + finding_hash = finding.get("result_hash") + if finding_hash: + sarif_finding["partialFingerprints"] = {"primaryLocationLineHash": finding_hash[:64]} + + sarif_findings.append(sarif_finding) + + sarif_output = { + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json", + "version": "2.1.0", + "runs": [{ + "tool": { + "driver": { + "fullName": "AquaSec Security Scanner", + "informationUri": "https://www.aquasec.com/", + "name": "AquaSec", + "version": "1.0.0", + "rules": sarif_unique_rules + } + }, + "results": sarif_findings + }] + } + + with open("aquasec_scan.sarif", "w") as f: + json.dump(sarif_output, f) + + print(f"Converted {len(sarif_findings)} findings to SARIF 2.1.0 format") + + - name: Upload Scan Results to GitHub Security + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: aquasec_scan.sarif + category: aquasec diff --git a/.github/workflows/aquasec_repository_scan.yml b/.github/workflows/aquasec_repository_scan.yml deleted file mode 100644 index 5d65080..0000000 --- a/.github/workflows/aquasec_repository_scan.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: AquaSec Full Repository Scan - -on: - workflow_dispatch: - pull_request: - types: [ opened, synchronize ] - -permissions: - contents: read - issues: write - pull-requests: write - security-events: write - -jobs: - aquasec: - name: AquaSec Full Repository Scan - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v6 - with: - persist-credentials: false - fetch-depth: 0 - - - name: Retrieve AquaSec Scan Results - env: - AQUA_KEY: ${{ secrets.AQUA_KEY }} - AQUA_SECRET: ${{ secrets.AQUA_SECRET }} - REPOSITORY_ID: ${{ secrets.AQUA_REPOSITORY_ID }} - run: | - set -euo pipefail - - echo "=== Authenticating with AquaSec ===" - METHOD="POST" - AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/v2/tokens" - TIMESTAMP=$(date -u +%s) - POST_BODY='{"group_id":1228,"allowed_endpoints":["GET"],"validity":240}' - STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" - SIGNATURE=$(echo -n "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "${AQUA_SECRET}" -hex | sed 's/.*= //g') - - AUTH_RESPONSE=$(curl -s -X $METHOD "$AUTH_ENDPOINT" \ - -H "Content-Type: application/json" \ - -H "X-API-Key: $AQUA_KEY" \ - -H "X-Timestamp: $TIMESTAMP" \ - -H "X-Signature: $SIGNATURE" \ - -d "$POST_BODY") - - RESPONSE_STATUS=$(echo "$AUTH_RESPONSE" | jq -r '.status') - - if [ "$RESPONSE_STATUS" = "200" ]; then - echo "Login successful." - BEARER_TOKEN=$(echo "$AUTH_RESPONSE" | jq -r '.data') - else - echo "Login failed with error message: $(echo "$AUTH_RESPONSE" | jq -r '.errors')" - exit 1 - fi - - echo "=== Receiving AquaSec Scan Results ===" - - SCAN_RESULTS_ENDPOINT="https://eu-1.codesec.aquasec.com/api/v1/scans/results" - SCAN_RESULTS=$(curl -s -X GET "$SCAN_RESULTS_ENDPOINT?repositoryIds=${REPOSITORY_ID}" \ - -H "Authorization: Bearer $BEARER_TOKEN" \ - -H "Accept: application/json") - - if [ -z "$SCAN_RESULTS" ]; then - echo "Failed to retrieve scan results" - exit 1 - fi - - echo "=== Scan Results ===" - echo "$SCAN_RESULTS" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4c9edc4..02fafe6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ __pycache__ # Terraform Plan output files *.sarif + +# Development script +run.sh From 0ec7cecd5ec93d56c2610253a3beaadbf08edf5d Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Tue, 30 Dec 2025 15:06:55 +0100 Subject: [PATCH 16/27] Scan summary table for GH comment logic --- .github/workflows/aquasec_repo_scan.yml | 115 ++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 9 deletions(-) diff --git a/.github/workflows/aquasec_repo_scan.yml b/.github/workflows/aquasec_repo_scan.yml index c74c4bb..ad78808 100644 --- a/.github/workflows/aquasec_repo_scan.yml +++ b/.github/workflows/aquasec_repo_scan.yml @@ -16,7 +16,7 @@ concurrency: cancel-in-progress: true jobs: - aquasec: + aquasec-scanning: name: AquaSec Full Repository Scan runs-on: ubuntu-latest steps: @@ -62,7 +62,7 @@ jobs: echo "=== Receiving AquaSec Scan Results ===" SCAN_RESULTS_ENDPOINT="https://eu-1.codesec.aquasec.com/api/v1/scans/results" - ALL_DATA="[]" + FINDINGS_JSON="[]" PAGE_NUM=1 PAGE_SIZE=100 TOTAL_EXPECTED=0 @@ -90,11 +90,11 @@ jobs: PAGE_COUNT=$(echo "$PAGE_DATA" | jq 'length') echo "Retrieved $PAGE_COUNT findings on page $PAGE_NUM" - ALL_DATA=$(echo "$ALL_DATA" "$PAGE_DATA" | jq -s 'add') + FINDINGS_JSON=$(echo "FINDINGS_JSON" "$PAGE_DATA" | jq -s 'add') - TOTAL_RETRIEVED=$(echo "$ALL_DATA" | jq 'length') + FINDINGS_COUNT=$(echo "FINDINGS_JSON" | jq 'length') - if [ "$TOTAL_RETRIEVED" -ge "$TOTAL_EXPECTED" ] || [ "$PAGE_COUNT" -eq 0 ]; then + if [ "FINDINGS_COUNT" -ge "$TOTAL_EXPECTED" ] || [ "$PAGE_COUNT" -eq 0 ]; then break fi @@ -102,10 +102,10 @@ jobs: sleep 2 done - TOTAL_RETRIEVED=$(echo "$ALL_DATA" | jq 'length') - echo "Total findings retrieved: $TOTAL_RETRIEVED" + FINDINGS_COUNT=$(echo "FINDINGS_JSON" | jq 'length') + echo "Total findings retrieved: FINDINGS_COUNT" - jq -n --argjson total "$TOTAL_RETRIEVED" --argjson data "$ALL_DATA" \ + jq -n --argjson total "FINDINGS_COUNT" --argjson data "FINDINGS_JSON" \ '{"total": $total, "size": $total, "page": 1, "data": $data}' > aquasec_scan_results.json echo "Full repository scan retrieved successfully" @@ -224,7 +224,7 @@ jobs: } with open("aquasec_scan.sarif", "w") as f: - json.dump(sarif_output, f) + json.dump(sarif_output, f, indent=2) print(f"Converted {len(sarif_findings)} findings to SARIF 2.1.0 format") @@ -233,3 +233,100 @@ jobs: with: sarif_file: aquasec_scan.sarif category: aquasec + + - name: Create Scan Summary Table + id: scan_summary_table + shell: python + run: | + import os + import json + import sys + from collections import Counter + + SARIF_PATH = "aquasec_scan.sarif" + SEVERITIES = ["CRITICAL", "HIGH", "MEDIUM", "LOW"] + CATEGORIES = ["sast", "vulnerabilities", "iacMisconfigurations", "secrets", "pipelineMisconfigurations", "license"] + + print("=== Generating Scan Summary Table ===") + try: + with open(SARIF_PATH, "r", encoding="utf-8") as f: + sarif = json.load(f) + + if "runs" not in sarif or not sarif["runs"]: + raise ValueError("SARIF file contains no runs") + + run = sarif["runs"][0] + rules = run.get("tool", {}).get("driver", {}).get("rules", []) + results = run.get("results", []) + + except (IOError, json.JSONDecodeError, ValueError) as e: + print(f"Error processing SARIF file: {e}", file=sys.stderr) + sys.exit(1) + + # Initialize counters for each category + category_severity_counts = {cat: Counter() for cat in CATEGORIES} + + # Count results by category and severity + for result in results: + rule_idx = result.get("ruleIndex") + if rule_idx is None or rule_idx >= len(rules): + continue + + rule = rules[rule_idx] + category = rule.get("name", "") + tags = rule.get("properties", {}).get("tags", []) + severity = next((s for s in SEVERITIES if s in tags), None) + + if category in CATEGORIES and severity: + category_severity_counts[category][severity] += 1 + + # Build Markdown summary table + headers = ["AQUASEC"] + SEVERITIES + ["TOTAL"] + summary_table = "| " + " | ".join(headers) + " |\n" + summary_table += "|---|---|---|---|---|---|\n" + + total_severity = Counter() + total_all = 0 + for category in CATEGORIES: + row = [category] + category_total = 0 + for severity in SEVERITIES: + count = category_severity_counts[category][severity] + row.append(str(count)) + total_severity[severity] += count + category_total += count + row.append(f"**{category_total}**") + total_all += category_total + summary_table += "| " + " | ".join(row) + " |\n" + + total_row = ["**➡️ Total**"] + [f"**{total_severity[sev]}**" for sev in SEVERITIES] + [f"**{total_all}**"] + summary_table += "| " + " | ".join(total_row) + " |" + + try: + if "GITHUB_OUTPUT" in os.environ: + with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f: + f.write("table< Date: Tue, 30 Dec 2025 15:13:56 +0100 Subject: [PATCH 17/27] Bug fix --- .github/workflows/aquasec_repo_scan.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/aquasec_repo_scan.yml b/.github/workflows/aquasec_repo_scan.yml index ad78808..651d5d2 100644 --- a/.github/workflows/aquasec_repo_scan.yml +++ b/.github/workflows/aquasec_repo_scan.yml @@ -90,11 +90,11 @@ jobs: PAGE_COUNT=$(echo "$PAGE_DATA" | jq 'length') echo "Retrieved $PAGE_COUNT findings on page $PAGE_NUM" - FINDINGS_JSON=$(echo "FINDINGS_JSON" "$PAGE_DATA" | jq -s 'add') + FINDINGS_JSON=$(echo "$FINDINGS_JSON" "$PAGE_DATA" | jq -s 'add') - FINDINGS_COUNT=$(echo "FINDINGS_JSON" | jq 'length') + FINDINGS_COUNT=$(echo "$FINDINGS_JSON" | jq 'length') - if [ "FINDINGS_COUNT" -ge "$TOTAL_EXPECTED" ] || [ "$PAGE_COUNT" -eq 0 ]; then + if [ "$FINDINGS_COUNT" -ge "$TOTAL_EXPECTED" ] || [ "$PAGE_COUNT" -eq 0 ]; then break fi @@ -102,10 +102,10 @@ jobs: sleep 2 done - FINDINGS_COUNT=$(echo "FINDINGS_JSON" | jq 'length') - echo "Total findings retrieved: FINDINGS_COUNT" + FINDINGS_COUNT=$(echo "$FINDINGS_JSON" | jq 'length') + echo "Total findings retrieved: $FINDINGS_COUNT" - jq -n --argjson total "FINDINGS_COUNT" --argjson data "FINDINGS_JSON" \ + jq -n --argjson total "$FINDINGS_COUNT" --argjson data "$FINDINGS_JSON" \ '{"total": $total, "size": $total, "page": 1, "data": $data}' > aquasec_scan_results.json echo "Full repository scan retrieved successfully" From 02a236b76183dbb3e7a8998730b09244fce0606c Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Tue, 30 Dec 2025 15:16:27 +0100 Subject: [PATCH 18/27] Bug fix --- .github/workflows/aquasec_repo_scan.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/aquasec_repo_scan.yml b/.github/workflows/aquasec_repo_scan.yml index 651d5d2..3291ec8 100644 --- a/.github/workflows/aquasec_repo_scan.yml +++ b/.github/workflows/aquasec_repo_scan.yml @@ -81,8 +81,19 @@ jobs: exit 1 fi + # Check if response is valid JSON + if ! echo "$PAGE_RESPONSE" | jq empty 2>/dev/null; then + echo "Invalid JSON response from API:" + echo "$PAGE_RESPONSE" + exit 1 + fi + if [ $PAGE_NUM -eq 1 ]; then TOTAL_EXPECTED=$(echo "$PAGE_RESPONSE" | jq -r '.total // 0') + if ! [[ "$TOTAL_EXPECTED" =~ ^[0-9]+$ ]]; then + echo "Error: Invalid total value from API: $TOTAL_EXPECTED" + exit 1 + fi echo "Total findings expected: $TOTAL_EXPECTED" fi From 61cc54f72ee7aa765ab401f09d434aadb46dd009 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Tue, 30 Dec 2025 15:19:10 +0100 Subject: [PATCH 19/27] Revert "Bug fix" This reverts commit 02a236b76183dbb3e7a8998730b09244fce0606c. --- .github/workflows/aquasec_repo_scan.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.github/workflows/aquasec_repo_scan.yml b/.github/workflows/aquasec_repo_scan.yml index 3291ec8..651d5d2 100644 --- a/.github/workflows/aquasec_repo_scan.yml +++ b/.github/workflows/aquasec_repo_scan.yml @@ -81,19 +81,8 @@ jobs: exit 1 fi - # Check if response is valid JSON - if ! echo "$PAGE_RESPONSE" | jq empty 2>/dev/null; then - echo "Invalid JSON response from API:" - echo "$PAGE_RESPONSE" - exit 1 - fi - if [ $PAGE_NUM -eq 1 ]; then TOTAL_EXPECTED=$(echo "$PAGE_RESPONSE" | jq -r '.total // 0') - if ! [[ "$TOTAL_EXPECTED" =~ ^[0-9]+$ ]]; then - echo "Error: Invalid total value from API: $TOTAL_EXPECTED" - exit 1 - fi echo "Total findings expected: $TOTAL_EXPECTED" fi From b383bcedf5e6896c6c20bb14d25c25eecd34ea65 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Tue, 30 Dec 2025 15:28:06 +0100 Subject: [PATCH 20/27] Bug fix --- .github/workflows/aquasec_repo_scan.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/aquasec_repo_scan.yml b/.github/workflows/aquasec_repo_scan.yml index 651d5d2..fbf6436 100644 --- a/.github/workflows/aquasec_repo_scan.yml +++ b/.github/workflows/aquasec_repo_scan.yml @@ -34,7 +34,15 @@ jobs: run: | set -euo pipefail + echo "=== Validating secret variables ===" + + if ! [[ "$REPOSITORY_ID" =~ ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$ ]]; then + echo "Error: AQUA_REPOSITORY_ID is not a valid UUID format" + exit 1 + fi + echo "=== Authenticating with AquaSec ===" + METHOD="POST" AUTH_ENDPOINT="https://eu-1.api.cloudsploit.com/v2/tokens" TIMESTAMP=$(date -u +%s) @@ -248,6 +256,7 @@ jobs: CATEGORIES = ["sast", "vulnerabilities", "iacMisconfigurations", "secrets", "pipelineMisconfigurations", "license"] print("=== Generating Scan Summary Table ===") + try: with open(SARIF_PATH, "r", encoding="utf-8") as f: sarif = json.load(f) From 9ebfc658ddc528132faae996f099cb01d3756118 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Tue, 30 Dec 2025 15:49:39 +0100 Subject: [PATCH 21/27] Code rabbit suggestions implemented --- .github/workflows/aquasec_repo_scan.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/aquasec_repo_scan.yml b/.github/workflows/aquasec_repo_scan.yml index fbf6436..ea3eac9 100644 --- a/.github/workflows/aquasec_repo_scan.yml +++ b/.github/workflows/aquasec_repo_scan.yml @@ -50,7 +50,7 @@ jobs: STRING_TO_SIGN="${TIMESTAMP}${METHOD}/v2/tokens${POST_BODY}" SIGNATURE=$(echo -n "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "${AQUA_SECRET}" -hex | sed 's/.*= //g') - AUTH_RESPONSE=$(curl -s -X $METHOD "$AUTH_ENDPOINT" \ + AUTH_RESPONSE=$(curl -s --max-time 30 -X $METHOD "$AUTH_ENDPOINT" \ -H "Content-Type: application/json" \ -H "X-API-Key: $AQUA_KEY" \ -H "X-Timestamp: $TIMESTAMP" \ @@ -80,7 +80,7 @@ jobs: REQUEST_URL="${SCAN_RESULTS_ENDPOINT}?repositoryIds=${REPOSITORY_ID}&size=${PAGE_SIZE}&page=${PAGE_NUM}" - PAGE_RESPONSE=$(curl -s -X GET "$REQUEST_URL" \ + PAGE_RESPONSE=$(curl -s --max-time 30 -X GET "$REQUEST_URL" \ -H "Authorization: Bearer $BEARER_TOKEN" \ -H "Accept: application/json") @@ -326,14 +326,16 @@ jobs: - name: GitHub scan summary comment if: github.event_name == 'pull_request' uses: actions/github-script@v8 + env: + SUMMARY_TABLE: ${{ steps.scan_summary_table.outputs.table }} with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const link = `https://github.com/${context.repo.owner}/${context.repo.repo}/security/code-scanning?query=pr%3A${context.issue.number}+is%3Aopen`; const sentence = `AquaSec has completed a full security repository scan ✅ You can find the analysis results for this PR branch on [this overview](${link}).\n Below is the summary of the findings:`; - const summaryTable = `${{ steps.scan_summary_table.outputs.table }}`; - const body = `${sentence}\n\n${summaryTable}`; - github.rest.issues.createComment({ + const summaryTable = process.env.SUMMARY_TABLE; + const body = sentence + "\n\n" + summaryTable; + await github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, From a692286131047f3ecb3bba0d6c198c82a0c86505 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Tue, 30 Dec 2025 15:57:09 +0100 Subject: [PATCH 22/27] Generated comment bug fixes --- .github/workflows/aquasec_repo_scan.yml | 31 +++++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/.github/workflows/aquasec_repo_scan.yml b/.github/workflows/aquasec_repo_scan.yml index ea3eac9..a9d465c 100644 --- a/.github/workflows/aquasec_repo_scan.yml +++ b/.github/workflows/aquasec_repo_scan.yml @@ -12,7 +12,7 @@ permissions: security-events: write concurrency: - group: ${{ github.ref }} + group: aquasec-scan-${{ github.ref }} cancel-in-progress: true jobs: @@ -331,13 +331,34 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | + const marker = ''; const link = `https://github.com/${context.repo.owner}/${context.repo.repo}/security/code-scanning?query=pr%3A${context.issue.number}+is%3Aopen`; const sentence = `AquaSec has completed a full security repository scan ✅ You can find the analysis results for this PR branch on [this overview](${link}).\n Below is the summary of the findings:`; const summaryTable = process.env.SUMMARY_TABLE; - const body = sentence + "\n\n" + summaryTable; - await github.rest.issues.createComment({ - issue_number: context.issue.number, + const body = marker + "\n" + sentence + "\n\n" + summaryTable; + + // Find existing comment + const { data: comments } = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, - body + issue_number: context.issue.number }); + + const existingComment = comments.find(c => c.body.includes(marker)); + + // Create a new comment or update existing one + if (existingComment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existingComment.id, + body + }); + } else { + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body + }); + } From 0d9ddf07539882496a58e293b739e5a9c723fa60 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Tue, 30 Dec 2025 16:07:48 +0100 Subject: [PATCH 23/27] Letting fingerprint logic on GH side --- .github/workflows/aquasec_repo_scan.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/aquasec_repo_scan.yml b/.github/workflows/aquasec_repo_scan.yml index a9d465c..5c83708 100644 --- a/.github/workflows/aquasec_repo_scan.yml +++ b/.github/workflows/aquasec_repo_scan.yml @@ -207,11 +207,6 @@ jobs: }] } - # Add finding unique hash for cross-scan deduplication - finding_hash = finding.get("result_hash") - if finding_hash: - sarif_finding["partialFingerprints"] = {"primaryLocationLineHash": finding_hash[:64]} - sarif_findings.append(sarif_finding) sarif_output = { From a9aca29df4f1a6dc0518b7164fbe10b6f46696ce Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Wed, 7 Jan 2026 11:02:55 +0100 Subject: [PATCH 24/27] Deleting obsolete trivy solution from the project --- .github/workflows/check_docker.yml | 79 --------------------------- .github/workflows/check_terraform.yml | 27 --------- .trivyignore | 9 --- trivy-secret.yaml | 27 --------- 4 files changed, 142 deletions(-) delete mode 100644 .github/workflows/check_docker.yml delete mode 100644 .trivyignore delete mode 100644 trivy-secret.yaml diff --git a/.github/workflows/check_docker.yml b/.github/workflows/check_docker.yml deleted file mode 100644 index 0fca2b3..0000000 --- a/.github/workflows/check_docker.yml +++ /dev/null @@ -1,79 +0,0 @@ -# TODO: Trivy scan for Dockerfile will be enabled in the upcoming issue: https://github.com/AbsaOSS/EventGate/issues/74 -#name: Docker Check -# -#on: -# pull_request: -# types: [ opened, synchronize, reopened ] -# push: -# branches: [ master ] -# workflow_dispatch: -# -#concurrency: -# group: static-docker-check-${{ github.ref }} -# cancel-in-progress: true -# -#permissions: -# contents: read -# security-events: write -# -#jobs: -# detect: -# name: Docker Changes Detection -# runs-on: ubuntu-latest -# outputs: -# docker_changed: ${{ steps.changes.outputs.docker_changed }} -# steps: -# - name: Checkout repository -# uses: actions/checkout@v5 -# with: -# persist-credentials: false -# fetch-depth: 0 -# -# - name: Check if docker file changed -# id: changes -# shell: bash -# run: | -# if [[ "${{ github.event_name }}" == "pull_request" ]]; then -# RANGE="${{ github.event.pull_request.base.sha }}...${{ github.sha }}" -# else -# RANGE="${{ github.sha }}~1...${{ github.sha }}" -# fi -# if git diff --name-only "$RANGE" | grep -qE '^Dockerfile$'; then -# echo "docker_changed=true" >> "$GITHUB_OUTPUT" -# else -# echo "docker_changed=false" >> "$GITHUB_OUTPUT" -# fi -# -# trivy-docker: -# name: Trivy Security Scan -# needs: detect -# if: needs.detect.outputs.docker_changed == 'true' -# runs-on: ubuntu-latest -# steps: -# - name: Checkout repository -# uses: actions/checkout@v5 -# with: -# persist-credentials: false -# fetch-depth: 0 -# -# - name: Setup Trivy -# uses: aquasecurity/setup-trivy@v0.2.4 -# -# - name: Trivy security scan -# run: | -# trivy config Dockerfile \ -# --format sarif \ -# --output $GITHUB_WORKSPACE/trivy_dockerfile.sarif -# -# - name: Upload Dockerfile SARIF -# uses: github/codeql-action/upload-sarif@v4 -# with: -# sarif_file: ${{ github.workspace }}/trivy_dockerfile.sarif -# -# noop: -# name: No Operation -# needs: detect -# if: needs.detect.outputs.docker_changed != 'true' -# runs-on: ubuntu-latest -# steps: -# - run: echo "No changes in the Dockerfile — passing." diff --git a/.github/workflows/check_terraform.yml b/.github/workflows/check_terraform.yml index ece21ab..40b4889 100644 --- a/.github/workflows/check_terraform.yml +++ b/.github/workflows/check_terraform.yml @@ -73,33 +73,6 @@ jobs: with: sarif_file: ${{ github.workspace }}/tflint_terraform.sarif -# TODO: Trivy scan for changed Terraform files will be enabled in the upcoming issue: https://github.com/AbsaOSS/EventGate/issues/74 -# trivy-terraform: -# name: Trivy Security Scan -# needs: detect -# if: needs.detect.outputs.terraform_changed == 'true' -# runs-on: ubuntu-latest -# steps: -# - name: Checkout repository -# uses: actions/checkout@v5 -# with: -# persist-credentials: false -# fetch-depth: 0 -# -# - name: Setup Trivy -# uses: aquasecurity/setup-trivy@v0.2.4 -# -# - name: Trivy security scan -# run: | -# trivy fs terraform/ \ -# --format sarif \ -# --output $GITHUB_WORKSPACE/trivy_terraform.sarif -# -# - name: Upload Terraform SARIF -# uses: github/codeql-action/upload-sarif@v4 -# with: -# sarif_file: ${{ github.workspace }}/trivy_terraform.sarif - noop: name: No Operation needs: detect diff --git a/.trivyignore b/.trivyignore deleted file mode 100644 index aa533b7..0000000 --- a/.trivyignore +++ /dev/null @@ -1,9 +0,0 @@ -# Critical issues -AVD-AWS-0104 - -# High issues -AVD-DS-0002 -AVD-DS-0019 - -# Medium issues -AVD-DS-0013 diff --git a/trivy-secret.yaml b/trivy-secret.yaml deleted file mode 100644 index 7613558..0000000 --- a/trivy-secret.yaml +++ /dev/null @@ -1,27 +0,0 @@ -rules: - - id: password-plaintext-assignment - category: exposed_credential - title: Plaintext password literal - severity: HIGH - keywords: - - password - regex: (?i)(["']?\w*password\w*["']?\s*[:=]\s*.+) - - - id: secret-plaintext-assignment - category: exposed_credential - title: Plaintext secret literal - severity: HIGH - keywords: - - secret - regex: (?i)(["']?\w*secret\w*["']?\s*[:=]\s*.+) - -enable-builtin-rules: - - aws-access-key-id - - aws-account-id - - aws-secret-access-key - - github-pat - - github-oauth - - github-app-token - - github-refresh-token - - github-fine-grained-pat - - gitlab-pat From 7a580f0e6d6332aa53573c04f5b9af702304f6d1 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Wed, 7 Jan 2026 11:21:18 +0100 Subject: [PATCH 25/27] Reacting on the comments to implement SHA into the workflows --- .github/workflows/aquasec_repo_scan.yml | 6 +++--- .github/workflows/check_python.yml | 18 +++++++++--------- .github/workflows/check_terraform.yml | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/aquasec_repo_scan.yml b/.github/workflows/aquasec_repo_scan.yml index 5c83708..72f2805 100644 --- a/.github/workflows/aquasec_repo_scan.yml +++ b/.github/workflows/aquasec_repo_scan.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v8e8c483db84b4bee98b60c0593521ed34d9990e8 with: persist-credentials: false fetch-depth: 0 @@ -232,7 +232,7 @@ jobs: print(f"Converted {len(sarif_findings)} findings to SARIF 2.1.0 format") - name: Upload Scan Results to GitHub Security - uses: github/codeql-action/upload-sarif@v4 + uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb with: sarif_file: aquasec_scan.sarif category: aquasec @@ -320,7 +320,7 @@ jobs: - name: GitHub scan summary comment if: github.event_name == 'pull_request' - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd env: SUMMARY_TABLE: ${{ steps.scan_summary_table.outputs.table }} with: diff --git a/.github/workflows/check_python.yml b/.github/workflows/check_python.yml index e07f10d..e1db2a3 100644 --- a/.github/workflows/check_python.yml +++ b/.github/workflows/check_python.yml @@ -23,7 +23,7 @@ jobs: python_changed: ${{ steps.changes.outputs.python_changed }} steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 with: persist-credentials: false fetch-depth: 0 @@ -50,13 +50,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 with: persist-credentials: false fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 with: python-version: '3.13' cache: 'pip' @@ -86,13 +86,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 with: persist-credentials: false fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 with: python-version: '3.13' cache: 'pip' @@ -111,12 +111,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 with: persist-credentials: false fetch-depth: 0 - - uses: actions/setup-python@v6 + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 with: python-version: '3.13' cache: 'pip' @@ -134,13 +134,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 with: persist-credentials: false fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 with: python-version: '3.13' cache: 'pip' diff --git a/.github/workflows/check_terraform.yml b/.github/workflows/check_terraform.yml index 40b4889..154fd82 100644 --- a/.github/workflows/check_terraform.yml +++ b/.github/workflows/check_terraform.yml @@ -23,7 +23,7 @@ jobs: terraform_changed: ${{ steps.changes.outputs.terraform_changed }} steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 with: persist-credentials: false fetch-depth: 0 @@ -50,13 +50,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 with: persist-credentials: false fetch-depth: 0 - name: Setup TFLint - uses: terraform-linters/setup-tflint@v6 + uses: terraform-linters/setup-tflint@4cb9feea73331a35b422df102992a03a44a3bb33 with: tflint_version: latest @@ -69,7 +69,7 @@ jobs: run: tflint --minimum-failure-severity=error -f sarif > "$GITHUB_WORKSPACE/tflint_terraform.sarif" - name: Upload TFLint SARIF file - uses: github/codeql-action/upload-sarif@v4 + uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb with: sarif_file: ${{ github.workspace }}/tflint_terraform.sarif From bf05a69b973d52e5568ce9294478ffb290a0ff73 Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Wed, 7 Jan 2026 11:35:52 +0100 Subject: [PATCH 26/27] Deleting the debugging dev script. --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index 02fafe6..4c9edc4 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,3 @@ __pycache__ # Terraform Plan output files *.sarif - -# Development script -run.sh From 74da4b17c9937728964e229e724ee4f8f3a8912d Mon Sep 17 00:00:00 2001 From: "Tobias.Mikula" Date: Wed, 7 Jan 2026 11:46:07 +0100 Subject: [PATCH 27/27] bug fix --- .github/workflows/aquasec_repo_scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aquasec_repo_scan.yml b/.github/workflows/aquasec_repo_scan.yml index 72f2805..bd6db26 100644 --- a/.github/workflows/aquasec_repo_scan.yml +++ b/.github/workflows/aquasec_repo_scan.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v8e8c483db84b4bee98b60c0593521ed34d9990e8 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 with: persist-credentials: false fetch-depth: 0