mirror of
https://github.com/TronoSfera/Law.git
synced 2026-05-18 18:13:46 +03:00
183 lines
5.8 KiB
YAML
183 lines
5.8 KiB
YAML
name: security-ci
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
pull_request:
|
|
push:
|
|
branches:
|
|
- master
|
|
- main
|
|
schedule:
|
|
- cron: "17 2 * * 1"
|
|
|
|
permissions:
|
|
contents: read
|
|
security-events: write
|
|
|
|
env:
|
|
BANDIT_MAX_HIGH: "0"
|
|
DEP_MAX_VULNS: "0"
|
|
TRIVY_MAX_HIGH: "0"
|
|
TRIVY_MAX_CRITICAL: "0"
|
|
|
|
jobs:
|
|
sast-and-dependencies:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.12"
|
|
|
|
- name: Install scanners
|
|
run: |
|
|
python -m pip install --upgrade pip
|
|
pip install bandit pip-audit
|
|
|
|
- name: Prepare reports directory
|
|
run: mkdir -p reports/security
|
|
|
|
- name: Run Bandit (SAST)
|
|
run: |
|
|
bandit -r app scripts -f json -o reports/security/bandit.json || true
|
|
|
|
- name: Run pip-audit (dependencies)
|
|
run: |
|
|
pip-audit -r requirements.txt --format json --output reports/security/pip-audit.json || true
|
|
|
|
- name: Build SAST/dependency summary
|
|
id: sast_deps_summary
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
BANDIT_HIGH=$(jq '[.results[]? | select(.issue_severity == "HIGH")] | length' reports/security/bandit.json)
|
|
DEP_VULNS=$(jq '
|
|
if type == "array" then length
|
|
elif has("vulnerabilities") then (.vulnerabilities | length)
|
|
elif has("dependencies") then ([.dependencies[]?.vulns[]?] | length)
|
|
else 0
|
|
end
|
|
' reports/security/pip-audit.json)
|
|
|
|
{
|
|
echo "SAST/Dependency Security Summary"
|
|
echo "bandit.high=${BANDIT_HIGH}"
|
|
echo "deps.vulns=${DEP_VULNS}"
|
|
echo "threshold.bandit.high=${BANDIT_MAX_HIGH}"
|
|
echo "threshold.deps.vulns=${DEP_MAX_VULNS}"
|
|
} | tee reports/security/sast-deps-summary.txt
|
|
|
|
echo "bandit_high=${BANDIT_HIGH}" >> "$GITHUB_OUTPUT"
|
|
echo "dep_vulns=${DEP_VULNS}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Upload SAST/dependency reports
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: security-sast-deps-reports
|
|
path: |
|
|
reports/security/bandit.json
|
|
reports/security/pip-audit.json
|
|
reports/security/sast-deps-summary.txt
|
|
if-no-files-found: error
|
|
retention-days: 30
|
|
|
|
- name: Enforce SAST/dependency thresholds
|
|
run: |
|
|
set -euo pipefail
|
|
BANDIT_HIGH="${{ steps.sast_deps_summary.outputs.bandit_high }}"
|
|
DEP_VULNS="${{ steps.sast_deps_summary.outputs.dep_vulns }}"
|
|
|
|
if [ "${BANDIT_HIGH}" -gt "${BANDIT_MAX_HIGH}" ]; then
|
|
echo "Bandit HIGH findings: ${BANDIT_HIGH} (max ${BANDIT_MAX_HIGH})"
|
|
exit 1
|
|
fi
|
|
if [ "${DEP_VULNS}" -gt "${DEP_MAX_VULNS}" ]; then
|
|
echo "Dependency vulnerabilities: ${DEP_VULNS} (max ${DEP_MAX_VULNS})"
|
|
exit 1
|
|
fi
|
|
|
|
container-scan:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Build backend image
|
|
run: |
|
|
docker build -t law-backend-security:${{ github.sha }} .
|
|
|
|
- name: Prepare reports directory
|
|
run: mkdir -p reports/security
|
|
|
|
- name: Run Trivy image scan (JSON report)
|
|
uses: aquasecurity/trivy-action@0.24.0
|
|
with:
|
|
image-ref: law-backend-security:${{ github.sha }}
|
|
format: json
|
|
output: reports/security/trivy-image.json
|
|
severity: HIGH,CRITICAL
|
|
exit-code: "0"
|
|
|
|
- name: Run Trivy image scan (SARIF)
|
|
uses: aquasecurity/trivy-action@0.24.0
|
|
with:
|
|
image-ref: law-backend-security:${{ github.sha }}
|
|
format: sarif
|
|
output: reports/security/trivy-image.sarif
|
|
severity: HIGH,CRITICAL
|
|
exit-code: "0"
|
|
|
|
- name: Build container scan summary
|
|
id: trivy_summary
|
|
run: |
|
|
set -euo pipefail
|
|
TRIVY_HIGH=$(jq '[.Results[]?.Vulnerabilities[]? | select(.Severity == "HIGH")] | length' reports/security/trivy-image.json)
|
|
TRIVY_CRITICAL=$(jq '[.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL")] | length' reports/security/trivy-image.json)
|
|
|
|
{
|
|
echo "Container Security Summary"
|
|
echo "trivy.high=${TRIVY_HIGH}"
|
|
echo "trivy.critical=${TRIVY_CRITICAL}"
|
|
echo "threshold.trivy.high=${TRIVY_MAX_HIGH}"
|
|
echo "threshold.trivy.critical=${TRIVY_MAX_CRITICAL}"
|
|
} | tee reports/security/trivy-summary.txt
|
|
|
|
echo "trivy_high=${TRIVY_HIGH}" >> "$GITHUB_OUTPUT"
|
|
echo "trivy_critical=${TRIVY_CRITICAL}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Upload Trivy reports
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: security-container-reports
|
|
path: |
|
|
reports/security/trivy-image.json
|
|
reports/security/trivy-image.sarif
|
|
reports/security/trivy-summary.txt
|
|
if-no-files-found: error
|
|
retention-days: 30
|
|
|
|
- name: Upload SARIF to Security tab
|
|
if: always()
|
|
uses: github/codeql-action/upload-sarif@v3
|
|
with:
|
|
sarif_file: reports/security/trivy-image.sarif
|
|
|
|
- name: Enforce container scan thresholds
|
|
run: |
|
|
set -euo pipefail
|
|
TRIVY_HIGH="${{ steps.trivy_summary.outputs.trivy_high }}"
|
|
TRIVY_CRITICAL="${{ steps.trivy_summary.outputs.trivy_critical }}"
|
|
|
|
if [ "${TRIVY_HIGH}" -gt "${TRIVY_MAX_HIGH}" ]; then
|
|
echo "Trivy HIGH findings: ${TRIVY_HIGH} (max ${TRIVY_MAX_HIGH})"
|
|
exit 1
|
|
fi
|
|
if [ "${TRIVY_CRITICAL}" -gt "${TRIVY_MAX_CRITICAL}" ]; then
|
|
echo "Trivy CRITICAL findings: ${TRIVY_CRITICAL} (max ${TRIVY_MAX_CRITICAL})"
|
|
exit 1
|
|
fi
|