Skip to content

Conversation

@tmikula-dev
Copy link
Collaborator

@tmikula-dev tmikula-dev commented Oct 17, 2025

Release Notes:

  • Changes that can make Terraform Static Check a mandatory action

Summary by CodeRabbit

  • New Features

    • Added targeted change-detection checks for Terraform, Docker, and Python that run analyses only when relevant files change.
    • Added a full-repository security scan that generates a summarized SARIF report and optional PR comment.
  • Improvements

    • Expanded credential/secret detection rules and updated scanning/linting integrations; introduced conditional/no-op paths when no changes detected.
  • Documentation

    • Reformatted README and updated developer guidance for scanning tools.
  • Maintenance

    • Modernized CI/workflow orchestration and simplified scan control flow.

@coderabbitai
Copy link

coderabbitai bot commented Oct 17, 2025

Walkthrough

Refactors CI into detect-first workflows for Terraform, Docker, and Python; adds repository Trivy full-scan with SARIF parsing and PR comments; introduces Trivy secret rules; removes legacy multi-job test.yml; updates various workflow metadata and action versions.

Changes

Cohort / File(s) Summary
Removed monolithic CI
​.github/workflows/test.yml
Deleted legacy multi-job CI pipeline (pylint, black, pytest, mypy) and its triggers.
Terraform workflow changes
​.github/workflows/check_terraform.yml
Replaced Trivy enforcement with git-diff detection, exports terraform_changed, adds conditional tflint job and a noop job, updates checkout/action versions and fetch-depth handling.
New Docker workflow
​.github/workflows/check_docker.yml
New detect job exporting docker_changed, conditional Trivy config scan on Dockerfile (SARIF upload), and noop job when no changes.
New Python workflow
​.github/workflows/check_python.yml
New detect job exporting python_changed; conditional analysis jobs (pylint, black, pytest, mypy) that run only when Python files changed; includes noop job.
Repository Trivy scan
​.github/workflows/trivy_repository_scan.yml
New full-repo Trivy filesystem scan producing SARIF, uploads SARIF, parses SARIF via inline Python to produce a findings table, and posts PR comment when applicable.
Trivy secret rules
trivy-secret.yaml
Added plaintext credential detection rules (password-plaintext-assignment, secret-plaintext-assignment) and enabled multiple built-in credential detectors (AWS, GitHub, GitLab tokens).
Docs & metadata
DEVELOPER.md, README.md, ​.github/workflows/check_pr_release_notes.yml
Updated Trivy command examples in DEVELOPER.md, reformatted Local Development table in README.md, and renamed/adjusted workflow metadata for PR release notes workflow.
Minor Terraform formatting
terraform/lambda.tf
Small formatting-only edit: removed an extra empty line in the aws_lambda_function resource.

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub Actions
    participant Detect as Detect Job
    participant Analyzer as Conditional Jobs
    participant Scanner as Tool (Trivy/TFLint/Pylint/Black/Mypy/Pytest)
    participant SARIF as SARIF Upload & Parser
    participant Noop as Noop Job

    GH->>Detect: trigger (push/pr/workflow_dispatch)
    Detect->>Detect: compute git diff range\nset <lang>_changed (true/false)

    alt changed == true
        Detect-->>Analyzer: emit changed=true
        GH->>Analyzer: run conditional jobs
        Analyzer->>Scanner: run respective tool(s)
        Scanner->>SARIF: produce SARIF (when applicable)
        SARIF->>GH: upload SARIF
        SARIF->>GH: parse SARIF -> generate summary table
        SARIF->>GH: (PR) post comment with summary
    else changed == false
        Detect-->>Noop: emit changed=false
        GH->>Noop: run noop (log minimal message)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Inspect git-diff range logic and fetch-depth=0 usage across detect jobs for PR vs push correctness.
  • Review SARIF parsing Python step in trivy_repository_scan.yml for robust JSON handling and accurate counts.
  • Verify conditional if: expressions and outputs wiring (e.g., terraform_changed, docker_changed, python_changed) and the noop job gating.
  • Confirm upgraded action versions (checkout@v5, upload-sarif@v4, setup-tflint@v6, setup-trivy) match required inputs/outputs.

Possibly related issues

Possibly related PRs

Suggested reviewers

  • Zejnilovic
  • ABMC831
  • petr-pokorny-absa
  • oto-macenauer-absa
  • miroslavpojer

Poem

