mirror of
https://github.com/ruvnet/RuView
synced 2026-06-09 10:13:17 +00:00
36e70bf229
* security: pin GitHub Actions to SHAs and bump vulnerable npm deps (#442) Addresses confirmed findings from issue #442 (Pentesterra/DevGuard). GitHub Actions — pin all third-party Action references in security-scan.yml and ci.yml to verified commit SHAs (with the matching version in a trailing comment for legibility): * snyk/actions/python -> v1.0.0 * aquasecurity/trivy-action -> v0.36.0 (security-scan.yml + ci.yml) * bridgecrewio/checkov-action -> v12.1347.0 * tenable/terrascan-action -> v1.4.1 * checkmarx/kics-github-action -> v2.1.20 (the action #442 named) * trufflesecurity/trufflehog -> v3.95.2 Verification: grep -rE 'uses:.*@(main|master|latest)$' .github/workflows/ returns no matches. npm deps in ui/mobile — add `overrides` forcing patched versions of the three packages flagged by the DevGuard scanner, regenerate package-lock.json: * @xmldom/xmldom@0.8.11 -> 0.8.13 * node-forge@1.3.3 -> ^1.4.0 (closes 3 HIGH advisories) * picomatch@2.3.1 -> ^2.3.2 (transitive in jest tooling) npm audit totals: 25 -> 22 advisories (5 HIGH -> 2 HIGH). Out of scope for this PR (tracked separately): * Sensing-server unauth REST API surface — opened as #443 pending design-intent confirmation from @ruvnet. * Bearer-token-shaped string in git history — confirmed test seed per repo owner; no rotation required. Refs: #442 Co-Authored-By: claude-flow <ruv@ruv.net> * chore: add Dependabot config for github-actions and ui/mobile npm (#442) Pairs with the SHA pinning from the previous commit so the pinned versions get automated weekly bumps rather than drifting back to mutable refs over time. Scoped to the two ecosystems #442 surfaced findings in: * github-actions (root) — the supply-chain risk * npm (ui/mobile) — the @xmldom/xmldom, node-forge, picomatch advisories Other ecosystems (pip, cargo, desktop UI npm) deliberately omitted — they can be added in a separate PR if desired. Refs: #442 Co-Authored-By: claude-flow <ruv@ruv.net> * chore(dependabot): expand to pip, cargo, and desktop UI npm (#442) Broadens the Dependabot config from the initial 2 ecosystems (github-actions + ui/mobile npm) to cover all 5 package surfaces in the repo so pinned dependencies stay current across the board: + npm /v2/crates/wifi-densepose-desktop/ui (vite advisory live) + pip / (requirements.txt loose pins) + cargo /v2 (no cargo audit in CI yet) Marginal cost is zero — Dependabot only opens PRs when an upstream bump exists, and per-ecosystem pull-request limits cap the noise. Each ecosystem labelled distinctly so PRs route cleanly. Refs: #442 Co-Authored-By: claude-flow <ruv@ruv.net> --------- Co-authored-by: claude-flow <ruv@ruv.net>
350 lines
9.7 KiB
YAML
350 lines
9.7 KiB
YAML
name: Continuous Integration
|
|
|
|
on:
|
|
push:
|
|
branches: [ main, develop, 'feature/*', 'feat/*', 'hotfix/*' ]
|
|
pull_request:
|
|
branches: [ main, develop ]
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
PYTHON_VERSION: '3.11'
|
|
NODE_VERSION: '18'
|
|
REGISTRY: ghcr.io
|
|
IMAGE_NAME: ${{ github.repository }}
|
|
|
|
jobs:
|
|
# Code Quality and Security Checks
|
|
code-quality:
|
|
name: Code Quality & Security
|
|
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: ${{ env.PYTHON_VERSION }}
|
|
cache: 'pip'
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
python -m pip install --upgrade pip
|
|
pip install -r requirements.txt
|
|
pip install black flake8 mypy bandit safety
|
|
|
|
- name: Code formatting check (Black)
|
|
run: black --check --diff src/ tests/
|
|
|
|
- name: Linting (Flake8)
|
|
run: flake8 src/ tests/ --max-line-length=88 --extend-ignore=E203,W503
|
|
|
|
- name: Type checking (MyPy)
|
|
run: mypy src/ --ignore-missing-imports
|
|
|
|
- name: Security scan (Bandit)
|
|
run: bandit -r src/ -f json -o bandit-report.json
|
|
continue-on-error: true
|
|
|
|
- name: Dependency vulnerability scan (Safety)
|
|
run: safety check --json --output safety-report.json
|
|
continue-on-error: true
|
|
|
|
- name: Upload security reports
|
|
uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: security-reports
|
|
path: |
|
|
bandit-report.json
|
|
safety-report.json
|
|
|
|
# Rust Workspace Tests
|
|
rust-tests:
|
|
name: Rust Workspace Tests
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Install Rust toolchain
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: Cache cargo
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cargo/registry
|
|
~/.cargo/git
|
|
v2/target
|
|
key: ${{ runner.os }}-cargo-${{ hashFiles('v2/Cargo.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-cargo-
|
|
|
|
- name: Run Rust tests
|
|
working-directory: v2
|
|
run: cargo test --workspace --no-default-features
|
|
|
|
# Unit and Integration Tests
|
|
test:
|
|
name: Tests
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
matrix:
|
|
python-version: ['3.10', '3.11', '3.12']
|
|
services:
|
|
postgres:
|
|
image: postgres:15
|
|
env:
|
|
POSTGRES_PASSWORD: postgres
|
|
POSTGRES_DB: test_wifi_densepose
|
|
options: >-
|
|
--health-cmd pg_isready
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
ports:
|
|
- 5432:5432
|
|
|
|
redis:
|
|
image: redis:7
|
|
options: >-
|
|
--health-cmd "redis-cli ping"
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
ports:
|
|
- 6379:6379
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Python ${{ matrix.python-version }}
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ matrix.python-version }}
|
|
cache: 'pip'
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
python -m pip install --upgrade pip
|
|
pip install -r requirements.txt
|
|
pip install pytest-cov pytest-xdist
|
|
|
|
- name: Run unit tests
|
|
env:
|
|
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_wifi_densepose
|
|
REDIS_URL: redis://localhost:6379/0
|
|
ENVIRONMENT: test
|
|
run: |
|
|
pytest tests/unit/ -v --cov=src --cov-report=xml --cov-report=html --junitxml=junit.xml
|
|
|
|
- name: Run integration tests
|
|
env:
|
|
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_wifi_densepose
|
|
REDIS_URL: redis://localhost:6379/0
|
|
ENVIRONMENT: test
|
|
run: |
|
|
pytest tests/integration/ -v --junitxml=integration-junit.xml
|
|
|
|
- name: Upload coverage reports
|
|
uses: codecov/codecov-action@v4
|
|
with:
|
|
file: ./coverage.xml
|
|
flags: unittests
|
|
name: codecov-umbrella
|
|
|
|
- name: Upload test results
|
|
uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: test-results-${{ matrix.python-version }}
|
|
path: |
|
|
junit.xml
|
|
integration-junit.xml
|
|
htmlcov/
|
|
|
|
# Performance and Load Tests
|
|
performance-test:
|
|
name: Performance Tests
|
|
runs-on: ubuntu-latest
|
|
needs: [test]
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
cache: 'pip'
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
python -m pip install --upgrade pip
|
|
pip install -r requirements.txt
|
|
pip install locust
|
|
|
|
- name: Start application
|
|
run: |
|
|
uvicorn src.api.main:app --host 0.0.0.0 --port 8000 &
|
|
sleep 10
|
|
|
|
- name: Run performance tests
|
|
run: |
|
|
locust -f tests/performance/locustfile.py --headless --users 50 --spawn-rate 5 --run-time 60s --host http://localhost:8000
|
|
|
|
- name: Upload performance results
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: performance-results
|
|
path: locust_report.html
|
|
|
|
# Docker Build and Test
|
|
docker-build:
|
|
name: Docker Build & Test
|
|
runs-on: ubuntu-latest
|
|
needs: [code-quality, test, rust-tests]
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Extract metadata
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
tags: |
|
|
type=ref,event=branch
|
|
type=ref,event=pr
|
|
type=sha,prefix={{branch}}-
|
|
type=raw,value=latest,enable={{is_default_branch}}
|
|
|
|
- name: Build and push Docker image
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: .
|
|
target: production
|
|
push: true
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
platforms: linux/amd64,linux/arm64
|
|
|
|
- name: Test Docker image
|
|
run: |
|
|
docker run --rm -d --name test-container -p 8000:8000 ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
|
|
sleep 10
|
|
curl -f http://localhost:8000/health || exit 1
|
|
docker stop test-container
|
|
|
|
- name: Run container security scan
|
|
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
|
with:
|
|
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
|
|
format: 'sarif'
|
|
output: 'trivy-results.sarif'
|
|
|
|
- name: Upload Trivy scan results
|
|
uses: github/codeql-action/upload-sarif@v3
|
|
if: always()
|
|
with:
|
|
sarif_file: 'trivy-results.sarif'
|
|
|
|
# API Documentation
|
|
docs:
|
|
name: API Documentation
|
|
runs-on: ubuntu-latest
|
|
needs: [docker-build]
|
|
if: github.ref == 'refs/heads/main'
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
cache: 'pip'
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
python -m pip install --upgrade pip
|
|
pip install -r requirements.txt
|
|
|
|
- name: Generate OpenAPI spec
|
|
run: |
|
|
python -c "
|
|
from src.api.main import app
|
|
import json
|
|
with open('openapi.json', 'w') as f:
|
|
json.dump(app.openapi(), f, indent=2)
|
|
"
|
|
|
|
- name: Deploy to GitHub Pages
|
|
uses: peaceiris/actions-gh-pages@v4
|
|
with:
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
publish_dir: ./docs
|
|
destination_dir: api-docs
|
|
|
|
# Notification
|
|
notify:
|
|
name: Notify
|
|
runs-on: ubuntu-latest
|
|
needs: [code-quality, test, rust-tests, performance-test, docker-build, docs]
|
|
if: always()
|
|
# GitHub Actions does not allow `secrets.X` directly in step-level `if:`
|
|
# expressions — only `env.X`. Promote the secret to env at job scope so
|
|
# the gating expression below is parseable.
|
|
env:
|
|
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
steps:
|
|
- name: Notify Slack on success
|
|
if: ${{ env.SLACK_WEBHOOK_URL != '' && needs.code-quality.result == 'success' && needs.test.result == 'success' && needs.docker-build.result == 'success' }}
|
|
uses: 8398a7/action-slack@v3
|
|
with:
|
|
status: success
|
|
channel: '#ci-cd'
|
|
text: '✅ CI pipeline completed successfully for ${{ github.ref }}'
|
|
|
|
- name: Notify Slack on failure
|
|
if: ${{ env.SLACK_WEBHOOK_URL != '' && (needs.code-quality.result == 'failure' || needs.test.result == 'failure' || needs.docker-build.result == 'failure') }}
|
|
uses: 8398a7/action-slack@v3
|
|
with:
|
|
status: failure
|
|
channel: '#ci-cd'
|
|
text: '❌ CI pipeline failed for ${{ github.ref }}'
|
|
|
|
- name: Create GitHub Release
|
|
if: github.ref == 'refs/heads/main' && needs.docker-build.result == 'success'
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: v${{ github.run_number }}
|
|
name: Release v${{ github.run_number }}
|
|
body: |
|
|
Automated release from CI pipeline
|
|
|
|
**Changes:**
|
|
${{ github.event.head_commit.message }}
|
|
|
|
**Docker Image:**
|
|
`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}`
|
|
draft: false
|
|
prerelease: false |