Update .gitea/workflows/security.yml
This commit is contained in:
@@ -28,9 +28,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
token: ${{ secrets.CI_BOT_TOKEN }}
|
token: ${{ secrets.CI_BOT_TOKEN }}
|
||||||
|
|
||||||
- name: Install jq (for parsing JSON)
|
|
||||||
run: sudo apt-get update && sudo apt-get install -y jq
|
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
@@ -39,41 +36,24 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip --root-user-action=ignore
|
python -m pip install --upgrade pip --root-user-action=ignore
|
||||||
# Pin safety to a v2 line where `check --json` is stable
|
pip install --root-user-action=ignore safety bandit semgrep
|
||||||
pip install --root-user-action=ignore "safety>=2,<3" bandit semgrep
|
|
||||||
|
|
||||||
- name: Run Safety check
|
- name: Run Safety check
|
||||||
run: |
|
run: |
|
||||||
if [ -f requirements.txt ]; then
|
safety check -r requirements.txt --json --output safety-report.json || true
|
||||||
safety check -r requirements.txt --json --output safety-report.json || true
|
safety check -r requirements-dev.txt --json --output safety-dev-report.json || true
|
||||||
else
|
|
||||||
echo "[]" > safety-report.json
|
|
||||||
fi
|
|
||||||
if [ -f requirements-dev.txt ]; then
|
|
||||||
safety check -r requirements-dev.txt --json --output safety-dev-report.json || true
|
|
||||||
else
|
|
||||||
echo "[]" > safety-dev-report.json
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Run Bandit security scan
|
- name: Run Bandit security scan
|
||||||
run: |
|
run: |
|
||||||
if [ -d src ]; then
|
bandit -r src/ -f json -o bandit-report.json || true
|
||||||
bandit -r src/ -f json -o bandit-report.json || true
|
|
||||||
else
|
|
||||||
echo '{"results":[]}' > bandit-report.json
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Run Semgrep security scan
|
- name: Run Semgrep security scan
|
||||||
run: |
|
run: |
|
||||||
if [ -d src ]; then
|
semgrep --config=auto src/ --json --output=semgrep-report.json || true
|
||||||
semgrep --config=auto src/ --json --output=semgrep-report.json || true
|
|
||||||
else
|
|
||||||
echo '{"results":[]}' > semgrep-report.json
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Upload security reports
|
- name: Upload security reports
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: security-reports-${{ github.run_number }}
|
name: security-reports-${{ github.run_number }}
|
||||||
path: |
|
path: |
|
||||||
safety-report.json
|
safety-report.json
|
||||||
@@ -85,43 +65,28 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "🔍 Checking for critical vulnerabilities..."
|
echo "🔍 Checking for critical vulnerabilities..."
|
||||||
|
|
||||||
# --- Safety results (robust to array/object formats) ---
|
# Check Safety results
|
||||||
summarize_safety () {
|
if [ -f safety-report.json ]; then
|
||||||
f="$1"
|
critical_count=$(jq '.vulnerabilities | length' safety-report.json 2>/dev/null || echo "0")
|
||||||
if [ -f "$f" ]; then
|
if [ "$critical_count" -gt 0 ]; then
|
||||||
count=$(jq -r '
|
echo "⚠️ Found $critical_count dependency vulnerabilities"
|
||||||
if type=="array" then length
|
jq '.vulnerabilities[] | "- \(.package_name) \(.installed_version): \(.vulnerability_id)"' safety-report.json
|
||||||
else ((.vulnerabilities // []) | length)
|
else
|
||||||
end
|
echo "✅ No dependency vulnerabilities found"
|
||||||
' "$f" 2>/dev/null || echo "0")
|
|
||||||
|
|
||||||
if [ "${count:-0}" -gt 0 ]; then
|
|
||||||
echo "⚠️ Found $count dependency vulnerabilities in $f"
|
|
||||||
jq -r '
|
|
||||||
if type=="array" then
|
|
||||||
.[] | "- \(.package_name // .name) \(.installed_version // ""): \(.vulnerability_id // .advisory // "N/A")"
|
|
||||||
else
|
|
||||||
(.vulnerabilities // [])[] | "- \(.package_name) \(.installed_version): \(.vulnerability_id)"
|
|
||||||
end
|
|
||||||
' "$f" || true
|
|
||||||
else
|
|
||||||
echo "✅ No dependency vulnerabilities found in $f"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
}
|
fi
|
||||||
summarize_safety safety-report.json
|
|
||||||
summarize_safety safety-dev-report.json
|
|
||||||
|
|
||||||
# --- Bandit results (count HIGH severity properly) ---
|
# Check Bandit results
|
||||||
if [ -f bandit-report.json ]; then
|
if [ -f bandit-report.json ]; then
|
||||||
high_severity=$(jq '[.results[]? | select(.issue_severity=="HIGH")] | length' bandit-report.json 2>/dev/null || echo "0")
|
high_severity=$(jq '.results[] | select(.issue_severity == "HIGH") | length' bandit-report.json 2>/dev/null | wc -l)
|
||||||
if [ "${high_severity:-0}" -gt 0 ]; then
|
if [ "$high_severity" -gt 0 ]; then
|
||||||
echo "⚠️ Found $high_severity high-severity security issues"
|
echo "⚠️ Found $high_severity high-severity security issues"
|
||||||
else
|
else
|
||||||
echo "✅ No high-severity security issues found"
|
echo "✅ No high-severity security issues found"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# License compliance check
|
# License compliance check
|
||||||
license-check:
|
license-check:
|
||||||
name: License Compliance
|
name: License Compliance
|
||||||
@@ -133,9 +98,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
token: ${{ secrets.CI_BOT_TOKEN }}
|
token: ${{ secrets.CI_BOT_TOKEN }}
|
||||||
|
|
||||||
- name: Install jq (for parsing JSON)
|
|
||||||
run: sudo apt-get update && sudo apt-get install -y jq
|
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
@@ -145,9 +107,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip --root-user-action=ignore
|
python -m pip install --upgrade pip --root-user-action=ignore
|
||||||
pip install --root-user-action=ignore pip-licenses
|
pip install --root-user-action=ignore pip-licenses
|
||||||
if [ -f requirements.txt ]; then
|
pip install --root-user-action=ignore -r requirements.txt
|
||||||
pip install --root-user-action=ignore -r requirements.txt
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Check licenses
|
- name: Check licenses
|
||||||
run: |
|
run: |
|
||||||
@@ -155,10 +115,11 @@ jobs:
|
|||||||
pip-licenses --format=json --output-file=licenses.json
|
pip-licenses --format=json --output-file=licenses.json
|
||||||
pip-licenses --format=markdown --output-file=licenses.md
|
pip-licenses --format=markdown --output-file=licenses.md
|
||||||
|
|
||||||
# Check for potentially problematic licenses
|
# Check for problematic licenses
|
||||||
problematic_licenses=("GPL" "AGPL" "LGPL")
|
problematic_licenses=("GPL" "AGPL" "LGPL")
|
||||||
|
|
||||||
for license in "${problematic_licenses[@]}"; do
|
for license in "${problematic_licenses[@]}"; do
|
||||||
if grep -iq "$license" licenses.json; then
|
if grep -i "$license" licenses.json; then
|
||||||
echo "⚠️ Found potentially problematic license: $license"
|
echo "⚠️ Found potentially problematic license: $license"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -167,7 +128,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload license report
|
- name: Upload license report
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: license-report-${{ github.run_number }}
|
name: license-report-${{ github.run_number }}
|
||||||
path: |
|
path: |
|
||||||
licenses.json
|
licenses.json
|
||||||
@@ -184,26 +145,25 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
token: ${{ secrets.CI_BOT_TOKEN }}
|
token: ${{ secrets.CI_BOT_TOKEN }}
|
||||||
|
|
||||||
- name: Install jq (for parsing JSON)
|
|
||||||
run: sudo apt-get update && sudo apt-get install -y jq
|
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.PYTHON_VERSION }}
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
|
|
||||||
|
- name: Install pip-check-updates equivalent
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip --root-user-action=ignore
|
||||||
|
pip install --root-user-action=ignore pip-review
|
||||||
|
|
||||||
- name: Check for outdated packages
|
- name: Check for outdated packages
|
||||||
run: |
|
run: |
|
||||||
echo "📦 Checking for outdated packages..."
|
echo "📦 Checking for outdated packages..."
|
||||||
if [ -f requirements.txt ]; then
|
pip install --root-user-action=ignore -r requirements.txt
|
||||||
python -m pip install --upgrade pip --root-user-action=ignore
|
|
||||||
pip install --root-user-action=ignore -r requirements.txt
|
|
||||||
fi
|
|
||||||
pip list --outdated --format=json > outdated-packages.json || true
|
pip list --outdated --format=json > outdated-packages.json || true
|
||||||
|
|
||||||
if [ -s outdated-packages.json ] && [ "$(cat outdated-packages.json)" != "[]" ]; then
|
if [ -s outdated-packages.json ]; then
|
||||||
echo "📋 Outdated packages found:"
|
echo "📋 Outdated packages found:"
|
||||||
jq -r '.[] | "- \(.name): \(.version) -> \(.latest_version)"' outdated-packages.json
|
cat outdated-packages.json | jq -r '.[] | "- \(.name): \(.version) -> \(.latest_version)"'
|
||||||
else
|
else
|
||||||
echo "✅ All packages are up to date"
|
echo "✅ All packages are up to date"
|
||||||
fi
|
fi
|
||||||
@@ -213,39 +173,45 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
if [ -s outdated-packages.json ] && [ "$(cat outdated-packages.json)" != "[]" ]; then
|
if [ -s outdated-packages.json ] && [ "$(cat outdated-packages.json)" != "[]" ]; then
|
||||||
echo "📝 Creating dependency update issue..."
|
echo "📝 Creating dependency update issue..."
|
||||||
|
|
||||||
|
# Create issue body
|
||||||
cat > issue-body.md << 'EOF'
|
cat > issue-body.md << 'EOF'
|
||||||
## 📦 Dependency Updates Available
|
## 📦 Dependency Updates Available
|
||||||
|
|
||||||
The following packages have updates available:
|
The following packages have updates available:
|
||||||
EOF
|
|
||||||
jq -r '.[] | "- **\(.name)**: \(.version) → \(.latest_version)"' outdated-packages.json >> issue-body.md
|
EOF
|
||||||
|
|
||||||
|
cat outdated-packages.json | jq -r '.[] | "- **\(.name)**: \(.version) → \(.latest_version)"' >> issue-body.md
|
||||||
|
|
||||||
cat >> issue-body.md << 'EOF'
|
cat >> issue-body.md << 'EOF'
|
||||||
|
|
||||||
## 🔍 Security Impact
|
## 🔍 Security Impact
|
||||||
|
|
||||||
Please review each update for:
|
Please review each update for:
|
||||||
- Security fixes
|
- Security fixes
|
||||||
- Breaking changes
|
- Breaking changes
|
||||||
- Compatibility issues
|
- Compatibility issues
|
||||||
|
|
||||||
## ✅ Action Items
|
## ✅ Action Items
|
||||||
|
|
||||||
- [ ] Review changelog for each package
|
- [ ] Review changelog for each package
|
||||||
- [ ] Test updates in development environment
|
- [ ] Test updates in development environment
|
||||||
- [ ] Update requirements.txt
|
- [ ] Update requirements.txt
|
||||||
- [ ] Run full test suite
|
- [ ] Run full test suite
|
||||||
- [ ] Deploy to staging for validation
|
- [ ] Deploy to staging for validation
|
||||||
|
|
||||||
---
|
---
|
||||||
*This issue was automatically created by the security workflow.*
|
*This issue was automatically created by the security workflow.*
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "Issue body created. In a real implementation, you would create a Gitea issue here."
|
echo "Issue body created. In a real implementation, you would create a Gitea issue here."
|
||||||
cat issue-body.md
|
cat issue-body.md
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload dependency reports
|
- name: Upload dependency reports
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: dependency-reports-${{ github.run_number }}
|
name: dependency-reports-${{ github.run_number }}
|
||||||
path: |
|
path: |
|
||||||
outdated-packages.json
|
outdated-packages.json
|
||||||
@@ -271,47 +237,33 @@ EOF
|
|||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip --root-user-action=ignore
|
python -m pip install --upgrade pip --root-user-action=ignore
|
||||||
pip install --root-user-action=ignore radon xenon vulture
|
pip install --root-user-action=ignore radon xenon vulture
|
||||||
if [ -f requirements.txt ]; then
|
pip install --root-user-action=ignore -r requirements.txt
|
||||||
pip install --root-user-action=ignore -r requirements.txt
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Calculate code complexity
|
- name: Calculate code complexity
|
||||||
run: |
|
run: |
|
||||||
echo "📊 Calculating code complexity..."
|
echo "📊 Calculating code complexity..."
|
||||||
if [ -d src ]; then
|
radon cc src/ --json > complexity-report.json
|
||||||
radon cc src/ --json > complexity-report.json
|
radon mi src/ --json > maintainability-report.json
|
||||||
radon mi src/ --json > maintainability-report.json
|
|
||||||
echo "🔍 Complexity Summary:"
|
echo "🔍 Complexity Summary:"
|
||||||
radon cc src/ --average
|
radon cc src/ --average
|
||||||
echo "🔧 Maintainability Summary:"
|
|
||||||
radon mi src/
|
echo "🔧 Maintainability Summary:"
|
||||||
else
|
radon mi src/
|
||||||
echo "{}" > complexity-report.json
|
|
||||||
echo "{}" > maintainability-report.json
|
|
||||||
echo "No src/ directory found; skipping detailed radon output."
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Find dead code
|
- name: Find dead code
|
||||||
run: |
|
run: |
|
||||||
echo "🧹 Checking for dead code..."
|
echo "🧹 Checking for dead code..."
|
||||||
if [ -d src ]; then
|
vulture src/ --json > dead-code-report.json || true
|
||||||
vulture src/ --json > dead-code-report.json || true
|
|
||||||
else
|
|
||||||
echo "[]" > dead-code-report.json
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Check for code smells
|
- name: Check for code smells
|
||||||
run: |
|
run: |
|
||||||
echo "👃 Checking for code smells..."
|
echo "👃 Checking for code smells..."
|
||||||
if [ -d src ]; then
|
xenon --max-absolute B --max-modules A --max-average A src/ || true
|
||||||
xenon --max-absolute B --max-modules A --max-average A src/ || true
|
|
||||||
else
|
|
||||||
echo "No src/ directory found; skipping xenon."
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Upload quality reports
|
- name: Upload quality reports
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: code-quality-reports-${{ github.run_number }}
|
name: code-quality-reports-${{ github.run_number }}
|
||||||
path: |
|
path: |
|
||||||
complexity-report.json
|
complexity-report.json
|
||||||
@@ -322,13 +274,10 @@ EOF
|
|||||||
security-summary:
|
security-summary:
|
||||||
name: Security Summary
|
name: Security Summary
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [dependency-scan, license-check, code-quality]
|
needs: [dependency-scan, docker-security-scan, license-check, code-quality]
|
||||||
if: always()
|
if: always()
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Install jq (for parsing JSON)
|
|
||||||
run: sudo apt-get update && sudo apt-get install -y jq
|
|
||||||
|
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
|
|
||||||
@@ -344,36 +293,30 @@ EOF
|
|||||||
echo "## 📊 Results" >> security-summary.md
|
echo "## 📊 Results" >> security-summary.md
|
||||||
echo "" >> security-summary.md
|
echo "" >> security-summary.md
|
||||||
|
|
||||||
# Dependency scan results (support array/object formats)
|
# Dependency scan results
|
||||||
if ls security-reports-*/safety-report.json >/dev/null 2>&1; then
|
if [ -f security-reports-*/safety-report.json ]; then
|
||||||
vuln_count=$(jq -s '
|
vuln_count=$(jq '.vulnerabilities | length' security-reports-*/safety-report.json 2>/dev/null || echo "0")
|
||||||
def countfile:
|
if [ "$vuln_count" -eq 0 ]; then
|
||||||
if type=="array" then length
|
|
||||||
else ((.vulnerabilities // []) | length)
|
|
||||||
end;
|
|
||||||
add | (if type=="number" then . else 0 end)
|
|
||||||
' security-reports-*/safety-report.json 2>/dev/null || echo "0")
|
|
||||||
if [ "${vuln_count:-0}" -eq 0 ]; then
|
|
||||||
echo "- ✅ **Dependency Scan**: No vulnerabilities found" >> security-summary.md
|
echo "- ✅ **Dependency Scan**: No vulnerabilities found" >> security-summary.md
|
||||||
else
|
else
|
||||||
echo "- ⚠️ **Dependency Scan**: ${vuln_count} vulnerabilities found" >> security-summary.md
|
echo "- ⚠️ **Dependency Scan**: $vuln_count vulnerabilities found" >> security-summary.md
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "- ❓ **Dependency Scan**: Results not available" >> security-summary.md
|
echo "- ❓ **Dependency Scan**: Results not available" >> security-summary.md
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Docker scan results (Trivy removed)
|
# Docker scan results (removed Trivy)
|
||||||
echo "- ⏭️ **Docker Scan**: Skipped (Trivy removed)" >> security-summary.md
|
echo "- ⏭️ **Docker Scan**: Skipped (Trivy removed)" >> security-summary.md
|
||||||
|
|
||||||
# License check results
|
# License check results
|
||||||
if ls license-report-*/licenses.json >/dev/null 2>&1; then
|
if [ -f license-report-*/licenses.json ]; then
|
||||||
echo "- ✅ **License Check**: Completed" >> security-summary.md
|
echo "- ✅ **License Check**: Completed" >> security-summary.md
|
||||||
else
|
else
|
||||||
echo "- ❓ **License Check**: Results not available" >> security-summary.md
|
echo "- ❓ **License Check**: Results not available" >> security-summary.md
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Code quality results
|
# Code quality results
|
||||||
if ls code-quality-reports-*/complexity-report.json >/dev/null 2>&1; then
|
if [ -f code-quality-reports-*/complexity-report.json ]; then
|
||||||
echo "- ✅ **Code Quality**: Analyzed" >> security-summary.md
|
echo "- ✅ **Code Quality**: Analyzed" >> security-summary.md
|
||||||
else
|
else
|
||||||
echo "- ❓ **Code Quality**: Results not available" >> security-summary.md
|
echo "- ❓ **Code Quality**: Results not available" >> security-summary.md
|
||||||
@@ -388,6 +331,6 @@ EOF
|
|||||||
|
|
||||||
- name: Upload security summary
|
- name: Upload security summary
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: security-summary-${{ github.run_number }}
|
name: security-summary-${{ github.run_number }}
|
||||||
path: security-summary.md
|
path: security-summary.md
|
||||||
|
Reference in New Issue
Block a user