🐇 A rabbit sniffs the diff in play,
Only scans what hopped in today,
Trivy sings, SARIF paints the chart,
TFLint hops in when Terraform takes part,
Noop curls up when changes stray away.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Trivy Scanning tool pilot implementation" is related to the main changes in this pull request. The PR introduces new Trivy scanning capabilities through multiple workflows (check_docker.yml, trivy_repository_scan.yml) and adds a new trivy-secret.yaml configuration file for credential detection. The title accurately reflects the "pilot implementation" aspect mentioned in the PR description and objectives, where the team explicitly states this is a "pilot implementation for Trivy scanning and related workflow changes." While the changeset also includes broader workflow refactoring, modular CI pattern changes, and other scanners/tools (TFLint, pylint, black, pytest, mypy), the Trivy scanning initiative is a central and explicitly stated component of this pilot effort.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/terraform-ci-linter-pilot-update

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
.github/workflows/check_terraform.yml (1)

19-19: Minor: Clarify the comment explaining workflow intent.

The comment "This job is implemented this way, because we need workflow mandatory" is unclear. Consider rephrasing to explain that the detect job ensures the workflow always executes (even with no changes) to maintain mandatory status in branch protection rules.

-  ## This job is implemented this way, because we need workflow mandatory
+  ## Detect job ensures workflow runs regardless of changes, making it mandatory in branch protection rules.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4af9f10 and 8beba93.

📒 Files selected for processing (1)
  • .github/workflows/check_terraform.yml (3 hunks)
🔇 Additional comments (4)
.github/workflows/check_terraform.yml (4)

45-46: Conditional execution structure looks good.

The needs: detect dependency and if: needs.detect.outputs.changed == 'true' conditions correctly gate the trivy and tflint jobs, ensuring they skip when terraform/ has no changes while maintaining overall workflow status via the noop job.

Also applies to: 83-84


122-127: Noop job effectively preserves mandatory workflow status.

The noop job ensures at least one job always completes successfully, preventing the workflow from being skipped entirely when terraform/ hasn't changed—a critical design pattern for making this workflow mandatory in branch protection.


25-25: Consistent checkout action upgrade to v5.

All three jobs (detect, trivy, tflint) uniformly upgrade to actions/checkout@v5 while preserving the fetch-depth: 0 configuration needed for git history operations.

Also applies to: 49-49, 87-87


32-42: I'll verify the critical claim about the git diff edge case and GitHub Actions behavior.

Let me verify one more critical detail about how HEAD~1...HEAD behaves on the first commit.

Critical issue is valid, but one suggested fix is flawed. The HEAD~1...HEAD approach does not gracefully handle first commits—it also fails with a fatal error.

Using git diff HEAD^ HEAD on the first commit results in "fatal: ambiguous argument 'HEAD^': unknown revision or path not in the working tree". The same applies to HEAD~1...HEAD. The review's claim that this approach "handles the initial commit gracefully" is incorrect.

The conditional check approach (using git rev-parse "${{ github.sha }}~1" to verify the parent exists) remains the correct solution. Remove the misleading suggestion about HEAD~1...HEAD.

Likely an incorrect or invalid review comment.

@tmikula-dev tmikula-dev self-assigned this Oct 17, 2025
@tmikula-dev tmikula-dev added the enhancement New feature or request label Oct 17, 2025
@tmikula-dev tmikula-dev linked an issue Oct 21, 2025 that may be closed by this pull request
@tmikula-dev tmikula-dev added the work in progress Work on this item is not yet finished (mainly intended for PRs) label Oct 21, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
Dockerfile (3)

21-26: Critical: Docker build fails due to missing COPY source paths.

The pipeline failures show COPY commands referencing build args that don't exist by default: ./trusted_certs and ./sasl_ssl_artifacts. When these directories are not provided at build time, the COPY operations fail, breaking the Docker image build.

Either provide default directories that exist in the repository, make these COPY operations conditional with fallbacks, or document that these build args are required and must be supplied during builds.

Suggested fix: Make COPY operations conditional or require the build args:

# Option 1: Make paths optional by checking if they exist
ARG TRUSTED_SSL_CERTS=./trusted_certs
ARG SASL_SSL_ARTIFACTS=./sasl_ssl_artifacts

# Create empty directories as fallbacks
RUN mkdir -p /opt/certs/ /opt/sasl_ssl_artifacts/

