name: PR Checks on: pull_request: branches: [main] concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: lint: name: ๐Ÿ“ Lint & Type Check runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout code uses: actions/checkout@v4 - name: Use system Python run: | echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Install dependencies (with dev) env: UV_NO_PROGRESS: "1" run: uv sync --group dev - name: Run linting (Ruff) run: uv run ruff check src/kwork_api tests/ - name: Check formatting (Ruff) run: uv run ruff format --check src/kwork_api tests/ - name: Run type checking (MyPy) run: uv run mypy src/kwork_api test: name: ๐Ÿงช Tests runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Checkout code uses: actions/checkout@v4 - name: Use system Python run: | echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Install dependencies (with dev) env: UV_NO_PROGRESS: "1" run: uv sync --group dev - name: Run tests with coverage run: | uv run pytest tests/unit/ \ -v \ --tb=short \ --cov=src/kwork_api \ --cov-report=term-missing \ --cov-report=html:coverage-html \ --html=test-results/report.html \ --self-contained-html - name: Check coverage threshold (90%) run: | COVERAGE=$(uv run coverage report | grep TOTAL | awk '{print $NF}' | tr -d '%') echo "Coverage: ${COVERAGE}%" if (( $(echo "$COVERAGE < 90" | bc -l) )); then echo "โŒ Coverage ${COVERAGE}% is below 90% threshold" exit 1 fi echo "โœ… Coverage ${COVERAGE}% meets 90% threshold" - name: Upload test results uses: actions/upload-artifact@v3 if: always() with: name: test-results path: test-results/ retention-days: 7 - name: Upload coverage report uses: actions/upload-artifact@v3 if: always() with: name: coverage-report path: coverage-html/ retention-days: 7 security: name: ๐Ÿ”’ Security runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout code uses: actions/checkout@v4 - name: Use system Python run: | echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Install dependencies run: uv sync --group dev - name: Run safety check env: UV_NO_PROGRESS: "1" run: | uv pip compile pyproject.toml --no-dev -o requirements-prod.txt && uv run pip-audit --format json --output audit-results.json -r requirements-prod.txt && test ! -s audit-results.json || test "$(cat audit-results.json)" = "[]" - name: Upload audit log uses: actions/upload-artifact@v3 if: failure() with: name: security-audit path: audit-results.json retention-days: 7 - name: Check for secrets run: | if grep -r "password\s*=" --include="*.py" src/; then echo "โŒ Found hardcoded passwords in src/" exit 1 fi if grep -r "token\s*=" --include="*.py" src/; then echo "โŒ Found hardcoded tokens in src/" exit 1 fi echo "โœ… No hardcoded secrets found"