Skip to content

Merge pull request #52 from DavidOsipov/renovate/node-22.x #70

Merge pull request #52 from DavidOsipov/renovate/node-22.x

Merge pull request #52 from DavidOsipov/renovate/node-22.x #70

Workflow file for this run

name: 🛡️ Bastion Quality Gates
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: '0 0 * * 0' # Weekly on Sunday
workflow_dispatch:
permissions:
pull-requests: read
security-events: write
contents: read
jobs:
Python_Tests:
uses: ./.github/workflows/python-tests.yml
# This workflow now depends on the successful completion of the python-tests workflow
Analyze:
needs: Python_Tests
runs-on: ubuntu-latest
strategy:
matrix:
tool: [bandit, ruff, mypy, flake8, pylint, codeql, snyk, pyright, cyclonedx]
steps:
- name: Checkout code
uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
- name: Set up Python
if: matrix.tool != 'codeql' # Snyk needs Python setup
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55
with:
python-version: '3.13'
- name: Cache pip dependencies
if: matrix.tool != 'codeql'
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684
with:
path: |
~/.cache/pip
~/.cache/pypoetry
/usr/local/lib/python3.13/site-packages
key: ${{ runner.os }}-poetry-${{ matrix.tool }}-${{ hashFiles('**/poetry.lock', 'pyproject.toml') }}
restore-keys: |
${{ runner.os }}-poetry-${{ matrix.tool }}-
${{ runner.os }}-poetry-
- name: Install Poetry
if: matrix.tool != 'codeql'
run: |
pip install poetry
poetry --version
- name: Install project dependencies
if: matrix.tool != 'codeql'
run: |
poetry install --with dev --no-interaction
- name: Install analysis tools
if: matrix.tool != 'codeql' && matrix.tool != 'snyk' && matrix.tool != 'pyright' && matrix.tool != 'cyclonedx'
run: |
poetry run pip install bandit ruff mypy flake8 pylint
poetry run bandit --version
poetry run ruff --version
poetry run mypy --version
poetry run flake8 --version
poetry run pylint --version
- name: Install Node.js for Pyright
if: matrix.tool == 'pyright'
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install Pyright
if: matrix.tool == 'pyright'
run: |
npm install -g pyright
pyright --version
- name: Install CycloneDX
if: matrix.tool == 'cyclonedx'
run: |
poetry run pip install cyclonedx-bom
poetry run cyclonedx-py --version || echo "CycloneDX installed"
- name: Setup Snyk CLI
if: matrix.tool == 'snyk'
uses: snyk/actions/setup@cdb760004ba9ea4d525f2e043745dfe85bb9077e
with:
snyk-version: latest
- name: Run Snyk Security Scan
if: matrix.tool == 'snyk'
env:
SNYK_TOKEN: ${{ secrets.SNYK_SECRET_TOKEN }}
DEBUG: snyk*
run: |
pip install poetry
pip install poetry-plugin-export
poetry export --format requirements.txt --output requirements.txt --with dev
pip install black blake3 click colorama flake8 gmpy2 isort mccabe msgpack-types mypy-extensions pathspec psutil pycodestyle pyflakes setuptools types-requests types-setuptools typing-extensions
snyk test --file=requirements.txt --sarif-file-output=snyk_report.sarif --skip-unresolved || snyk test --file=requirements.txt --sarif-file-output=snyk_report.sarif --skip-unresolved --all-projects
- name: Run Bandit
if: matrix.tool == 'bandit'
run: poetry run bandit -r . -o bandit_report.json --format json --exclude tests,.git || true
- name: Run Ruff
if: matrix.tool == 'ruff'
run: poetry run ruff check . --output-format json --output-file ruff_report.json --exclude tests,.git || true
- name: Run Mypy
if: matrix.tool == 'mypy'
run: poetry run mypy . 2>&1 | tee mypy_report.txt || true
- name: Run Flake8
if: matrix.tool == 'flake8'
run: poetry run flake8 . --output-file flake8_report.txt --format=pylint || true
- name: Run Pylint
if: matrix.tool == 'pylint'
run: poetry run pylint --recursive=y . --output-format=json > pylint_report.json || true
- name: Run Pyright
if: matrix.tool == 'pyright'
run: pyright --outputjson > pyright_report.json || true
- name: Generate Software Bill of Materials (SBOM)
if: matrix.tool == 'cyclonedx'
run: |
poetry run cyclonedx-py -o cyclonedx_report.json -j . || true
- name: Initialize CodeQL
if: matrix.tool == 'codeql'
uses: github/codeql-action/init@main
with:
languages: python
- name: Perform CodeQL Analysis
if: matrix.tool == 'codeql'
uses: github/codeql-action/analyze@main
with:
output: codeql_report.sarif
- name: Upload report artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: ${{ matrix.tool }}-report
path: |
${{ matrix.tool }}_report.*
codeql_report.sarif
SonarQube:
needs: Analyze
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
with:
fetch-depth: 0
- name: Download analysis reports
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e
with:
path: reports
- name: Process reports and prepare for SonarQube
run: |
mkdir -p processed_reports
# Function to safely move reports
safe_move_report() {
local source_dir="$1"
local report_file="$2"
local target_file="$3"
if [ -f "${source_dir}/${report_file}" ]; then
echo "✅ Found ${report_file}"
cp "${source_dir}/${report_file}" "${target_file}"
return 0
else
echo "⚠️ Warning: ${report_file} not found in ${source_dir}"
# For JSON reports, create an empty valid JSON file
if [[ "${report_file}" == *".json" ]]; then
echo "Creating empty JSON file for ${target_file}"
echo "[]" > "${target_file}"
# For SARIF reports, create a minimal valid SARIF file
elif [[ "${report_file}" == *".sarif" ]]; then
echo "Creating minimal SARIF file for ${target_file}"
echo '{"version":"2.1.0","runs":[{"tool":{"driver":{"name":"Missing Report","rules":[]}},"results":[]}]}' > "${target_file}"
# For text reports, create an empty file
else
echo "Creating empty file for ${target_file}"
touch "${target_file}"
fi
return 1
fi
}
# Initialize list of available report paths for SonarQube
sonar_args=""
# Process each report type
safe_move_report "reports/bandit-report" "bandit_report.json" "processed_reports/bandit_report.json"
if [ $? -eq 0 ]; then
sonar_args="${sonar_args} -Dsonar.python.bandit.reportPaths=processed_reports/bandit_report.json"
fi
safe_move_report "reports/ruff-report" "ruff_report.json" "processed_reports/ruff_report.json"
if [ $? -eq 0 ]; then
sonar_args="${sonar_args} -Dsonar.python.ruff.reportPaths=processed_reports/ruff_report.json"
fi
safe_move_report "reports/mypy-report" "mypy_report.txt" "processed_reports/mypy_report.txt"
if [ $? -eq 0 ]; then
sonar_args="${sonar_args} -Dsonar.python.mypy.reportPaths=processed_reports/mypy_report.txt"
fi
safe_move_report "reports/flake8-report" "flake8_report.txt" "processed_reports/flake8_report.txt"
if [ $? -eq 0 ]; then
sonar_args="${sonar_args} -Dsonar.python.flake8.reportPaths=processed_reports/flake8_report.txt"
fi
safe_move_report "reports/pylint-report" "pylint_report.json" "processed_reports/pylint_report.json"
if [ $? -eq 0 ]; then
sonar_args="${sonar_args} -Dsonar.python.pylint.reportPaths=processed_reports/pylint_report.json"
fi
# Process SARIF reports and combine into a single list if both exist
sarif_reports=""
safe_move_report "reports/codeql-report" "codeql_report.sarif" "processed_reports/codeql_report.sarif"
if [ $? -eq 0 ]; then
sarif_reports="processed_reports/codeql_report.sarif"
fi
safe_move_report "reports/snyk-report" "snyk_report.sarif" "processed_reports/snyk_report.sarif"
if [ $? -eq 0 ]; then
if [ -n "$sarif_reports" ]; then
sarif_reports="${sarif_reports},processed_reports/snyk_report.sarif"
else
sarif_reports="processed_reports/snyk_report.sarif"
fi
fi
if [ -n "$sarif_reports" ]; then
sonar_args="${sonar_args} -Dsonar.sarifReportPaths=${sarif_reports}"
fi
safe_move_report "reports/pyright-report" "pyright_report.json" "processed_reports/pyright_report.json"
if [ $? -eq 0 ]; then
sonar_args="${sonar_args} -Dsonar.externalIssuesReportPaths=processed_reports/pyright_report.json"
fi
safe_move_report "reports/cyclonedx-report" "cyclonedx_report.json" "processed_reports/cyclonedx_report.json"
if [ $? -eq 0 ]; then
sonar_args="${sonar_args} -Dsonar.dependencyCheck.jsonReportPath=processed_reports/cyclonedx_report.json"
fi
# Store SonarQube args in environment variable for next step
echo "SONAR_EXTRA_ARGS=${sonar_args}" >> $GITHUB_ENV
# Print summary
echo "✨ Report processing complete. SonarQube will use the following reports:"
echo "${sonar_args}"
- name: Analyze with SonarQube
uses: SonarSource/sonarqube-scan-action@aa494459d7c39c106cc77b166de8b4250a32bb97
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
with:
args: >
-Dsonar.projectKey=DavidOsipov_PostQuantum-Feldman-VSS
-Dsonar.organization=davidosipov
-Dsonar.python.version=3.10-3.13
-Dsonar.languages=python
${{ env.SONAR_EXTRA_ARGS }}