# Conditionally copy only if directories exist and have files
COPY --chown=0:0 ${TRUSTED_SSL_CERTS}/*.pem /opt/certs/ 2>/dev/null || true
COPY ${SASL_SSL_ARTIFACTS} /opt/sasl_ssl_artifacts/ 2>/dev/null || true

Or:

# Option 2: Require the build args and ensure they're provided
ARG TRUSTED_SSL_CERTS
ARG SASL_SSL_ARTIFACTS

COPY ${TRUSTED_SSL_CERTS} /opt/certs/
COPY ${SASL_SSL_ARTIFACTS} /opt/sasl_ssl_artifacts/

18-18: Minor: FROM --platform flag uses constant value.

Hadolint warns against using constant platform flags in FROM statements, as this limits portability and should typically be left to runtime configuration or build context.

This is a low-priority warning but can be addressed by removing the platform specification if cross-platform builds aren't a requirement, or documenting the ARM64-specific constraint.


66-66: Verify LDFLAGS path for librdkafka.

Line 66 sets LDFLAGS="-L/opt", but line 53 installs librdkafka to the default location (likely /usr/local/lib). The LDFLAGS path should match the installation directory:

- CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/opt" python setup.py install
+ CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" python setup.py install
🧹 Nitpick comments (3)
Dockerfile (1)

50-53: Consider adding checksums for downloaded binaries.

Lines 50 and 63 download source archives without verifying integrity. Adding checksums improves security and reproducibility:

RUN \
  mkdir -p /tmp/env-install-workdir/librdkafka && \
  cd /tmp/env-install-workdir/librdkafka && \
  wget https://github.com/edenhill/librdkafka/archive/v2.4.0.tar.gz && \
  echo "expected_sha256_hash  v2.4.0.tar.gz" | sha256sum -c - && \
  tar -xf v2.4.0.tar.gz && \
  # ... rest of build

Also applies to: 63-66

.github/workflows/check_python.yml (1)

35-44: Change detection logic is sound but consider edge cases.

The detect job correctly uses git diff with proper branching logic for PRs vs pushes. However, the pattern ^(src|tests)/ matches files at any path depth; ensure this covers nested directories like src/module/file.py (which it does).

One edge case: If only configuration files like setup.cfg or pytest.ini change, Python analysis still runs. Consider whether config-only changes should trigger the workflow.

.github/workflows/check_docker.yml (1)

40-40: Dockerfile detection pattern matches only root-level Dockerfile.

Line 40 uses pattern ^Dockerfile$, which only matches the Dockerfile at the repository root. If other Dockerfiles exist in subdirectories (e.g., services/api/Dockerfile), they won't trigger this workflow.

If the repo has multiple Dockerfiles, update the pattern:

if git diff --name-only "$RANGE" | grep -qE '(^|/)Dockerfile'; then

Otherwise, document that only the root Dockerfile is scanned.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c972f06 and c65866f.

📒 Files selected for processing (7)
  • .github/workflows/check_docker.yml (1 hunks)
  • .github/workflows/check_python.yml (1 hunks)
  • .github/workflows/check_terraform.yml (2 hunks)
  • .github/workflows/test.yml (0 hunks)
  • DEVELOPER.md (1 hunks)
  • Dockerfile (1 hunks)
  • README.md (1 hunks)
💤 Files with no reviewable changes (1)
  • .github/workflows/test.yml
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • DEVELOPER.md
🧰 Additional context used
🪛 GitHub Actions: Static Docker Check
Dockerfile

[error] 5-5: failed to calculate checksum of ref ac1187db-1850-4397-a0f7-3b6e6ef293d6::/trusted_certs: "/trusted_certs" not found


[error] 7-7: failed to calculate checksum of ref ac1187db-1850-4397-a0f7-3b6e6ef293d6::/sasl_ssl_artifacts: not found


[warning] 18-18: FromPlatformFlagConstDisallowed: FROM --platform flag should not use constant value "linux/arm64"


[error] 74-74: COPY $SASL_SSL_ARTIFACTS /opt/sasl_ssl_artifacts/ exited with error due to missing source path

🔇 Additional comments (5)
.github/workflows/check_python.yml (2)

127-128: Pytest coverage threshold at 80% is strict—verify it's achievable.

The --cov-fail-under=80 flag enforces 80% coverage on tests. Ensure the test suite actually meets this threshold; if tests fail due to coverage gaps, CI will block merges.

Consider running locally to verify coverage:

pytest --cov=. -v tests/ --cov-fail-under=80

103-105: This review comment is incorrect and should be dismissed.

The workflow's approach is intentional and documented. The detect job gates all downstream analysis jobs to run only when Python files change (lines 48-49: if: needs.detect.outputs.python_changed == 'true'). When Python changes are detected, validating the full codebase—not just diffs—is the documented, recommended practice per DEVELOPER.md, which explicitly instructs developers to run checks on "all files currently tracked by Git" using black $(git ls-files '*.py') and pylint $(git ls-files '*.py').

This two-tier design (detect → validate full consistency) is sound: it avoids redundant checks when no Python changes exist while ensuring codebase-wide quality standards when changes occur.

Likely an incorrect or invalid review comment.

.github/workflows/check_terraform.yml (3)

35-44: Terraform change detection aligns with Python and Docker workflows.

The detect job uses identical logic and structure to the Python and Docker workflows, which is excellent for consistency. The pattern ^terraform/ correctly identifies changes in the terraform directory.


91-97: Trivy scan from terraform/ subdirectory is appropriate.

The Trivy scan at line 94 runs from the terraform/ working directory, scanning the current directory (.). This is correct and aligns with the Python workflow's approach of scanning only the relevant code paths.


48-49: I need to gather more specific information about TFLint's version history and when SARIF support was introduced.

TFLint SARIF support is well-established; no action needed.

SARIF format support was added to TFLint in v0.35.0, and the CLI currently supports -f sarif as a documented output format option. When using terraform-linters/setup-tflint with tflint_version: latest, the action retrieves the latest TFLint version, which includes stable SARIF support. The concern about version-dependent SARIF availability is not applicable—TFLint's 0.x version scheme does not have a v1.40, and SARIF has been a standard, supported output format for years without breaking changes.

@github-advanced-security
Copy link

This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation.

@tmikula-dev
Copy link
Collaborator Author

Please look at the suggested solution. This PILOT has a team goal to understand and set the standard of working with workflows and scanners inside our projects. I did follow the splitting the workflows for determined purposes. Open to the discussion.

Copy link
Contributor

@miroslavpojer miroslavpojer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • read

id: check-types
run: mypy .

trivy-python:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that in PR Trivy should should be limited to all chages files.
I believe we should introduce Trivy run once a "day"|"???" across entrire workspace.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the new version in commit: 0e6e234. And share your thoughts:)

with:
sarif_file: ${{ github.workspace }}/tflint_terraform.sarif

trivy-terraform:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I do not agree with solution. I would isolate Trivy to its own PR changes related flow.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is now isolated in the automatic midnight test scan. Only place, where the Trivy is still implemented is in docker-check. This decision was due to your recommendation. You can see the implementation in: 0e6e234.

src/conf_path.py Outdated
import os



Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and others are fake changes for testing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, these changes are made, so I can show, how workflow behaves here on GH. Will not be part of final solution.

DEVELOPER.md Outdated
### Run Trivy

For running Trivy tool locally run the following command from the root file:
For running Trivy tool locally run you can run one of following commands from the root file:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
For running Trivy tool locally run you can run one of following commands from the root file:
For running Trivy tool locally you can run one of following commands from the root file:

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as off-topic.

@tmikula-dev tmikula-dev changed the title Terraform Static Check - PILOT update Trivy Scanning tool pilot implementation Oct 29, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
.github/workflows/trivy_auto_repository_scan.yml (1)

28-33: Add explicit validation to ensure Trivy SARIF output exists and is valid before downstream steps consume it.

The workflow's subsequent steps—the GitHub SARIF upload and Python script parsing—depend directly on trivy_repository_report.sarif being created and valid. While Trivy exits non-zero on internal failures, an edge-case scenario where it produces truncated or malformed SARIF but still exits successfully could cause confusing failures downstream. The suggested validation step catches this by confirming the file exists and contains valid JSON, providing clear error messages upfront rather than propagating issues to dependent steps.

The proposed diff is sound and improves workflow robustness.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b657be8 and 99c4124.

📒 Files selected for processing (1)
  • .github/workflows/trivy_auto_repository_scan.yml (1 hunks)

@AbsaOSS AbsaOSS deleted a comment from github-actions bot Oct 29, 2025
@AbsaOSS AbsaOSS deleted a comment from github-actions bot Oct 29, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
.github/workflows/trivy_repository_scan.yml (2)

97-108: Minor: Inconsistent error handling for missing GITHUB_OUTPUT.

When GITHUB_OUTPUT is not set (line 104), the script prints a warning but continues with exit code 0, which means the downstream comment step will receive an empty summary table. For consistency with the IOError handling (line 108), either exit with code 1 here or handle the fallback more explicitly. In practice, GITHUB_OUTPUT is always set in GitHub Actions environments, so this is a defensive edge case.

Consider either treating missing GITHUB_OUTPUT as a fatal error:

           else:
-              print("Warning: GITHUB_OUTPUT not set", file=sys.stderr)
+              raise RuntimeError("GITHUB_OUTPUT environment variable not set")

Or explicitly validate before writing. Either approach makes the error path consistent with the IOError handler below.


25-31: Confirm scanner scope aligns with pilot objectives.

The workflow includes four scanners: vuln, secret, misconfig, and license. Given this is a pilot to establish standards across projects, verify this scanner configuration matches your intended scope. For example, some teams may want to exclude license scanning or add additional scanners. Consider documenting the rationale in the repository's security scanning guidelines.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1fb029b and 64e0ec6.

📒 Files selected for processing (1)
  • .github/workflows/trivy_repository_scan.yml (1 hunks)
🔇 Additional comments (3)
.github/workflows/trivy_repository_scan.yml (3)

111-126: Conditional check properly addresses PR context requirement.

The if: github.event_name == 'pull_request' condition on line 112 correctly gates the PR comment step, ensuring it only runs when triggered by a pull request event, not manual workflow_dispatch runs. This addresses the past critical issue and is the appropriate solution.


3-6: Confirm dual trigger approach aligns with team standards.

The workflow triggers on both workflow_dispatch (manual) and pull_request events. While this provides flexibility—allowing both automatic PR scanning and on-demand manual scans—confirm this dual-trigger pattern aligns with the standards the pilot intends to establish. For reference, the past review approved the conditional gating of the PR comment step (line 112), which handles this dual-trigger scenario correctly.


25-26: No action required — version is current.

The aquasecurity/setup-trivy action version v0.2.4 is the latest version, so the pinned version used in the workflow is appropriate and follows best practices for maintaining reproducible CI/CD pipelines.

Comment on lines 38 to 109
- name: Create scan summary table
id: scan_summary_table
run: |
python <<'PY'
import os
import json
import sys
from collections import Counter
SARIF_PATH = "trivy_repository_report.sarif"
SEVERITIES = ["CRITICAL", "HIGH", "MEDIUM", "LOW"]
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", [])
counts = 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 severity
for res in results:
try:
rule_idx = res.get("ruleIndex")
if rule_idx is None or rule_idx >= len(rules):
continue
rule = rules[rule_idx]
tags = rule.get("properties", {}).get("tags", [])
sev = next((s for s in SEVERITIES if s in tags), None)
if sev:
counts[sev] += 1
except (KeyError, IndexError, TypeError) as e:
print(f"Warning: Error processing result: {e}", file=sys.stderr)
continue
headers = SEVERITIES + ["TOTAL"]
values = [str(counts.get(s, 0)) for s in SEVERITIES]
total = sum(counts.get(s, 0) for s in SEVERITIES)
values.append(str(total))
# Build Markdown summary table
summary_table = "| " + " | ".join(headers) + " |\n"
summary_table += "|" + "|".join(["---"] * len(headers)) + "|\n"
summary_table += "| " + " | ".join(values) + " |"

# Set output
try:
if "GITHUB_OUTPUT" in os.environ:
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f:
f.write("table<<EOF\n")
f.write(summary_table + "\n")
f.write("EOF\n")
else:
print("Warning: GITHUB_OUTPUT not set", file=sys.stderr)

except IOError as e:
print(f"Error writing output: {e}", file=sys.stderr)
sys.exit(1)
PY
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify SARIF structure assumptions for severity extraction.

The Python script assumes severity information is located in rule.properties.tags, but this depends on Trivy's specific SARIF output structure. Verify that Trivy places severity information in this exact location; if severity is instead a property of the result or in a different SARIF field, the severity counts will be incorrect.

You can verify this by running Trivy and inspecting the generated trivy_repository_report.sarif file to confirm the structure matches the script's expectations:


🏁 Script executed:

#!/bin/bash
# Generate sample SARIF to inspect structure
trivy fs --format sarif --output /tmp/sample.sarif . 2>/dev/null || true

# Display relevant portions of the SARIF structure
echo "=== Sample rule structure ==="
jq '.runs[0].tool.driver.rules[0] | {id, shortDescription, properties}' /tmp/sample.sarif 2>/dev/null || echo "File not generated"

echo "=== Sample result structure ==="
jq '.runs[0].results[0] | {ruleId, ruleIndex, message, properties}' /tmp/sample.sarif 2>/dev/null || echo "No results in sample"

Length of output: 101


Let me search more specifically for Trivy's SARIF structure with examples:

Verify SARIF structure assumptions for severity extraction with actual Trivy output or source code inspection.

The Python script assumes severity is in rule.properties.tags based on Trivy's SARIF implementation which maps severity levels using the toSarifErrorLevel function, but the exact SARIF structure cannot be definitively confirmed through web search alone. Without access to an actual Trivy SARIF output file or the repository's Trivy source code examination, the severity extraction approach in the script remains unverified.

To confirm correctness, inspect a real SARIF file from Trivy (e.g., in the repository's test data or CI outputs) to verify the location of severity information matches the script's expectations of rules[ruleIndex].properties.tags.


🌐 Web query:

Trivy SARIF output format severity field location

💡 Result:

Short answer — where Trivy puts severity in SARIF:

  • Trivy maps its severity to the SARIF result "level" (error/warning/note/none) for each result. [1][2]
  • Trivy also embeds severity metadata in the SARIF properties (e.g., properties.tags includes the Trivy severity string and properties["security-severity"] holds a numeric CVSS-like score); rule/defaultConfiguration.level and rule.properties may also be populated. [1][2]
  • Consumers that follow the SARIF 2.1.0 spec should read result.level first, and can consult result.properties / rule.defaultConfiguration.level / rule.properties for Trivy-specific severity details. [3]

Sources:
[1] Trivy source (pkg/report/sarif.go) — mapping and properties.
[2] Trivy SARIF documentation / examples.
[3] SARIF v2.1.0 specification (result.level and rule.defaultConfiguration.level).


Fix severity extraction to use SARIF result.level as primary source.

The Python script extracts severity only from rule.properties.tags, but according to SARIF 2.1.0 specification and Trivy's implementation, the primary severity location is result.level. The script should read result.level first, with fallback to result.properties.tags or result.properties["security-severity"] for additional context. The current approach bypasses the standard SARIF severity field and relies on an indirect lookup through rules, which may miss severities or fail if ruleIndex is incorrect.

Update lines 72–81 to check result.level or result.properties as the primary source:

# Count results by severity
for res in results:
    try:
        # Check result.level (primary per SARIF 2.1.0) or result.properties.tags
        sev = None
        if "level" in res:
            level_map = {"error": "CRITICAL", "warning": "HIGH", "note": "MEDIUM", "none": "LOW"}
            sev = level_map.get(res["level"])
        if not sev:
            # Fallback to properties.tags if level not found
            tags = res.get("properties", {}).get("tags", [])
            sev = next((s for s in SEVERITIES if s in tags), None)
        if sev:
            counts[sev] += 1
    except (KeyError, TypeError) as e:
        print(f"Warning: Error processing result: {e}", file=sys.stderr)
        continue

@AbsaOSS AbsaOSS deleted a comment from github-actions bot Oct 30, 2025
@AbsaOSS AbsaOSS deleted a comment from github-actions bot Oct 30, 2025
@AbsaOSS AbsaOSS deleted a comment from github-actions bot Oct 30, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ae6449 and 4456c25.

📒 Files selected for processing (1)
  • .github/workflows/trivy_repository_scan.yml (1 hunks)
🔇 Additional comments (6)
.github/workflows/trivy_repository_scan.yml (6)

3-12: Conditional logic for PR-only steps is properly gated.

The workflow triggers on both workflow_dispatch and pull_request, and the PR comment step at line 130 correctly uses if: github.event_name == 'pull_request' to skip when triggered manually. This properly addresses the past concern about context availability.


28-33: Trivy command properly generates SARIF output file.

The command correctly specifies --format sarif and outputs to trivy_repository_report.sarif, which addresses the past critical issue and enables the downstream SARIF upload and summary parsing steps to function correctly.


92-112: Table generation and aggregation logic is sound.

The Markdown table structure is correct with proper column alignment, and the aggregation logic properly counts results by category and severity across all rows.


115-126: GITHUB_OUTPUT writing uses safe heredoc pattern with proper validation.

The implementation correctly checks for GITHUB_OUTPUT environment variable and uses the heredoc pattern (EOF delimiter) for safe multi-line output. Error handling is appropriate.


53-72: SARIF validation is comprehensive with clear error messages.

The SARIF file loading includes defensive checks for required structure (runs, tool, driver keys) and handles parsing errors gracefully with informative exit messages.


129-143: PR comment step is properly conditional and constructs informative comment.

The conditional if: github.event_name == 'pull_request' prevents failures on manual dispatch. The comment body includes a direct link to the security overview and embeds the summary table from the previous step.

Comment on lines 75 to 89
for res in results:
try:
rule_idx = res.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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Use SARIF standard result.level field for severity extraction.

The current code extracts severity only from rule.properties.tags, bypassing the SARIF 2.1.0 specification's primary severity field (result.level). This is fragile and non-standard. Per Trivy's implementation, result.level (error/warning/note/none) should be the primary severity source, with fallback to tags or properties only if missing.

This issue was flagged in a past review but remains unaddressed.

Apply this diff to check result.level first:

  # Count results by category and severity
  for res in results:
      try:
          # Extract category from tags (required)
          tags = res.get("properties", {}).get("tags", [])
          category = next((c for c in CATEGORIES if c in tags), None)
          if not category:
              continue
          
          # Extract severity: check result.level (primary per SARIF spec)
          severity = None
          if "level" in res:
              level_map = {"error": "CRITICAL", "warning": "HIGH", "note": "MEDIUM", "none": "LOW"}
              severity = level_map.get(res["level"])
          
          # Fallback to tags if result.level not available
          if not severity:
              severity = next((s for s in SEVERITIES if s in tags), None)
          
          if severity:
              category_severity_counts[category][severity] += 1
      except (KeyError, TypeError) as e:
          print(f"Warning: Error processing result: {e}", file=sys.stderr)
          continue

This approach follows the SARIF standard, uses Trivy's result.level as the authoritative severity source, and removes the fragile ruleIndex lookup dependency.

🤖 Prompt for AI Agents
.github/workflows/trivy_repository_scan.yml around lines 75-89: the code
currently derives severity only from rule.properties.tags and uses ruleIndex
lookups; update logic to treat SARIF result.level as the primary severity source
(map {"error":"CRITICAL","warning":"HIGH","note":"MEDIUM","none":"LOW"}), fall
back to extracting severity from tags if level is missing, and stop relying on
ruleIndex for severity (still use tags only to determine category and as
fallback for severity); ensure you handle missing fields safely and keep the
existing exception handling.

@AbsaOSS AbsaOSS deleted a comment from github-actions bot Oct 30, 2025
@github-actions
Copy link

Trivy has completed a full security repository scan ✅ You can find the analysis results for this PR branch on this overview.
Below is the summary of the findings:

TRIVY CRITICAL HIGH MEDIUM LOW TOTAL
vulnerability 0 0 0 0 0
secret 0 6 0 0 6
misconfiguration 1 2 2 10 15
license 0 0 0 0 0
➡️ Total 1 8 2 10 21

@tmikula-dev
Copy link
Collaborator Author

tmikula-dev commented Oct 30, 2025

In the Trivy scan tool official documentation, are listed features, that are enabled only to AquaSec (via this link]). For example SAST, Malware Scanning, Sandbox scanning, Leaked secrets validation etc. This solution is the closest we can get to the official scanning. There is still option to create new secret regex rules to expand our secret scanning. I am also not sure, if this current version of the workflow should trigger only, when the PR is created or every time the PR is updated.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4456c25 and ac4df24.

📒 Files selected for processing (1)
  • .github/workflows/trivy_repository_scan.yml (1 hunks)
🔇 Additional comments (3)
.github/workflows/trivy_repository_scan.yml (3)

3-6: ✓ PR context conditional correctly implemented.

The workflow now properly handles both workflow_dispatch and pull_request events via the conditional at line 129 (if: github.event_name == 'pull_request'), preventing failures when triggered manually.


28-33: ✓ SARIF output format correctly specified.

The Trivy command now properly generates SARIF output with --format sarif --output trivy_repository_report.sarif, enabling downstream SARIF upload and parsing steps.


128-143: ✓ PR comment step properly guarded and uses secure token handling.

The conditional check at line 129 ensures the step runs only for pull requests, and secrets.GITHUB_TOKEN is correctly used instead of hardcoded credentials.

Comment on lines +74 to +89
# 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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Critical: Use SARIF standard result.level as primary severity source.

The severity extraction still bypasses the SARIF 2.1.0 specification by reading only from rule.properties.tags (line 81, 84). Per SARIF spec and Trivy's implementation, result.level (error/warning/note/none) is the authoritative severity field. The current approach is fragile, non-standard, and may produce incorrect severity counts. This was flagged in a prior review but remains unaddressed.

Apply this diff to prioritize result.level:

  # Count results by category and severity
  for result in results:
      try:
          # Extract category from result tags (required)
          result_tags = result.get("properties", {}).get("tags", [])
          category = next((c for c in CATEGORIES if c in result_tags), None)
          if not category:
              continue
          
          # Extract severity: check result.level (primary per SARIF spec)
          severity = None
          if "level" in result:
              level_map = {"error": "CRITICAL", "warning": "HIGH", "note": "MEDIUM", "none": "LOW"}
              severity = level_map.get(result["level"])
          
          # Fallback to tags if result.level not available
          if not severity:
              severity = next((s for s in SEVERITIES if s in result_tags), None)
          
          if severity:
              category_severity_counts[category][severity] += 1
      except (KeyError, TypeError) as e:
          print(f"Warning: Error processing result: {e}", file=sys.stderr)
          continue

This approach:

  • Uses result.level as the authoritative severity source
  • Falls back to tags only if level is missing
  • Removes the fragile ruleIndex lookup dependency
  • Follows the SARIF 2.1.0 standard and Trivy's design

I'll verify this review comment by examining the actual file and confirming the SARIF specification details.





🏁 Script executed:

#!/bin/bash
# Examine the workflow file and surrounding context
cat ".github/workflows/trivy_repository_scan.yml" | head -150 | tail -90

Length of output: 4251


🏁 Script executed:

#!/bin/bash
# Get the full script context to understand the data structures
cat ".github/workflows/trivy_repository_scan.yml"

Length of output: 5602


🌐 Web query:

SARIF 2.1.0 specification result.level severity field

💡 Result:

Summary — result.level in SARIF 2.1.0

  • Field: runs[].results[].level (optional). [1]
  • Allowed values and meanings:
    • "warning": rule was evaluated and a problem was found. [1]
    • "error": rule was evaluated and a serious problem was found. [1]
    • "note": rule was evaluated and a minor problem or opportunity to improve. [1]
    • "none": “severity” does not apply because result.kind is not "fail". [1]
  • Rules: if present it must be one of the above; level relates to result.kind (if kind is present and level ≠ "none", kind MUST be "fail"); if kind is absent it defaults to "fail". [1]
  • Spec / reference: SARIF 2.1.0 (OASIS). [1][2]

Sources:
[1] OASIS — Static Analysis Results Interchange Format (SARIF) Version 2.1.0 (section 3.27.10 and related).
[2] SARIF project site / documentation (overview for v2.1.0).



---

🌐 Web query:

```web
Trivy SARIF output result.level severity field

💡 Result:

Trivy maps its severities to SARIF result.level as follows:

  • CRITICAL, HIGH → "error". [1]
  • MEDIUM → "warning". [1]
  • LOW, UNKNOWN → "note". [1]
  • other → "none". [1]

(Trivy can emit SARIF via --format sarif; see Trivy reporting docs.) [2]

Sources: [1] DeepWiki summary of Trivy SARIF mapping (references Trivy's sarif.go). [2] Trivy reporting / SARIF docs.


Correct the severity level mappings in the proposed fix.

The review identifies a valid concern—the code should use result.level as primary severity source per SARIF spec, which Trivy does populate. However, the suggested level_map contains incorrect mappings:

Trivy maps CRITICAL/HIGH to "error", MEDIUM to "warning", and LOW/UNKNOWN to "note". The proposed diff maps "warning" to "HIGH" and "note" to "MEDIUM", which contradicts Trivy's actual output.

Correct mappings should be:

  • "error""CRITICAL" (or "HIGH"—choose one, as Trivy conflates both)
  • "warning""MEDIUM"
  • "note""LOW"
  • "none""LOW" (or skip)

Apply the suggested approach of using result.level as primary source, but fix the level_map conversions to match Trivy's actual severity mappings.

🤖 Prompt for AI Agents
.github/workflows/trivy_repository_scan.yml around lines 74-89: the code should
use result["level"] (SARIF/Trivy) as the primary severity source and the
level_map must be corrected to match Trivy: map "error" -> CRITICAL (or HIGH),
"warning" -> MEDIUM, "note" -> LOW, and treat "none" as LOW or skip; update the
logic to prefer result.get("level") and only fall back to tags-based mapping
when level is missing, then convert the Trivy level via the corrected level_map
before incrementing category_severity_counts.

@tmikula-dev tmikula-dev removed the work in progress Work on this item is not yet finished (mainly intended for PRs) label Oct 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Trivy Scanning tool pilot implementation

3 participants