Files
security-workflows/.gitea/workflows/security-scan.yml
T
renovate-bot 27c4db980e fix(scan): merge semgrep + trivy into one job to avoid act_runner race
act_runner v0.6.1 fails when 2 jobs in the same task chown the shared workspace in parallel. Sequential steps inside one job sidestep the issue.

Trivy step uses if: always() so both tools surface findings in a single run.
2026-05-11 23:11:39 +00:00

80 lines
3.1 KiB
YAML

name: Security Scan (reusable)
# Reusable workflow consumed by per-repo security.yml stubs across the
# Hellion stack. Runs Semgrep SAST + Trivy filesystem scan sequentially
# inside a single job. Either tool failing fails the calling workflow.
#
# Why one job, not two parallel jobs:
# act_runner v0.6.1 has a race condition when two jobs in the same task
# share a workspace and chown it in parallel — one container never gets
# /var/run/act/ provisioned and silent-fails. Sequential steps avoid it.
on:
workflow_call:
inputs:
severity:
description: 'Trivy severity threshold (e.g. CRITICAL,HIGH or just CRITICAL)'
required: false
type: string
default: 'CRITICAL,HIGH'
semgrep-config:
description: 'Semgrep config (default auto detects rules per language)'
required: false
type: string
default: 'auto'
semgrep-exclude-rules:
description: 'Semgrep rule IDs to exclude, comma-separated (e.g. csharp.lang.security.sqli.csharp-sqli)'
required: false
type: string
default: ''
jobs:
scan:
name: Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install Semgrep
run: pip install --no-cache-dir semgrep
- name: Install Trivy
# Direct install via the official upstream script. The aquasecurity/
# trivy-action wrapper does nested checkouts and auth-juggling that
# does not play well with Self-Hosted Gitea Actions, this is more
# robust and a smaller surface.
run: curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin
- name: Run Semgrep SAST
# --config=auto pulls language-appropriate rule packs from semgrep.dev
# without requiring an account. --error makes the step fail when ERROR
# findings exist. WARNING-level rules still run for visibility but do
# not fail the build (they would dominate the noise).
# Per-repo rule exclusion via the semgrep-exclude-rules input.
env:
EXCLUDE_RULES: ${{ inputs.semgrep-exclude-rules }}
run: |
args="--config=${{ inputs.semgrep-config }} --error --severity=ERROR"
if [ -n "$EXCLUDE_RULES" ]; then
for rule in $(echo "$EXCLUDE_RULES" | tr ',' ' '); do
args="$args --exclude-rule=$rule"
done
fi
echo "Running: semgrep scan $args"
semgrep scan $args
- name: Run Trivy filesystem scan
# if: always() — surface Trivy findings even when Semgrep fails first,
# so a single run gives the full combined picture.
# Scans dependency manifests (NuGet, npm, package-lock etc.) against
# the NVD CVE database. --ignore-unfixed skips findings that have
# no patched version available so we focus on actionable items.
if: always()
run: trivy fs --severity ${{ inputs.severity }} --exit-code 1 --ignore-unfixed .