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") in upload-pack.c and dumps
core on every fetch. Every checkout therefore failed before the scan
started, which is why all security runs have been red since then.
Reproduced against every repo, from multiple clients, on git 2.52 and
2.55, and on Gitea 1.26.1 as well as 1.26.4. SSH, the web UI and the
API are unaffected — only the smart-HTTP pack transfer dies.
Semgrep and Trivy operate on the working tree and do not need history,
so the sources are pulled as a tar archive over plain HTTP. This sidesteps
upload-pack entirely. Revert to actions/checkout once the fetch path is
fixed upstream.
110 lines
4.8 KiB
YAML
110 lines
4.8 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 sources
|
|
# Deliberately NOT actions/checkout: 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") in upload-pack.c
|
|
# and dumps core on every fetch, so any git-based checkout fails before
|
|
# the scan even starts. Reproducible on every repo, every client, and on
|
|
# git 2.52 as well as 2.55 — SSH and the web UI are unaffected.
|
|
#
|
|
# Semgrep and Trivy only need the working tree, not history, so we pull
|
|
# the source archive over plain HTTP instead. Swap this back to
|
|
# actions/checkout once the upstream fetch path works again.
|
|
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
|
|
# 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.
|
|
#
|
|
# Version pinned: the install script otherwise hits api.github.com to
|
|
# resolve "latest", which is unauthenticated and burns through the
|
|
# self-hosted runner's GitHub rate-limit on each push. Pinning skips
|
|
# the API call entirely. Renovate-bot keeps the version current:
|
|
# 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
|
|
# --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 .
|