feat: critical security hardening for THUNES workflows (#1) #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| # ENFORCEMENT POLICY (Phase 13 Sprint 1.13): | |
| # All quality gates MUST pass before merge. Failures block merges to protect main branch. | |
| # - Ruff linting (code style) | |
| # - Black formatting (consistent formatting) | |
| # - Mypy type checking (type safety) | |
| # - Pytest (205+/228 tests passing) | |
| # This prevents the documentation drift that allowed broken tests to reach main. | |
| permissions: | |
| contents: read # Default read-only (elevated permissions granted per-job) | |
| on: | |
| push: | |
| branches: [main, develop] | |
| pull_request: | |
| branches: [main, develop] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| lint-and-test: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read # Checkout code | |
| pull-requests: write # Codecov PR comments | |
| actions: write # Enable pip cache save/restore | |
| strategy: | |
| matrix: | |
| python-version: ["3.12"] | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a20 # v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: 'pip' | |
| - name: Install dependencies (with retry) | |
| uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3 | |
| with: | |
| timeout_minutes: 5 | |
| max_attempts: 3 | |
| retry_wait_seconds: 30 | |
| command: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements-dev.txt | |
| # Note: Using requirements-dev.txt (core + testing/linting only) | |
| # This reduces CI build time from ~10 min to ~2-3 min by excluding | |
| # heavy research dependencies (vectorbt, optuna, matplotlib, jupyter) | |
| - name: Run ruff (linting) | |
| run: | | |
| ruff check src tests | |
| if [ $? -ne 0 ]; then | |
| echo "::error::Ruff linting failed - fix issues before merge" | |
| exit 1 | |
| fi | |
| - name: Run black (formatting check) | |
| run: | | |
| black --check src tests | |
| if [ $? -ne 0 ]; then | |
| echo "::error::Black formatting check failed - run 'make format' to fix" | |
| exit 1 | |
| fi | |
| - name: Run mypy (type checking) | |
| run: | | |
| mypy src | |
| if [ $? -ne 0 ]; then | |
| echo "::error::Type checking failed - fix type hints before merge" | |
| exit 1 | |
| fi | |
| - name: Run tests with coverage | |
| run: | | |
| set -e # Exit immediately on test failure | |
| pytest -v --cov=src --cov-report=xml --cov-report=term-missing | |
| # Explicit exit code check (pytest returns non-zero on failures) | |
| if [ $? -ne 0 ]; then | |
| echo "::error::Tests failed - blocking merge to protect main branch" | |
| exit 1 | |
| fi | |
| - name: Verify test passage (deployment gate) | |
| if: always() | |
| run: | | |
| if [ ! -f coverage.xml ]; then | |
| echo "::error::No coverage report generated - tests may have crashed" | |
| exit 1 | |
| fi | |
| echo "✅ Tests passed - deployment gate satisfied" | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@edd20798ab377991aad21abfb1f2d5e093b681e8 # v4.0.0 | |
| with: | |
| file: ./coverage.xml | |
| fail_ci_if_error: false |