name: Security # Self-contained security scan: Semgrep SAST + Trivy filesystem scan. # # Deliberately NOT calling the reusable workflow in security-workflows: # act_runner fetches reusable workflows by cloning them over HTTPS, and git # fetch over HTTPS is broken on this Gitea instance since 2026-08-12 # (`git upload-pack --stateless-rpc` aborts with # BUG("packfile_uris requires sideband-all") and dumps core). The runner only # kept working because it still had a June copy in its action cache. Inlining # removes that dependency entirely. # # For the same reason the sources are pulled as a tar archive instead of via # actions/checkout. Restore the reusable call once the fetch path is fixed. # # Why one job, not two parallel jobs: act_runner v0.6.1 has a race when two # jobs in the same task share a workspace and chown it in parallel. on: push: branches: [main, master] pull_request: schedule: - cron: '0 6 * * 1' workflow_dispatch: env: TRIVY_SEVERITY: 'CRITICAL,HIGH' SEMGREP_EXCLUDE_RULES: '' jobs: scan: name: Security Scan runs-on: ubuntu-latest steps: - name: Checkout sources env: TOKEN: ${{ github.token }} # On pull_request the merge SHA may not be archivable, use the head. REF: ${{ github.event.pull_request.head.sha || github.sha }} SERVER: ${{ github.server_url }} REPO: ${{ github.repository }} run: | set -eu echo "Fetching archive for $REPO @ $REF" curl -sfL --retry 3 --retry-delay 5 \ -H "Authorization: token $TOKEN" \ "$SERVER/$REPO/archive/$REF.tar.gz" -o /tmp/source.tar.gz tar xzf /tmp/source.tar.gz --strip-components=1 rm -f /tmp/source.tar.gz echo "Extracted $(find . -type f | wc -l) files" - name: Set up Python uses: actions/setup-python@v6 with: python-version: '3.x' - name: Install Semgrep run: pip install --no-cache-dir semgrep - name: Install Trivy # Version pinned so the install script does not hit api.github.com to # resolve "latest", which burns the runner's unauthenticated rate limit. # renovate: datasource=github-releases depName=aquasecurity/trivy run: curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin v0.70.0 - name: Run Semgrep SAST run: | args="--config=auto --error --severity=ERROR" if [ -n "$SEMGREP_EXCLUDE_RULES" ]; then for rule in $(echo "$SEMGREP_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. if: always() run: trivy fs --severity "$TRIVY_SEVERITY" --exit-code 1 --ignore-unfixed .