Skip to content

Security Analysis & Linting #11

Security Analysis & Linting

Security Analysis & Linting #11

name: Security Analysis & Linting
on:
push:
branches: [master, main]
pull_request:
branches: [master, main]
schedule:
# Run weekly on Sundays at midnight
- cron: '0 0 * * 0'
jobs:
lint:
name: Lint & Format Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ruff mypy
- name: Run Ruff linter
run: ruff check src/ --output-format=github
- name: Run Ruff formatter check
run: ruff format src/ --check
- name: Run mypy type checking
run: mypy src/ --ignore-missing-imports --no-error-summary || true
sast:
name: Python SAST (Bandit)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Bandit
run: pip install bandit[toml]
- name: Run Bandit SAST scan
run: |
bandit -r src/ -f json -o bandit-report.json || true
bandit -r src/ -f txt -o bandit-report.txt || true
bandit -r src/ --severity-level medium --confidence-level medium
- name: Upload Bandit report
uses: actions/upload-artifact@v4
if: always()
with:
name: bandit-sast-report
path: |
bandit-report.json
bandit-report.txt
semgrep:
name: Semgrep SAST
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Semgrep
run: semgrep scan --config auto --config p/python --config p/security-audit --json -o semgrep-report.json src/ || true
- name: Run Semgrep (text output)
run: semgrep scan --config auto --config p/python --config p/security-audit src/
- name: Upload Semgrep report
uses: actions/upload-artifact@v4
if: always()
with:
name: semgrep-sast-report
path: semgrep-report.json
sonarqube:
name: SonarQube Local Analysis
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-cov
pip install -e .
- name: Run tests with coverage
run: |
pytest --cov=src/growmcp --cov-report=xml:coverage.xml || true
continue-on-error: true
- name: Install SonarScanner
run: |
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3006-linux.zip
unzip sonar-scanner-cli-5.0.1.3006-linux.zip
echo "$PWD/sonar-scanner-5.0.1.3006-linux/bin" >> $GITHUB_PATH
- name: Run SonarScanner (Local Analysis)
run: |
sonar-scanner \
-Dsonar.projectKey=growmcp \
-Dsonar.projectName="Groww MCP Server" \
-Dsonar.sources=src/growmcp \
-Dsonar.python.version=3.11 \
-Dsonar.python.coverage.reportPaths=coverage.xml \
-Dsonar.exclusions="**/__pycache__/**,**/*.pyc,**/.venv/**" \
-Dsonar.qualitygate.wait=false \
-Dsonar.scanner.dumpToFile=sonar-report.properties \
|| true
- name: Upload SonarScanner report
uses: actions/upload-artifact@v4
if: always()
with:
name: sonar-local-report
path: |
sonar-report.properties
.scannerwork/
dependency-check:
name: Dependency Security Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install pip-audit
run: pip install pip-audit
- name: Install project dependencies
run: pip install -e .
- name: Run pip-audit
run: pip-audit --desc --format json --output pip-audit-report.json || true
- name: Run pip-audit (text output)
run: pip-audit --desc
- name: Upload pip-audit report
uses: actions/upload-artifact@v4
if: always()
with:
name: dependency-audit-report
path: pip-audit-report.json
secrets-scan:
name: Secret Detection
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Gitleaks
run: |
wget https://github.com/gitleaks/gitleaks/releases/download/v8.18.4/gitleaks_8.18.4_linux_x64.tar.gz
tar -xzf gitleaks_8.18.4_linux_x64.tar.gz
chmod +x gitleaks
- name: Run Gitleaks
run: ./gitleaks detect --source . --report-format json --report-path gitleaks-report.json -v || true
- name: Upload Gitleaks report
uses: actions/upload-artifact@v4
if: always()
with:
name: gitleaks-secrets-report
path: gitleaks-report.json
docker-lint:
name: Dockerfile Lint (Hadolint)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Hadolint
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Dockerfile
format: json
output-file: hadolint-report.json
failure-threshold: warning
continue-on-error: true
- name: Run Hadolint (text output)
run: docker run --rm -i hadolint/hadolint < Dockerfile || true
- name: Upload Hadolint report
uses: actions/upload-artifact@v4
if: always()
with:
name: hadolint-report
path: hadolint-report.json
docker-security:
name: Docker Image Security (Trivy)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Docker image
run: docker build -t growmcp:scan .
continue-on-error: true
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'growmcp:scan'
format: 'json'
output: 'trivy-image-report.json'
severity: 'CRITICAL,HIGH,MEDIUM'
vuln-type: 'os,library'
continue-on-error: true
- name: Run Trivy (table output)
uses: aquasecurity/trivy-action@master
with:
image-ref: 'growmcp:scan'
format: 'table'
severity: 'CRITICAL,HIGH,MEDIUM'
continue-on-error: true
- name: Upload Trivy report
uses: actions/upload-artifact@v4
if: always()
with:
name: trivy-image-report
path: trivy-image-report.json
docker-filesystem-scan:
name: Docker Filesystem Scan (Trivy)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Trivy filesystem scan
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'json'
output: 'trivy-fs-report.json'
severity: 'CRITICAL,HIGH,MEDIUM'
continue-on-error: true
- name: Run Trivy filesystem (table output)
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'table'
severity: 'CRITICAL,HIGH,MEDIUM'
- name: Scan Dockerfile for misconfigurations
uses: aquasecurity/trivy-action@master
with:
scan-type: 'config'
scan-ref: '.'
format: 'table'
severity: 'CRITICAL,HIGH,MEDIUM'
continue-on-error: true
- name: Upload Trivy filesystem report
uses: actions/upload-artifact@v4
if: always()
with:
name: trivy-filesystem-report
path: trivy-fs-report.json