-
Notifications
You must be signed in to change notification settings - Fork 3
ci(security): SAST, secret and SCA gates #225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -179,6 +179,83 @@ jobs: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo '- `${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.build_tag }}`' >> "$GITHUB_STEP_SUMMARY" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ─── Image CVE scan ──────────────────────────────────────────────────────── | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Scans the manifest that was just pushed — the only place where base-image | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # (nginx:1.27-alpine) and OS-package CVEs are visible. The repo-level pass | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # (trivy.yml) sees the lock file and Dockerfile, never the shipped layers. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Report-only for now (`--exit-code 0`): findings go to "Security -> Code | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # scanning" and the job log, and promotion proceeds. To bar a vulnerable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # image from promotion — the policy target — set `--exit-code 1` here and add | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # `trivy-image` to `dispatch-umbrella`'s `needs`. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Scoped to main: the promotion path this gate is meant to guard. Branch | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # dispatches now push a tagged `.<branch>` image too (insight#1994) but never | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # reach the umbrella, so they are left unscanned to keep dispatch cheap — | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # drop the `github.ref` half of the condition below to cover them as well. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trivy-image: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Trivy image scan (report-only) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| needs: merge | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| timeout-minutes: 20 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contents: read # checkout (.trivyignore waivers) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| packages: read # pull the image under scan from GHCR | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| security-events: write # upload SARIF to Code Scanning | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Checkout | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| persist-credentials: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Trivy image scan (CRITICAL/HIGH) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Trivy pulls straight from the registry (TRIVY_USERNAME/TRIVY_PASSWORD) rather than | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # via a mounted docker socket, so no daemon and no local `docker pull` is needed. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # `--ignore-unfixed` keeps the output to what a base-image bump can actually fix. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # A multi-arch manifest resolves to the runner's platform (linux/amd64); the arm64 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # leg shares the same base image and package set, so one pass is representative. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TRIVY_IMAGE: aquasec/trivy:0.72.0@sha256:cffe3f5161a47a6823fbd23d985795b3ed72a4c806da4c4df16266c02accdd6f | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IMAGE_REF: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.merge.outputs.build_tag }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TRIVY_USERNAME: ${{ github.actor }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Scanning ${IMAGE_REF}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Two passes over the same warm DB cache: a readable table in the log, SARIF for | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Code Scanning. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docker run --rm \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -v /tmp/trivy-cache:/root/.cache \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -e TRIVY_USERNAME -e TRIVY_PASSWORD \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$TRIVY_IMAGE" image \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --severity CRITICAL,HIGH \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --pkg-types os,library \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --ignore-unfixed \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --exit-code 0 \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --no-progress \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --format table \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$IMAGE_REF" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docker run --rm \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -v "${{ github.workspace }}:/work" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -v /tmp/trivy-cache:/root/.cache \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -e TRIVY_USERNAME -e TRIVY_PASSWORD \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$TRIVY_IMAGE" image \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --severity CRITICAL,HIGH \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --pkg-types os,library \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --ignore-unfixed \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --exit-code 0 \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --no-progress \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --format sarif --output /work/trivy-image.sarif \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+231
to
+249
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
if [ -f .github/workflows/docker.yml ]; then
sed -n '200,270p' .github/workflows/docker.yml | cat -n
else
echo ".github/workflows/docker.yml not found"
fi
echo
echo "== trivy references in workflow =="
rg -n "trivy|TRIVY|scanners|sarif|secret" .github/workflows/docker.yml || true
echo
echo "== related PR/workflow files =="
git ls-files '.github/workflows/*' . | sed -n '1,120p'Repository: constructorfabric/insight-front Length of output: 9673 🌐 Web query:
💡 Result: To generate a SARIF report for an image scan using Trivy v0.72, you can use the built-in Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== trivy workflow excerpt =="
if [ -f .github/workflows/trivy.yml ]; then
sed -n '1,240p' .github/workflows/trivy.yml | cat -n
else
echo ".github/workflows/trivy.yml not found"
fi
echo
echo "== secret scanner references across workflows =="
rg -n "trivy|upload-sarif|secrets|secret|scanners|SARIF" .github/workflows/trivy.yml .github/workflows/docker.yml .github/workflows/semgrep.yml .github/workflows/trufflehog.yml || trueRepository: constructorfabric/insight-front Length of output: 15552 Vulnerability-only image scans here. Trivy image scans default to Proposed fix "$TRIVY_IMAGE" image \
+ --scanners vuln \
--severity CRITICAL,HIGH \
@@
"$TRIVY_IMAGE" image \
+ --scanners vuln \
--severity CRITICAL,HIGH \📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$IMAGE_REF" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Upload SARIF to GitHub Code Scanning | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: always() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: github/codeql-action/upload-sarif@fb0994ef1c058010acf1efccff928b0a83b1ed54 # v4.32.6 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sarif_file: trivy-image.sarif | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| category: trivy-image | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ─── Umbrella chart dispatch ─────────────────────────────────────────────── | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # After a successful main-branch image build, trigger the umbrella chart | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # workflow in constructorfabric/insight so it bumps the frontend subchart | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| name: Semgrep SAST | ||
|
|
||
| # Report-only SAST gate (constructorfabric/insight#1478), mirroring | ||
| # constructorfabric/insight's semgrep.yml so findings stay comparable across the two | ||
| # repos. | ||
| # | ||
| # Findings (Semgrep `--config auto` — per-language auto-detection via the registry, | ||
| # matching the org GitLab semgrep-scan component; no `p/rust`/`p/csharp` here since this | ||
| # repo is TypeScript + a little Python in scripts/ci) surface in the GitHub | ||
| # "Security -> Code scanning" tab (SARIF upload) AND as a count in the job summary, but | ||
| # they DO NOT block: `semgrep scan` runs WITHOUT `--error`. Flip to blocking once the | ||
| # baseline is triaged and clean (zero un-waived findings) by adding `--error` here and | ||
| # marking `sast` a required status check. | ||
| # | ||
| # Secret detection is intentionally excluded (`--exclude-rule generic.secrets...`); the | ||
| # separate TruffleHog gate (trufflehog.yml) owns secret scanning. | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: [main] | ||
| schedule: | ||
| # Nightly full-tree baseline (independent of what any PR touched), 03:27 UTC. | ||
| - cron: "27 3 * * *" | ||
| workflow_dispatch: | ||
|
|
||
| # A new push obsoletes any run still in flight for the same ref. | ||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| sast: | ||
| name: sast | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 20 | ||
| permissions: | ||
| contents: read # checkout | ||
| security-events: write # upload SARIF to Code Scanning | ||
| steps: | ||
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Semgrep scan (report-only — ratchet to blocking with --error once baseline is clean) | ||
| # Runs the digest-pinned Semgrep image via `docker run` (not a `container:` job) so the | ||
| # checkout and SARIF-upload JS actions keep the host runner's Node — the Semgrep image | ||
| # does not ship Node. No `--error`: findings are reported, never block. Secrets excluded | ||
| # (TruffleHog owns them). `.semgrepignore` in the repo root prunes build/dep artifacts | ||
| # and the vendored cypilot kit. | ||
| # NB: `--config auto` requires metrics ON (it sends language/rule/finding counts — not | ||
| # source — to semgrep.dev to select rules), so `--metrics off` is intentionally omitted. | ||
| run: | | ||
| docker run --rm \ | ||
| -v "${{ github.workspace }}:/src" \ | ||
| -w /src \ | ||
| semgrep/semgrep:1.170.0@sha256:c98f8829eea377274ee4b10656458b078b88232469b2ff913f091c2317347c9d \ | ||
| semgrep scan \ | ||
| --config auto \ | ||
| --exclude-rule generic.secrets.security.detected-generic-secret \ | ||
| --sarif --output semgrep.sarif | ||
|
Comment on lines
+60
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
sed -n '1,120p' .github/workflows/semgrep.yml
echo
echo "== repo Semgrep references =="
rg -n "semgrep|generic\.secrets|detected-generic-secret|sarif|CodeQL|Code Scanning" .github . 2>/dev/null | head -200
echo
echo "== search for Semgrep config files if any =="
git ls-files | grep -E '(^|/)semgrep|^\.semgrep|semgrep\.yaml|\.semgrepignore|\.semgrep$' || true
python3 - <<'PY'
from pathlib import Path
p=Path('.github/workflows/semgrep.yml')
text=p.read_text() if p.exists() else ''
for i,line in enumerate(text.splitlines(),1):
if 'exclude-rule' in line or 'semgrep scan' in line or 'semgrep.sarif' in line:
print(f'{p}:{i}:{line}')
PYRepository: constructorfabric/insight-front Length of output: 9846 🌐 Web query:
💡 Result: To exclude a specific Semgrep rule—such as detected-generic-secret—from your scans, you can use several methods depending on whether you want to exclude it globally, via the command line, or for specific files [1][2][3]. The full rule ID for generic secret detection typically follows the format generic.secrets.security.detected-generic-secret (or a variation depending on your configuration source) [4][5]. You should verify the exact rule ID in your Semgrep dashboard or by inspecting the rule file [6][3]. Methods to exclude the rule: 1. Command-Line Interface (CLI): Use the --exclude-rule flag when running a scan [6][3]. This is the most direct way to ignore a rule globally for a specific execution [2]. semgrep scan --exclude-rule <rule_ID> 2. Inline Comments: To ignore the rule for specific lines of code, add a nosemgrep comment on the line preceding the finding [1][2][3]. // nosemgrep: <rule_ID> 3. Rule-Level Path Exclusion: If you want to keep the rule active but skip it for certain files or directories, you can modify the rule itself (or create a custom version) by adding a paths: exclude: section in the rule's YAML configuration [1][4][7]. rules: - id: <rule_ID>... paths: exclude: - "path/to/ignore/*" 4. Semgrep Platform: If you are using the Semgrep AppSec Platform, you can triage findings as false positives or ignored risks directly in the dashboard [2][8][3]. These decisions persist across future scans, preventing the finding from being reported again [3]. For maintaining consistent ignores across a project without using CLI flags, creating a custom rule that extends the original but adds a paths: exclude: filter is a common practice [4][2]. Citations:
🌐 Web query:
💡 Result: To exclude a specific rule by its ID when running Semgrep CLI, use the --exclude-rule flag followed by the rule ID [1][2]. Based on your query, the correct command syntax is: semgrep --exclude-rule generic.secrets.security.detected-generic-secret This flag can be used multiple times in a single command to exclude more than one rule [1]. For other ways to manage rule exclusions: - Inline comments: To ignore a specific rule in your code, you can add a comment with the nosemgrep annotation immediately before the flagged code (e.g., // nosemgrep: rule-id) [3][2]. - Rule configuration: You can edit the rule definition itself to include paths filters if you only want to exclude the rule on specific files or directories [3][4]. - Semgrep AppSec Platform: For secrets scans specifically, you can also manage ignores through the Semgrep AppSec Platform if applicable to your configuration [3]. The --exclude-rule flag is available in Semgrep CLI versions that support rule filtering by ID [5]. Since you are using version 1.170.0, this functionality is fully supported [1][6]. Citations:
🌐 Web query:
💡 Result: Semgrep does not have a flag named Citations:
🌐 Web query:
💡 Result: Semgrep’s generic secrets detection, often referred to as "Generic secrets AI" or "AI augmented rules," is a feature designed to detect potential credentials (such as API keys and passwords) by identifying common keywords and surrounding context rather than relying solely on specific, hardcoded patterns [1]. To configure and enable generic secrets, you do not use a local "auto config" file in the traditional sense; instead, the feature is enabled and managed directly through the Semgrep AppSec Platform [1]. How to enable Generic Secrets: 1. Sign in to the Semgrep AppSec Platform. 2. Navigate to Settings > General > Secrets [1]. 3. Locate the Generic secrets section and toggle the switch to "On" [1]. Once enabled, subsequent scans will automatically incorporate generic secrets rules [1]. You can verify that these rules are active by checking the CLI output during a scan, which will display a confirmation message stating: "AI augmented rules are active for secrets detection" [1]. Key aspects of Generic Secrets: - Analysis Method: Findings identified via this method are analyzed by "Semgrep Multimodal" to eliminate false positives and highlight high-signal, actionable results [1]. - Management: You can manage and filter these findings in the Semgrep AppSec Platform under the Findings page by selecting the "Generic" option in the "Secret type" filter [1]. - Policies: You can further control how your organization handles these secrets by navigating to Rules & policies > Policies > Secrets in the AppSec Platform, where you can filter by "Analysis method" to distinguish between Semantic and Generic analysis [2]. For standard secret detection, Semgrep also supports custom rules and validator configurations, which can be managed via the Semgrep Editor in the AppSec Platform [3][2][4]. Citations:
Exclude all enabled secret rules from the Semgrep SARIF.
🤖 Prompt for AI Agents |
||
|
|
||
| - name: Summarize findings in the job summary | ||
| if: always() | ||
| # Null-guarded append (repo convention, cf. ci.yml). Renders a severity + per-rule | ||
| # breakdown from the SARIF using the stdlib (no jq dependency). | ||
| run: | | ||
| [ -f semgrep.sarif ] || exit 0 | ||
| [ -n "${GITHUB_STEP_SUMMARY:-}" ] || exit 0 | ||
| # Link the summary to Code scanning. On PRs the analysis is attributed to the PR | ||
| # (merge ref) — NOT the branch ref — so filter by pr:<n>; on push/schedule/dispatch | ||
| # filter by branch. GITHUB_REF_NAME is "<n>/merge" on pull_request events. | ||
| CS_BASE="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/security/code-scanning" | ||
| if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then | ||
| CS_URL="${CS_BASE}?query=is%3Aopen+pr%3A${GITHUB_REF_NAME%/merge}" | ||
| else | ||
| CS_URL="${CS_BASE}?query=is%3Aopen+branch%3A${GITHUB_REF_NAME}" | ||
| fi | ||
| python3 - semgrep.sarif "$GITHUB_STEP_SUMMARY" "$CS_URL" <<'PY' | ||
| import json, sys, collections | ||
| d = json.load(open(sys.argv[1], encoding="utf-8")) | ||
| out = open(sys.argv[2], "a", encoding="utf-8") | ||
| cs_url = sys.argv[3] | ||
| res = [x for r in d.get("runs", []) for x in r.get("results", [])] | ||
| total = len(res) | ||
| sev = collections.Counter((x.get("level") or "warning") for x in res) | ||
| rules = collections.Counter(x.get("ruleId", "?").split(".")[-1] for x in res) | ||
| w = out.write | ||
| w("## Semgrep SAST (report-only)\n\n") | ||
| w(f"**{total}** finding(s) from `auto` (secrets excluded — TruffleHog owns those). " | ||
| f"This check does **not** block; full details in [Security -> Code scanning]({cs_url}).\n\n") | ||
|
Comment on lines
+91
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "Files:"
git ls-files .github/workflows/semgrep.yml | sed -n '1,20p'
echo
echo "Relevant workflow section:"
if [ -f .github/workflows/semgrep.yml ]; then
nl -ba .github/workflows/semgrep.yml | sed -n '1,180p'
else
echo "missing .github/workflows/semgrep.yml"
fi
echo
echo "Search for Code scanning reference and fork SARIF behavior:"
rg -n "fork|pull_request|sarif|Code scanning|Code scanning|code scanning|secrets excluded|TruffleHog|check does" .github/workflows/semgrep.yml .github/workflows || trueRepository: constructorfabric/insight-front Length of output: 275 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "Relevant workflow section:"
if [ -f .github/workflows/semgrep.yml ]; then
awk '{printf "%5d\t%s\n", NR, $0}' .github/workflows/semgrep.yml | sed -n '1,180p'
else
echo "missing .github/workflows/semgrep.yml"
fi
echo
echo "Search for fork/SARIF/Code scanning references:"
grep -En "fork|pull_request|sarif|Code scanning|code scanning|secrets excluded|TruffleHog" .github/workflows/semgrep.yml .github/workflows || trueRepository: constructorfabric/insight-front Length of output: 8271 Do not promise Code Scanning details for fork PRs. The SARIF upload is skipped for fork pull requests, but the job summary always says full details are available in Security -> Code scanning. Make that wording and link conditional on the same upload condition, or state that details are unavailable for fork PRs. 🤖 Prompt for AI Agents |
||
| if total: | ||
| w("| Severity | Count |\n|---|---:|\n") | ||
| for s in ("error", "warning", "note"): | ||
| if sev.get(s): | ||
| w(f"| {s} | {sev[s]} |\n") | ||
| w("\n<details><summary>Findings by rule</summary>\n\n| Count | Rule |\n|---:|---|\n") | ||
| for rid, n in rules.most_common(): | ||
| w(f"| {n} | `{rid}` |\n") | ||
| w("\n</details>\n") | ||
| w("\n_Report-only: becomes blocking when `--error` is added and the baseline is clean._\n") | ||
| PY | ||
|
|
||
| - name: Upload SARIF to GitHub Code Scanning | ||
| # Skip on fork PRs: they receive a read-only token and cannot upload to Code Scanning, | ||
| # which would otherwise red-X this report-only job. | ||
| if: ${{ always() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} | ||
| uses: github/codeql-action/upload-sarif@fb0994ef1c058010acf1efccff928b0a83b1ed54 # v4.32.6 | ||
| with: | ||
| sarif_file: semgrep.sarif | ||
| category: semgrep | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,169 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Trivy SCA | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^|/)(\.github/workflows/trivy\.yml|\.github/workflows/docker\.yml|\.trivyignore|README|.*\.md)$' || true
echo "== trivy workflow =="
if [ -f .github/workflows/trivy.yml ]; then
nl -ba .github/workflows/trivy.yml | sed -n '1,130p'
fi
echo "== docker workflow relevant =="
if [ -f .github/workflows/docker.yml ]; then
nl -ba .github/workflows/docker.yml | sed -n '130,250p'
fi
echo "== trivyignore =="
if [ -f .trivyignore ]; then
nl -ba .trivyignore | sed -n '1,120p'
fi
echo "== search trivy invocations =="
rg -n "docker run|trivy|ignorefile|-w\b|--ignorefile|checkout \(\.trivyignore waivers\)|contents: read" .github/workflows || trueRepository: constructorfabric/insight-front Length of output: 6528 🌐 Web query:
💡 Result: The default location for the Trivy ignore file is a file named.trivyignore located in the current working directory [1][2][3]. You can specify a different ignore file location using the --ignorefile flag [4][2][3]. When using this flag, you must provide the path to your custom ignore file [5]. Key considerations for using --ignorefile: - The path provided to --ignorefile should be reachable by the Trivy process [5]. - In containerized environments, if you are running Trivy as a container, ensure the ignore file is mounted into the container at the path you specify in the --ignorefile flag so that Trivy can access it [5]. - Trivy may not produce a warning or error if the file specified by --ignorefile does not exist or cannot be accessed, so ensure the path is correctly configured [6]. - Note that.trivyignore (and the --ignorefile mechanism) generally applies to scan results; for some scan types (like misconfigurations in specific file formats such as Terraform or Dockerfiles), Trivy also supports inline comments for ignoring specific issues [7]. Citations:
🌐 Web query:
💡 Result: In the Trivy CLI, the default behavior regarding ignore files is as follows: Default Ignore File By default, Trivy automatically looks for a file named.trivyignore in the current working directory [1][2]. This file is used to specify vulnerabilities, misconfigurations, or secrets to be ignored during a scan [3]. Using the --ignorefile Option You can specify a custom ignore file path using the --ignorefile flag [1][4]. 1. Usage: When you provide a path via --ignorefile, Trivy uses that specific file instead of the default.trivyignore [3][5]. 2. Strict Requirement: If you explicitly specify an ignore file using the --ignorefile flag, Trivy expects that file to exist [6]. If the specified file is missing, the scan will fail with a fatal error [6]. This differs from the default behavior, where the absence of a.trivyignore file in the current directory does not cause the scan to fail [6]. 3. Supported Formats: -.trivyignore: The legacy format (plain text) [3][5]. -.trivyignore.yaml (or.yml): A structured YAML format that allows for more granular control, such as ignoring findings based on file paths, PURLs, or expiration dates [3][5]. Note that if you are using the YAML format, you must explicitly provide the path using the --ignorefile flag [3][5]. Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== workflow file sizes =="
wc -l .github/workflows/trivy.yml .github/workflows/docker.yml 2>/dev/null || true
echo "== trivy workflow =="
sed -n '1L,180Lp' .github/workflows/trivy.yml 2>/dev/null | awk '{printf "%5d %s\n", NR, $0}'
echo "== docker workflow relevant =="
sed -n '130L,260Lp' .github/workflows/docker.yml 2>/dev/null | awk '{printf "%5d %s\n", NR, $0}'
echo "== trivyignore =="
if [ -f .trivyignore ]; then
sed -n '1L,160Lp' .trivyignore | awk '{printf "%5d %s\n", NR, $0}'
else
echo ".trivyignore not found"
fi
echo "== relevant searches =="
rg -n "docker run|--scan|trivy|pull|image|repository|fs|sbom|ignorefile|--ignorefile|-w\b|checkout \(\.trivyignore waivers\)|contents: read|# checkout" .github/workflows || trueRepository: constructorfabric/insight-front Length of output: 297 🌐 Web query:
💡 Result: To use a.trivyignore file when running Trivy in a Docker container, you must mount the file into the container and point Trivy to it using the --ignorefile flag [1]. Example Docker Command To scan an image while using a.trivyignore file located in your current directory, use the following command: docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v $(pwd)/.trivyignore:/root/.trivyignore \ -v Citations:
🌐 Web query:
💡 Result: The --ignorefile flag in Trivy is used to specify a file that contains identifiers for vulnerabilities, misconfigurations, secrets, or licenses to be ignored during a scan [1][2]. By default, Trivy looks for a file named.trivyignore [3][4]. Key details regarding the --ignorefile option include: Supported Formats: Trivy supports both.trivyignore (plain text) and.trivyignore.yaml (YAML) files [1]. The YAML format allows for more granular control, such as specifying paths, package URLs (purls), and expiration dates for ignored findings [1]. Configuration File Usage: In addition to the command-line flag, you can set the ignore file path in your Trivy configuration file using the ignorefile setting [3][4]. Experimental Feature: While.trivyignore is standard, the use of.trivyignore.yaml is sometimes noted as requiring explicit specification via the --ignorefile flag, as it may be treated as an experimental feature depending on your specific version [1]. Distinction from Skipping: It is important to distinguish --ignorefile (which filters out specific findings/results) from flags like --skip-files or --skip-dirs (which control which files or directories Trivy traverses or scans entirely) [1][5]. Citations:
🏁 Script executed: #!/bin/bash
set +e
echo "== shell env =="
printf 'SHELL=%s\nPWD=%s\n' "$SHELL" "$PWD"
echo "== files =="
git ls-files .github/workflows/trivy.yml .github/workflows/docker.yml .trivyignore README.md SECURITY.md CLAUDE.md 2>/dev/null
echo "== trivy workflow =="
python3 - <<'PY'
from pathlib import Path
p = Path(".github/workflows/trivy.yml")
print(f"exists={p.exists()} size={p.stat().st_size if p.exists() else 0}")
for i,line in enumerate(p.read_text(errors="replace").splitlines(),1):
print(f"{i:5d} {line}")
PY
echo "== docker workflow =="
python3 - <<'PY'
from pathlib import Path
p = Path(".github/workflows/docker.yml")
print(f"exists={p.exists()} size={p.stat().st_size if p.exists() else 0}")
for i,line in enumerate(p.read_text(errors="replace").splitlines(),1):
if 130 <= i <= 260:
print(f"{i:5d} {line}")
PY
echo "== trivy workflow relevant search =="
python3 - <<'PY'
from pathlib import Path
txt = Path(".github/workflows/trivy.yml").read_text(errors="replace")
for needle in ["docker run", "trivy", "ignorefile", "contents: read", "checkout"]:
print(f"\n-- {needle} --")
for lineno, line in enumerate(txt.splitlines(), 1):
if needle in line:
start=max(1, lineno-3); end=min(len(txt.splitlines()), lineno+5)
for sn in range(start, end+1):
print(f"{sn:5d} {txt.splitlines()[sn-1]}")
PY
echo "== .trivyignore presence and lines =="
python3 - <<'PY'
from pathlib import Path
p = Path(".trivyignore")
print(f"exists={p.exists()} size={p.stat().st_size if p.exists() else 0}")
if p.exists():
for i,line in enumerate(p.read_text(errors="replace").splitlines(),1):
print(f"{i:5d} {line}")
PYRepository: constructorfabric/insight-front Length of output: 26025 🌐 Web query:
💡 Result: In Trivy 0.72.0, the --ignorefile flag is used to specify the file containing ignore rules [1]. The default value for this flag, when it is not explicitly provided, is.trivyignore [1][2][3]. Key points regarding the behavior of --ignorefile: 1. Automatic vs. Explicit Loading: While Trivy automatically looks for.trivyignore in the working directory by default, files with the.yaml or.yml extension (such as.trivyignore.yaml) must generally be explicitly specified using the --ignorefile flag [4][5]. 2. File Parsing: Trivy detects the format based on the file extension [6]. If the specified file ends in.yaml or.yml, Trivy attempts to parse it as a structured YAML configuration [6][4]. Otherwise, it is parsed as a legacy.trivyignore file [6][5]. 3. Missing Files: If you provide a specific path via --ignorefile and the file does not exist, Trivy will treat this as an error and stop execution [7]. This behavior changed in recent versions to prevent silent misconfigurations in CI/CD pipelines [7][8]. If you need to support environments where the file might not be present, ensure the file is created or adjust your pipeline logic to handle its absence [7]. In summary, you do not need to set the flag if you are using the default.trivyignore [1][3]. If you are using.trivyignore.yaml or any other custom filename, you must use --ignorefile to ensure it is loaded correctly [4][5]. Citations:
Make Trivy reads 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Software-composition analysis over the source tree (constructorfabric/insight#1478). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Two passes, matching the org's GitLab trivy-scan component: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # gate — CRITICAL only, blocks. Stop-the-line: a CRITICAL CVE or an embedded secret in a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # dependency manifest must be fixed or waived in `.trivyignore` before merge. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Baseline today: 0 CRITICAL, so the gate starts green. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # report — HIGH/MEDIUM/LOW, never blocks. Findings land in "Security -> Code scanning" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # (SARIF) plus a job-summary table. Baseline today: 10 HIGH / 16 MEDIUM / 3 LOW, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # almost all from build-time tooling declared under `dependencies`. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Scope: this scans the repository (`trivy fs`) — lock file, Dockerfile, configs. It does NOT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # see the image that ships: base-image and OS-package CVEs are covered by the `trivy-image` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # job in docker.yml, which runs against the pushed manifest. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # The report pass deliberately drops the secret scanner (`--scanners vuln,misconfig`): Code | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Scanning alerts on a public repository are world-readable, and Trivy's secret findings quote | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # the surrounding match. Secrets stay in the blocking gate, where TruffleHog is the primary | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # owner anyway (trufflehog.yml). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Dev dependencies are excluded by Trivy's pnpm default — they are not in the shipped bundle. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Add `--include-dev-deps` if we ever want build-time supply-chain coverage here too. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| on: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pull_request: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| branches: [main] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| push: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| branches: [main] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| schedule: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Nightly, 03:41 UTC — after the TruffleHog sweep (03:13) and Semgrep baseline (03:27), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # so a bad night shows up as three separate red checks rather than one pile. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - cron: "41 3 * * *" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| workflow_dispatch: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| concurrency: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| group: ${{ github.workflow }}-${{ github.ref }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cancel-in-progress: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contents: read | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Digest-pinned Trivy, same convention as semgrep.yml / trufflehog.yml. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TRIVY_IMAGE: aquasec/trivy:0.72.0@sha256:cffe3f5161a47a6823fbd23d985795b3ed72a4c806da4c4df16266c02accdd6f | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| gate: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: gate (CRITICAL) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| timeout-minutes: 15 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| persist-credentials: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Trivy fs scan — CRITICAL only (blocking) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # `--ignore-unfixed` keeps the gate actionable: a CRITICAL with no released fix cannot | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # be resolved by the PR author, so it belongs in the report pass, not in a merge block. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Waivers go in `.trivyignore` at the repo root, date-scoped: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # CVE-2026-12345 exp:2026-12-31 # tracked in <issue>, fix queued | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docker run --rm \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -v "${{ github.workspace }}:/src:ro" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$TRIVY_IMAGE" fs \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --scanners vuln,secret,misconfig \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --severity CRITICAL \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --ignore-unfixed \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --exit-code 1 \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --no-progress \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /src | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+57
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== candidate workflows =="
git ls-files '.github/workflows/*' | sed -n '1,120p'
echo
echo "== trivy workflow excerpt =="
if [ -f .github/workflows/trivy.yml ]; then
nl -ba .github/workflows/trivy.yml | sed -n '1,120p'
fi
echo
echo "== docker workflow trivy mentions =="
rg -n -C 4 'trivy|TRIVY|--ignorefile|-w /src|docker run' .github/workflows docker.yml . 2>/dev/null | sed -n '1,220p' || true
echo
echo "== trivyignore files =="
git ls-files | grep -E '(^|/)\.trivyignore$' || true
echo
echo "== changed/files context around .github/workflows/trivy.yml =="
git status --shortRepository: constructorfabric/insight-front Length of output: 411 🌐 Web query:
💡 Result: The default path for the Trivy ignore file is.trivyignore [1][2][3]. When running Trivy in a Docker container, you must ensure the ignore file is accessible to the containerized Trivy process. You can use the --ignorefile flag to specify a custom path, but because Trivy runs inside a container, you must mount the local ignore file into the container using the -v (volume) flag [4]. If you have a file named.trivyignore in your current local directory and wish to use it when scanning, you can run: docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v Citations:
🌐 Web query:
💡 Result: Trivy automatically checks for a file named.trivyignore in your current working directory by default [1]. If this file exists, Trivy will load it without requiring any additional configuration [1]. Key points regarding the ignore file: 1. Default Behavior: Trivy is configured to look for.trivyignore in the directory where the command is executed [2][3][1]. 2. Using --ignorefile: You can explicitly specify a different file or path using the --ignorefile flag (e.g., trivy image --ignorefile path/to/custom-ignore-file my-image:latest) [3][4][1]. 3. Validation: If you use the --ignorefile flag to specify a path, Trivy will verify that the file exists [5]. If the file cannot be found, Trivy will return an error [5][6]. 4. Supported Formats: While the default.trivyignore file is standard, Trivy also supports experimental YAML-based ignore files (e.g.,.trivyignore.yaml), which must be explicitly specified via the --ignorefile flag [7]. You do not need to provide any arguments for Trivy to utilize the.trivyignore file located in your current working directory; it is the default location [2][8][1]. Citations:
🌐 Web query:
💡 Result: By default, Trivy looks for an.trivyignore file in the current working directory [1][2][3]. The --ignorefile flag is used to specify the path to an ignore file if it is located elsewhere or has a different name [1][4]. Additionally, you can configure the path to the ignore file within a Trivy configuration file (typically trivy.yaml) by setting the ignorefile parameter [1][5]. Citations:
Point the By default Trivy loads 🔧 Proposed fix - name: Trivy fs scan — CRITICAL only (blocking)
run: |
docker run --rm \
-v "${{ github.workspace }}:/src:ro" \
+ -w /src \
"$TRIVY_IMAGE" fs \
--scanners vuln,secret,misconfig \
--severity CRITICAL \
--ignore-unfixed \
+ --ignorefile /src/.trivyignore \
--exit-code 1 \
--no-progress \
/src📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| report: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: report (HIGH/MEDIUM/LOW) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| timeout-minutes: 15 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contents: read # checkout | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| security-events: write # upload SARIF to Code Scanning | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| persist-credentials: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Trivy fs scan — HIGH/MEDIUM/LOW (never blocks) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Two output formats from two runs over the same cached DB: SARIF for Code Scanning, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # JSON for the summary table below. `--exit-code 0` on both — this pass only reports. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docker run --rm \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -v "${{ github.workspace }}:/src" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -v /tmp/trivy-cache:/root/.cache \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$TRIVY_IMAGE" fs \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --scanners vuln,misconfig \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --severity HIGH,MEDIUM,LOW \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --exit-code 0 \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --no-progress \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --format sarif --output /src/trivy-fs.sarif \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /src | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docker run --rm \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -v "${{ github.workspace }}:/src" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -v /tmp/trivy-cache:/root/.cache \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$TRIVY_IMAGE" fs \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --scanners vuln,misconfig \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --severity HIGH,MEDIUM,LOW \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --exit-code 0 \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --no-progress \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --format json --output /src/trivy-fs.json \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /src | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Summarize findings in the job summary | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: always() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Null-guarded append (repo convention, cf. ci.yml). Groups by package so the summary | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # reflects the unit of remediation ("bump X") rather than the CVE count. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ -f trivy-fs.json ] || exit 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ -n "${GITHUB_STEP_SUMMARY:-}" ] || exit 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CS_BASE="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/security/code-scanning" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CS_URL="${CS_BASE}?query=is%3Aopen+pr%3A${GITHUB_REF_NAME%/merge}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CS_URL="${CS_BASE}?query=is%3Aopen+branch%3A${GITHUB_REF_NAME}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| python3 - trivy-fs.json "$GITHUB_STEP_SUMMARY" "$CS_URL" <<'PY' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import json, sys, collections | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| d = json.load(open(sys.argv[1], encoding="utf-8")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out = open(sys.argv[2], "a", encoding="utf-8") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cs_url = sys.argv[3] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w = out.write | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vulns, miscfg = [], [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for r in d.get("Results") or []: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vulns += r.get("Vulnerabilities") or [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| miscfg += [(r.get("Target"), m) for m in (r.get("Misconfigurations") or [])] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w("## Trivy SCA (report-only)\n\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w(f"**{len(vulns)}** vulnerabilit(ies) + **{len(miscfg)}** misconfiguration(s) at " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| f"HIGH/MEDIUM/LOW. CRITICAL is handled by the blocking `gate` job. " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| f"Full details in [Security -> Code scanning]({cs_url}).\n\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if vulns: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sev = collections.Counter(v["Severity"] for v in vulns) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w("| Severity | Count |\n|---|---:|\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for s in ("HIGH", "MEDIUM", "LOW"): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if sev.get(s): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w(f"| {s} | {sev[s]} |\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # One row per (package, version): that is what an upgrade actually fixes. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bundles = collections.defaultdict(list) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for v in vulns: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bundles[(v["PkgName"], v.get("InstalledVersion", "?"))].append(v) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rank = {"HIGH": 0, "MEDIUM": 1, "LOW": 2} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w("\n<details><summary>By package</summary>\n\n| Package | Max | CVEs | Fixed in |\n|---|---|---:|---|\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (pkg, ver), items in sorted( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bundles.items(), key=lambda kv: (min(rank.get(i["Severity"], 3) for i in kv[1]), kv[0])): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| worst = min(items, key=lambda i: rank.get(i["Severity"], 3))["Severity"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fixes = sorted({i.get("FixedVersion") or "-" for i in items}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w(f"| `{pkg}@{ver}` | {worst} | {len(items)} | {', '.join(fixes)} |\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w("\n</details>\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if miscfg: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w("\n<details><summary>Misconfigurations</summary>\n\n| Severity | ID | Target | Title |\n|---|---|---|---|\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for target, m in miscfg: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w(f"| {m['Severity']} | `{m['ID']}` | `{target}` | {m.get('Title', '')} |\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w("\n</details>\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PY | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Upload SARIF to GitHub Code Scanning | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Skip on fork PRs: read-only token cannot upload, which would red-X this report-only job. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: ${{ always() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: github/codeql-action/upload-sarif@fb0994ef1c058010acf1efccff928b0a83b1ed54 # v4.32.6 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sarif_file: trivy-fs.sarif | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| category: trivy-fs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: constructorfabric/insight-front
Length of output: 232
🏁 Script executed:
Repository: constructorfabric/insight-front
Length of output: 6385
🌐 Web query:
Trivy container image scan multi-platform image default platform --platform documentation💡 Result:
In Trivy, the --platform flag is used to specify the operating system and architecture (in the format os/architecture) for scanning multi-platform container images [1][2]. Regarding the default behavior and the --platform flag: - Default Behavior: When the --platform flag is not specified, Trivy attempts to load the image based on the platform of the host machine where Trivy is running [1][3]. For example, on a linux/amd64 host, Trivy defaults to scanning the linux/amd64 version of a multi-arch image [1][3]. - Using --platform: If you need to scan a specific architecture or OS variant, you can use the --platform argument to explicitly set the desired platform [1][3]. For example: trivy image --platform=linux/arm64 [YOUR_IMAGE_NAME] Additional Considerations: - Compatibility: The --platform flag is primarily intended for multi-platform images. If you specify a platform that does not exist within the image's manifest, the scan result may depend on how the underlying registry or container engine handles the request, as Trivy aims to mimic the behavior of standard container tools like Docker [4][5]. - Local vs. Remote: When scanning local images (e.g., from Docker Engine), Trivy relies on the container engine to provide the image content [3][6]. When scanning remote images, Trivy interacts directly with the registry, which can sometimes lead to differing behaviors compared to local scanning if platform auto-detection is not aligned [6]. - Configuration: You can also set this parameter in the Trivy configuration file using the image.platform key [7].
Citations:
🌐 Web query:
GitHub Code Scanning SARIF upload max 5 results upload-sarif multiple SARIF files💡 Result:
GitHub Code Scanning supports uploading multiple SARIF files for a single commit [1][2]. To upload multiple files, you must ensure each file represents a unique set of results by assigning each a unique "category" [1][3]. By default, code scanning expects one SARIF file per analysis; uploading a second file for the same category and tool will overwrite the previous results [1][4]. If you attempt to upload multiple files for the same tool and category within a single GitHub Actions workflow run, the configuration is considered invalid, and the run will fail [1][3]. Key details for managing multiple SARIF files: - The
upload-sarifaction'ssarif_fileinput accepts both a single file path and a directory path [1][5]. When a directory is provided, the action recursively searches for and uploads all files ending in.sarif [6]. - Each SARIF file in a directory upload must be identified as a unique set, often by ensuring each file contains a uniquerunAutomationDetails.idif a category is not explicitly provided [4][3]. - While SARIF supports multiple files, GitHub imposes strict limits on the data contained within those files [7][8]. For example, a single run can contain a maximum of 25,000 results, with only the top 5,000 results displayed [7][8]. If a file exceeds these thresholds, it may be rejected or truncated [7][8]. The "5 results" limit mentioned in your query does not exist as a global hard limit for uploads, though specific data objects within the SARIF structure are subject to various hard and soft limits (e.g., maximum results per run, maximum locations per result) [7][9][8].Citations:
Scan the published arm64 image as well.
The workflow builds
linux/amd64andlinux/arm64, but this check resolves the tag from the runner and scans only amd64. Add an explicit arm64 pass with--platform linux/arm64and upload it under a distinct SARIF category so both image architectures are covered by Code Scanning.🤖 Prompt for AI Agents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not required, publishing only amd64
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ktursunov, the current workflow appears to publish both architectures: the build matrix pusheslinux/amd64andlinux/arm64, andmergeassembles them into one multi-arch manifest. As written, the scan covers only the amd64 variant.If arm64 publication is no longer intended, removing the arm64 matrix leg would make this finding inapplicable; otherwise, the separate arm64 scan remains relevant.