From 5860b8487d6837ba429db2352e38ae27ff6991f3 Mon Sep 17 00:00:00 2001 From: TPTBusiness Date: Fri, 17 Apr 2026 22:35:01 +0200 Subject: [PATCH] ci: add CodeQL workflow, switch release to release-please, simplify CI - ci.yml: lint + bandit (PyCQA/bandit-action) + pytest test/backtesting/ - release.yml: switch from manual tag-based to release-please auto-changelog - codeql.yml: new weekly + on-push CodeQL Python analysis Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 119 ++++++++++++++-------------------- .github/workflows/codeql.yml | 31 +++++++++ .github/workflows/release.yml | 93 ++------------------------ 3 files changed, 88 insertions(+), 155 deletions(-) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eba123a9..e7b3101e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,86 +2,67 @@ name: CI on: push: - branches: [ main, develop ] - paths-ignore: - - '**.md' - - 'docs/**' - - 'LICENSE' + branches: [master, main] pull_request: - branches: [ main ] - paths-ignore: - - '**.md' - - 'docs/**' - - 'LICENSE' - -env: - PYTHONUNBUFFERED: "1" + branches: [master, main] permissions: contents: read + security-events: write jobs: - test: - name: Test (Python ${{ matrix.python-version }}, ${{ matrix.os }}) - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - python-version: ["3.10", "3.11"] - os: [ubuntu-latest] - + lint: + runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + cache: "pip" - - name: Cache pip dependencies - uses: actions/cache@v4 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-py${{ matrix.python-version }}-pip-${{ hashFiles('**/requirements.txt', '**/pyproject.toml') }} - restore-keys: | - ${{ runner.os }}-py${{ matrix.python-version }}-pip- + - name: Install Ruff + run: pip install ruff - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -e ".[test]" - pip install -r requirements.txt + - name: Lint & Format Check + run: | + ruff check . + ruff format --check . - - name: List installed packages - run: pip list + security: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 - - name: Run tests with coverage - run: | - pytest test/ \ - -v \ - --cov=rdagent \ - --cov-report=xml \ - --cov-report=html \ - --cov-report=term-missing \ - --durations=10 \ - -x + - name: Run Bandit (Security Scan) + uses: PyCQA/bandit-action@v1 + with: + targets: "rdagent/" + severity: medium - - name: Upload coverage to Codecov - if: matrix.python-version == '3.10' && github.ref == 'refs/heads/main' - uses: codecov/codecov-action@v4 - with: - file: ./coverage.xml - flags: unittests - name: codecov-umbrella - fail_ci_if_error: false - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + test: + runs-on: ubuntu-latest + needs: lint + steps: + - uses: actions/checkout@v4 - - name: Upload coverage HTML report - if: always() - uses: actions/upload-artifact@v4 - with: - name: coverage-html-report-py${{ matrix.python-version }} - path: htmlcov/ - retention-days: 7 + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + cache: "pip" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e ".[test]" || pip install -r requirements.txt + pip install pytest pytest-cov + + - name: Run unit tests (no Docker needed) + run: | + pytest test/backtesting/ -v --tb=short + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: false diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..909683c9 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,31 @@ +name: CodeQL + +on: + push: + branches: [master, main] + pull_request: + branches: [master, main] + schedule: + - cron: "0 6 * * 1" # Every Monday at 06:00 UTC + +permissions: + contents: read + security-events: write + actions: read + +jobs: + analyze: + name: Analyze (Python) + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: github/codeql-action/init@v3 + with: + languages: python + queries: security-and-quality + + - uses: github/codeql-action/analyze@v3 + with: + category: "/language:python" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aaef1be9..f59ec22c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,96 +2,17 @@ name: Release on: push: - tags: - - 'v*' - - 'V*' + branches: [master, main] permissions: contents: write - packages: write + pull-requests: write jobs: - release: - name: Create Release + release-please: runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.10" - - - name: Install build tools - run: | - python -m pip install --upgrade pip - pip install build twine - - - name: Build package - run: python -m build - - - name: Check package - run: twine check dist/* - - - name: Verify no closed-source assets - run: | - echo "=== Verifying Release Package ===" - - # Extract and check contents - python -c " - import tarfile - import sys - - with tarfile.open('dist/' + [f for f in __import__('os').listdir('dist') if f.endswith('.tar.gz')][0], 'r:gz') as tar: - names = tar.getnames() - closed_patterns = ['git_ignore_folder', 'results/', '.env', 'models/local', 'prompts/local'] - - found = False - for name in names: - for pattern in closed_patterns: - if pattern in name: - print(f'ERROR: Found closed-source asset: {name}') - found = True - - if found: - sys.exit(1) - print('✓ No closed-source assets in package') - " - - - name: Generate release notes - id: release_notes - run: | - # Try to find changelog for this version - VERSION=${GITHUB_REF#refs/tags/} - CHANGELOG_FILE="changelog/${VERSION}.md" - - if [ -f "$CHANGELOG_FILE" ]; then - echo "body_path=$CHANGELOG_FILE" >> $GITHUB_OUTPUT - elif [ -f "CHANGELOG.md" ]; then - # Extract section for this version from main changelog - echo "body_path=CHANGELOG.md" >> $GITHUB_OUTPUT - else - echo "body_path=" >> $GITHUB_OUTPUT - fi - - - name: Create GitHub Release - uses: softprops/action-gh-release@v2 - with: - body_path: ${{ steps.release_notes.outputs.body_path || '' }} - files: dist/* - draft: false - prerelease: false - generate_release_notes: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Publish to PyPI - if: startsWith(github.ref, 'refs/tags/v') - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} - run: twine upload dist/* + - uses: googleapis/release-please-action@v4 + with: + release-type: python + token: ${{ secrets.GITHUB_TOKEN }}